From patchwork Sun Nov 13 22:00:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Christoph_M=C3=BCllner?= X-Patchwork-Id: 60559 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EF8853887F6F for ; Sun, 13 Nov 2022 22:01:27 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-ej1-x62c.google.com (mail-ej1-x62c.google.com [IPv6:2a00:1450:4864:20::62c]) by sourceware.org (Postfix) with ESMTPS id 4350A38582BE for ; Sun, 13 Nov 2022 22:01:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4350A38582BE Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=vrull.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=vrull.eu Received: by mail-ej1-x62c.google.com with SMTP id bj12so24084288ejb.13 for ; Sun, 13 Nov 2022 14:01:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vrull.eu; s=google; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=1bSXsOS+VUYDprHrzkeqG72GxXv5xQGcYnaVWomTRpM=; b=cSAxnMFaOx3LWRO1WWVRxjxKvgmGgyH3e8hlRsfrLmwr/S49IekudbW2u7ZJnn+qNc bruH8ne7ziATS1kbYhMpnXUVrCPSuB7w4bPrEeAK6PfE4jodR39Q45d2RnbhBekVdTpZ b2Rz7FSzmpaR8BthzWhA49sGZJVcX6fVG1P9LWXC422WY661B16h9USuYBbEHCYAs5o3 b86OgdB6Nql53lBYV4OPpbfX8C4Di7sdgVoDSDOdVa4CWxKOG93gJDF6BrinnN4YSJQT pgH5l6+eenlL5ZLsNITmedJxVjTmFkD/HFRRu0RsCPYqF01vjV/XCDGS62nY0UKd44+l L6Ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=1bSXsOS+VUYDprHrzkeqG72GxXv5xQGcYnaVWomTRpM=; b=ga48xqqSMoShUh/VJJx8U/GnbQS4bUUTeohqmxQeLJLcr6YhzCMnSbJfphvvZW+HBc zh+WHyTvXAKS5zE2YVnnkq13beqpTO+4fsKT7N265PkKxwQgzZAnJBDCy6bYaZDBsPoK 0SN2vjXqhn3OyDdrzGe8EuWLt8L84VwyPvMMkCOtO0mnwR8Z20ppo5UiqmtNNZWj6H3g VY2MbXSmCobuz6eiJ5mMaAybWOpKTmU1zKL30RRKdnDEW23tbXY4JYxGvT+O1v6JTUjh qU80CVclZj/tH1Bhl35Ysh/otpsuG+sjcVbDuVu1yctbvClFDAzi3ktLhU25V1ziCPl0 DInw== X-Gm-Message-State: ANoB5pmFrQZqh0Kt41geBetKNUPcQ0fghewZR+eNfx6Jgp0nvtlqF83T fZ61BR/ZDPdUxXCEU7Bu8FSmXexM3IK/M+Kc X-Google-Smtp-Source: AA0mqf6Cr6VjPHm9Lpso3SyMS9FA8OC2w4Z7ud1iVBDjSyw1jEiQaurmmInD2laOM7QbiV497QDzcA== X-Received: by 2002:a17:907:c282:b0:78d:36d7:92ae with SMTP id tk2-20020a170907c28200b0078d36d792aemr8595385ejc.113.1668376860507; Sun, 13 Nov 2022 14:01:00 -0800 (PST) Received: from beast.fritz.box (62-178-148-172.cable.dynamic.surfer.at. [62.178.148.172]) by smtp.gmail.com with ESMTPSA id jz22-20020a17090775f600b0073dc4385d3bsm3379324ejc.105.2022.11.13.14.00.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Nov 2022 14:00:59 -0800 (PST) From: Christoph Muellner To: gcc-patches@gcc.gnu.org, Kito Cheng , Jim Wilson , Palmer Dabbelt , Andrew Waterman , Philipp Tomsich , Cooper Qu , Lifang Xia , Yunhai Shang , Zhiwei Liu Cc: "moiz.hussain" , "M . Moiz Hussain" Subject: [RFC PATCH] riscv: thead: Add support for XTheadMemPair ISA extension Date: Sun, 13 Nov 2022 23:00:57 +0100 Message-Id: <20221113220057.2753718-1-christoph.muellner@vrull.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_MANYTO, KAM_SHORT, LIKELY_SPAM_BODY, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 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 Sender: "Gcc-patches" From: "moiz.hussain" The XTheadMacXTheadMemPair ISA extension provides load/store pair instructions: * th.ldd * th.sdd * th.lwd * th.lwud * th.swd We added the following unnamed patterns to the peephole.md stage: * load/store pair patterns for 4 instructions * load/store pair patterns for 2 instructions It was also required to add define_insn patterns to thead.md: * th_mov_mempair_ * th_mov_mempair_di_si_zero_ext * th_mov_mempair_di_si_sign_ext * th_mov_mempair_si_si_zero_ext * th_mov_mempair_si_si_sign_ext Much of the code has been inspired by the MIPS and the aarch64 backend. Also the new test cases were inspired by other architectures. The patch is meant to apply on top of the XThead* series that has been posted here: https://gcc.gnu.org/pipermail/gcc-patches/2022-November/605980.html This patch is in RFC mode as we still need to sort out some failing tests. However, we'd like to get some feedback from the RISC-V maintainers on the approach that we have taken. Especially since the patch is already quite big. Signed-off-by: M. Moiz Hussain --- gcc/common/config/riscv/riscv-common.cc | 2 + gcc/config/riscv/peephole.md | 336 +++++++++ gcc/config/riscv/riscv-opts.h | 4 +- gcc/config/riscv/riscv-protos.h | 9 + gcc/config/riscv/riscv.cc | 701 ++++++++++++++++++ gcc/config/riscv/thead.md | 83 +++ .../gcc.target/riscv/xtheadmempair-1.c | 39 + .../gcc.target/riscv/xtheadmempair-10.c | 35 + .../gcc.target/riscv/xtheadmempair-11.c | 22 + .../gcc.target/riscv/xtheadmempair-12.c | 23 + .../gcc.target/riscv/xtheadmempair-13.c | 31 + .../gcc.target/riscv/xtheadmempair-14.c | 36 + .../gcc.target/riscv/xtheadmempair-15.c | 20 + .../gcc.target/riscv/xtheadmempair-16.c | 24 + .../gcc.target/riscv/xtheadmempair-17.c | 16 + .../gcc.target/riscv/xtheadmempair-18.c | 67 ++ .../gcc.target/riscv/xtheadmempair-18.h | 59 ++ .../gcc.target/riscv/xtheadmempair-19.c | 86 +++ .../gcc.target/riscv/xtheadmempair-2.c | 24 + .../gcc.target/riscv/xtheadmempair-20.c | 23 + .../gcc.target/riscv/xtheadmempair-3.c | 35 + .../gcc.target/riscv/xtheadmempair-4.c | 25 + .../gcc.target/riscv/xtheadmempair-5.c | 23 + .../gcc.target/riscv/xtheadmempair-6.c | 22 + .../gcc.target/riscv/xtheadmempair-7.c | 22 + .../gcc.target/riscv/xtheadmempair-8.c | 31 + .../gcc.target/riscv/xtheadmempair-9.c | 36 + 27 files changed, 1833 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-10.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-11.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-12.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-13.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-14.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-15.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-16.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-17.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-18.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-18.h create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-19.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-20.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-5.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-6.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-7.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-8.c create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-9.c diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 8e1449d3543..b541c55976b 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -230,6 +230,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"xtheadfmemidx", ISA_SPEC_CLASS_NONE, 1, 0}, {"xtheadmac", ISA_SPEC_CLASS_NONE, 1, 0}, {"xtheadmemidx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"xtheadmempair", ISA_SPEC_CLASS_NONE, 1, 0}, {"xtheadsync", ISA_SPEC_CLASS_NONE, 1, 0}, /* Terminate the list. */ @@ -1265,6 +1266,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"xtheadfmemidx", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADFMEMIDX}, {"xtheadmac", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADMAC}, {"xtheadmemidx", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADMEMIDX}, + {"xtheadmempair", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADMEMPAIR}, {"xtheadsync", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADSYNC}, {NULL, NULL, 0} diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md index d9477f46338..2e1b6fff314 100644 --- a/gcc/config/riscv/peephole.md +++ b/gcc/config/riscv/peephole.md @@ -38,3 +38,339 @@ (define_peephole2 { operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5])); }) + +;; +;; .................... +;; +;; T-HEAD EXTENSION MEMPAIR - 4 instr LOADS +;; +;; .................... + +;; LOAD +;; T-HEAD: Four DI loads, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 8 "r") + (set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "memory_operand" "")) + (set (match_operand:DI 2 "register_operand" "") + (match_operand:DI 3 "memory_operand" "")) + (set (match_operand:DI 4 "register_operand" "") + (match_operand:DI 5 "memory_operand" "")) + (set (match_operand:DI 6 "register_operand" "") + (match_operand:DI 7 "memory_operand" "")) + (match_dup 8)] + "TARGET_XTHEADMEMPAIR && TARGET_64BIT + && riscv_load_store_bonding_p_4instr (operands, DImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, DImode, + SIGN_EXTEND, true)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: Four SI unsigned loads, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 8 "r") + (set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:SI 1 "memory_operand" ""))) + (set (match_operand:DI 2 "register_operand" "") + (zero_extend:DI (match_operand:SI 3 "memory_operand" ""))) + (set (match_operand:DI 4 "register_operand" "") + (zero_extend:DI (match_operand:SI 5 "memory_operand" ""))) + (set (match_operand:DI 6 "register_operand" "") + (zero_extend:DI (match_operand:SI 7 "memory_operand" ""))) + (match_dup 8)] + "TARGET_XTHEADMEMPAIR + && riscv_load_store_bonding_p_4instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + ZERO_EXTEND, true)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: Four SI signed loads, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 8 "r") + (set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "memory_operand" ""))) + (set (match_operand:DI 2 "register_operand" "") + (sign_extend:DI (match_operand:SI 3 "memory_operand" ""))) + (set (match_operand:DI 4 "register_operand" "") + (sign_extend:DI (match_operand:SI 5 "memory_operand" ""))) + (set (match_operand:DI 6 "register_operand" "") + (sign_extend:DI (match_operand:SI 7 "memory_operand" ""))) + (match_dup 8)] + "TARGET_XTHEADMEMPAIR + && riscv_load_store_bonding_p_4instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + SIGN_EXTEND, true)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: Four SI loads, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 8 "r") + (set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "memory_operand" "")) + (set (match_operand:SI 4 "register_operand" "") + (match_operand:SI 5 "memory_operand" "")) + (set (match_operand:SI 6 "register_operand" "") + (match_operand:SI 7 "memory_operand" "")) + (match_dup 8)] + "TARGET_XTHEADMEMPAIR + && riscv_load_store_bonding_p_4instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + SIGN_EXTEND, true)) + DONE; + else + FAIL; +}) + +;; +;; .................... +;; +;; T-HEAD EXTENSION MEMPAIR - 4 instr STORES +;; +;; .................... + +;; STORE +;; T-HEAD: Four DI stores, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 8 "r") + (set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "register_operand" "")) + (set (match_operand:DI 2 "memory_operand" "") + (match_operand:DI 3 "register_operand" "")) + (set (match_operand:DI 4 "memory_operand" "") + (match_operand:DI 5 "register_operand" "")) + (set (match_operand:DI 6 "memory_operand" "") + (match_operand:DI 7 "register_operand" "")) + (match_dup 8)] + "TARGET_XTHEADMEMPAIR && TARGET_64BIT + && riscv_load_store_bonding_p_4instr (operands, DImode, false)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, false, DImode, + SIGN_EXTEND, true)) + DONE; + else + FAIL; +}) + +;; STORE +;; T-HEAD: Four SI stores, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 8 "r") + (set (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "memory_operand" "") + (match_operand:SI 3 "register_operand" "")) + (set (match_operand:SI 4 "memory_operand" "") + (match_operand:SI 5 "register_operand" "")) + (set (match_operand:SI 6 "memory_operand" "") + (match_operand:SI 7 "register_operand" "")) + (match_dup 8)] + "TARGET_XTHEADMEMPAIR && !TARGET_64BIT + && riscv_load_store_bonding_p_4instr (operands, SImode, false)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, false, SImode, + SIGN_EXTEND, true)) + DONE; + else + FAIL; +}) + +;; +;; .................... +;; +;; T-HEAD EXTENSION MEMPAIR - 2 instr LOADS +;; +;; .................... + +;; LOAD +;; T-HEAD: A pair of two DI loads, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "memory_operand" "")) + (set (match_operand:DI 2 "register_operand" "") + (match_operand:DI 3 "memory_operand" "")) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR && TARGET_64BIT + && riscv_load_store_bonding_p_2instr (operands, DImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, DImode, + SIGN_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: A pair of two DI extend unsigned SI loads, +;; with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:SI 1 "memory_operand" ""))) + (set (match_operand:DI 2 "register_operand" "") + (zero_extend:DI (match_operand:SI 3 "memory_operand" ""))) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR + && riscv_load_store_bonding_p_2instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + ZERO_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: A pair of two DI extend signed SI loads, +;; with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "memory_operand" ""))) + (set (match_operand:DI 2 "register_operand" "") + (sign_extend:DI (match_operand:SI 3 "memory_operand" ""))) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR + && riscv_load_store_bonding_p_2instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + SIGN_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: A pair of two SI extend unsigned SI loads, +;; with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:SI 1 "memory_operand" ""))) + (set (match_operand:SI 2 "register_operand" "") + (zero_extend:SI (match_operand:SI 3 "memory_operand" ""))) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR && !TARGET_64BIT + && riscv_load_store_bonding_p_2instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + ZERO_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: A pair of two SI extend signed SI loads, +;; with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:SI 1 "memory_operand" ""))) + (set (match_operand:SI 2 "register_operand" "") + (sign_extend:SI (match_operand:SI 3 "memory_operand" ""))) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR && !TARGET_64BIT + && riscv_load_store_bonding_p_2instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + SIGN_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; LOAD +;; T-HEAD: A pair of two SI loads, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "memory_operand" "")) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR && !TARGET_64BIT + && riscv_load_store_bonding_p_2instr (operands, SImode, true)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, true, SImode, + SIGN_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; +;; .................... +;; +;; T-HEAD EXTENSION MEMPAIR - 2 instr STORES +;; +;; .................... + +;; STORE +;; T-HEAD: A pair of two DI stores, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "register_operand" "")) + (set (match_operand:DI 2 "memory_operand" "") + (match_operand:DI 3 "register_operand" "")) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR && TARGET_64BIT + && riscv_load_store_bonding_p_2instr (operands, DImode, false)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, false, DImode, + SIGN_EXTEND, false)) + DONE; + else + FAIL; +}) + +;; STORE +;; T-HEAD: A pair of two SI stores, with non-adjusted offset +(define_peephole2 + [(match_scratch:P 4 "r") + (set (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "memory_operand" "") + (match_operand:SI 3 "register_operand" "")) + (match_dup 4)] + "TARGET_XTHEADMEMPAIR + && riscv_load_store_bonding_p_2instr (operands, SImode, false)" + [(const_int 0)] +{ + if (th_riscv_gen_adjusted_mempair (operands, false, SImode, + SIGN_EXTEND, false)) + DONE; + else + FAIL; +}) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 18daac40dbd..626de51d644 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -205,7 +205,9 @@ enum stack_protector_guard { #define TARGET_XTHEADMAC ((riscv_xthead_subext & MASK_XTHEADMAC) != 0) #define MASK_XTHEADMEMIDX (1 << 7) #define TARGET_XTHEADMEMIDX ((riscv_xthead_subext & MASK_XTHEADMEMIDX) != 0) -#define MASK_XTHEADSYNC (1 << 8) +#define MASK_XTHEADMEMPAIR (1 << 8) +#define TARGET_XTHEADMEMPAIR ((riscv_xthead_subext & MASK_XTHEADMEMPAIR) != 0) +#define MASK_XTHEADSYNC (1 << 9) #define TARGET_XTHEADSYNC ((riscv_xthead_subext & MASK_XTHEADSYNC) != 0) #endif /* ! GCC_RISCV_OPTS_H */ diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 5a718bb62b4..9161bef50a6 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -54,7 +54,16 @@ extern bool riscv_split_64bit_move_p (rtx, rtx); extern void riscv_split_doubleword_move (rtx, rtx); extern const char *riscv_output_move (rtx, rtx); extern const char *riscv_output_return (); +extern bool riscv_load_store_bonding_p_2instr (rtx*, machine_mode, bool); +extern bool riscv_load_store_bonding_p_4instr (rtx*, machine_mode, bool); +extern int riscv_ldrstr_offset_compare (const void *, const void *); +extern void riscv_swap_ldrstr_operands (rtx*, bool); +extern bool extract_base_offset_in_addr (rtx mem, rtx *base, rtx *offset); #ifdef RTX_CODE +extern const char *th_riscv_output_mempair_move (rtx*, machine_mode, + enum rtx_code); +extern bool th_riscv_gen_adjusted_mempair (rtx*, bool, machine_mode, + enum rtx_code, bool); extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx); extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx); extern void riscv_expand_conditional_branch (rtx, enum rtx_code, rtx, rtx); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 5a0a2b0c2db..8cd24c29fc1 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "alias.h" #include "tree.h" +#include "fold-const.h" #include "stringpool.h" #include "attribs.h" #include "varasm.h" @@ -55,6 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "predict.h" #include "tree-pass.h" +#include "tree-dfa.h" #include "opts.h" #include "tm-constrs.h" #include "rtl-iter.h" @@ -2835,6 +2837,705 @@ riscv_output_move (rtx dest, rtx src) gcc_unreachable (); } +/* If MEM is in the form of "base+offset", extract the two parts + of address and set to BASE and OFFSET, otherwise return false + after clearing BASE and OFFSET. */ + +bool +extract_base_offset_in_addr (rtx mem, rtx *base, rtx *offset) +{ + rtx addr; + + gcc_assert (MEM_P (mem)); + + addr = XEXP (mem, 0); + + if (REG_P (addr)) + { + *base = addr; + *offset = const0_rtx; + return true; + } + + if (GET_CODE (addr) == PLUS + && REG_P (XEXP (addr, 0)) && CONST_INT_P (XEXP (addr, 1))) + { + *base = XEXP (addr, 0); + *offset = XEXP (addr, 1); + return true; + } + + *base = NULL_RTX; + *offset = NULL_RTX; + + return false; +} + +#ifdef RTX_CODE +/* Return the appropriate instructions to move SRC into DEST. */ + +/* If REVERSED is null, return true if memory reference *MEM2 comes + immediately after memory reference *MEM1. Do not change the references + in this case. + + Otherwise, check if *MEM1 and *MEM2 are consecutive memory references and, + if they are, try to make them use constant offsets from the same base + register. Return true on success. When returning true, set *REVERSED + to true if *MEM1 comes after *MEM2, false if *MEM1 comes before *MEM2. */ +static bool +riscv_check_consecutive_mems (rtx *mem1, rtx *mem2, bool *reversed) +{ + if (reversed) + *reversed = false; + + if (GET_RTX_CLASS (GET_CODE (XEXP (*mem1, 0))) == RTX_AUTOINC + || GET_RTX_CLASS (GET_CODE (XEXP (*mem2, 0))) == RTX_AUTOINC) + return false; + + if (!MEM_SIZE_KNOWN_P (*mem1) || !MEM_SIZE_KNOWN_P (*mem2)) + return false; + + auto size1 = MEM_SIZE (*mem1); + auto size2 = MEM_SIZE (*mem2); + + rtx base1, base2, offset1, offset2; + extract_base_offset_in_addr (*mem1, &base1, &offset1); + extract_base_offset_in_addr (*mem2, &base2, &offset2); + + /* Make sure at least one memory is in base+offset form. */ + if (!(base1 && offset1) && !(base2 && offset2)) + return false; + + /* If both mems already use the same base register, just check the + offsets. */ + if (base1 && base2 && rtx_equal_p (base1, base2)) + { + if (!offset1 || !offset2) + return false; + + if (known_eq (UINTVAL (offset1) + size1, UINTVAL (offset2))) + return true; + + if (known_eq (UINTVAL (offset2) + size2, UINTVAL (offset1)) && reversed) + { + *reversed = true; + return true; + } + + return false; + } + + /* Otherwise, check whether the MEM_EXPRs and MEM_OFFSETs together + guarantee that the values are consecutive. */ + if (MEM_EXPR (*mem1) + && MEM_EXPR (*mem2) + && MEM_OFFSET_KNOWN_P (*mem1) + && MEM_OFFSET_KNOWN_P (*mem2)) + { + poly_int64 expr_offset1; + poly_int64 expr_offset2; + tree expr_base1 = get_addr_base_and_unit_offset (MEM_EXPR (*mem1), + &expr_offset1); + tree expr_base2 = get_addr_base_and_unit_offset (MEM_EXPR (*mem2), + &expr_offset2); + if (!expr_base1 + || !expr_base2 + || !DECL_P (expr_base1) + || !operand_equal_p (expr_base1, expr_base2, OEP_ADDRESS_OF)) + return false; + + expr_offset1 += MEM_OFFSET (*mem1); + expr_offset2 += MEM_OFFSET (*mem2); + + if (known_eq (expr_offset1 + size1, expr_offset2)) + ; + else if (known_eq (expr_offset2 + size2, expr_offset1) && reversed) + *reversed = true; + else + return false; + + if (reversed) + { + if (base2) + { + rtx addr1 = plus_constant (Pmode, XEXP (*mem2, 0), + expr_offset1 - expr_offset2); + *mem1 = replace_equiv_address_nv (*mem1, addr1); + } + else + { + rtx addr2 = plus_constant (Pmode, XEXP (*mem1, 0), + expr_offset2 - expr_offset1); + *mem2 = replace_equiv_address_nv (*mem2, addr2); + } + } + return true; + } + + return false; +} + +/* Given OPERANDS of consecutive load/store that can be merged, + swap them if they are not in ascending order. */ +void +riscv_swap_ldrstr_operands (rtx* operands, bool load) +{ + int mem_op = load ? 1 : 0; + bool reversed = false; + if (!riscv_check_consecutive_mems (operands + mem_op, + operands + mem_op + 2, &reversed)) + gcc_unreachable (); + + if (reversed) + { + /* Irrespective of whether this is a load or a store, + we do the same swap. */ + std::swap (operands[0], operands[2]); + std::swap (operands[1], operands[3]); + } +} + +/* If X is a PLUS of a CONST_INT, return the two terms in *BASE_PTR + and *OFFSET_PTR. Return X in *BASE_PTR and 0 in *OFFSET_PTR otherwise. */ + +static void +riscv_split_plus (rtx x, rtx *base_ptr, HOST_WIDE_INT *offset_ptr) +{ + if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1))) + { + *base_ptr = XEXP (x, 0); + *offset_ptr = INTVAL (XEXP (x, 1)); + } + else + { + *base_ptr = x; + *offset_ptr = 0; + } +} + +const char * +th_riscv_output_mempair_move (rtx *operands, machine_mode mode, + enum rtx_code code) +{ + unsigned width; + rtx reg1, reg2, mem1, mem2, base1, base2; + HOST_WIDE_INT offset1, offset2; + rtx output_operands[5]; + + width = GET_MODE_SIZE (mode).to_constant (); + + // LOAD + if (which_alternative == 0) + { + reg1 = copy_rtx (operands[0]); + reg2 = copy_rtx (operands[2]); + mem1 = copy_rtx (operands[1]); + mem2 = copy_rtx (operands[3]); + } + // STORE + else if (which_alternative == 1) + { + reg1 = copy_rtx (operands[1]); + reg2 = copy_rtx (operands[3]); + mem1 = copy_rtx (operands[0]); + mem2 = copy_rtx (operands[2]); + } + + riscv_split_plus (XEXP (mem1, 0), &base1, &offset1); + riscv_split_plus (XEXP (mem2, 0), &base2, &offset2); + + // LOAD + if (which_alternative == 0) + { + switch (width) + { + case 4: + { + gcc_assert (!(offset1 % 8)); + + output_operands[0] = copy_rtx (reg1); + output_operands[1] = copy_rtx (reg2); + output_operands[2] = copy_rtx (base1); + output_operands[3] = gen_rtx_CONST_INT (mode, (offset1 >> 3)); + output_operands[4] = gen_rtx_CONST_INT (mode, 3); + + if (code == ZERO_EXTEND) + output_asm_insn ("th.lwud %0, %1, (%2), %3, %4", + output_operands); + else if (code == SIGN_EXTEND) + output_asm_insn ("th.lwd %0, %1, (%2), %3, %4", + output_operands); + else + abort (); + break; + } + case 8: + { + gcc_assert (!(offset1 % 16)); + + output_operands[0] = copy_rtx (reg1); + output_operands[1] = copy_rtx (reg2); + output_operands[2] = copy_rtx (base1); + output_operands[3] = gen_rtx_CONST_INT (mode, (offset1 >> 4)); + output_operands[4] = gen_rtx_CONST_INT (mode, 4); + + output_asm_insn ("th.ldd %0, %1, (%2), %3, %4", output_operands); + break; + } + default: + abort (); + } + } + // STORE + else if (which_alternative == 1) + { + switch (width) + { + case 4: + { + gcc_assert (!(offset1 % 8)); + + output_operands[0] = copy_rtx (reg1); + output_operands[1] = copy_rtx (reg2); + output_operands[2] = copy_rtx (base1); + output_operands[3] = gen_rtx_CONST_INT (mode, (offset1 >> 3)); + output_operands[4] = gen_rtx_CONST_INT (mode, 3); + + output_asm_insn ("th.swd %z0, %z1, (%2), %3, %4", output_operands); + break; + } + case 8: + { + gcc_assert (!(offset1 % 16)); + + output_operands[0] = copy_rtx (reg1); + output_operands[1] = copy_rtx (reg2); + output_operands[2] = copy_rtx (base1); + output_operands[3] = gen_rtx_CONST_INT (mode, (offset1 >> 4)); + output_operands[4] = gen_rtx_CONST_INT (mode, 4); + + output_asm_insn ("th.sdd %z0, %z1, (%2), %3, %4", output_operands); + break; + } + default: + abort (); + } + } + // UNKNOWN + else + { + abort (); + } + return ""; +} +#endif + +/* Given OPERANDS of consecutive load/store, check if we can merge + them into load-pair or store-pair instructions by adjusting the + offset. LOAD is true if they are load instructions. + MODE is the mode of memory operands. + + Given below consecutive stores: + + sd a2, 0x100 (a1) + sd a3, 0x108 (a1) + sd a4, 0x110 (a1) + sd a5, 0x118 (a1) + + Though the offsets are out of the range supported by stp, we can + still pair them after adjusting the offset, like: + + addi t0, a1, 0x100 + th.sdd a2, a3, 0 (t0), 0, 4 + th.sdd a4, a5, 16 (t0), 0, 4 + + The peephole patterns detecting this opportunity should guarantee + the scratch register is avaliable. + + The function works for 4 consecutive load/store pairs. */ +bool +riscv_load_store_bonding_p_4instr (rtx *operands, machine_mode mode, +bool load_p) +{ + HOST_WIDE_INT msize; + msize = GET_MODE_SIZE (mode).to_constant (); + + constexpr int NUM_INSTR = 4; + + rtx reg[NUM_INSTR], mem[NUM_INSTR], base[NUM_INSTR]; + rtx temp_operands[2*NUM_INSTR]; + + enum reg_class rc[NUM_INSTR]; + HOST_WIDE_INT offset[NUM_INSTR]; + + /* We make changes on a copy as we may still bail out. */ + for (int i = 0; i < (2*NUM_INSTR); i++) + temp_operands[i] = copy_rtx (operands[i]); + + /* Sort the operands. */ + gcc_stablesort (temp_operands, NUM_INSTR, 2 * sizeof (rtx *), + riscv_ldrstr_offset_compare); + + for (int i = 0; i < NUM_INSTR; i++) + { + reg[i] = (load_p)? temp_operands[2*i] : temp_operands[(2*i) + 1]; + mem[i] = (load_p)? temp_operands[(2*i) + 1] : temp_operands[(2*i)]; + } + + for (int i = 0; i < NUM_INSTR; i++) + { + riscv_split_plus (XEXP (mem[i], 0), &base[i], &offset[i]); + rc[i] = REGNO_REG_CLASS (REGNO (reg[i])); + } + + for (int i = 0; i < NUM_INSTR; i++) + { + /* All bases are reg. */ + if (!REG_P (base[i])) + { + return false; + } + /* The mems cannot be volatile. */ + if (MEM_VOLATILE_P (mem[i])) + { + return false; + } + /* Base regs do not match. */ + if (!rtx_equal_p (base[i], base[(i+1) % NUM_INSTR])) + { + return false; + } + } + +/* Either of the loads is clobbering base register. It is legitimate to + bond loads if second load clobbers base register. However, hardware + does not support such bonding. */ + if (load_p + && (REGNO (reg[0]) == REGNO (base[0]) + || (REGNO (reg[1]) == REGNO (base[0]))) + && (REGNO (reg[2]) == REGNO (base[0]) + || (REGNO (reg[3]) == REGNO (base[3]))) + && (REGNO (reg[1]) == REGNO (base[1]) + || (REGNO (reg[2]) == REGNO (base[2])))) + { + return false; + } + + /* Loading in same registers. */ + if (load_p + && (REGNO (reg[0]) == REGNO (reg[1])) + && (REGNO (reg[1]) == REGNO (reg[2])) + && (REGNO (reg[2]) == REGNO (reg[3]))) + { + return false; + } + + /* The loads/stores are not of same type. */ + if (rc[0] != rc[1] + && rc[1] != rc[2] + && rc[2] != rc[3] + && !reg_class_subset_p (rc[0], rc[1]) + && !reg_class_subset_p (rc[1], rc[0]) + && !reg_class_subset_p (rc[2], rc[3]) + && !reg_class_subset_p (rc[3], rc[2]) + && !reg_class_subset_p (rc[1], rc[2]) + && !reg_class_subset_p (rc[2], rc[3])) + { + return false; + } + + if ((abs (offset[0] - offset[1]) != msize) + || (abs (offset[2] - offset[3]) != msize) + || (abs (offset[1] - offset[2]) != msize)) + { + return false; + } + return true; +} + +/* Given OPERANDS of consecutive load/store, check if we can merge + them into load-pair or store-pair instructions by adjusting the + offset. LOAD is true if they are load instructions. + MODE is the mode of memory operands. + + Given below consecutive stores: + + sd a2, 0x100 (a1) + sd a3, 0x108 (a1) + sd a4, 0x110 (a1) + sd a5, 0x118 (a1) + + Though the offsets are out of the range supported by stp, we can + still pair them after adjusting the offset, like: + + addi t0, a1, 0x100 + th.sdd a2, a3, 0 (t0), 0, 4 + th.sdd a4, a5, 16 (t0), 0, 4 + + The peephole patterns detecting this opportunity should guarantee + the scratch register is avaliable. + + The function works for 2 consecutive load/store pairs. */ +bool +riscv_load_store_bonding_p_2instr (rtx *operands, machine_mode mode, +bool load_p) +{ + HOST_WIDE_INT msize; + msize = GET_MODE_SIZE (mode).to_constant (); + + constexpr int NUM_INSTR = 2; + + rtx reg[NUM_INSTR], mem[NUM_INSTR], base[NUM_INSTR]; + rtx temp_operands[2*NUM_INSTR]; + + enum reg_class rc[NUM_INSTR]; + HOST_WIDE_INT offset[NUM_INSTR]; + + /* We make changes on a copy as we may still bail out. */ + for (int i = 0; i < (2*NUM_INSTR); i++) + temp_operands[i] = copy_rtx (operands[i]); + + /* Sort the operands. */ + gcc_stablesort (temp_operands, NUM_INSTR, 2 * sizeof (rtx *), + riscv_ldrstr_offset_compare); + + for (int i = 0; i < NUM_INSTR; i++) + { + reg[i] = (load_p)? temp_operands[2*i] : temp_operands[(2*i) + 1]; + mem[i] = (load_p)? temp_operands[(2*i) + 1] : temp_operands[(2*i)]; + } + + for (int i = 0; i < NUM_INSTR; i++) + { + riscv_split_plus (XEXP (mem[i], 0), &base[i], &offset[i]); + rc[i] = REGNO_REG_CLASS (REGNO (reg[i])); + } + + for (int i = 0; i < NUM_INSTR; i++) + { + /* All bases are reg. */ + if (!REG_P (base[i])) + { + return false; + } + /* The mems cannot be volatile. */ + if (MEM_VOLATILE_P (mem[i])) + { + return false; + } + /* Base regs do not match. */ + if (!rtx_equal_p (base[i], base[(i+1) % NUM_INSTR])) + { + return false; + } + } + +/* Either of the loads is clobbering base register. It is legitimate to + bond loads if second load clobbers base register. However, hardware + does not support such bonding. */ + if (load_p + && (REGNO (reg[0]) == REGNO (base[0]) + || (REGNO (reg[1]) == REGNO (base[0])))) + { + return false; + } + + /* Loading in same registers. */ + if (load_p + && REGNO (reg[0]) == REGNO (reg[1])) + { + return false; + } + + /* The loads/stores are not of same type. */ + if (rc[0] != rc[1] + && !reg_class_subset_p (rc[0], rc[1]) + && !reg_class_subset_p (rc[1], rc[0])) + { + return false; + } + + if (abs (offset[0] - offset[1]) != msize) + { + return false; + } + return true; +} + +/* Taking X and Y to be pairs of RTX, one pointing to a MEM rtx and the + other pointing to a REG rtx containing an offset, compare the offsets + of the two pairs. + + Return: + + 1 iff offset (X) > offset (Y) + 0 iff offset (X) == offset (Y) + -1 iff offset (X) < offset (Y) */ +int +riscv_ldrstr_offset_compare (const void *x, const void *y) +{ + const rtx * operands_1 = (const rtx *) x; + const rtx * operands_2 = (const rtx *) y; + rtx mem_1, mem_2, base, offset_1, offset_2; + + if (MEM_P (operands_1[0])) + mem_1 = operands_1[0]; + else + mem_1 = operands_1[1]; + + if (MEM_P (operands_2[0])) + mem_2 = operands_2[0]; + else + mem_2 = operands_2[1]; + + /* Extract the offsets. */ + extract_base_offset_in_addr (mem_1, &base, &offset_1); + extract_base_offset_in_addr (mem_2, &base, &offset_2); + + gcc_assert (offset_1 != NULL_RTX && offset_2 != NULL_RTX); + + return wi::cmps (INTVAL (offset_1), INTVAL (offset_2)); +} + +/* Given OPERANDS of consecutive load/store, this function pairs them + into LDP/STP after adjusting the offset. It depends on the fact + that the operands can be sorted so the offsets are correct for STP. + MODE is the mode of memory operands. CODE is the rtl operator + which should be applied to all memory operands, it's SIGN_EXTEND, + ZERO_EXTEND or UNKNOWN. */ + +bool +th_riscv_gen_adjusted_mempair (rtx *operands, bool load, +machine_mode mode, enum rtx_code code, bool is_four_insns) +{ + rtx base, offset_1, t1, t2, scratch; + HOST_WIDE_INT off_val_1, base_off, new_off_1, + off_upper_limit, off_lower_limit, msize; + + int NUM_INSTR = 2; + if (is_four_insns) + NUM_INSTR = 4; + + rtx temp_operands[2*NUM_INSTR], mem[NUM_INSTR]; + bool emit_adjust_insn = false; + bool misaligned_offset = false; + + scratch = copy_rtx (operands[2*NUM_INSTR]); + msize = GET_MODE_SIZE (mode).to_constant (); + + /* Sort the mem operands. */ + gcc_stablesort (operands, NUM_INSTR, 2 * sizeof (rtx *), + riscv_ldrstr_offset_compare); + + /* We make changes on a copy as we may still bail out. */ + for (int i = 0; i < (2*NUM_INSTR); i++) + temp_operands[i] = copy_rtx (operands[i]); + + for (int i = 0; i < NUM_INSTR; i++) + mem[i] = copy_rtx (load? temp_operands[(2*i) + 1] : temp_operands[2*i]); + + extract_base_offset_in_addr (mem[0], &base, &offset_1); + gcc_assert (base != NULL_RTX && offset_1 != NULL_RTX); + + off_val_1 = INTVAL (offset_1); + + switch (msize) + { + case 4: + { + off_upper_limit = 3 << 3; + off_lower_limit = 0; + misaligned_offset = (off_val_1 % 8)? true : false; + break; + } + case 8: + { + off_upper_limit = 3 << 4; + off_lower_limit = 0; + misaligned_offset = (off_val_1 % 16)? true : false; + break; + } + default: + abort (); + } + + /* Offset of the first STP/LDP. */ + if ((off_val_1 < off_lower_limit) + || (off_val_1 > off_upper_limit) + || misaligned_offset) + { + emit_adjust_insn = true; + new_off_1 = 0; + base_off = abs (new_off_1 - off_val_1); + } + + for (int i = 0; i < NUM_INSTR; i++) + { + if (emit_adjust_insn) + { + replace_equiv_address_nv (mem[i], plus_constant (Pmode, scratch, + (new_off_1 + (i*msize))), true); + } + operands[2*i] = (load)? temp_operands[2*i] : mem[i]; + operands[(2*i) + 1] = (load)? mem[i] : temp_operands[(2*i) + 1]; + } + + if (is_four_insns) + { + if (!riscv_load_store_bonding_p_4instr (operands, mode, load)) + { + return false; + } + } + else + { + if (!riscv_load_store_bonding_p_2instr (operands, mode, load)) + { + return false; + } + } + + /* Sign extension for loads. */ + for (int i = 0; i < NUM_INSTR; i++) + { + if (load && GET_MODE_SIZE (GET_MODE (mem[i])).to_constant () == 4) + { + if (code == ZERO_EXTEND) + { + mem[i] = gen_rtx_ZERO_EXTEND (Pmode, mem[i]); + } + else if (code == SIGN_EXTEND) + { + mem[i] = gen_rtx_SIGN_EXTEND (Pmode, mem[i]); + } + else + { + abort (); + } + } + operands[2*i] = (load)? temp_operands[2*i] : mem[i]; + operands[(2*i) + 1] = (load)? mem[i] : temp_operands[(2*i) + 1]; + } + + /* Emit adjusting instruction. */ + if (emit_adjust_insn) + { + emit_insn (gen_rtx_SET (scratch, plus_constant (Pmode, base, base_off))); + } + + /* Emit ld/sd paired instructions. */ + t1 = gen_rtx_SET (operands[0], operands[1]); + t2 = gen_rtx_SET (operands[2], operands[3]); + emit_insn (gen_rtx_PARALLEL (mode, gen_rtvec (2, t1, t2))); + if (is_four_insns) + { + t1 = gen_rtx_SET (operands[4], operands[5]); + t2 = gen_rtx_SET (operands[6], operands[7]); + emit_insn (gen_rtx_PARALLEL (mode, gen_rtvec (2, t1, t2))); + } + return true; +} + const char * riscv_output_return () { diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md index 995703ff349..4414f8690d6 100644 --- a/gcc/config/riscv/thead.md +++ b/gcc/config/riscv/thead.md @@ -250,3 +250,86 @@ (define_insn "*th_sextw_msubhisi4" (set_attr "mode" "SI")] ) +;; MEMPAIR load/store 64/32 bit +(define_insn "*th_mov_mempair_" + [(set (match_operand:GPR 0 "nonimmediate_operand" "=r, m") + (match_operand:GPR 1 "move_operand" "m, r")) + (set (match_operand:GPR 2 "nonimmediate_operand" "=r, m") + (match_operand:GPR 3 "move_operand" "m, r"))] + "TARGET_XTHEADMEMPAIR && reload_completed + && (register_operand (operands[0], mode) + || reg_or_0_operand (operands[1], mode)) + && (register_operand (operands[2], mode) + || reg_or_0_operand (operands[3], mode))" + { return th_riscv_output_mempair_move (operands, mode, + SIGN_EXTEND); } + [(set_attr "move_type" "load, store") + (set_attr "mode" "")]) + +;; MEMPAIR load DI extended unsigned SI +(define_insn "*th_mov_mempair_di_si_zero_ext" + [(set (match_operand 0 "nonimmediate_operand" "=r") + (zero_extend:DI (match_operand 1 "move_operand" "m"))) + (set (match_operand 2 "nonimmediate_operand" "=r") + (zero_extend:DI (match_operand 3 "move_operand" "m")))] + "TARGET_XTHEADMEMPAIR && reload_completed + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], SImode)) + && (register_operand (operands[2], DImode) + || reg_or_0_operand (operands[3], SImode))" + { return th_riscv_output_mempair_move (operands, SImode, + ZERO_EXTEND); } + [(set_attr "move_type" "load") + (set_attr "mode" "DI") + (set_attr "length" "8")]) + +;; MEMPAIR load DI extended signed SI +(define_insn "*th_mov_mempair_di_si_sign_ext" + [(set (match_operand 0 "nonimmediate_operand" "=r") + (sign_extend:DI (match_operand 1 "move_operand" "m"))) + (set (match_operand 2 "nonimmediate_operand" "=r") + (sign_extend:DI (match_operand 3 "move_operand" "m")))] + "TARGET_XTHEADMEMPAIR && reload_completed + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], SImode)) + && (register_operand (operands[2], DImode) + || reg_or_0_operand (operands[3], SImode))" + { return th_riscv_output_mempair_move (operands, SImode, + SIGN_EXTEND); } + [(set_attr "move_type" "load") + (set_attr "mode" "DI") + (set_attr "length" "8")]) + +;; MEMPAIR load SI extended unsigned SI +(define_insn "*th_mov_mempair_si_si_zero_ext" + [(set (match_operand 0 "nonimmediate_operand" "=r") + (zero_extend:SI (match_operand 1 "move_operand" "m"))) + (set (match_operand 2 "nonimmediate_operand" "=r") + (zero_extend:SI (match_operand 3 "move_operand" "m")))] + "TARGET_XTHEADMEMPAIR && reload_completed + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode)) + && (register_operand (operands[2], SImode) + || reg_or_0_operand (operands[3], SImode))" + { return th_riscv_output_mempair_move (operands, SImode, + ZERO_EXTEND); } + [(set_attr "move_type" "load") + (set_attr "mode" "SI") + (set_attr "length" "4")]) + +;; MEMPAIR load SI extended signed SI +(define_insn "*th_mov_mempair_si_si_sign_ext" + [(set (match_operand 0 "nonimmediate_operand" "=r") + (sign_extend:SI (match_operand 1 "move_operand" "m"))) + (set (match_operand 2 "nonimmediate_operand" "=r") + (sign_extend:SI (match_operand 3 "move_operand" "m")))] + "TARGET_XTHEADMEMPAIR && reload_completed + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode)) + && (register_operand (operands[2], SImode) + || reg_or_0_operand (operands[3], SImode))" + { return th_riscv_output_mempair_move (operands, SImode, + SIGN_EXTEND); } + [(set_attr "move_type" "load") + (set_attr "mode" "SI") + (set_attr "length" "4")]) diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-1.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-1.c new file mode 100644 index 00000000000..e26b1d82c75 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +#include + +#define A_SIZE 32 + +unsigned long long array[A_SIZE]; +unsigned long long temp[A_SIZE]; + +void bar (void); + +// Type your code here, or load an example. +int +foo (void) { + for (int i=0; ia; + *b = p->b; +} + +/* { dg-final { scan-assembler-times "addi\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.ldd\t" 1 { target { rv64 } } } */ + +/* { dg-final { scan-assembler-times "addi\t" 2 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.lwd\t" 2 { target { rv32 } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-14.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-14.c new file mode 100644 index 00000000000..446bce83a64 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-14.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +void +store (int *arr, int x, int y, int z) +{ + arr[400] = x; + arr[401] = y; + + arr[500] = z; + arr[501] = x; +} + + +void +store_long (long long int *arr, long long int x, long long int y) +{ + arr[400] = x; + arr[401] = y; + + arr[403] = y; + arr[404] = x; +} + +/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv64 } } } */ + +/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 6 { target { rv32 } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-15.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-15.c new file mode 100644 index 00000000000..bdc2e0bd0ea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-15.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +long long +load_long (long long int *arr) +{ + return arr[400] << 1 + arr[401] << 1 + arr[403] << 1 + arr[404] << 1; +} + +/* { dg-final { scan-assembler-times "addi\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.ldd\t" 2 { target { rv64 } } } */ + +/* { dg-final { scan-assembler-times "addi\t" 1 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.lwd\t" 4 { target { rv32 } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-16.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-16.c new file mode 100644 index 00000000000..2c9ffbc33b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-16.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +void +store_offset (int *array, int x, int y) +{ + array[1085] = x; + array[1084] = y; + + array[1086] = y; + array[1087] = 5; +} + +/* { dg-final { scan-assembler-times "addi\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.ldd\t" 2 { target { rv64 } } } */ + +/* { dg-final { scan-assembler-times "addi\t" 1 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.lwd\t" 4 { target { rv32 } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-17.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-17.c new file mode 100644 index 00000000000..8d0fa88547c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-17.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +int +load (int *arr) +{ + return arr[527] << 1 + arr[400] << 1 + arr[401] << 1 + arr[528] << 1; +} + +/* { dg-final { scan-assembler-times "th.lwd\t" 2 } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.c new file mode 100644 index 00000000000..05685720fab --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.c @@ -0,0 +1,67 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +#include "xtheadmempair-18.h" + +CONST_FN (2, int32_t, 0); +/* { dg-final { scan-assembler-times "th.swd\t" 1 } */ + +CONST_FN (4, int32_t, 0); +/* { dg-final { scan-assembler-times "th.swd\t" 2 } */ + +CONST_FN (8, int32_t, 0); +/* { dg-final { scan-assembler-times "th.swd\t" 4 } */ + +CONST_FN (16, int32_t, 0); +/* { dg-final { scan-assembler-times "th.swd\t" 8 } */ + +CONST_FN (2, int32_t, 1); +/* { dg-final { scan-assembler-times "th.swd\t" 1 } */ + +CONST_FN (4, int32_t, 1); +/* { dg-final { scan-assembler-times "th.swd\t" 2 } */ + +CONST_FN (8, int32_t, 1); +/* { dg-final { scan-assembler-times "th.swd\t" 4 } */ + +DUP_FN (2, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 1 } */ + +DUP_FN (4, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 2 } */ + +DUP_FN (8, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 4 } */ + +CONS2_FN (1, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 1 } */ + +CONS2_FN (2, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 2 } */ + +CONS2_FN (4, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 4 } */ + +CONS2_FN (8, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 8 } */ + +CONS2_FN (16, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 16 } */ + +CONS4_FN (1, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 2 } */ + +CONS4_FN (2, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 4 } */ + +CONS4_FN (4, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 8 } */ + +CONS4_FN (8, int32_t); +/* { dg-final { scan-assembler-times "th.swd\t" 16 } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.h b/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.h new file mode 100644 index 00000000000..dc41ec7a571 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.h @@ -0,0 +1,59 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif +#include + +#define PRAGMA(X) _Pragma (#X) +#define UNROLL(COUNT) PRAGMA (GCC unroll (COUNT)) + +#define CONST_FN(COUNT, TYPE, VAL) \ + void \ + const_##COUNT##_##TYPE##_##VAL (TYPE *x) \ + { \ + UNROLL (COUNT) \ + for (int i = 0; i < COUNT; ++i) \ + x[i] = VAL; \ + } + +#define DUP_FN(COUNT, TYPE) \ + void \ + dup_##COUNT##_##TYPE (TYPE *x, TYPE val) \ + { \ + UNROLL (COUNT) \ + for (int i = 0; i < COUNT; ++i) \ + x[i] = val; \ + } + +#define CONS2_FN(COUNT, TYPE) \ + void \ + cons2_##COUNT##_##TYPE (TYPE *x, TYPE val0, TYPE val1) \ + { \ + UNROLL (COUNT) \ + for (int i = 0; i < COUNT * 2; i += 2) \ + { \ + x[i + 0] = val0; \ + x[i + 1] = val1; \ + } \ + } + +#define CONS4_FN(COUNT, TYPE) \ + void \ + cons4_##COUNT##_##TYPE (TYPE *x, TYPE val0, TYPE val1, \ + TYPE val2, TYPE val3) \ + { \ + UNROLL (COUNT) \ + for (int i = 0; i < COUNT * 4; i += 4) \ + { \ + x[i + 0] = val0; \ + x[i + 1] = val1; \ + x[i + 2] = val2; \ + x[i + 3] = val3; \ + } \ + } + + diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-19.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-19.c new file mode 100644 index 00000000000..1b8866daeae --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-19.c @@ -0,0 +1,86 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +#include "xtheadmempair-18.h" + +CONST_FN (2, int64_t, 0); +/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv32 } } } */ + +CONST_FN (4, int64_t, 0); +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */ + +CONST_FN (8, int64_t, 0); +/* { dg-final { scan-assembler-times "th.sdd\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 8 { target { rv32 } } } */ + +CONST_FN (16, int64_t, 0); +/* { dg-final { scan-assembler-times "th.sdd\t" 8 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 16 { target { rv32 } } } */ + +CONST_FN (2, int64_t, 1); +/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv32 } } } */ + +CONST_FN (4, int64_t, 1); +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */ + +CONST_FN (8, int64_t, 1); +/* { dg-final { scan-assembler-times "th.sdd\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 8 { target { rv32 } } } */ + +DUP_FN (2, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv32 } } } */ + +DUP_FN (4, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */ + +DUP_FN (8, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 8 { target { rv32 } } } */ + +CONS2_FN (1, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv32 } } } */ + +CONS2_FN (2, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */ + +CONS2_FN (4, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 8 { target { rv32 } } } */ + +CONS2_FN (8, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 8 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 16 { target { rv32 } } } */ + +CONS2_FN (16, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 16 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 32 { target { rv32 } } } */ + +CONS4_FN (1, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */ + +CONS4_FN (2, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 8 { target { rv32 } } } */ + +CONS4_FN (4, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 8 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 16 { target { rv32 } } } */ + +CONS4_FN (8, int64_t); +/* { dg-final { scan-assembler-times "th.sdd\t" 16 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 32 { target { rv32 } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-2.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-2.c new file mode 100644 index 00000000000..e784419025a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-2.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +#include + +__int128 a; + +void +foo (int e) +{ + a = 25 << 52 + 10 + e; + uint64_t c, d; + c = a >> 64; + d = a; +} + +/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 { target { rv32 } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-20.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-20.c new file mode 100644 index 00000000000..531fba41090 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-20.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +typedef struct +{ + int a, b, c, d, e; +} S; + +void foo (S *); + +void test (int x) +{ + S s = { .a = x }; + foo (&s); +} + +/* { dg-final { scan-assembler-times "th.swd\t" 2 } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-3.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-3.c new file mode 100644 index 00000000000..e59da57722b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-3.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +#include + +int arr[4][4]; + +void +foo (int x, int y) +{ + arr[0][1] = x; + arr[1][0] = y; + arr[2][0] = x; + arr[1][1] = y; + arr[0][2] = x; + arr[0][3] = y; + arr[1][2] = x; + arr[2][1] = y; + arr[3][0] = x; + arr[3][1] = y; + arr[2][2] = x; + arr[1][3] = y; + arr[2][3] = x; + arr[3][2] = y; +} + +/* { dg-final { scan-assembler-times "addi\t" 2 } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 2 } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-4.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-4.c new file mode 100644 index 00000000000..c920c475b68 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-4.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +int x[4] = {-4,-5,6,7}; + +int +foo() +{ + int a,b,c,d; + + a = x[0]; + b = x[1]; + c = x[2]; + d = x[3]; + return a+b+c+d; +} + +/* { dg-final { scan-assembler-times "th.lwd\t" 2 } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-5.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-5.c new file mode 100644 index 00000000000..780e76cbc21 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-5.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +int x[4] = {-4,-5,6,7}; +int y[4]; + +unsigned int* +foo() +{ + y[0] = (unsigned int) x[0]; + y[2] = (unsigned int) x[1]; + y[1] = (unsigned int) x[2]; + y[3] = (unsigned int) x[3]; + return y; +} + +/* { dg-final { scan-assembler-times "th.lwud\t" 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-6.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-6.c new file mode 100644 index 00000000000..c19433cf20f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-6.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +int x[4] = {-4,-5,6,7}; + +int +foo() +{ + int a,b; + + a = x[0]; + b = x[1]; + return a+b; +} + +/* { dg-final { scan-assembler-times "th.lwd\t" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-7.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-7.c new file mode 100644 index 00000000000..af3ee1b3739 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-7.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +int x[4] = {-4,-5,6,7}; +int y[4]; + +unsigned int* foo() { + y[2] = (unsigned int) x[1]; + y[1] = (unsigned int) x[2]; + y[3] = (unsigned int) x[3]; + return y; +} + +/* { dg-final { scan-assembler-times "th.lwud\t" 1 } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 1 } } */ +/* { dg-final { scan-assembler-times "addi\t" 5 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-8.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-8.c new file mode 100644 index 00000000000..76d83d7f9d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-8.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +typedef int VINT32 __attribute__ ((vector_size((16)))); + +void +memory_operation (void * __restrict src, void * __restrict dest, int num) +{ + VINT32 *vsrc = (VINT32 *) src; + VINT32 *vdest = (VINT32 *) dest; + int i; + + for (i = 0; i < num - 1; i += 2) + { + vdest[i] = vdest[i] + vsrc[i]; + vdest[i + 1] = vdest[i + 1] + vsrc[i + 1]; + } +} + +/* { dg-final { scan-assembler-times "th.lwd\t" 8 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.lwd\t" 8 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv32 } } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-9.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-9.c new file mode 100644 index 00000000000..f8ed6663777 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-9.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Oz" "-Os"} } */ +/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */ + +#ifndef __riscv_xtheadmempair +#error Feature macro not defined +#endif + +typedef unsigned __attribute__((mode(DI))) uint64_t; + +struct S0 { + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint64_t f4; + uint64_t f5; +} a; +struct S2 { + uint64_t f0; + uint64_t f2; + struct S0 f3; +}; + +void fn1 () { + struct S2 b = {0, 1, 7, 4073709551611, 4, 8, 7}; + a = b.f3; +} + +/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.ldd\t" 2 { target { rv64 } } } */ +/* { dg-final { scan-assembler-times "th.sdd\t" 2 { target { rv64 } } } */ + +/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.lwd\t" 4 { target { rv32 } } } */ +/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } */