{"id":2230221,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2230221/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/20260429132902.2452529-1-michiel@synopsys.com/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/1.1/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<20260429132902.2452529-1-michiel@synopsys.com>","date":"2026-04-29T13:29:02","name":"RISC-V: Extract fusion logic to riscv-fusion.cc","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"914f29a59a2a37027b78de42f2d1943bac67ca94","submitter":{"id":93030,"url":"http://patchwork.ozlabs.org/api/1.1/people/93030/?format=json","name":"Michiel Derhaeg","email":"Michiel.Derhaeg@synopsys.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/20260429132902.2452529-1-michiel@synopsys.com/mbox/","series":[{"id":502059,"url":"http://patchwork.ozlabs.org/api/1.1/series/502059/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=502059","date":"2026-04-29T13:29:02","name":"RISC-V: Extract fusion logic to riscv-fusion.cc","version":1,"mbox":"http://patchwork.ozlabs.org/series/502059/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2230221/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2230221/checks/","tags":{},"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256\n header.s=pfptdkimsnps header.b=LyM5t4EA;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256\n header.s=mail header.b=Ly3bZuE/;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256\n header.s=pfptdkimsnps header.b=LyM5t4EA;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256\n header.s=mail header.b=Ly3bZuE/","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=synopsys.com","sourceware.org; spf=pass smtp.mailfrom=synopsys.com","server2.sourceware.org;\n arc=none smtp.remote-ip=148.163.156.19"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g5J7c5Fnsz1yHX\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 23:29:47 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id EF53A4BB1C1D\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 13:29:44 +0000 (GMT)","from mx0a-00230701.pphosted.com (mx0a-00230701.pphosted.com\n [148.163.156.19])\n by sourceware.org (Postfix) with ESMTPS id 0B91A4B9DB56\n for <gcc-patches@gcc.gnu.org>; Wed, 29 Apr 2026 13:29:04 +0000 (GMT)","from pps.filterd (m0297266.ppops.net [127.0.0.1])\n by mx0a-00230701.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n 63TDPTvU2301861; Wed, 29 Apr 2026 06:29:03 -0700","from smtprelay-out1.synopsys.com (smtprelay-out1.synopsys.com\n [149.117.87.133])\n by mx0a-00230701.pphosted.com (PPS) with ESMTPS id 4duj9pg8md-1\n (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);\n Wed, 29 Apr 2026 06:29:03 -0700 (PDT)","from mailhost.synopsys.com (badc-mailhost1.synopsys.com\n [10.192.0.17])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits)\n client-signature RSA-PSS (2048 bits))\n (Client CN \"mailhost.synopsys.com\", Issuer \"SNPSica2\" (verified OK))\n by smtprelay-out1.synopsys.com (Postfix) with ESMTPS id D65E0401F2;\n Wed, 29 Apr 2026 13:29:02 +0000 (UTC)","from us01arcgnu3.synopsys.com (unknown [10.194.34.166])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (Client did not present a certificate)\n by mailhost.synopsys.com (Postfix) with ESMTPS id 49901A00CA;\n Wed, 29 Apr 2026 13:29:02 +0000 (UTC)","by us01arcgnu3.synopsys.com (Postfix, from userid 10074339)\n id 0FAD62441D3DE; Wed, 29 Apr 2026 06:29:02 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org EF53A4BB1C1D","OpenDKIM Filter v2.11.0 sourceware.org 0B91A4B9DB56"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 0B91A4B9DB56","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 0B91A4B9DB56","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777469345; cv=none;\n b=iP0Z4RUgO0z6o3NT3WtMnOU7HJ4CH689J48AwxC1m7jSIvMqcXAAVh68Se9tBYs1N7hL+8Yu+76xhpqzeD3USW9m4Su2WAV1pdXkdmAvYwQ6XO0KZwVdLnMtCjWy+oMcqCAfdPdftuz63sBigLC+HhXW8r3L/Qo2lT0A/f7jmPY=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777469345; c=relaxed/simple;\n bh=aAZzaGaUxWqHiR3a60peGpSwmS/SEVeuho86Mk8hLsE=;\n h=DKIM-Signature:DKIM-Signature:From:To:Subject:Date:Message-Id:\n MIME-Version;\n b=mtFu4o0lgd9GM+3v6Z2ZXBlXMnT7ASFy/qwv+WCRQrkKIcTX9JISrlNZQhb1RbTaaYLitJ9OHMHN9eALwMGOmxNx2+3xdCI0gggONs/+/q++II4LV8sgSRq3+KJdhcCBbq3ehLj//rupxDXNXL8gpvZ1wJUP6IKESwFiZhVW5p0=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=synopsys.com; h=\n cc:content-transfer-encoding:date:from:message-id:mime-version\n :subject:to; s=pfptdkimsnps; bh=jni10CeAnT9zR/NOpfHJRXDoi8id0nfP\n k4nQm1ylDOc=; b=LyM5t4EAHP2Sqk3OljQAaeREW24hH6ljzcsvBAMVPfD7q0eQ\n gorvi6+LtqKCSrhD2L3PyREuvWdNopZ8otRy8ZiKYf8Ti9WId/5UzgnD9HrHPPil\n wwLaEnIGb6nuzPyeDdDPoC5ePhTdJCDgZJnf6rhGSuYpOeYZ2fpX0782we8xN/mI\n GoXr1dCqaPKoQ9TT1YFjwqShqJ2oWQQCYJCvQei4cegFovN6oeF5kzP/GGfs/oS5\n 97jJmchRWC0J390QiFFQa43ghEi68gpXvRnYyedZTELsLgOYfiLiauQPxSUiWgk/\n SNi7AaKza+/L171Mrf9ZaMTwyKJ0mQ1Mz8gyQg==","v=1; a=rsa-sha256; c=relaxed/simple; d=synopsys.com; s=mail;\n t=1777469342; bh=aAZzaGaUxWqHiR3a60peGpSwmS/SEVeuho86Mk8hLsE=;\n h=From:To:Cc:Subject:Date:From;\n b=Ly3bZuE/UW/ss0shTWRiPmImNq/1iL4T0LuD2f36p2f1ua/q/m/UiR3UOKOaLs3YO\n oBNIzYkOTb9ln0SSXON++/Lyufq3tdZh6VAC8QNj1dP1oSxZ5uqipOF0e8udfmzkbb\n Nh6TRhOsqOtP9smotY/OBHx8SpalDaRZNtEH3zw4V3PixngcO5sYF4ZjfTQMnsMq1m\n vzSrPFPaZmk6SgVpiz3HeHxxk1mfMolEWT7OE30+w0FJDNtflmTfo8hKkck2zzJTa/\n d6PRpKxlpvKNpqlgGe40uBJXrONFs223T+YwwLYHNDlFVURdBaHoHMb8GNt66d/9Qy\n bAO2gclFwVQ2g=="],"X-SNPS-Relay":"synopsys.com","From":"Michiel Derhaeg <Michiel.Derhaeg@synopsys.com>","To":"jeffrey.law@oss.qualcomm.com","Cc":"gcc-patches@gcc.gnu.org","Subject":"[PATCH] RISC-V: Extract fusion logic to riscv-fusion.cc","Date":"Wed, 29 Apr 2026 06:29:02 -0700","Message-Id":"<20260429132902.2452529-1-michiel@synopsys.com>","X-Mailer":"git-send-email 2.37.1","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Proofpoint-ORIG-GUID":"st4aSPBaakYBYeO2VnE9ZV89IyCMxVUc","X-Proofpoint-GUID":"st4aSPBaakYBYeO2VnE9ZV89IyCMxVUc","X-Proofpoint-Spam-Details-Enc":"AW1haW4tMjYwNDI5MDEzNiBTYWx0ZWRfXwsPNCjAgHgkW\n VNdEzcvkvrlAqgW7/5iMF6LBAopgBZJUWui2dNSUboJ1CEt2CUOMCN9zNjZPK/QgiGgH6S7aelN\n GBQF2HVaU792pt/wTS2pqAVjn00L/frKxz0qgezvTfsXUDy1IFZLLyfCyWNZes8GFVGBmOcC1sG\n EbQEHiLB/+G+RTcCTjQVMA4J4PQWsL8y+3GDbKagymkbBUz2K/+KWNLS5YgW34C2guT7h2DpEx4\n h/d9TckC7QscxO8guOKYkMWyevPYZ0OC8rU7LQT14EeFkaFez7SDm3jzplm5BmaYNuGHDV+vnA4\n jh6JwBIA6TfaFjVTTA4CQHkLnZTlNxoMsE2m2ZrUAc3epScYz26t/pF14pVjJ7PjIWvr5qXmbG0\n TFSPVWdUn3sBX05phptghqXuGPh9tWaduA+derYILfyNzhlGBS/xs6vTyToECINJVk9WlpRCipN\n k40CN0Y1PYWBjBskPHw==","X-Authority-Analysis":"v=2.4 cv=RJyD2Yi+ c=1 sm=1 tr=0 ts=69f2079f cx=c_pps\n a=t4gDRyhI9k+KZ5gXRQysFQ==:117 a=t4gDRyhI9k+KZ5gXRQysFQ==:17\n a=A5OVakUREuEA:10 a=qPHU084jO2kA:10 a=VkNPw1HP01LnGYTKEx00:22\n a=tU_645BZ7FZt8VqRJtHG:22 a=Wo6YDfOMAEstGd-0DxeT:22 a=mDV3o1hIAAAA:8\n a=jIQo8A4GAAAA:8 a=You7alB4s4cj0Mz1If8A:9","X-Proofpoint-Virus-Version":"vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49\n definitions=2026-04-28_05,2026-04-28_01,2025-10-01_01","X-Proofpoint-Spam-Details":"rule=outbound_active_cloned_notspam\n policy=outbound_active_cloned score=0 adultscore=0 malwarescore=0\n impostorscore=0 bulkscore=0 suspectscore=0 clxscore=1015 lowpriorityscore=0\n priorityscore=1501 spamscore=0 phishscore=0 classifier=typeunknown\n authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1\n engine=8.22.0-2604200000 definitions=main-2604290136","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"Simple non-functional change.\n\nI'm planning to add many more cases to riscv_macro_fusion_pair_p so it\nis moved to a separate source file to prevent riscv.cc from becoming\ntoo unwieldy.\n\nAlso added some tests to verify the cases that are actually tied to\nmtunes present upstream. Unfortunately, many of them are not.\n\nRegtested for rv32gc & rv64gc with the new tests included in the baseline.\n\ngcc/ChangeLog:\n\n        * config.gcc: Added riscv-fusion.o\n        * config/riscv/riscv-protos.h (enum riscv_fusion_pairs):\n        (riscv_macro_fusion_p): Added declaration.\n        (riscv_macro_fusion_pair_p): Idem.\n        (riscv_get_fusible_ops): Idem.\n        * config/riscv/riscv.cc (enum riscv_fusion_pairs):\n        (riscv_macro_fusion_p): Moved to riscv-fusion.cc\n        (riscv_fusion_enabled_p): Idem.\n        (riscv_set_is_add): Idem.\n        (riscv_set_is_addi): Idem.\n        (riscv_set_is_adduw): Idem.\n        (riscv_set_is_shNadd): Idem.\n        (riscv_set_is_shNadduw): Idem.\n        (riscv_macro_fusion_pair_p): Idem.\n        (riscv_get_fusible_ops): New function to access tune_param->fusible_ops\n        from riscv-fusion.cc.\n        * config/riscv/t-riscv: Added riscv-fusion.cc\n        * config/riscv/riscv-fusion.cc: New file.\n\ngcc/testsuite/ChangeLog:\n\n        * gcc.target/riscv/fusion-auipc-addi.c: New test.\n        * gcc.target/riscv/fusion-lui-addi.c: New test.\n        * gcc.target/riscv/fusion-zexth.c: New test.\n        * gcc.target/riscv/fusion-zextw.c: New test.\n\nSigned-off-by: Michiel Derhaeg <michiel@synopsys.com>\n---\n gcc/config.gcc                                |   2 +-\n gcc/config/riscv/riscv-fusion.cc              | 762 ++++++++++++++++++\n gcc/config/riscv/riscv-protos.h               |  24 +\n gcc/config/riscv/riscv.cc                     | 745 +----------------\n gcc/config/riscv/t-riscv                      |   7 +\n .../gcc.target/riscv/fusion-auipc-addi.c      |  11 +\n .../gcc.target/riscv/fusion-lui-addi.c        |  15 +\n gcc/testsuite/gcc.target/riscv/fusion-zexth.c |  15 +\n gcc/testsuite/gcc.target/riscv/fusion-zextw.c |  15 +\n 9 files changed, 854 insertions(+), 742 deletions(-)\n create mode 100644 gcc/config/riscv/riscv-fusion.cc\n create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-auipc-addi.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-lui-addi.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-zexth.c\n create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-zextw.c","diff":"diff --git a/gcc/config.gcc b/gcc/config.gcc\nindex 8fe99616f82..50d8b75acf2 100644\n--- a/gcc/config.gcc\n+++ b/gcc/config.gcc\n@@ -572,7 +572,7 @@ riscv*)\n \textra_objs=\"riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o\"\n \textra_objs=\"${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o riscv-vect-permconst.o\"\n \textra_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\"\n-\textra_objs=\"${extra_objs} thead.o riscv-target-attr.o riscv-zicfilp.o riscv-bclr-lowest-set-bit.o riscv-opt-popretz.o\"\n+\textra_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\"\n \td_target_objs=\"riscv-d.o\"\n \textra_headers=\"riscv_vector.h riscv_crypto.h riscv_bitmanip.h riscv_th_vector.h sifive_vector.h andes_vector.h\"\n \ttarget_gtfiles=\"$target_gtfiles \\$(srcdir)/config/riscv/riscv-vector-builtins.cc\"\ndiff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc\nnew file mode 100644\nindex 00000000000..5bce3eda0a6\n--- /dev/null\n+++ b/gcc/config/riscv/riscv-fusion.cc\n@@ -0,0 +1,762 @@\n+/* Subroutines used for instruction fusion for RISC-V.\n+   Copyright (C) 2026 Free Software Foundation, Inc.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify\n+it under the terms of the GNU General Public License as published by\n+the Free Software Foundation; either version 3, or (at your option)\n+any later version.\n+\n+GCC is distributed in the hope that it will be useful,\n+but WITHOUT ANY WARRANTY; without even the implied warranty of\n+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+GNU General Public License for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3.  If not see\n+<http://www.gnu.org/licenses/>.  */\n+\n+#define IN_TARGET_CODE 1\n+\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"backend.h\"\n+#include \"target.h\"\n+#include \"rtl.h\"\n+#include \"regs.h\"\n+#include \"insn-config.h\"\n+#include \"recog.h\"\n+#include \"function.h\"\n+#include \"memmodel.h\"\n+#include \"emit-rtl.h\"\n+#include \"tm_p.h\"\n+#include \"riscv-protos.h\"\n+\n+/* Implement TARGET_SCHED_MACRO_FUSION_P.  Return true if target supports\n+   instruction fusion of some sort.  */\n+\n+bool\n+riscv_macro_fusion_p (void)\n+{\n+  return riscv_get_fusible_ops () != RISCV_FUSE_NOTHING;\n+}\n+\n+/* Return true iff the instruction fusion described by OP is enabled.  */\n+\n+static bool\n+riscv_fusion_enabled_p (enum riscv_fusion_pairs op)\n+{\n+  return riscv_get_fusible_ops () & op;\n+}\n+\n+/* Matches an add:\n+   (set (reg:DI rd) (plus:SI (reg:SI rs1) (reg:SI rs2))) */\n+\n+static bool\n+riscv_set_is_add (rtx set)\n+{\n+  return (GET_CODE (SET_SRC (set)) == PLUS\n+\t  && REG_P (XEXP (SET_SRC (set), 0))\n+\t  && REG_P (XEXP (SET_SRC (set), 1))\n+\t  && REG_P (SET_DEST (set)));\n+}\n+\n+/* Matches an addi:\n+   (set (reg:DI rd) (plus:SI (reg:SI rs1) (const_int imm))) */\n+\n+static bool\n+riscv_set_is_addi (rtx set)\n+{\n+  return (GET_CODE (SET_SRC (set)) == PLUS\n+\t  && REG_P (XEXP (SET_SRC (set), 0))\n+\t  && CONST_INT_P (XEXP (SET_SRC (set), 1))\n+\t  && REG_P (SET_DEST (set)));\n+}\n+\n+/* Matches an add.uw:\n+  (set (reg:DI rd)\n+    (plus:DI (zero_extend:DI (reg:SI rs1)) (reg:DI rs2))) */\n+\n+static bool\n+riscv_set_is_adduw (rtx set)\n+{\n+  return (GET_CODE (SET_SRC (set)) == PLUS\n+\t  && GET_CODE (XEXP (SET_SRC (set), 0)) == ZERO_EXTEND\n+\t  && REG_P (XEXP (XEXP (SET_SRC (set), 0), 0))\n+\t  && REG_P (XEXP (SET_SRC (set), 1))\n+\t  && REG_P (SET_DEST (set)));\n+}\n+\n+/* Matches a shNadd:\n+  (set (reg:DI rd)\n+       (plus:DI (ashift:DI (reg:DI rs1) (const_int N)) (reg:DI rS2)) */\n+\n+static bool\n+riscv_set_is_shNadd (rtx set)\n+{\n+  return (GET_CODE (SET_SRC (set)) == PLUS\n+\t  && GET_CODE (XEXP (SET_SRC (set), 0)) == ASHIFT\n+\t  && REG_P (XEXP (XEXP (SET_SRC (set), 0), 0))\n+\t  && CONST_INT_P (XEXP (XEXP (SET_SRC (set), 0), 1))\n+\t  && (INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 1\n+\t      || INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 2\n+\t      || INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 3)\n+\t  && REG_P (SET_DEST (set)));\n+}\n+\n+/* Matches a shNadd.uw:\n+  (set (reg:DI rd)\n+       (plus:DI (and:DI (ashift:DI (reg:DI rs1) (const_int N))\n+\t\t\t(const_int N))\n+\t\t(reg:DI rs2)) */\n+\n+static bool\n+riscv_set_is_shNadduw (rtx set)\n+{\n+  return (GET_CODE (SET_SRC (set)) == PLUS\n+\t  && GET_CODE (XEXP (SET_SRC (set), 0)) == AND\n+\t  && GET_CODE (XEXP (XEXP (SET_SRC (set), 0), 0)) == ASHIFT\n+\t  && REG_P (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 0))\n+\t  && CONST_INT_P (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1))\n+\t  && (INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 1\n+\t      || INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 2\n+\t      || INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 3)\n+\t  && REG_P (SET_DEST (set)));\n+}\n+\n+/* Implement TARGET_SCHED_MACRO_FUSION_PAIR_P.  Return true if PREV and CURR\n+   should be kept together during scheduling.  */\n+\n+bool\n+riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)\n+{\n+  /* If fusion is not enabled, then there's nothing to do.  */\n+  if (!riscv_macro_fusion_p ())\n+    return false;\n+\n+  /* If PREV is already marked as fused, then we can't fuse CURR with PREV\n+     and if we were to fuse them we'd end up with a blob of insns that\n+     essentially are an atomic unit which is bad for scheduling.  */\n+  if (SCHED_GROUP_P (prev))\n+    return false;\n+\n+  rtx prev_set = single_set (prev);\n+  rtx curr_set = single_set (curr);\n+  /* prev and curr are simple SET insns i.e. no flag setting or branching.  */\n+  bool simple_sets_p = prev_set && curr_set && !any_condjump_p (curr);\n+  bool sched1 = can_create_pseudo_p ();\n+\n+  unsigned int prev_dest_regno = (prev_set && REG_P (SET_DEST (prev_set))\n+\t\t\t\t  ? REGNO (SET_DEST (prev_set))\n+\t\t\t\t  : FIRST_PSEUDO_REGISTER);\n+  unsigned int curr_dest_regno = (curr_set && REG_P (SET_DEST (curr_set))\n+\t\t\t\t  ? REGNO (SET_DEST (curr_set))\n+\t\t\t\t  : FIRST_PSEUDO_REGISTER);\n+\n+  if (simple_sets_p\n+      && (riscv_fusion_enabled_p (RISCV_FUSE_ZEXTW)\n+\t  || riscv_fusion_enabled_p (RISCV_FUSE_ZEXTWS))\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (slli) == (set (reg:DI rD)\n+\t\t\t       (ashift:DI (reg:DI rS) (const_int 32)))\n+\t   curr (slri) == (set (reg:DI rD)\n+\t\t\t       (lshiftrt:DI (reg:DI rD) (const_int <shift>)))\n+\t with <shift> being either 32 for FUSE_ZEXTW, or\n+\t\t\t `less than 32 for FUSE_ZEXTWS. */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == ASHIFT\n+\t  && GET_CODE (SET_SRC (curr_set)) == LSHIFTRT\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == curr_dest_regno\n+\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))\n+\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n+\t  && INTVAL (XEXP (SET_SRC (prev_set), 1)) == 32\n+\t  && ((INTVAL (XEXP (SET_SRC (curr_set), 1)) == 32\n+\t       && riscv_fusion_enabled_p (RISCV_FUSE_ZEXTW) )\n+\t      || (INTVAL (XEXP (SET_SRC (curr_set), 1)) < 32\n+\t\t  && riscv_fusion_enabled_p (RISCV_FUSE_ZEXTWS))))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_ZEXTWS\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_ZEXTH)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (slli) == (set (reg:DI rD)\n+\t\t\t       (ashift:DI (reg:DI rS) (const_int 48)))\n+\t   curr (slri) == (set (reg:DI rD)\n+\t\t\t       (lshiftrt:DI (reg:DI rD) (const_int 48))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == ASHIFT\n+\t  && GET_CODE (SET_SRC (curr_set)) == LSHIFTRT\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == curr_dest_regno\n+\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))\n+\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n+\t  && INTVAL (XEXP (SET_SRC (prev_set), 1)) == 48\n+\t  && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 48)\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file,\"RISCV_FUSE_ZEXTH\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LDINDEXED)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (add) == (set (reg:DI rD)\n+\t\t\t      (plus:DI (reg:DI rS1) (reg:DI rS2))\n+\t   curr (ld)  == (set (reg:DI rD)\n+\t\t\t      (mem:DI (reg:DI rD))) */\n+\n+      if (MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n+\t  && GET_CODE (SET_SRC (prev_set)) == PLUS\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 1)))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LDINDEXED\\n\");\n+\t  return true;\n+\t}\n+\n+      /* We are trying to match the following:\n+\t   prev (add) == (set (reg:DI rD)\n+\t\t\t      (plus:DI (reg:DI rS1) (reg:DI rS2)))\n+\t   curr (lw)  == (set (any_extend:DI (mem:SUBX (reg:DI rD)))) */\n+\n+      if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n+\t   || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))\n+\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n+\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno\n+\t  && GET_CODE (SET_SRC (prev_set)) == PLUS\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 1)))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LDINDEXED\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_EXPANDED_LD)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* For the \"expanded add/load fusion\" family we have 2 main\n+\t categories: memory loads with displacement (i.e. with imm offset)\n+\t and loads without displacement (i.e. with offset = x0).\n+\n+\t For loads without displacement we'll need:\n+\t - add + ld (done in RISCV_FUSE_LDINDEXED)\n+\t - addi + ld (done in RISCV_FUSE_LDPREINCREMENT)\n+\t - shNadd + ld\n+\t - add.uw + lw\n+\t - shNadd.uw + lw\n+\n+\t For loads with displacement/immediates:\n+\t with lw with immediate):\n+\t - add + ld with displacement\n+\t - addi + ld with displacement\n+\t - shNadd + ld with displacement\n+\t - add.uw + lw with displacement\n+\t - shNadd.uw + lw with displacement */\n+\n+      /* We're trying to match a curr_set ld with displacement:\n+\t  prev (add|addi) = (set (reg:DI rd) (...))\n+\t  curr (ld)  == (set (reg:DI rD)\n+\t\t(mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */\n+      if (MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS\n+\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n+\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n+\t{\n+\t  if (riscv_set_is_add (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\n+\t  if (riscv_set_is_addi (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\n+\t  if (riscv_set_is_shNadd (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\t}\n+\n+      /* We're trying to match a ld without displacement:\n+\t  prev (addi|shNadd) = (reg:DI rD) (...))\n+\t  curr (ld)  == (set (reg:DI rD)\n+\t\t\t     (mem:DI (reg:DI rD))) */\n+      if (MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno)\n+\t{\n+\t  if (riscv_set_is_addi (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\n+\t  if (riscv_set_is_shNadd (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\t}\n+\n+      /* We're trying to match a curr_set lw with displacement:\n+\t  prev (add.uw|shNadd.uw) = (set (reg:DI rd) (...))\n+\t  curr (lw)  == (set (reg:DI rd)\n+\t\t(any_extend:DI (mem:SUBX (plus:DI ((reg:DI rd)\n+\t\t\t\t\t\t   (const_int IMM)))) */\n+      if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n+\t   || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))\n+\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == PLUS\n+\t  && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n+\t  && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n+\t      == prev_dest_regno))\n+\t{\n+\t  if (riscv_set_is_adduw (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\n+\t  if (riscv_set_is_shNadduw (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\t}\n+\n+      /* We're trying to match a curr_set lw without displacement:\n+\t  prev (add.uw|shNadd.uw) = (set (reg:DI rd) (...))\n+\t  curr (ld|lh|lw)  == (set (reg:DI rd)\n+\t\t(any_extend:DI (mem:SUBX (reg:DI rsd)))) */\n+      if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n+\t   || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))\n+\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n+\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n+\t{\n+\t  if (riscv_set_is_adduw (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\n+\t  if (riscv_set_is_shNadduw (prev_set))\n+\t    {\n+\t      if (dump_file)\n+\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n+\t      return true;\n+\t    }\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LDPREINCREMENT)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (add) == (set (reg:DI rS)\n+\t\t\t      (plus:DI (reg:DI rS) (const_int))\n+\t   curr (ld)  == (set (reg:DI rD)\n+\t\t\t      (mem:DI (reg:DI rS))) */\n+\n+      if (MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n+\t  && GET_CODE (SET_SRC (prev_set)) == PLUS\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n+\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1)))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LDPREINCREMENT\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LUI_ADDI)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (lui)  == (set (reg:DI rD) (const_int UPPER_IMM_20))\n+\t   curr (addi) == (set (reg:DI rD)\n+\t\t\t       (plus:DI (reg:DI rD) (const_int IMM12))) */\n+\n+      if ((GET_CODE (SET_SRC (curr_set)) == LO_SUM\n+\t   || (GET_CODE (SET_SRC (curr_set)) == PLUS\n+\t       && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n+\t       && SMALL_OPERAND (INTVAL (XEXP (SET_SRC (curr_set), 1)))))\n+\t  && (GET_CODE (SET_SRC (prev_set)) == HIGH\n+\t      || (CONST_INT_P (SET_SRC (prev_set))\n+\t\t  && LUI_OPERAND (INTVAL (SET_SRC (prev_set))))))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LUI_ADDI\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_AUIPC_ADDI)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (auipc) == (set (reg:DI rD) (unspec:DI [...] UNSPEC_AUIPC))\n+\t   curr (addi)  == (set (reg:DI rD)\n+\t\t\t\t(plus:DI (reg:DI rD) (const_int IMM12)))\n+\t and\n+\t   prev (auipc) == (set (reg:DI rD) (unspec:DI [...] UNSPEC_AUIPC))\n+\t   curr (addi)  == (set (reg:DI rD)\n+\t\t\t\t(lo_sum:DI (reg:DI rD) (const_int IMM12))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == UNSPEC\n+\t  && XINT (SET_SRC (prev_set), 1) == UNSPEC_AUIPC\n+\t  && (GET_CODE (SET_SRC (curr_set)) == LO_SUM\n+\t      || (GET_CODE (SET_SRC (curr_set)) == PLUS\n+\t\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n+\t\t  && SMALL_OPERAND (INTVAL (XEXP (SET_SRC (curr_set), 1))))))\n+\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_AUIPC_ADDI\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LUI_LD)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (lui)  == (set (reg:DI rD) (const_int UPPER_IMM_20))\n+\t   curr (ld)  == (set (reg:DI rD)\n+\t\t\t      (mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */\n+\n+      /* A LUI_OPERAND accepts (const_int 0), but we won't emit that as LUI.  So\n+\t reject that case explicitly.  */\n+      if (CONST_INT_P (SET_SRC (prev_set))\n+\t  && SET_SRC (prev_set) != CONST0_RTX (GET_MODE (SET_DEST (prev_set)))\n+\t  && LUI_OPERAND (INTVAL (SET_SRC (prev_set)))\n+\t  && MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS\n+\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n+\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LUI_LD\\n\");\n+\t  return true;\n+\t}\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == HIGH\n+\t  && MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == LO_SUM\n+\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n+\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LUI_LD\\n\");\n+\t  return true;\n+\t}\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == HIGH\n+\t  && (GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n+\t      || GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND)\n+\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && (GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == LO_SUM\n+\t      && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n+\t      && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n+\t\t  == prev_dest_regno)))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_LUI_LD\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_AUIPC_LD)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (auipc) == (set (reg:DI rD) (unspec:DI [...] UNSPEC_AUIPC))\n+\t   curr (ld)  == (set (reg:DI rD)\n+\t\t\t      (mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == UNSPEC\n+\t  && XINT (prev_set, 1) == UNSPEC_AUIPC\n+\t  && MEM_P (SET_SRC (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS)\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_AUIPC_LD\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_CACHE_ALIGNED_STD))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (sd) == (set (mem (plus (reg sp|fp) (const_int)))\n+\t\t\t      (reg rS1))\n+\t   curr (sd) == (set (mem (plus (reg sp|fp) (const_int)))\n+\t\t\t      (reg rS2)) */\n+\n+      if (MEM_P (SET_DEST (prev_set))\n+\t  && MEM_P (SET_DEST (curr_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  /* We can probably relax this condition.  The documentation is a bit\n+\t     unclear about sub-word cases.  So we just model DImode for now.  */\n+\t  && GET_MODE (SET_DEST (curr_set)) == DImode\n+\t  && GET_MODE (SET_DEST (prev_set)) == DImode)\n+\t{\n+\t  rtx base_prev, base_curr, offset_prev, offset_curr;\n+\n+\t  extract_base_offset_in_addr (SET_DEST (prev_set), &base_prev, &offset_prev);\n+\t  extract_base_offset_in_addr (SET_DEST (curr_set), &base_curr, &offset_curr);\n+\n+\t  /* Proceed only if we find both bases, both bases are register and\n+\t     bases are the same register.  */\n+\t  if (base_prev != NULL_RTX && base_curr != NULL_RTX\n+\t      && REG_P (base_prev) && REG_P (base_curr)\n+\t      && REGNO (base_prev) != REGNO (base_curr)\n+\t      /* The alignment of hte base pointer is more useful than the\n+\t\t alignment of the memory reference for determining if we're\n+\t\t on opposite sides of a cache line.  */\n+\t      && REGNO_POINTER_ALIGN (ORIGINAL_REGNO (base_prev)) >= 128)\n+\t    {\n+\t      /* The two stores must be contained within opposite halves of the\n+\t\t same 16 byte aligned block of memory.  We know the pointer\n+\t\t has suitable alignment, so we just need to check the offsets\n+\t\t of the two stores for suitable alignment.  */\n+\n+\t      /* Get the smaller offset into OFFSET_PREV.  */\n+\t      if (INTVAL (offset_prev) > INTVAL (offset_curr))\n+\t\tstd::swap (offset_prev, offset_curr);\n+\n+\t      /* We have a match if the smaller offset (OFFSET_PREV) is 16\n+\t\t byte aligned and the higher offset is 8 bytes more than the\n+\t\t lower offset.  */\n+\t      if ((INTVAL (offset_prev) % 16) == 0\n+\t\t  && (INTVAL (offset_prev) + 8 == INTVAL (offset_curr)))\n+\t\t{\n+\t\t  if (dump_file)\n+\t\t    fprintf (dump_file, \"RISCV_FUSE_ALIGNED_STD\\n\");\n+\t\t  return true;\n+\t\t}\n+\t    }\n+\t}\n+    }\n+\n+  /* More general form of the RISCV_FUSE_CACHE_ALIGNED_STD.  The\n+     major difference is the dependency on the stores being opposite\n+     halves of a cache line is dropped.  Instead the lowest address\n+     needs 2X the alignment of the object and the higher address\n+     immediately followed the first object.  */\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_ALIGNED_STD))\n+    {\n+      /* We are trying to match the following:\n+\tprev (sd) == (set (mem (plus (reg rS1) (const_int)))\n+\t\t\t  (reg rS2))\n+\tcurr (sd) == (set (mem (plus (reg rS1) (const_int)))\n+\t\t\t  (reg rS3)) */\n+\n+      if (MEM_P (SET_DEST (prev_set))\n+\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n+\t  && MEM_P (SET_DEST (curr_set))\n+\t  /* Stores must have the same width */\n+\t  && GET_MODE (SET_DEST (curr_set)) == GET_MODE (SET_DEST (prev_set)))\n+\t{\n+\t  rtx base_prev, base_curr, offset_prev, offset_curr;\n+\t  unsigned mode_size;\n+\n+\t  extract_base_offset_in_addr (SET_DEST (prev_set),\n+\t\t\t\t       &base_prev, &offset_prev);\n+\t  extract_base_offset_in_addr (SET_DEST (curr_set),\n+\t\t\t\t       &base_curr, &offset_curr);\n+\n+\t  /* Proceed only if we find both bases, both bases\n+\t     are registers and bases are the same register.  */\n+\t  if (base_prev != NULL_RTX && base_curr != NULL_RTX\n+\t      && REG_P (base_prev) && REG_P (base_curr)\n+\t      && REGNO (base_prev) == REGNO (base_curr))\n+\t    {\n+\t      machine_mode mode = GET_MODE (SET_DEST (curr_set));\n+\t      mode_size = estimated_poly_value (GET_MODE_SIZE (mode));\n+\n+\t      HOST_WIDE_INT offset_prev_int = INTVAL (offset_prev);\n+\t      HOST_WIDE_INT offset_curr_int = INTVAL (offset_curr);\n+\n+\t      /* Get the smaller offset into OFFSET_PREV_INT.  */\n+\t      if (offset_prev_int > offset_curr_int)\n+\t\tstd::swap (offset_prev_int, offset_curr_int);\n+\n+\t      /* We've normalized, so we need to check that the lower\n+\t\t address is aligned to 2X the size of the object.  The\n+\t\t higher address must be the lower address plus the\n+\t\t size of the object.  */\n+\t      if (((offset_prev_int % (2 * mode_size)) == 0)\n+\t\t  && offset_prev_int + mode_size == offset_curr_int)\n+\t\t{\n+\t\t  if (dump_file)\n+\t\t    fprintf (dump_file, \"RISCV_FUSE_ALIGNED_STD\\n\");\n+\t\t  return true;\n+\t\t}\n+\t    }\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_BFEXT)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t   prev (slli) == (set (reg:DI rD)\n+\t\t\t       (ashift:DI (reg:DI rS) (const_int)))\n+\t   curr (srli) == (set (reg:DI rD)\n+\t\t\t       (lshiftrt:DI (reg:DI rD) (const_int))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == ASHIFT\n+\t  && (GET_CODE (SET_SRC (curr_set)) == LSHIFTRT\n+\t      || GET_CODE (SET_SRC (curr_set)) == ASHIFTRT)\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n+\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))\n+\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1)))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_BFEXT\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_B_ALUI)\n+      && (sched1 || prev_dest_regno == curr_dest_regno))\n+    {\n+      /* We are trying to match the following:\n+\t  prev (orc.b) == (set (reg rD)\n+\t\t\t\t(unspec (reg rS1)))\n+\t  curr (not) == (set (reg rD2) (not (reg rD))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == UNSPEC\n+\t  && GET_CODE (SET_SRC (curr_set)) == NOT\n+\t  && XINT (SET_SRC (prev_set), 1) == UNSPEC_ORC_B\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno)\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n+\t  return true;\n+\t}\n+\n+      /* We are trying to match the following:\n+\t  prev (ctz) == (set (reg rD) (ctz (reg rS1)))\n+\t  curr (andi) == (set (reg rD)\n+\t\t\t\t(and (reg rD) (const_int 63))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == CTZ\n+\t  && GET_CODE (SET_SRC (curr_set)) == AND\n+\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n+\t  && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 63\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno)\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n+\t  return true;\n+\t}\n+\n+      /* We are trying to match the following:\n+\t  prev (sub) == (set (reg rD)\n+\t\t\t\t(minus (const_int 0) (reg rS2))\n+\t  curr (max) == (set (reg rD)\n+\t\t\t\t(smax (reg rD) (reg rS2))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == MINUS\n+\t  && (XEXP (SET_SRC (prev_set), 0)\n+\t      == CONST0_RTX (GET_MODE (SET_SRC (prev_set))))\n+\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 0))\n+\t  && GET_CODE (SET_SRC (curr_set)) == SMAX\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 1))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 1))\n+\t  && (REGNO (XEXP (SET_SRC (prev_set), 1))\n+\t      == REGNO (XEXP (SET_SRC (curr_set), 1))))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n+\t  return true;\n+\t}\n+\n+      /* We are trying to match the following:\n+\t  prev (neg) == (set (reg rD) (neg (reg rS1)))\n+\t  curr (max) == (set (reg rD)\n+\t\t\t\t(smax (reg rD) (reg rS1))) */\n+\n+      if (GET_CODE (SET_SRC (prev_set)) == NEG\n+\t  && GET_CODE (SET_SRC (curr_set)) == SMAX\n+\t  && REG_P (SET_DEST (prev_set))\n+\t  && REG_P (SET_DEST (curr_set))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n+\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n+\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n+\t  && REG_P (XEXP (SET_SRC (curr_set), 1))\n+\t  && (REGNO (XEXP (SET_SRC (prev_set), 0))\n+\t      == REGNO (XEXP (SET_SRC (curr_set), 1))))\n+\t{\n+\t  if (dump_file)\n+\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n+\t  return true;\n+\t}\n+    }\n+\n+  return false;\n+}\ndiff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h\nindex dd029c70413..1ddfd10c5d8 100644\n--- a/gcc/config/riscv/riscv-protos.h\n+++ b/gcc/config/riscv/riscv-protos.h\n@@ -814,6 +814,30 @@ const unsigned int RISCV_BUILTIN_CLASS = (1 << RISCV_BUILTIN_SHIFT) - 1;\n extern bool riscv_expand_strcmp (rtx, rtx, rtx, rtx, rtx);\n extern bool riscv_expand_strlen (rtx, rtx, rtx, rtx);\n \n+/* Routines implemented in riscv-fusion.cc.  */\n+enum riscv_fusion_pairs\n+{\n+  RISCV_FUSE_NOTHING = 0,\n+  RISCV_FUSE_ZEXTW = (1 << 0),\n+  RISCV_FUSE_ZEXTH = (1 << 1),\n+  RISCV_FUSE_ZEXTWS = (1 << 2),\n+  RISCV_FUSE_LDINDEXED = (1 << 3),\n+  RISCV_FUSE_LUI_ADDI = (1 << 4),\n+  RISCV_FUSE_AUIPC_ADDI = (1 << 5),\n+  RISCV_FUSE_LUI_LD = (1 << 6),\n+  RISCV_FUSE_AUIPC_LD = (1 << 7),\n+  RISCV_FUSE_LDPREINCREMENT = (1 << 8),\n+  RISCV_FUSE_ALIGNED_STD = (1 << 9),\n+  RISCV_FUSE_CACHE_ALIGNED_STD = (1 << 10),\n+  RISCV_FUSE_BFEXT = (1 << 11),\n+  RISCV_FUSE_EXPANDED_LD = (1 << 12),\n+  RISCV_FUSE_B_ALUI = (1 << 13),\n+};\n+\n+extern bool riscv_macro_fusion_p (void);\n+extern bool riscv_macro_fusion_pair_p (rtx_insn *, rtx_insn *);\n+extern unsigned int riscv_get_fusible_ops (void);\n+\n /* Routines implemented in thead.cc.  */\n extern bool extract_base_offset_in_addr (rtx, rtx *, rtx *);\n extern bool th_mempair_operands_p (rtx[4], bool, machine_mode);\ndiff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc\nindex 615750f0744..14786d5ebac 100644\n--- a/gcc/config/riscv/riscv.cc\n+++ b/gcc/config/riscv/riscv.cc\n@@ -274,25 +274,6 @@ struct riscv_integer_op {\n    The worst case is LUI, ADDI, SLLI, ADDI, SLLI, ADDI, SLLI, ADDI.  */\n #define RISCV_MAX_INTEGER_OPS 8\n \n-enum riscv_fusion_pairs\n-{\n-  RISCV_FUSE_NOTHING = 0,\n-  RISCV_FUSE_ZEXTW = (1 << 0),\n-  RISCV_FUSE_ZEXTH = (1 << 1),\n-  RISCV_FUSE_ZEXTWS = (1 << 2),\n-  RISCV_FUSE_LDINDEXED = (1 << 3),\n-  RISCV_FUSE_LUI_ADDI = (1 << 4),\n-  RISCV_FUSE_AUIPC_ADDI = (1 << 5),\n-  RISCV_FUSE_LUI_LD = (1 << 6),\n-  RISCV_FUSE_AUIPC_LD = (1 << 7),\n-  RISCV_FUSE_LDPREINCREMENT = (1 << 8),\n-  RISCV_FUSE_ALIGNED_STD = (1 << 9),\n-  RISCV_FUSE_CACHE_ALIGNED_STD = (1 << 10),\n-  RISCV_FUSE_BFEXT = (1 << 11),\n-  RISCV_FUSE_EXPANDED_LD = (1 << 12),\n-  RISCV_FUSE_B_ALUI = (1 << 13),\n-};\n-\n /* Costs of various operations on the different architectures.  */\n \n struct riscv_tune_param\n@@ -11109,731 +11090,13 @@ riscv_sched_reorder (FILE *, int, rtx_insn **ready, int *nreadyp, int)\n }\n \n \n-/* Implement TARGET_SCHED_MACRO_FUSION_P.  Return true if target supports\n-   instruction fusion of some sort.  */\n-\n-static bool\n-riscv_macro_fusion_p (void)\n-{\n-  return tune_param->fusible_ops != RISCV_FUSE_NOTHING;\n-}\n-\n-/* Return true iff the instruction fusion described by OP is enabled.  */\n-\n-static bool\n-riscv_fusion_enabled_p(enum riscv_fusion_pairs op)\n-{\n-  return tune_param->fusible_ops & op;\n-}\n \n-/* Matches an add:\n-   (set (reg:DI rd) (plus:SI (reg:SI rs1) (reg:SI rs2))) */\n+/* Return the set of fusible operations for the current tune.  */\n \n-static bool\n-riscv_set_is_add (rtx set)\n-{\n-  return (GET_CODE (SET_SRC (set)) == PLUS\n-\t  && REG_P (XEXP (SET_SRC (set), 0))\n-\t  && REG_P (XEXP (SET_SRC (set), 1))\n-\t  && REG_P (SET_DEST (set)));\n-}\n-\n-/* Matches an addi:\n-   (set (reg:DI rd) (plus:SI (reg:SI rs1) (const_int imm))) */\n-\n-static bool\n-riscv_set_is_addi (rtx set)\n-{\n-  return (GET_CODE (SET_SRC (set)) == PLUS\n-\t  && REG_P (XEXP (SET_SRC (set), 0))\n-\t  && CONST_INT_P (XEXP (SET_SRC (set), 1))\n-\t  && REG_P (SET_DEST (set)));\n-}\n-\n-/* Matches an add.uw:\n-  (set (reg:DI rd)\n-    (plus:DI (zero_extend:DI (reg:SI rs1)) (reg:DI rs2))) */\n-\n-static bool\n-riscv_set_is_adduw (rtx set)\n-{\n-  return (GET_CODE (SET_SRC (set)) == PLUS\n-\t  && GET_CODE (XEXP (SET_SRC (set), 0)) == ZERO_EXTEND\n-\t  && REG_P (XEXP (XEXP (SET_SRC (set), 0), 0))\n-\t  && REG_P (XEXP (SET_SRC (set), 1))\n-\t  && REG_P (SET_DEST (set)));\n-}\n-\n-/* Matches a shNadd:\n-  (set (reg:DI rd)\n-       (plus:DI (ashift:DI (reg:DI rs1) (const_int N)) (reg:DI rS2)) */\n-\n-static bool\n-riscv_set_is_shNadd (rtx set)\n-{\n-  return (GET_CODE (SET_SRC (set)) == PLUS\n-\t  && GET_CODE (XEXP (SET_SRC (set), 0)) == ASHIFT\n-\t  && REG_P (XEXP (XEXP (SET_SRC (set), 0), 0))\n-\t  && CONST_INT_P (XEXP (XEXP (SET_SRC (set), 0), 1))\n-\t  && (INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 1\n-\t      || INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 2\n-\t      || INTVAL (XEXP (XEXP (SET_SRC (set), 0), 1)) == 3)\n-\t  && REG_P (SET_DEST (set)));\n-}\n-\n-/* Matches a shNadd.uw:\n-  (set (reg:DI rd)\n-       (plus:DI (and:DI (ashift:DI (reg:DI rs1) (const_int N))\n-\t\t\t(const_int N))\n-\t\t(reg:DI rs2)) */\n-\n-static bool\n-riscv_set_is_shNadduw (rtx set)\n-{\n-  return (GET_CODE (SET_SRC (set)) == PLUS\n-\t  && GET_CODE (XEXP (SET_SRC (set), 0)) == AND\n-\t  && GET_CODE (XEXP (XEXP (SET_SRC (set), 0), 0)) == ASHIFT\n-\t  && REG_P (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 0))\n-\t  && CONST_INT_P (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1))\n-\t  && (INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 1\n-\t      || INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 2\n-\t      || INTVAL (XEXP (XEXP (XEXP (SET_SRC (set), 0), 0), 1)) == 3)\n-\t  && REG_P (SET_DEST (set)));\n-}\n-\n-/* Implement TARGET_SCHED_MACRO_FUSION_PAIR_P.  Return true if PREV and CURR\n-   should be kept together during scheduling.  */\n-\n-static bool\n-riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)\n+unsigned int\n+riscv_get_fusible_ops (void)\n {\n-  /* If fusion is not enabled, then there's nothing to do.  */\n-  if (!riscv_macro_fusion_p ())\n-    return false;\n-\n-  /* If PREV is already marked as fused, then we can't fuse CURR with PREV\n-     and if we were to fuse them we'd end up with a blob of insns that\n-     essentially are an atomic unit which is bad for scheduling.  */\n-  if (SCHED_GROUP_P (prev))\n-    return false;\n-\n-  rtx prev_set = single_set (prev);\n-  rtx curr_set = single_set (curr);\n-  /* prev and curr are simple SET insns i.e. no flag setting or branching.  */\n-  bool simple_sets_p = prev_set && curr_set && !any_condjump_p (curr);\n-  bool sched1 = can_create_pseudo_p ();\n-\n-  unsigned int prev_dest_regno = (prev_set && REG_P (SET_DEST (prev_set))\n-\t\t\t\t  ? REGNO (SET_DEST (prev_set))\n-\t\t\t\t  : FIRST_PSEUDO_REGISTER);\n-  unsigned int curr_dest_regno = (curr_set && REG_P (SET_DEST (curr_set))\n-\t\t\t\t  ? REGNO (SET_DEST (curr_set))\n-\t\t\t\t  : FIRST_PSEUDO_REGISTER);\n-\n-  if (simple_sets_p\n-      && (riscv_fusion_enabled_p (RISCV_FUSE_ZEXTW)\n-\t  || riscv_fusion_enabled_p (RISCV_FUSE_ZEXTWS))\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (slli) == (set (reg:DI rD)\n-\t\t\t       (ashift:DI (reg:DI rS) (const_int 32)))\n-\t   curr (slri) == (set (reg:DI rD)\n-\t\t\t       (lshiftrt:DI (reg:DI rD) (const_int <shift>)))\n-\t with <shift> being either 32 for FUSE_ZEXTW, or\n-\t\t\t `less than 32 for FUSE_ZEXTWS. */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == ASHIFT\n-\t  && GET_CODE (SET_SRC (curr_set)) == LSHIFTRT\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == curr_dest_regno\n-\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))\n-\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n-\t  && INTVAL (XEXP (SET_SRC (prev_set), 1)) == 32\n-\t  && ((INTVAL (XEXP (SET_SRC (curr_set), 1)) == 32\n-\t       && riscv_fusion_enabled_p (RISCV_FUSE_ZEXTW) )\n-\t      || (INTVAL (XEXP (SET_SRC (curr_set), 1)) < 32\n-\t\t  && riscv_fusion_enabled_p (RISCV_FUSE_ZEXTWS))))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_ZEXTWS\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_ZEXTH)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (slli) == (set (reg:DI rD)\n-\t\t\t       (ashift:DI (reg:DI rS) (const_int 48)))\n-\t   curr (slri) == (set (reg:DI rD)\n-\t\t\t       (lshiftrt:DI (reg:DI rD) (const_int 48))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == ASHIFT\n-\t  && GET_CODE (SET_SRC (curr_set)) == LSHIFTRT\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == curr_dest_regno\n-\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))\n-\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n-\t  && INTVAL (XEXP (SET_SRC (prev_set), 1)) == 48\n-\t  && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 48)\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file,\"RISCV_FUSE_ZEXTH\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LDINDEXED)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (add) == (set (reg:DI rD)\n-\t\t\t      (plus:DI (reg:DI rS1) (reg:DI rS2))\n-\t   curr (ld)  == (set (reg:DI rD)\n-\t\t\t      (mem:DI (reg:DI rD))) */\n-\n-      if (MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n-\t  && GET_CODE (SET_SRC (prev_set)) == PLUS\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 1)))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LDINDEXED\\n\");\n-\t  return true;\n-\t}\n-\n-      /* We are trying to match the following:\n-\t   prev (add) == (set (reg:DI rD)\n-\t\t\t      (plus:DI (reg:DI rS1) (reg:DI rS2)))\n-\t   curr (lw)  == (set (any_extend:DI (mem:SUBX (reg:DI rD)))) */\n-\n-      if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n-\t   || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))\n-\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n-\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno\n-\t  && GET_CODE (SET_SRC (prev_set)) == PLUS\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 1)))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LDINDEXED\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_EXPANDED_LD)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* For the \"expanded add/load fusion\" family we have 2 main\n-\t categories: memory loads with displacement (i.e. with imm offset)\n-\t and loads without displacement (i.e. with offset = x0).\n-\n-\t For loads without displacement we'll need:\n-\t - add + ld (done in RISCV_FUSE_LDINDEXED)\n-\t - addi + ld (done in RISCV_FUSE_LDPREINCREMENT)\n-\t - shNadd + ld\n-\t - add.uw + lw\n-\t - shNadd.uw + lw\n-\n-\t For loads with displacement/immediates:\n-\t with lw with immediate):\n-\t - add + ld with displacement\n-\t - addi + ld with displacement\n-\t - shNadd + ld with displacement\n-\t - add.uw + lw with displacement\n-\t - shNadd.uw + lw with displacement */\n-\n-      /* We're trying to match a curr_set ld with displacement:\n-\t  prev (add|addi) = (set (reg:DI rd) (...))\n-\t  curr (ld)  == (set (reg:DI rD)\n-\t\t(mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */\n-      if (MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS\n-\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n-\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n-\t{\n-\t  if (riscv_set_is_add (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\n-\t  if (riscv_set_is_addi (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\n-\t  if (riscv_set_is_shNadd (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\t}\n-\n-      /* We're trying to match a ld without displacement:\n-\t  prev (addi|shNadd) = (reg:DI rD) (...))\n-\t  curr (ld)  == (set (reg:DI rD)\n-\t\t\t     (mem:DI (reg:DI rD))) */\n-      if (MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno)\n-\t{\n-\t  if (riscv_set_is_addi (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\n-\t  if (riscv_set_is_shNadd (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\t}\n-\n-      /* We're trying to match a curr_set lw with displacement:\n-\t  prev (add.uw|shNadd.uw) = (set (reg:DI rd) (...))\n-\t  curr (lw)  == (set (reg:DI rd)\n-\t\t(any_extend:DI (mem:SUBX (plus:DI ((reg:DI rd)\n-\t\t\t\t\t\t   (const_int IMM)))) */\n-      if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n-\t   || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))\n-\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == PLUS\n-\t  && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n-\t  && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n-\t      == prev_dest_regno))\n-\t{\n-\t  if (riscv_set_is_adduw (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\n-\t  if (riscv_set_is_shNadduw (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\t}\n-\n-      /* We're trying to match a curr_set lw without displacement:\n-\t  prev (add.uw|shNadd.uw) = (set (reg:DI rd) (...))\n-\t  curr (ld|lh|lw)  == (set (reg:DI rd)\n-\t\t(any_extend:DI (mem:SUBX (reg:DI rsd)))) */\n-      if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n-\t   || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))\n-\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n-\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n-\t{\n-\t  if (riscv_set_is_adduw (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\n-\t  if (riscv_set_is_shNadduw (prev_set))\n-\t    {\n-\t      if (dump_file)\n-\t\tfprintf (dump_file, \"RISCV_FUSE_EXPANDED_LD\\n\");\n-\t      return true;\n-\t    }\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LDPREINCREMENT)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (add) == (set (reg:DI rS)\n-\t\t\t      (plus:DI (reg:DI rS) (const_int))\n-\t   curr (ld)  == (set (reg:DI rD)\n-\t\t\t      (mem:DI (reg:DI rS))) */\n-\n-      if (MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n-\t  && GET_CODE (SET_SRC (prev_set)) == PLUS\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n-\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1)))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LDPREINCREMENT\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LUI_ADDI)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (lui)  == (set (reg:DI rD) (const_int UPPER_IMM_20))\n-\t   curr (addi) == (set (reg:DI rD)\n-\t\t\t       (plus:DI (reg:DI rD) (const_int IMM12))) */\n-\n-      if ((GET_CODE (SET_SRC (curr_set)) == LO_SUM\n-\t   || (GET_CODE (SET_SRC (curr_set)) == PLUS\n-\t       && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n-\t       && SMALL_OPERAND (INTVAL (XEXP (SET_SRC (curr_set), 1)))))\n-\t  && (GET_CODE (SET_SRC (prev_set)) == HIGH\n-\t      || (CONST_INT_P (SET_SRC (prev_set))\n-\t\t  && LUI_OPERAND (INTVAL (SET_SRC (prev_set))))))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LUI_ADDI\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_AUIPC_ADDI)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (auipc) == (set (reg:DI rD) (unspec:DI [...] UNSPEC_AUIPC))\n-\t   curr (addi)  == (set (reg:DI rD)\n-\t\t\t\t(plus:DI (reg:DI rD) (const_int IMM12)))\n-\t and\n-\t   prev (auipc) == (set (reg:DI rD) (unspec:DI [...] UNSPEC_AUIPC))\n-\t   curr (addi)  == (set (reg:DI rD)\n-\t\t\t\t(lo_sum:DI (reg:DI rD) (const_int IMM12))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == UNSPEC\n-\t  && XINT (SET_SRC (prev_set), 1) == UNSPEC_AUIPC\n-\t  && (GET_CODE (SET_SRC (curr_set)) == LO_SUM\n-\t      || (GET_CODE (SET_SRC (curr_set)) == PLUS\n-\t\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n-\t\t  && SMALL_OPERAND (INTVAL (XEXP (SET_SRC (curr_set), 1))))))\n-\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_AUIPC_ADDI\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_LUI_LD)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (lui)  == (set (reg:DI rD) (const_int UPPER_IMM_20))\n-\t   curr (ld)  == (set (reg:DI rD)\n-\t\t\t      (mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */\n-\n-      /* A LUI_OPERAND accepts (const_int 0), but we won't emit that as LUI.  So\n-\t reject that case explicitly.  */\n-      if (CONST_INT_P (SET_SRC (prev_set))\n-\t  && SET_SRC (prev_set) != CONST0_RTX (GET_MODE (SET_DEST (prev_set)))\n-\t  && LUI_OPERAND (INTVAL (SET_SRC (prev_set)))\n-\t  && MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS\n-\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n-\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LUI_LD\\n\");\n-\t  return true;\n-\t}\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == HIGH\n-\t  && MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == LO_SUM\n-\t  && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))\n-\t  && REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == prev_dest_regno)\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LUI_LD\\n\");\n-\t  return true;\n-\t}\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == HIGH\n-\t  && (GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND\n-\t      || GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND)\n-\t  && MEM_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && (GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == LO_SUM\n-\t      && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n-\t      && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))\n-\t\t  == prev_dest_regno)))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_LUI_LD\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_AUIPC_LD)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (auipc) == (set (reg:DI rD) (unspec:DI [...] UNSPEC_AUIPC))\n-\t   curr (ld)  == (set (reg:DI rD)\n-\t\t\t      (mem:DI (plus:DI (reg:DI rD) (const_int IMM12)))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == UNSPEC\n-\t  && XINT (prev_set, 1) == UNSPEC_AUIPC\n-\t  && MEM_P (SET_SRC (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS)\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_AUIPC_LD\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_CACHE_ALIGNED_STD))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (sd) == (set (mem (plus (reg sp|fp) (const_int)))\n-\t\t\t      (reg rS1))\n-\t   curr (sd) == (set (mem (plus (reg sp|fp) (const_int)))\n-\t\t\t      (reg rS2)) */\n-\n-      if (MEM_P (SET_DEST (prev_set))\n-\t  && MEM_P (SET_DEST (curr_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  /* We can probably relax this condition.  The documentation is a bit\n-\t     unclear about sub-word cases.  So we just model DImode for now.  */\n-\t  && GET_MODE (SET_DEST (curr_set)) == DImode\n-\t  && GET_MODE (SET_DEST (prev_set)) == DImode)\n-\t{\n-\t  rtx base_prev, base_curr, offset_prev, offset_curr;\n-\n-\t  extract_base_offset_in_addr (SET_DEST (prev_set), &base_prev, &offset_prev);\n-\t  extract_base_offset_in_addr (SET_DEST (curr_set), &base_curr, &offset_curr);\n-\n-\t  /* Proceed only if we find both bases, both bases are register and\n-\t     bases are the same register.  */\n-\t  if (base_prev != NULL_RTX && base_curr != NULL_RTX\n-\t      && REG_P (base_prev) && REG_P (base_curr)\n-\t      && REGNO (base_prev) != REGNO (base_curr)\n-\t      /* The alignment of hte base pointer is more useful than the\n-\t\t alignment of the memory reference for determining if we're\n-\t\t on opposite sides of a cache line.  */\n-\t      && REGNO_POINTER_ALIGN (ORIGINAL_REGNO (base_prev)) >= 128)\n-\t    {\n-\t      /* The two stores must be contained within opposite halves of the\n-\t\t same 16 byte aligned block of memory.  We know the pointer\n-\t\t has suitable alignment, so we just need to check the offsets\n-\t\t of the two stores for suitable alignment.  */\n-\n-\t      /* Get the smaller offset into OFFSET_PREV.  */\n-\t      if (INTVAL (offset_prev) > INTVAL (offset_curr))\n-\t\tstd::swap (offset_prev, offset_curr);\n-\n-\t      /* We have a match if the smaller offset (OFFSET_PREV) is 16\n-\t\t byte aligned and the higher offset is 8 bytes more than the\n-\t\t lower offset.  */\n-\t      if ((INTVAL (offset_prev) % 16) == 0\n-\t\t  && (INTVAL (offset_prev) + 8 == INTVAL (offset_curr)))\n-\t\t{\n-\t\t  if (dump_file)\n-\t\t    fprintf (dump_file, \"RISCV_FUSE_ALIGNED_STD\\n\");\n-\t\t  return true;\n-\t\t}\n-\t    }\n-\t}\n-    }\n-\n-  /* More general form of the RISCV_FUSE_CACHE_ALIGNED_STD.  The\n-     major difference is the dependency on the stores being opposite\n-     halves of a cache line is dropped.  Instead the lowest address\n-     needs 2X the alignment of the object and the higher address\n-     immediately followed the first object.  */\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_ALIGNED_STD))\n-    {\n-      /* We are trying to match the following:\n-\tprev (sd) == (set (mem (plus (reg rS1) (const_int)))\n-\t\t\t  (reg rS2))\n-\tcurr (sd) == (set (mem (plus (reg rS1) (const_int)))\n-\t\t\t  (reg rS3)) */\n-\n-      if (MEM_P (SET_DEST (prev_set))\n-\t  && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))\n-\t  && MEM_P (SET_DEST (curr_set))\n-\t  /* Stores must have the same width */\n-\t  && GET_MODE (SET_DEST (curr_set)) == GET_MODE (SET_DEST (prev_set)))\n-\t{\n-\t  rtx base_prev, base_curr, offset_prev, offset_curr;\n-\t  unsigned mode_size;\n-\n-\t  extract_base_offset_in_addr (SET_DEST (prev_set),\n-\t\t\t\t       &base_prev, &offset_prev);\n-\t  extract_base_offset_in_addr (SET_DEST (curr_set),\n-\t\t\t\t       &base_curr, &offset_curr);\n-\n-\t  /* Proceed only if we find both bases, both bases\n-\t     are registers and bases are the same register.  */\n-\t  if (base_prev != NULL_RTX && base_curr != NULL_RTX\n-\t      && REG_P (base_prev) && REG_P (base_curr)\n-\t      && REGNO (base_prev) == REGNO (base_curr))\n-\t    {\n-\t      machine_mode mode = GET_MODE (SET_DEST (curr_set));\n-\t      mode_size = estimated_poly_value (GET_MODE_SIZE (mode));\n-\n-\t      HOST_WIDE_INT offset_prev_int = INTVAL (offset_prev);\n-\t      HOST_WIDE_INT offset_curr_int = INTVAL (offset_curr);\n-\n-\t      /* Get the smaller offset into OFFSET_PREV_INT.  */\n-\t      if (offset_prev_int > offset_curr_int)\n-\t\tstd::swap (offset_prev_int, offset_curr_int);\n-\n-\t      /* We've normalized, so we need to check that the lower\n-\t\t address is aligned to 2X the size of the object.  The\n-\t\t higher address must be the lower address plus the\n-\t\t size of the object.  */\n-\t      if (((offset_prev_int % (2 * mode_size)) == 0)\n-\t\t  && offset_prev_int + mode_size == offset_curr_int)\n-\t\t{\n-\t\t  if (dump_file)\n-\t\t    fprintf (dump_file, \"RISCV_FUSE_ALIGNED_STD\\n\");\n-\t\t  return true;\n-\t\t}\n-\t    }\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_BFEXT)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t   prev (slli) == (set (reg:DI rD)\n-\t\t\t       (ashift:DI (reg:DI rS) (const_int)))\n-\t   curr (srli) == (set (reg:DI rD)\n-\t\t\t       (lshiftrt:DI (reg:DI rD) (const_int))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == ASHIFT\n-\t  && (GET_CODE (SET_SRC (curr_set)) == LSHIFTRT\n-\t      || GET_CODE (SET_SRC (curr_set)) == ASHIFTRT)\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n-\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))\n-\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1)))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_BFEXT\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  if (simple_sets_p && riscv_fusion_enabled_p (RISCV_FUSE_B_ALUI)\n-      && (sched1 || prev_dest_regno == curr_dest_regno))\n-    {\n-      /* We are trying to match the following:\n-\t  prev (orc.b) == (set (reg rD)\n-\t\t\t\t(unspec (reg rS1)))\n-\t  curr (not) == (set (reg rD2) (not (reg rD))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == UNSPEC\n-\t  && GET_CODE (SET_SRC (curr_set)) == NOT\n-\t  && XINT (SET_SRC (prev_set), 1) == UNSPEC_ORC_B\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno)\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n-\t  return true;\n-\t}\n-\n-      /* We are trying to match the following:\n-\t  prev (ctz) == (set (reg rD) (ctz (reg rS1)))\n-\t  curr (andi) == (set (reg rD)\n-\t\t\t\t(and (reg rD) (const_int 63))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == CTZ\n-\t  && GET_CODE (SET_SRC (curr_set)) == AND\n-\t  && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))\n-\t  && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 63\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno)\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n-\t  return true;\n-\t}\n-\n-      /* We are trying to match the following:\n-\t  prev (sub) == (set (reg rD)\n-\t\t\t\t(minus (const_int 0) (reg rS2))\n-\t  curr (max) == (set (reg rD)\n-\t\t\t\t(smax (reg rD) (reg rS2))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == MINUS\n-\t  && (XEXP (SET_SRC (prev_set), 0)\n-\t      == CONST0_RTX (GET_MODE (SET_SRC (prev_set))))\n-\t  && CONST_INT_P (XEXP (SET_SRC (prev_set), 0))\n-\t  && GET_CODE (SET_SRC (curr_set)) == SMAX\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 1))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 1))\n-\t  && (REGNO (XEXP (SET_SRC (prev_set), 1))\n-\t      == REGNO (XEXP (SET_SRC (curr_set), 1))))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n-\t  return true;\n-\t}\n-\n-      /* We are trying to match the following:\n-\t  prev (neg) == (set (reg rD) (neg (reg rS1)))\n-\t  curr (max) == (set (reg rD)\n-\t\t\t\t(smax (reg rD) (reg rS1))) */\n-\n-      if (GET_CODE (SET_SRC (prev_set)) == NEG\n-\t  && GET_CODE (SET_SRC (curr_set)) == SMAX\n-\t  && REG_P (SET_DEST (prev_set))\n-\t  && REG_P (SET_DEST (curr_set))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 0))\n-\t  && REGNO (XEXP (SET_SRC (curr_set), 0)) == prev_dest_regno\n-\t  && REG_P (XEXP (SET_SRC (prev_set), 0))\n-\t  && REG_P (XEXP (SET_SRC (curr_set), 1))\n-\t  && (REGNO (XEXP (SET_SRC (prev_set), 0))\n-\t      == REGNO (XEXP (SET_SRC (curr_set), 1))))\n-\t{\n-\t  if (dump_file)\n-\t    fprintf (dump_file, \"RISCV_FUSE_B_ALUI\\n\");\n-\t  return true;\n-\t}\n-    }\n-\n-  return false;\n+  return tune_param->fusible_ops;\n }\n \n /* Adjust the cost/latency of instructions for scheduling.\ndiff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv\nindex 2761e5e20c0..1f06a3697b6 100644\n--- a/gcc/config/riscv/t-riscv\n+++ b/gcc/config/riscv/t-riscv\n@@ -95,6 +95,13 @@ riscv-opt-popretz.o: $(srcdir)/config/riscv/riscv-opt-popretz.cc $(CONFIG_H) \\\n \t$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \\\n \t\t$(srcdir)/config/riscv/riscv-opt-popretz.cc\n \n+riscv-fusion.o: $(srcdir)/config/riscv/riscv-fusion.cc $(CONFIG_H) \\\n+  $(SYSTEM_H) coretypes.h $(TM_H) $(TARGET_H) $(RTL_H) $(REGS_H) \\\n+  $(RECOG_H) $(FUNCTION_H) $(EMIT_RTL_H) $(TM_P_H) insn-config.h \\\n+  $(srcdir)/config/riscv/riscv-protos.h\n+\t$(COMPILE) $<\n+\t$(POSTCOMPILE)\n+\n riscv-c.o: $(srcdir)/config/riscv/riscv-c.cc $(CONFIG_H) $(SYSTEM_H) \\\n     coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) $(TARGET_H)\n \t$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \\\ndiff --git a/gcc/testsuite/gcc.target/riscv/fusion-auipc-addi.c b/gcc/testsuite/gcc.target/riscv/fusion-auipc-addi.c\nnew file mode 100644\nindex 00000000000..03ff27481dd\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fusion-auipc-addi.c\n@@ -0,0 +1,11 @@\n+/* { dg-do compile } */\n+/* { dg-skip-if \"\" { *-*-* } { \"-O0\" \"-O1\" \"-Og\" \"-Os\" \"-Oz\" \"-flto\" } } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -mtune=sifive-p600-series -mcmodel=medany -mexplicit-relocs -fno-section-anchors -fdump-rtl-sched1\" } */\n+/* { dg-final { scan-rtl-dump \"RISCV_FUSE_AUIPC_ADDI\" \"sched1\" } } */\n+/* { dg-final { scan-assembler \"auipc\\ta0,%pcrel_hi\\\\(x\\\\)\\n\\taddi\\ta0,a0,%pcrel_lo\\\\(\\\\.LA\\[0-9\\]+\\\\)\" } } */\n+\n+extern void use(long *);\n+void foo(void) {\n+  extern long x;\n+  use(&x);\n+}\ndiff --git a/gcc/testsuite/gcc.target/riscv/fusion-lui-addi.c b/gcc/testsuite/gcc.target/riscv/fusion-lui-addi.c\nnew file mode 100644\nindex 00000000000..97976cc94ca\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fusion-lui-addi.c\n@@ -0,0 +1,15 @@\n+/* { dg-do compile } */\n+/* { dg-skip-if \"\" { *-*-* } { \"-O0\" \"-O1\" \"-Og\" \"-Os\" \"-Oz\" \"-flto\" } } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -mtune=sifive-p600-series -fdump-rtl-sched1\" } */\n+/* { dg-final { check-function-bodies \"**\" \"\" } } */\n+/* { dg-final { scan-rtl-dump \"RISCV_FUSE_LUI_ADDI\" \"sched1\" } } */\n+\n+/*\n+**foo:\n+**\tli\ta0,305418240\n+**\taddi\ta0,a0,1656\n+**\tret\n+*/\n+long foo(void) {\n+  return 0x12345678L;\n+}\ndiff --git a/gcc/testsuite/gcc.target/riscv/fusion-zexth.c b/gcc/testsuite/gcc.target/riscv/fusion-zexth.c\nnew file mode 100644\nindex 00000000000..63be24ab200\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fusion-zexth.c\n@@ -0,0 +1,15 @@\n+/* { dg-do compile } */\n+/* { dg-skip-if \"\" { *-*-* } { \"-O0\" \"-O1\" \"-Og\" \"-Os\" \"-Oz\" \"-flto\" } } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -mtune=xiangshan-nanhu -fdump-rtl-sched2\" } */\n+/* { dg-final { check-function-bodies \"**\" \"\" } } */\n+/* { dg-final { scan-rtl-dump \"RISCV_FUSE_ZEXTH\" \"sched2\" } } */\n+\n+/*\n+**foo:\n+**\tslli\ta0,a0,48\n+**\tsrli\ta0,a0,48\n+**\tret\n+*/\n+unsigned long foo(unsigned long x) {\n+  return (unsigned long)(unsigned short)x;\n+}\ndiff --git a/gcc/testsuite/gcc.target/riscv/fusion-zextw.c b/gcc/testsuite/gcc.target/riscv/fusion-zextw.c\nnew file mode 100644\nindex 00000000000..b64344b76e6\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/riscv/fusion-zextw.c\n@@ -0,0 +1,15 @@\n+/* { dg-do compile } */\n+/* { dg-skip-if \"\" { *-*-* } { \"-O0\" \"-O1\" \"-Og\" \"-Os\" \"-Oz\" \"-flto\" } } */\n+/* { dg-options \"-march=rv64gc -mabi=lp64d -mtune=xiangshan-nanhu -fdump-rtl-sched2\" } */\n+/* { dg-final { check-function-bodies \"**\" \"\" } } */\n+/* { dg-final { scan-rtl-dump \"RISCV_FUSE_ZEXTWS\" \"sched2\" } } */\n+\n+/*\n+**foo:\n+**\tslli\ta0,a0,32\n+**\tsrli\ta0,a0,32\n+**\tret\n+*/\n+unsigned long foo(unsigned long x) {\n+  return (unsigned long)(unsigned int)x;\n+}\n","prefixes":[]}