public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v2 00/11] RISC-V: Add XThead* extension support
@ 2022-12-19  1:08 Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 01/11] riscv: attr: Synchronize comments with code Christoph Muellner
                   ` (10 more replies)
  0 siblings, 11 replies; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This series introduces support for the T-Head specific RISC-V ISA extensions
which are available e.g. on the T-Head XuanTie C906.

The ISA spec can be found here:
  https://github.com/T-head-Semi/thead-extension-spec

The series begins with two preparation patches, that do not introduce
any functional changes.  The first patch just fixes the comment order
to the code order.  And the second patch restructures the register
save/restore code in the CFA expansion, which simplifies the
XTheadMemPair patch.

This series adds basic support (i.e. awareness of the extension name and test
macro) for the following XThead* extensions:
* XTheadBa
* XTheadBb
* XTheadBs
* XTheadCmo
* XTheadCondMov
* XTheadFMemIdx
* XTheadFmv
* XTheadInt
* XTheadMac
* XTheadMemIdx
* XTheadMemPair
* XTheadSync

The series includes optimizations for most of these extensions
(the exceptions are XTheadInt and XTheadMemIdx).

The series also introduces support for "-mcpu=thead-c906", which also
enables all available XThead* ISA extensions of the T-Head C906.

All patches have been tested and don't introduce regressions for RV32 or
RV64. Therefore partial inclusion of this series is possible.

Christoph Müllner (10):
  riscv: attr: Synchronize comments with code
  riscv: Restructure callee-saved register save/restore code
  riscv: Add basic XThead* vendor extension support
  riscv: riscv-cores.def: Add T-Head XuanTie C906
  riscv: thead: Add support for the XTheadBa ISA extension
  riscv: thead: Add support for the XTheadBs ISA extension
  riscv: thead: Add support for th XTheadBb ISA extension
  riscv: thead: Add support for XTheadCondMov ISA extensions
  riscv: thead: Add support for XTheadMac ISA extension
  riscv: thead: Add support for XTheadFmv ISA extension

moiz.hussain (1):
  riscv: thead: Add support for XTheadMemPair ISA extension

 gcc/common/config/riscv/riscv-common.cc       |  26 +
 gcc/config/riscv/bitmanip.md                  |  52 +-
 gcc/config/riscv/constraints.md               |   8 +
 gcc/config/riscv/iterators.md                 |   4 +
 gcc/config/riscv/peephole.md                  | 298 ++++++
 gcc/config/riscv/predicates.md                |   4 +
 gcc/config/riscv/riscv-cores.def              |   4 +
 gcc/config/riscv/riscv-opts.h                 |  26 +
 gcc/config/riscv/riscv-protos.h               |  11 +-
 gcc/config/riscv/riscv.cc                     | 919 ++++++++++++++++--
 gcc/config/riscv/riscv.md                     |  72 +-
 gcc/config/riscv/riscv.opt                    |   3 +
 gcc/config/riscv/thead.md                     | 385 ++++++++
 .../gcc.target/riscv/mcpu-thead-c906.c        |  28 +
 .../gcc.target/riscv/xtheadba-addsl.c         |  55 ++
 gcc/testsuite/gcc.target/riscv/xtheadba.c     |  14 +
 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c |  20 +
 .../gcc.target/riscv/xtheadbb-extu-2.c        |  22 +
 .../gcc.target/riscv/xtheadbb-extu.c          |  22 +
 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c |  18 +
 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c |  45 +
 .../gcc.target/riscv/xtheadbb-srri.c          |  21 +
 gcc/testsuite/gcc.target/riscv/xtheadbb.c     |  14 +
 gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c |  13 +
 gcc/testsuite/gcc.target/riscv/xtheadbs.c     |  14 +
 gcc/testsuite/gcc.target/riscv/xtheadcmo.c    |  14 +
 .../riscv/xtheadcondmov-mveqz-imm-eqz.c       |  38 +
 .../riscv/xtheadcondmov-mveqz-imm-not.c       |  38 +
 .../riscv/xtheadcondmov-mveqz-reg-eqz.c       |  38 +
 .../riscv/xtheadcondmov-mveqz-reg-not.c       |  38 +
 .../riscv/xtheadcondmov-mvnez-imm-cond.c      |  38 +
 .../riscv/xtheadcondmov-mvnez-imm-nez.c       |  38 +
 .../riscv/xtheadcondmov-mvnez-reg-cond.c      |  38 +
 .../riscv/xtheadcondmov-mvnez-reg-nez.c       |  38 +
 .../gcc.target/riscv/xtheadcondmov.c          |  14 +
 .../gcc.target/riscv/xtheadfmemidx.c          |  14 +
 .../gcc.target/riscv/xtheadfmv-fmv.c          |  24 +
 gcc/testsuite/gcc.target/riscv/xtheadfmv.c    |  14 +
 gcc/testsuite/gcc.target/riscv/xtheadint.c    |  14 +
 .../gcc.target/riscv/xtheadmac-mula-muls.c    |  43 +
 gcc/testsuite/gcc.target/riscv/xtheadmac.c    |  14 +
 gcc/testsuite/gcc.target/riscv/xtheadmemidx.c |  14 +
 .../gcc.target/riscv/xtheadmempair-1.c        |  29 +
 .../gcc.target/riscv/xtheadmempair-10.c       |  36 +
 .../gcc.target/riscv/xtheadmempair-11.c       |  18 +
 .../gcc.target/riscv/xtheadmempair-12.c       |  20 +
 .../gcc.target/riscv/xtheadmempair-13.c       |  23 +
 .../gcc.target/riscv/xtheadmempair-14.c       |  30 +
 .../gcc.target/riscv/xtheadmempair-15.c       |  15 +
 .../gcc.target/riscv/xtheadmempair-16.c       |  18 +
 .../gcc.target/riscv/xtheadmempair-17.c       |  13 +
 .../gcc.target/riscv/xtheadmempair-18.c       |  49 +
 .../gcc.target/riscv/xtheadmempair-19.c       |  86 ++
 .../gcc.target/riscv/xtheadmempair-2.c        |  26 +
 .../gcc.target/riscv/xtheadmempair-20.c       |  21 +
 .../gcc.target/riscv/xtheadmempair-3.c        |  30 +
 .../gcc.target/riscv/xtheadmempair-4.c        |  20 +
 .../gcc.target/riscv/xtheadmempair-5.c        |  21 +
 .../gcc.target/riscv/xtheadmempair-6.c        |  19 +
 .../gcc.target/riscv/xtheadmempair-7.c        |  22 +
 .../gcc.target/riscv/xtheadmempair-8.c        |  29 +
 .../gcc.target/riscv/xtheadmempair-9.c        |  37 +
 .../gcc.target/riscv/xtheadmempair-helper.h   |  52 +
 .../gcc.target/riscv/xtheadmempair.c          |  13 +
 gcc/testsuite/gcc.target/riscv/xtheadsync.c   |  14 +
 65 files changed, 3116 insertions(+), 92 deletions(-)
 create mode 100644 gcc/config/riscv/thead.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadba-addsl.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadba.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbs.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcmo.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-eqz.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-not.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-eqz.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-not.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-cond.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-nez.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-cond.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-nez.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadint.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmac-mula-muls.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmac.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmemidx.c
 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-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
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-helper.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadsync.c

-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 01/11] riscv: attr: Synchronize comments with code
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  2:48   ` Kito Cheng
  2022-12-19  1:08 ` [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code Christoph Muellner
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

The comment above the enumeration of existing attributes got out of
order and a few entries were forgotten.
This patch synchronizes the comments according to the list.
This commit does not include any functional change.

gcc/ChangeLog:

	* config/riscv/riscv.md: Sync comments with code.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/riscv.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index df57e2b0b4a..a8bb331f25c 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -220,7 +220,6 @@ (define_attr "enabled" "no,yes"
 ;; mfc		transfer from coprocessor
 ;; const	load constant
 ;; arith	integer arithmetic instructions
-;; auipc	integer addition to PC
 ;; logical      integer logical instructions
 ;; shift	integer shift instructions
 ;; slt		set less than instructions
@@ -236,9 +235,13 @@ (define_attr "enabled" "no,yes"
 ;; fcvt		floating point convert
 ;; fsqrt	floating point square root
 ;; multi	multiword sequence (or user asm statements)
+;; auipc	integer addition to PC
+;; sfb_alu  SFB ALU instruction
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
 ;; bitmanip	bit manipulation instructions
+;; rotate   rotation instructions
+;; atomic   atomic instructions
 ;; Classification of RVV instructions which will be added to each RVV .md pattern and used by scheduler.
 ;; rdvlenb     vector byte length vlenb csrr read
 ;; rdvl        vector length vl csrr read
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 01/11] riscv: attr: Synchronize comments with code Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  6:30   ` Kito Cheng
  2022-12-19  1:08 ` [PATCH v2 03/11] riscv: Add basic XThead* vendor extension support Christoph Muellner
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch restructures the loop over the GP registers
which saves/restores then as part of the prologue/epilogue.
No functional change is intended by this patch, but it
offers the possibility to use load-pair/store-pair instructions.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_next_saved_reg): New function.
	(riscv_is_eh_return_data_register): New function.
	(riscv_for_each_saved_reg): Restructure loop.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/riscv.cc | 94 +++++++++++++++++++++++++++------------
 1 file changed, 66 insertions(+), 28 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 6dd2ab2d11e..a8d5e1dac7f 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -4835,6 +4835,49 @@ riscv_save_restore_reg (machine_mode mode, int regno,
   fn (gen_rtx_REG (mode, regno), mem);
 }
 
+/* Return the next register up from REGNO up to LIMIT for the callee
+   to save or restore.  OFFSET will be adjusted accordingly.
+   If INC is set, then REGNO will be incremented first.  */
+
+static unsigned int
+riscv_next_saved_reg (unsigned int regno, unsigned int limit,
+		      HOST_WIDE_INT *offset, bool inc = true)
+{
+  if (inc)
+    regno++;
+
+  while (regno <= limit)
+    {
+      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+	{
+	  *offset = *offset - UNITS_PER_WORD;
+	  break;
+	}
+
+      regno++;
+    }
+  return regno;
+}
+
+/* Return TRUE if provided REGNO is eh return data register.  */
+
+static bool
+riscv_is_eh_return_data_register (unsigned int regno)
+{
+  unsigned int i, regnum;
+
+  if (!crtl->calls_eh_return)
+    return false;
+
+  for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
+    if (regno == regnum)
+      {
+	return true;
+      }
+
+  return false;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -4844,36 +4887,31 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 			  bool epilogue, bool maybe_eh_return)
 {
   HOST_WIDE_INT offset;
+  unsigned int regno;
+  unsigned int start = GP_REG_FIRST;
+  unsigned int limit = GP_REG_LAST;
 
   /* Save the link register and s-registers. */
-  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ();
-  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
-      {
-	bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
-
-	/* If this is a normal return in a function that calls the eh_return
-	   builtin, then do not restore the eh return data registers as that
-	   would clobber the return value.  But we do still need to save them
-	   in the prologue, and restore them for an exception return, so we
-	   need special handling here.  */
-	if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
-	  {
-	    unsigned int i, regnum;
-
-	    for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
-		 i++)
-	      if (regno == regnum)
-		{
-		  handle_reg = FALSE;
-		  break;
-		}
-	  }
-
-	if (handle_reg)
-	  riscv_save_restore_reg (word_mode, regno, offset, fn);
-	offset -= UNITS_PER_WORD;
-      }
+  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ()
+	   + UNITS_PER_WORD;
+  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
+       regno <= limit;
+       regno = riscv_next_saved_reg (regno, limit, &offset))
+    {
+      if (cfun->machine->reg_is_wrapped_separately[regno])
+	continue;
+
+      /* If this is a normal return in a function that calls the eh_return
+	 builtin, then do not restore the eh return data registers as that
+	 would clobber the return value.  But we do still need to save them
+	 in the prologue, and restore them for an exception return, so we
+	 need special handling here.  */
+      if (epilogue && !maybe_eh_return
+	  && riscv_is_eh_return_data_register (regno))
+	continue;
+
+      riscv_save_restore_reg (word_mode, regno, offset, fn);
+    }
 
   /* This loop must iterate over the same space as its companion in
      riscv_compute_frame_info.  */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 03/11] riscv: Add basic XThead* vendor extension support
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 01/11] riscv: attr: Synchronize comments with code Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  6:32   ` Kito Cheng
  2022-12-19  1:08 ` [PATCH v2 04/11] riscv: riscv-cores.def: Add T-Head XuanTie C906 Christoph Muellner
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch add basic support for the following XThead* ISA extensions:

* XTheadBa
* XTheadBb
* XTheadBs
* XTheadCmo
* XTheadCondMov
* XTheadFMemIdx
* XTheadFmv
* XTheadInt
* XTheadMac
* XTheadMemIdx
* XTheadMemPair
* XTheadSync

The extensions are just recognized by the compiler and feature test
macros are generated (which this patch also brings tests for).

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc: Add xthead* extensions.
	* config/riscv/riscv-opts.h (MASK_XTHEADBA): New.
	(TARGET_XTHEADBA): New.
	(MASK_XTHEADBB): New.
	(TARGET_XTHEADBB): New.
	(MASK_XTHEADBS): New.
	(TARGET_XTHEADBS): New.
	(MASK_XTHEADCMO): New.
	(TARGET_XTHEADCMO): New.
	(MASK_XTHEADCONDMOV): New.
	(TARGET_XTHEADCONDMOV): New.
	(MASK_XTHEADFMEMIDX): New.
	(TARGET_XTHEADFMEMIDX): New.
	(MASK_XTHEADFMV): New.
	(TARGET_XTHEADFMV): New.
	(MASK_XTHEADINT): New.
	(TARGET_XTHEADINT): New.
	(MASK_XTHEADMAC): New.
	(TARGET_XTHEADMAC): New.
	(MASK_XTHEADMEMIDX): New.
	(TARGET_XTHEADMEMIDX): New.
	(MASK_XTHEADMEMPAIR): New.
	(TARGET_XTHEADMEMPAIR): new.
	(MASK_XTHEADSYNC): New.
	(TARGET_XTHEADSYNC): New.
	* config/riscv/riscv.opt: Add riscv_xthead_subext.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadba.c: New test.
	* gcc.target/riscv/xtheadbb.c: New test.
	* gcc.target/riscv/xtheadbs.c: New test.
	* gcc.target/riscv/xtheadcmo.c: New test.
	* gcc.target/riscv/xtheadcondmov.c: New test.
	* gcc.target/riscv/xtheadfmemidx.c: New test.
	* gcc.target/riscv/xtheadfmv.c: New test.
	* gcc.target/riscv/xtheadint.c: New test.
	* gcc.target/riscv/xtheadmac.c: New test.
	* gcc.target/riscv/xtheadmemidx.c: New test.
	* gcc.target/riscv/xtheadmempair.c: New test.
	* gcc.target/riscv/xtheadsync.c: New test.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/common/config/riscv/riscv-common.cc       | 26 +++++++++++++++++++
 gcc/config/riscv/riscv-opts.h                 | 26 +++++++++++++++++++
 gcc/config/riscv/riscv.opt                    |  3 +++
 gcc/testsuite/gcc.target/riscv/xtheadba.c     | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadbb.c     | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadbs.c     | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadcmo.c    | 14 ++++++++++
 .../gcc.target/riscv/xtheadcondmov.c          | 14 ++++++++++
 .../gcc.target/riscv/xtheadfmemidx.c          | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadfmv.c    | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadint.c    | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadmac.c    | 14 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadmemidx.c | 14 ++++++++++
 .../gcc.target/riscv/xtheadmempair.c          | 13 ++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadsync.c   | 14 ++++++++++
 15 files changed, 222 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadba.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbs.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcmo.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadint.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmac.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmemidx.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadsync.c

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 4b7f777c103..84f7de8a16e 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -222,6 +222,19 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
   {"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
   {"svnapot", ISA_SPEC_CLASS_NONE, 1, 0},
 
+  {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadbs", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadcmo", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadcondmov", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadfmemidx", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadfmv", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xtheadint", 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.  */
   {NULL, ISA_SPEC_CLASS_NONE, 0, 0}
 };
@@ -1247,6 +1260,19 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"svinval", &gcc_options::x_riscv_sv_subext, MASK_SVINVAL},
   {"svnapot", &gcc_options::x_riscv_sv_subext, MASK_SVNAPOT},
 
+  {"xtheadba",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
+  {"xtheadbb",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
+  {"xtheadbs",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBS},
+  {"xtheadcmo",     &gcc_options::x_riscv_xthead_subext, MASK_XTHEADCMO},
+  {"xtheadcondmov", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADCONDMOV},
+  {"xtheadfmemidx", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADFMEMIDX},
+  {"xtheadfmv",     &gcc_options::x_riscv_xthead_subext, MASK_XTHEADFMV},
+  {"xtheadint",     &gcc_options::x_riscv_xthead_subext, MASK_XTHEADINT},
+  {"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/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 25fd85b09b1..4d433d5e9fe 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -189,4 +189,30 @@ enum stack_protector_guard {
    ? 0 \
    : 32 << (__builtin_popcount (riscv_zvl_flags) - 1))
 
+#define MASK_XTHEADBA      (1 << 0)
+#define MASK_XTHEADBB      (1 << 1)
+#define MASK_XTHEADBS      (1 << 2)
+#define MASK_XTHEADCMO     (1 << 3)
+#define MASK_XTHEADCONDMOV (1 << 4)
+#define MASK_XTHEADFMEMIDX (1 << 5)
+#define MASK_XTHEADFMV     (1 << 6)
+#define MASK_XTHEADINT     (1 << 7)
+#define MASK_XTHEADMAC     (1 << 8)
+#define MASK_XTHEADMEMIDX  (1 << 9)
+#define MASK_XTHEADMEMPAIR (1 << 10)
+#define MASK_XTHEADSYNC    (1 << 11)
+
+#define TARGET_XTHEADBA      ((riscv_xthead_subext & MASK_XTHEADBA) != 0)
+#define TARGET_XTHEADBB      ((riscv_xthead_subext & MASK_XTHEADBB) != 0)
+#define TARGET_XTHEADBS      ((riscv_xthead_subext & MASK_XTHEADBS) != 0)
+#define TARGET_XTHEADCMO     ((riscv_xthead_subext & MASK_XTHEADCMO) != 0)
+#define TARGET_XTHEADCONDMOV ((riscv_xthead_subext & MASK_XTHEADCONDMOV) != 0)
+#define TARGET_XTHEADFMEMIDX ((riscv_xthead_subext & MASK_XTHEADFMEMIDX) != 0)
+#define TARGET_XTHEADFMV     ((riscv_xthead_subext & MASK_XTHEADFMV) != 0)
+#define TARGET_XTHEADINT     ((riscv_xthead_subext & MASK_XTHEADINT) != 0)
+#define TARGET_XTHEADMAC     ((riscv_xthead_subext & MASK_XTHEADMAC) != 0)
+#define TARGET_XTHEADMEMIDX  ((riscv_xthead_subext & MASK_XTHEADMEMIDX) != 0)
+#define TARGET_XTHEADMEMPAIR ((riscv_xthead_subext & MASK_XTHEADMEMPAIR) != 0)
+#define TARGET_XTHEADSYNC    ((riscv_xthead_subext & MASK_XTHEADSYNC) != 0)
+
 #endif /* ! GCC_RISCV_OPTS_H */
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 7c3ca48d1cc..3f2dd24d59b 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -233,6 +233,9 @@ int riscv_zm_subext
 TargetVariable
 int riscv_sv_subext
 
+TargetVariable
+int riscv_xthead_subext
+
 Enum
 Name(isa_spec_class) Type(enum riscv_isa_spec_class)
 Supported ISA specs (for use with the -misa-spec= option):
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadba.c b/gcc/testsuite/gcc.target/riscv/xtheadba.c
new file mode 100644
index 00000000000..14cdb1ffe2e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadba.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadba" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadba" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadba
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb.c b/gcc/testsuite/gcc.target/riscv/xtheadbb.c
new file mode 100644
index 00000000000..66988abf221
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadbb
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbs.c b/gcc/testsuite/gcc.target/riscv/xtheadbs.c
new file mode 100644
index 00000000000..808d7378a7b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbs.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbs" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbs" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadbs
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcmo.c b/gcc/testsuite/gcc.target/riscv/xtheadcmo.c
new file mode 100644
index 00000000000..eab8fef421c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcmo.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcmo" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcmo" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadcmo
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c
new file mode 100644
index 00000000000..a239c3f9f46
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadcondmov
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c
new file mode 100644
index 00000000000..e450c5e5c5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadfmemidx" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadfmemidx" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadfmemidx
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmv.c b/gcc/testsuite/gcc.target/riscv/xtheadfmv.c
new file mode 100644
index 00000000000..e97e8f461f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmv.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadfmv" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadfmv" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadfmv
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadint.c b/gcc/testsuite/gcc.target/riscv/xtheadint.c
new file mode 100644
index 00000000000..ee6989a380e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadint.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadint" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadint" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadint
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmac.c b/gcc/testsuite/gcc.target/riscv/xtheadmac.c
new file mode 100644
index 00000000000..7c635407b31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmac.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadmac" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadmac" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadmac
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c b/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c
new file mode 100644
index 00000000000..076eab00f54
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadmemidx" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadmemidx" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadmemidx
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair.c
new file mode 100644
index 00000000000..5135d2175dc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadmempair" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadmempair
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadsync.c b/gcc/testsuite/gcc.target/riscv/xtheadsync.c
new file mode 100644
index 00000000000..835d60c96e9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadsync.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadsync" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadsync" { target { rv64 } } } */
+
+#ifndef __riscv_xtheadsync
+#error Feature macro not defined
+#endif
+
+int
+foo (int a)
+{
+  return a;
+}
+
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 04/11] riscv: riscv-cores.def: Add T-Head XuanTie C906
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (2 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 03/11] riscv: Add basic XThead* vendor extension support Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  6:58   ` Kito Cheng
  2022-12-19  1:08 ` [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension Christoph Muellner
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This adds T-Head's XuanTie C906 to the list of known cores as "thead-c906".
The C906 is shipped for quite some time (it is the core of the Allwinner D1).
Note, that the tuning struct for the C906 is already part of GCC (it is
also name "thead-c906").

gcc/ChangeLog:

	* config/riscv/riscv-cores.def (RISCV_CORE): Add "thead-c906".

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/mcpu-thead-c906.c: New test.

Changes for v2:
- Enable all supported vendor extensions

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/riscv-cores.def              |  4 +++
 .../gcc.target/riscv/mcpu-thead-c906.c        | 28 +++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c

diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def
index 31ad34682c5..307381802fa 100644
--- a/gcc/config/riscv/riscv-cores.def
+++ b/gcc/config/riscv/riscv-cores.def
@@ -73,4 +73,8 @@ RISCV_CORE("sifive-s76",      "rv64imafdc", "sifive-7-series")
 RISCV_CORE("sifive-u54",      "rv64imafdc", "sifive-5-series")
 RISCV_CORE("sifive-u74",      "rv64imafdc", "sifive-7-series")
 
+RISCV_CORE("thead-c906",      "rv64imafdc_xtheadba_xtheadbb_xtheadbs_xtheadcmo_"
+			      "xtheadcondmov_xtheadfmemidx_xtheadmac_"
+			      "xtheadmemidx_xtheadmempair_xtheadsync",
+			      "thead-c906")
 #undef RISCV_CORE
diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c b/gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c
new file mode 100644
index 00000000000..a71b43a6167
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
+/* { dg-options "-mcpu=thead-c906" { target { rv64 } } } */
+/* T-Head XuanTie C906 => rv64imafdc */
+
+#if !((__riscv_xlen == 64)		\
+      && !defined(__riscv_32e)		\
+      && defined(__riscv_mul)		\
+      && defined(__riscv_atomic)	\
+      && (__riscv_flen == 64)		\
+      && defined(__riscv_compressed)	\
+      && defined(__riscv_xtheadba)	\
+      && defined(__riscv_xtheadbb)	\
+      && defined(__riscv_xtheadbs)	\
+      && defined(__riscv_xtheadcmo)	\
+      && defined(__riscv_xtheadcondmov)	\
+      && defined(__riscv_xtheadfmemidx)	\
+      && defined(__riscv_xtheadmac)	\
+      && defined(__riscv_xtheadmemidx)	\
+      && defined(__riscv_xtheadmempair)	\
+      && defined(__riscv_xtheadsync))
+#error "unexpected arch"
+#endif
+
+int main()
+{
+  return 0;
+}
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (3 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 04/11] riscv: riscv-cores.def: Add T-Head XuanTie C906 Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19 13:19   ` Kito Cheng
  2022-12-19  1:08 ` [PATCH v2 06/11] riscv: thead: Add support for the XTheadBs " Christoph Muellner
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch adds support for the XTheadBa ISA extension.
The new INSN pattern is defined in a new file to separate
this vendor extension from the standard extensions.

gcc/ChangeLog:

	* config/riscv/riscv.md: Include thead.md
	* config/riscv/thead.md: New file.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadba-addsl.c: New test.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/riscv.md                     |  1 +
 gcc/config/riscv/thead.md                     | 31 +++++++++++
 .../gcc.target/riscv/xtheadba-addsl.c         | 55 +++++++++++++++++++
 3 files changed, 87 insertions(+)
 create mode 100644 gcc/config/riscv/thead.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadba-addsl.c

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index a8bb331f25c..571349b1ca5 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3073,4 +3073,5 @@ (define_insn "riscv_prefetchi_<mode>"
 (include "pic.md")
 (include "generic.md")
 (include "sifive-7.md")
+(include "thead.md")
 (include "vector.md")
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
new file mode 100644
index 00000000000..0257cbfad3e
--- /dev/null
+++ b/gcc/config/riscv/thead.md
@@ -0,0 +1,31 @@
+;; Machine description for T-Head vendor extensions
+;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; XTheadBa
+
+(define_insn "*th_addsl"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	(plus:X (ashift:X (match_operand:X 1 "register_operand" "r")
+			  (match_operand:QI 2 "immediate_operand" "I"))
+		(match_operand:X 3 "register_operand" "r")))]
+  "TARGET_XTHEADBA
+   && (INTVAL (operands[2]) >= 0) && (INTVAL (operands[2]) <= 3)"
+  "th.addsl\t%0,%1,%3,%2"
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<X:MODE>")])
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadba-addsl.c b/gcc/testsuite/gcc.target/riscv/xtheadba-addsl.c
new file mode 100644
index 00000000000..5004735a246
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadba-addsl.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadba" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadba" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+long
+test_1 (long a, long b)
+{
+  /* th.addsl aX, aX, 1  */
+  return a + (b << 1);
+}
+
+int
+foos (short *x, int n)
+{
+  /* th.addsl aX, aX, 1  */
+  return x[n];
+}
+
+long
+test_2 (long a, long b)
+{
+  /* th.addsl aX, aX, 2  */
+  return a + (b << 2);
+}
+
+int
+fooi (int *x, int n)
+{
+  /* th.addsl aX, aX, 2  */
+  return x[n];
+}
+
+long
+test_3 (long a, long b)
+{
+  /* th.addsl aX, aX, 3  */
+  return a + (b << 3);
+}
+
+long
+fool (long *x, int n)
+{
+  /* th.addsl aX, aX, 2 (rv32)  */
+  /* th.addsl aX, aX, 3 (rv64)  */
+  return x[n];
+}
+
+/* { dg-final { scan-assembler-times "th.addsl\[ \t\]*a\[0-9\]+,a\[0-9\]+,a\[0-9\]+,1" 2 } } */
+
+/* { dg-final { scan-assembler-times "th.addsl\[ \t\]*a\[0-9\]+,a\[0-9\]+,a\[0-9\]+,2" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.addsl\[ \t\]*a\[0-9\]+,a\[0-9\]+,a\[0-9\]+,2" 2 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "th.addsl\[ \t\]*a\[0-9\]+,a\[0-9\]+,a\[0-9\]+,3" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.addsl\[ \t\]*a\[0-9\]+,a\[0-9\]+,a\[0-9\]+,3" 2 { target { rv64 } } } } */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 06/11] riscv: thead: Add support for the XTheadBs ISA extension
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (4 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19 14:00   ` Kito Cheng
  2022-12-19  1:08 ` [PATCH v2 07/11] riscv: thead: Add support for th XTheadBb " Christoph Muellner
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch adds support for the XTheadBs ISA extension.
The new INSN pattern is defined in a new file to separate
this vendor extension from the standard extensions.
The cost model adjustment reuses the xbs:bext cost.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_rtx_costs): Add xthead:tst cost.
	* config/riscv/thead.md (*th_tst): New INSN.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadbs-tst.c: New test.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/riscv.cc                     |  4 ++--
 gcc/config/riscv/thead.md                     | 11 +++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c | 13 +++++++++++++
 3 files changed, 26 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a8d5e1dac7f..537515771c6 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2400,8 +2400,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	  *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
 	  return true;
 	}
-      /* bext pattern for zbs.  */
-      if (TARGET_ZBS && outer_code == SET
+      /* bit extraction pattern (zbs:bext, xtheadbs:tst).  */
+      if ((TARGET_ZBS || TARGET_XTHEADBS) && outer_code == SET
 	  && GET_CODE (XEXP (x, 1)) == CONST_INT
 	  && INTVAL (XEXP (x, 1)) == 1)
 	{
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index 0257cbfad3e..0e23644ef59 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -29,3 +29,14 @@ (define_insn "*th_addsl"
   "th.addsl\t%0,%1,%3,%2"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "<X:MODE>")])
+
+;; XTheadBs
+
+(define_insn "*th_tst"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	(zero_extract:X (match_operand:X 1 "register_operand" "r")
+			(const_int 1)
+			(match_operand 2 "immediate_operand" "i")))]
+  "TARGET_XTHEADBS"
+  "th.tst\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c b/gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c
new file mode 100644
index 00000000000..674cec09128
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbs" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbs" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+long
+foo1 (long i)
+{
+  return 1L & (i >> 20);
+}
+
+/* { dg-final { scan-assembler-times "th.tst\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 07/11] riscv: thead: Add support for th XTheadBb ISA extension
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (5 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 06/11] riscv: thead: Add support for the XTheadBs " Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 08/11] riscv: thead: Add support for XTheadCondMov ISA extensions Christoph Muellner
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch adds support for the XTheadBb ISA extension.
Thus, there is a functional overlap of the new instructions with
existing Bitmanip instruction, which allows a good amount of code
sharing. However, the vendor extensions are cleanly separated from
the standard extensions (e.g. by using INSN expand pattern that
will re-emit RTL that matches the patterns of either Bitmanip or
XThead INSNs).

gcc/ChangeLog:

	* config/riscv/bitmanip.md (clzdi2): New expand.
	(clzsi2): New expand.
	(ctz<mode>2): New expand.
	(popcount<mode>2): New expand.
	(<bitmanip_optab>si2): Rename INSN.
	(*<bitmanip_optab>si2): Hide INSN name.
	(<bitmanip_optab>di2): Rename INSN.
	(*<bitmanip_optab>di2): Hide INSN name.
	(rotrsi3): Remove INSN.
	(rotr<mode>3): Add expand.
	(*rotrsi3): New INSN.
	(rotrdi3): Rename INSN.
	(*rotrdi3): Hide INSN name.
	(rotrsi3_sext): Rename INSN.
	(*rotrsi3_sext): Hide INSN name.
	(bswap<mode>2): Remove INSN.
	(bswapdi2): Add expand.
	(bswapsi2): Add expand.
	(*bswap<mode>2): Hide INSN name.
	* config/riscv/riscv.cc (riscv_rtx_costs): Add costs for sign
	extraction.
	* config/riscv/riscv.md (extv<mode>): New expand.
	(extzv<mode>): New expand.
	* config/riscv/thead.md (*th_srrisi3): New INSN.
	(*th_srridi3): New INSN.
	(*th_ext<mode>): New INSN.
	(*th_extu<mode>): New INSN.
	(*th_clz<mode>2): New INSN.
	(*th_revsi2): New INSN.
	(*th_revdi2): New INSN.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadbb-ext.c: New test.
	* gcc.target/riscv/xtheadbb-extu-2.c: New test.
	* gcc.target/riscv/xtheadbb-extu.c: New test.
	* gcc.target/riscv/xtheadbb-ff1.c: New test.
	* gcc.target/riscv/xtheadbb-rev.c: New test.
	* gcc.target/riscv/xtheadbb-srri.c: New test.

Changes for v2:
- Merge all XTheadB* support patches
- Remove useless operand sanity checks for extv<mode> and extzv<mode>
- Prefer c.andi over th.extu if possible
- Add ff1 tests for clz/ctz
- Fix ext/extu test cases
- Enable tests for RV32

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/bitmanip.md                  | 52 +++++++++++++--
 gcc/config/riscv/riscv.cc                     |  9 +++
 gcc/config/riscv/riscv.md                     | 20 ++++++
 gcc/config/riscv/thead.md                     | 66 +++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c | 20 ++++++
 .../gcc.target/riscv/xtheadbb-extu-2.c        | 22 +++++++
 .../gcc.target/riscv/xtheadbb-extu.c          | 22 +++++++
 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c | 18 +++++
 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c | 45 +++++++++++++
 .../gcc.target/riscv/xtheadbb-srri.c          | 21 ++++++
 10 files changed, 289 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index d17133d58c1..70e72a35d7d 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -185,6 +185,26 @@ (define_insn "*slliuw"
 
 ;; ZBB extension.
 
+(define_expand "clzdi2"
+  [(set (match_operand:DI 0 "register_operand")
+	(clz:DI (match_operand:DI 1 "register_operand")))]
+  "TARGET_64BIT && (TARGET_ZBB || TARGET_XTHEADBB)")
+
+(define_expand "clzsi2"
+  [(set (match_operand:SI 0 "register_operand")
+	(clz:SI (match_operand:SI 1 "register_operand")))]
+  "TARGET_ZBB || (!TARGET_64BIT && TARGET_XTHEADBB)")
+
+(define_expand "ctz<mode>2"
+  [(set (match_operand:GPR 0 "register_operand")
+	(ctz:GPR (match_operand:GPR 1 "register_operand")))]
+  "TARGET_ZBB")
+
+(define_expand "popcount<mode>2"
+  [(set (match_operand:GPR 0 "register_operand")
+	(popcount:GPR (match_operand:GPR 1 "register_operand")))]
+  "TARGET_ZBB")
+
 (define_insn "*<optab>_not<mode>"
   [(set (match_operand:X 0 "register_operand" "=r")
         (bitmanip_bitwise:X (not:X (match_operand:X 1 "register_operand" "r"))
@@ -216,7 +236,7 @@ (define_insn "*xor_not<mode>"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "<X:MODE>")])
 
-(define_insn "<bitmanip_optab>si2"
+(define_insn "*<bitmanip_optab>si2"
   [(set (match_operand:SI 0 "register_operand" "=r")
         (clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r")))]
   "TARGET_ZBB"
@@ -233,7 +253,7 @@ (define_insn "*<bitmanip_optab>disi2"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "SI")])
 
-(define_insn "<bitmanip_optab>di2"
+(define_insn "*<bitmanip_optab>di2"
   [(set (match_operand:DI 0 "register_operand" "=r")
         (clz_ctz_pcnt:DI (match_operand:DI 1 "register_operand" "r")))]
   "TARGET_64BIT && TARGET_ZBB"
@@ -273,7 +293,17 @@ (define_insn "*zero_extendhi<GPR:mode>2_zbb"
   [(set_attr "type" "bitmanip,load")
    (set_attr "mode" "HI")])
 
-(define_insn "rotrsi3"
+(define_expand "rotr<mode>3"
+  [(set (match_operand:GPR 0 "register_operand")
+	(rotatert:GPR (match_operand:GPR 1 "register_operand")
+		     (match_operand:QI 2 "arith_operand")))]
+  "TARGET_ZBB || TARGET_XTHEADBB"
+{
+  if (TARGET_XTHEADBB && !immediate_operand (operands[2], VOIDmode))
+    FAIL;
+})
+
+(define_insn "*rotrsi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(rotatert:SI (match_operand:SI 1 "register_operand" "r")
 		     (match_operand:QI 2 "arith_operand" "rI")))]
@@ -281,7 +311,7 @@ (define_insn "rotrsi3"
   "ror%i2%~\t%0,%1,%2"
   [(set_attr "type" "bitmanip")])
 
-(define_insn "rotrdi3"
+(define_insn "*rotrdi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
 	(rotatert:DI (match_operand:DI 1 "register_operand" "r")
 		     (match_operand:QI 2 "arith_operand" "rI")))]
@@ -289,7 +319,7 @@ (define_insn "rotrdi3"
   "ror%i2\t%0,%1,%2"
   [(set_attr "type" "bitmanip")])
 
-(define_insn "rotrsi3_sext"
+(define_insn "*rotrsi3_sext"
   [(set (match_operand:DI 0 "register_operand" "=r")
 	(sign_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "r")
 				     (match_operand:QI 2 "register_operand" "r"))))]
@@ -329,7 +359,17 @@ (define_insn "orcb<mode>2"
   "TARGET_ZBB"
   "orc.b\t%0,%1")
 
-(define_insn "bswap<mode>2"
+(define_expand "bswapdi2"
+  [(set (match_operand:DI 0 "register_operand")
+	(bswap:DI (match_operand:DI 1 "register_operand")))]
+  "TARGET_64BIT && (TARGET_ZBB || TARGET_XTHEADBB)")
+
+(define_expand "bswapsi2"
+  [(set (match_operand:SI 0 "register_operand")
+	(bswap:SI (match_operand:SI 1 "register_operand")))]
+  "(!TARGET_64BIT && TARGET_ZBB) || TARGET_XTHEADBB")
+
+(define_insn "*bswap<mode>2"
   [(set (match_operand:X 0 "register_operand" "=r")
         (bswap:X (match_operand:X 1 "register_operand" "r")))]
   "TARGET_ZBB"
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 537515771c6..b57c1f1d727 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2408,6 +2408,15 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	  *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
 	  return true;
 	}
+      gcc_fallthrough ();
+    case SIGN_EXTRACT:
+      if (TARGET_XTHEADBB && outer_code == SET
+	  && CONST_INT_P (XEXP (x, 1))
+	  && CONST_INT_P (XEXP (x, 2)))
+	{
+	  *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
+	  return true;
+	}
       return false;
 
     case ASHIFT:
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 571349b1ca5..8bdf3c128f3 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3067,6 +3067,26 @@ (define_insn "riscv_prefetchi_<mode>"
   "prefetch.i\t%a0"
 )
 
+(define_expand "extv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			 (match_operand 2 "const_int_operand")
+			 (match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+)
+
+(define_expand "extzv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			 (match_operand 2 "const_int_operand")
+			 (match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+{
+  if (TARGET_XTHEADBB
+      && (INTVAL (operands[2]) < 8) && (INTVAL (operands[3]) == 0))
+    FAIL;
+})
+
 (include "bitmanip.md")
 (include "sync.md")
 (include "peephole.md")
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index 0e23644ef59..c3cbb49eb58 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -30,6 +30,72 @@ (define_insn "*th_addsl"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "<X:MODE>")])
 
+;; XTheadBb
+
+(define_insn "*th_srrisi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(rotatert:SI (match_operand:SI 1 "register_operand" "r")
+		     (match_operand:QI 2 "immediate_operand" "I")))]
+  "TARGET_XTHEADBB"
+  { return TARGET_64BIT ? "th.srriw\t%0,%1,%2" : "th.srri\t%0,%1,%2"; }
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*th_srridi3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(rotatert:DI (match_operand:DI 1 "register_operand" "r")
+		     (match_operand:QI 2 "immediate_operand" "I")))]
+  "TARGET_XTHEADBB && TARGET_64BIT"
+  "th.srri\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*th_ext<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			(match_operand 2 "const_int_operand")
+			(match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+  return "th.ext\t%0,%1,%2,%3";
+}
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_extu<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			(match_operand 2 "const_int_operand")
+			(match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+  return "th.extu\t%0,%1,%2,%3";
+}
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_clz<mode>2"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	(clz:X (match_operand:X 1 "register_operand" "r")))]
+  "TARGET_XTHEADBB"
+  "th.ff1\t%0,%1"
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<X:MODE>")])
+
+(define_insn "*th_revsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(bswap:SI (match_operand:SI 1 "register_operand" "r")))]
+  "TARGET_XTHEADBB"
+  { return TARGET_64BIT ? "th.revw\t%0,%1" : "th.rev\t%0,%1"; }
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*th_revdi2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(bswap:DI (match_operand:DI 1 "register_operand" "r")))]
+  "TARGET_XTHEADBB && TARGET_64BIT"
+  "th.rev\t%0,%1"
+  [(set_attr "type" "bitmanip")])
+
 ;; XTheadBs
 
 (define_insn "*th_tst"
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
new file mode 100644
index 00000000000..60fb7d44e39
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+  long a:9;
+  long b:26;
+  long c:22;
+};
+
+long
+foo (struct bar *s)
+{
+  return s->b;
+}
+
+/* { dg-final { scan-assembler "th.ext\t" } } */
+/* { dg-final { scan-assembler-not "andi" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
new file mode 100644
index 00000000000..029be93f401
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+  unsigned long a:6;
+  unsigned long b:26;
+  unsigned long c:22;
+};
+
+/* We prefer andi over th.extu because it can be compressed.  */
+
+unsigned long
+foo (struct bar *s)
+{
+  return s->a;
+}
+
+/* { dg-final { scan-assembler-not "th.extu\t" } } */
+/* { dg-final { scan-assembler "andi\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
new file mode 100644
index 00000000000..e0492f1f5ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+  unsigned long a:5;
+  unsigned long b:26;
+  unsigned long c:22;
+};
+
+unsigned long
+foo (struct bar *s)
+{
+  return s->b;
+}
+
+/* { dg-final { scan-assembler "th.extu\t" } } */
+/* { dg-final { scan-assembler-not "andi" } } */
+/* { dg-final { scan-assembler-not "slli" } } */
+/* { dg-final { scan-assembler-not "srli" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
new file mode 100644
index 00000000000..72038c4e281
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+foo (unsigned long a)
+{
+  return __builtin_clzl (a);
+}
+
+int
+bar (unsigned long a)
+{
+  return __builtin_ctzl (a);
+}
+
+/* { dg-final { scan-assembler-times "th.ff1\t" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
new file mode 100644
index 00000000000..411d52007d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+unsigned int
+foo32 (unsigned int x)
+{
+  return (((x << 24) & 0xff000000)
+	  | ((x << 8) & 0xff0000)
+	  | ((x >> 8) & 0xff00)
+	  | ((x >> 24) & 0xff));
+}
+
+unsigned int
+foo32_1 (unsigned int x)
+{
+  return __builtin_bswap32 (x);
+}
+
+#if __riscv_xlen == 64
+unsigned long
+foo64 (unsigned long x)
+{
+  return (((x << 56) & 0xff00000000000000ull)
+	  | ((x << 40) & 0xff000000000000ull)
+	  | ((x << 24) & 0xff0000000000ull)
+	  | ((x << 8) & 0xff00000000ull)
+	  | ((x >> 8) & 0xff000000)
+	  | ((x >> 24) & 0xff0000)
+	  | ((x >> 40) & 0xff00)
+	  | ((x >> 56) & 0xff));
+}
+
+unsigned long
+foo64_1 (unsigned long x)
+{
+  return __builtin_bswap64 (x);
+}
+#endif
+
+/* { dg-final { scan-assembler-times "th.rev\t" 2 { target { rv32 } } } } */
+
+/* { dg-final { scan-assembler-times "th.revw\t" 2 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.rev\t" 2 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
new file mode 100644
index 00000000000..033a500dfe9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+unsigned long
+foo1 (unsigned long rs1)
+{
+    long shamt = __riscv_xlen - 11;
+    return (rs1 << shamt)
+	   | (rs1 >> ((__riscv_xlen - shamt) & (__riscv_xlen - 1)));
+}
+unsigned long
+foo2 (unsigned long rs1)
+{
+    unsigned long shamt = __riscv_xlen - 11;
+    return (rs1 >> shamt)
+	   | (rs1 << ((__riscv_xlen - shamt) & (__riscv_xlen - 1)));
+}
+
+/* { dg-final { scan-assembler-times "th.srri" 2 } } */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 08/11] riscv: thead: Add support for XTheadCondMov ISA extensions
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (6 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 07/11] riscv: thead: Add support for th XTheadBb " Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 09/11] riscv: thead: Add support for XTheadMac ISA extension Christoph Muellner
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch adds support for XTheadCondMov ISA extension.
The extension brings a one-sided conditional move (no else-assignment).
Given that GCC has a great if-conversion pass, we don't need to do much,
besides properly expanding mov<mode>cc accordingly and adjust the cost
model.

gcc/ChangeLog:

	* config/riscv/iterators.md (TARGET_64BIT): Add GPR2 iterator.
	* config/riscv/riscv-protos.h (riscv_expand_conditional_move):
	Add prototype.
	* config/riscv/riscv.cc (riscv_rtx_costs): Add costs for
	XTheadCondMov.
	(riscv_expand_conditional_move): New function.
	(riscv_expand_conditional_move_onesided): New function.
	* config/riscv/riscv.md: Add support for XTheadCondMov.
	* config/riscv/thead.md (*th_cond_mov<GPR:mode><GPR2:mode>): Add
	support for XTheadCondMov.
	(*th_cond_gpr_mov<GPR:mode><GPR2:mode>): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadcondmov-mveqz-imm-eqz.c: New test.
	* gcc.target/riscv/xtheadcondmov-mveqz-imm-not.c: New test.
	* gcc.target/riscv/xtheadcondmov-mveqz-reg-eqz.c: New test.
	* gcc.target/riscv/xtheadcondmov-mveqz-reg-not.c: New test.
	* gcc.target/riscv/xtheadcondmov-mvnez-imm-cond.c: New test.
	* gcc.target/riscv/xtheadcondmov-mvnez-imm-nez.c: New test.
	* gcc.target/riscv/xtheadcondmov-mvnez-reg-cond.c: New test.
	* gcc.target/riscv/xtheadcondmov-mvnez-reg-nez.c: New test.

Changes for v2:
- Properly gate expansion constraints to avoid failing INSN lookup
- Restrict subreg comparisons

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/iterators.md                 |   4 +
 gcc/config/riscv/riscv-protos.h               |   2 +-
 gcc/config/riscv/riscv.cc                     | 100 +++++++++++++++---
 gcc/config/riscv/riscv.md                     |  17 ++-
 gcc/config/riscv/thead.md                     |  37 +++++++
 .../riscv/xtheadcondmov-mveqz-imm-eqz.c       |  38 +++++++
 .../riscv/xtheadcondmov-mveqz-imm-not.c       |  38 +++++++
 .../riscv/xtheadcondmov-mveqz-reg-eqz.c       |  38 +++++++
 .../riscv/xtheadcondmov-mveqz-reg-not.c       |  38 +++++++
 .../riscv/xtheadcondmov-mvnez-imm-cond.c      |  38 +++++++
 .../riscv/xtheadcondmov-mvnez-imm-nez.c       |  38 +++++++
 .../riscv/xtheadcondmov-mvnez-reg-cond.c      |  38 +++++++
 .../riscv/xtheadcondmov-mvnez-reg-nez.c       |  38 +++++++
 13 files changed, 440 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-eqz.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-not.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-eqz.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-not.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-cond.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-nez.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-cond.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-nez.c

diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index efdd3ccc9a7..1c5f3dd5681 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -26,6 +26,10 @@
 ;; from the same template.
 (define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
 
+;; A copy of GPR that can be used when a pattern has two independent
+;; modes.
+(define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
+
 ;; This mode iterator allows :P to be used for patterns that operate on
 ;; pointer-sized quantities.  Exactly one of the two alternatives will match.
 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index e17e003f8e2..7975bc4f438 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -58,8 +58,8 @@ extern const char *riscv_output_return ();
 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);
-extern void riscv_expand_conditional_move (rtx, rtx, rtx, rtx_code, rtx, rtx);
 #endif
+extern bool riscv_expand_conditional_move (rtx, rtx, rtx, rtx);
 extern rtx riscv_legitimize_call_address (rtx);
 extern void riscv_set_return_address (rtx, rtx);
 extern bool riscv_expand_block_move (rtx, rtx, rtx);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index b57c1f1d727..21ec7a6225b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2300,8 +2300,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
       return false;
 
     case IF_THEN_ELSE:
-      if (TARGET_SFB_ALU
-	  && register_operand (XEXP (x, 1), mode)
+      if ((TARGET_SFB_ALU || TARGET_XTHEADCONDMOV)
+	  && reg_or_0_operand (XEXP (x, 1), mode)
 	  && sfb_alu_operand (XEXP (x, 2), mode)
 	  && comparison_operator (XEXP (x, 0), VOIDmode))
 	{
@@ -3098,13 +3098,30 @@ riscv_extend_comparands (rtx_code code, rtx *op0, rtx *op1)
     }
 }
 
-/* Convert a comparison into something that can be used in a branch.  On
-   entry, *OP0 and *OP1 are the values being compared and *CODE is the code
-   used to compare them.  Update them to describe the final comparison.  */
+/* Convert a comparison into something that can be used in a branch or
+   conditional move.  On entry, *OP0 and *OP1 are the values being
+   compared and *CODE is the code used to compare them.
+
+   Update *CODE, *OP0 and *OP1 so that they describe the final comparison.
+   If NEED_EQ_NE_P, then only EQ or NE comparisons against zero are
+   emitted.  */
 
 static void
-riscv_emit_int_compare (enum rtx_code *code, rtx *op0, rtx *op1)
+riscv_emit_int_compare (enum rtx_code *code, rtx *op0, rtx *op1,
+			bool need_eq_ne_p = false)
 {
+  if (need_eq_ne_p)
+    {
+      rtx cmp_op0 = *op0;
+      rtx cmp_op1 = *op1;
+      if (*code == EQ || *code == NE)
+	{
+	  *op0 = riscv_zero_if_equal (cmp_op0, cmp_op1);
+	  *op1 = const0_rtx;
+	  return;
+	}
+    }
+
   if (splittable_const_int_operand (*op1, VOIDmode))
     {
       HOST_WIDE_INT rhs = INTVAL (*op1);
@@ -3290,16 +3307,71 @@ riscv_expand_conditional_branch (rtx label, rtx_code code, rtx op0, rtx op1)
   emit_jump_insn (gen_condjump (condition, label));
 }
 
-/* If (CODE OP0 OP1) holds, move CONS to DEST; else move ALT to DEST.  */
+/* Helper to emit two one-sided conditional moves for the movecc.  */
 
-void
-riscv_expand_conditional_move (rtx dest, rtx cons, rtx alt, rtx_code code,
-			       rtx op0, rtx op1)
+static void
+riscv_expand_conditional_move_onesided (rtx dest, rtx cons, rtx alt,
+					rtx_code code, rtx op0, rtx op1)
 {
-  riscv_emit_int_compare (&code, &op0, &op1);
-  rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
-  emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond,
-						      cons, alt)));
+  machine_mode mode = GET_MODE (dest);
+
+  gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
+  gcc_assert (reg_or_0_operand (cons, mode));
+  gcc_assert (reg_or_0_operand (alt, mode));
+
+  riscv_emit_int_compare (&code, &op0, &op1, true);
+  rtx cond = gen_rtx_fmt_ee (code, mode, op0, op1);
+
+  rtx tmp1 = gen_reg_rtx (mode);
+  rtx tmp2 = gen_reg_rtx (mode);
+
+  emit_insn (gen_rtx_SET (tmp1, gen_rtx_IF_THEN_ELSE (mode, cond,
+						      cons, const0_rtx)));
+
+  /* We need to expand a sequence for both blocks and we do that such,
+     that the second conditional move will use the inverted condition.
+     We use temporaries that are or'd to the dest register.  */
+  cond = gen_rtx_fmt_ee ((code == EQ) ? NE : EQ, mode, op0, op1);
+  emit_insn (gen_rtx_SET (tmp2, gen_rtx_IF_THEN_ELSE (mode, cond,
+						      alt, const0_rtx)));
+
+  emit_insn (gen_rtx_SET (dest, gen_rtx_IOR (mode, tmp1, tmp2)));
+ }
+
+/* Emit a cond move: If OP holds, move CONS to DEST; else move ALT to DEST.
+   Return 0 if expansion failed.  */
+
+bool
+riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
+{
+  machine_mode mode = GET_MODE (dest);
+  rtx_code code = GET_CODE (op);
+  rtx op0 = XEXP (op, 0);
+  rtx op1 = XEXP (op, 1);
+
+  if (TARGET_XTHEADCONDMOV
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && reg_or_0_operand (cons, mode)
+      && reg_or_0_operand (alt, mode)
+      && GET_MODE (op) == mode
+      && GET_MODE (op0) == mode
+      && GET_MODE (op1) == mode
+      && (code == EQ || code == NE))
+    {
+      riscv_expand_conditional_move_onesided (dest, cons, alt, code, op0, op1);
+      return true;
+    }
+  else if (TARGET_SFB_ALU
+	   && mode == word_mode)
+    {
+      riscv_emit_int_compare (&code, &op0, &op1);
+      rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+      emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
+							  cond, cons, alt)));
+      return true;
+    }
+
+  return false;
 }
 
 /* Implement TARGET_FUNCTION_ARG_BOUNDARY.  Every parameter gets at
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 8bdf3c128f3..34327bfb01f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -242,6 +242,7 @@ (define_attr "enabled" "no,yes"
 ;; bitmanip	bit manipulation instructions
 ;; rotate   rotation instructions
 ;; atomic   atomic instructions
+;; condmove	conditional moves
 ;; Classification of RVV instructions which will be added to each RVV .md pattern and used by scheduler.
 ;; rdvlenb     vector byte length vlenb csrr read
 ;; rdvl        vector length vl csrr read
@@ -333,7 +334,7 @@ (define_attr "type"
   "unknown,branch,jump,call,load,fpload,store,fpstore,
    mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
    fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip,rotate,
-   atomic,rdvlenb,rdvl,vsetvl,vlde,vste,vldm,vstm,vlds,vsts,
+   atomic,condmove,rdvlenb,rdvl,vsetvl,vlde,vste,vldm,vstm,vlds,vsts,
    vldux,vldox,vstux,vstox,vldff,vldr,vstr,
    vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,
    vimul,vidiv,viwmul,vimuladd,viwmuladd,vimerge,vimov,
@@ -2288,17 +2289,15 @@ (define_insn "*branch<mode>"
 (define_expand "mov<mode>cc"
   [(set (match_operand:GPR 0 "register_operand")
 	(if_then_else:GPR (match_operand 1 "comparison_operator")
-			  (match_operand:GPR 2 "register_operand")
+			  (match_operand:GPR 2 "reg_or_0_operand")
 			  (match_operand:GPR 3 "sfb_alu_operand")))]
-  "TARGET_SFB_ALU"
+  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
 {
-  rtx cmp = operands[1];
-  /* We only handle word mode integer compares for now.  */
-  if (GET_MODE (XEXP (cmp, 0)) != word_mode)
+  if (riscv_expand_conditional_move (operands[0], operands[1],
+				     operands[2], operands[3]))
+    DONE;
+  else
     FAIL;
-  riscv_expand_conditional_move (operands[0], operands[2], operands[3],
-				 GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1));
-  DONE;
 })
 
 (define_insn "*mov<GPR:mode><X:mode>cc"
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index c3cbb49eb58..9f03d1d43b4 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -106,3 +106,40 @@ (define_insn "*th_tst"
   "TARGET_XTHEADBS"
   "th.tst\t%0,%1,%2"
   [(set_attr "type" "bitmanip")])
+
+;; XTheadCondMov
+
+(define_insn "*th_cond_mov<GPR:mode><GPR2:mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r,r")
+	(if_then_else:GPR
+	 (match_operator 4 "equality_operator"
+		[(match_operand:GPR2 1 "register_operand" "r,r")
+		 (const_int 0)])
+	 (match_operand:GPR 2 "reg_or_0_operand" "rJ,0")
+	 (match_operand:GPR 3 "reg_or_0_operand" "0,rJ")))]
+  "TARGET_XTHEADCONDMOV"
+{
+  if (which_alternative == 0)
+    return "th.mv%C4z\t%0,%z2,%1";
+
+  /* Invert the condition and take else-block.  */
+  rtx_code code = GET_CODE (operands[4]);
+  code = (code == EQ) ? NE : EQ;
+  operands[4] = gen_rtx_fmt_ee (code, VOIDmode, const0_rtx, const0_rtx);
+  return "th.mv%C4z\t%0,%z3,%1";
+}
+  [(set_attr "type" "condmove")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_cond_gpr_mov<GPR:mode><GPR2:mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r,r")
+	(if_then_else:GPR
+	 (match_operand:GPR2 1 "register_operand" "r,r")
+	 (match_operand:GPR 2 "reg_or_0_operand" "rJ,0")
+	 (match_operand:GPR 3 "reg_or_0_operand" "0,rJ")))]
+  "TARGET_XTHEADCONDMOV"
+  "@
+   th.mvnez\t%0,%z2,%1
+   th.mveqz\t%0,%z3,%1"
+  [(set_attr "type" "condmove")
+   (set_attr "mode" "<GPR:MODE>")])
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-eqz.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-eqz.c
new file mode 100644
index 00000000000..913ae43f21b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-eqz.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond)
+{
+  if (cond == 0)
+    return 1025;
+  return x;
+}
+
+long
+not_long_int (long x, int cond)
+{
+  if (cond == 0)
+    return 1025l;
+  return x;
+}
+
+int
+not_int_long (int x, long cond)
+{
+  if (cond == 0)
+    return 1025;
+  return x;
+}
+
+long
+not_long_long (long x, int cond)
+{
+  if (cond == 0)
+    return 1025l;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mveqz" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-not.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-not.c
new file mode 100644
index 00000000000..1bc8b838233
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-imm-not.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond)
+{
+  if (!cond)
+    return 1025;
+  return x;
+}
+
+long
+not_long_int (long x, int cond)
+{
+  if (!cond)
+    return 1025l;
+  return x;
+}
+
+int
+not_int_long (int x, long cond)
+{
+  if (!cond)
+    return 1025;
+  return x;
+}
+
+long
+not_long_long (long x, int cond)
+{
+  if (!cond)
+    return 1025l;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mveqz" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-eqz.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-eqz.c
new file mode 100644
index 00000000000..8ef5869a89b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-eqz.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond, int v)
+{
+  if (cond == 0)
+    return v;
+  return x;
+}
+
+long
+not_long_int (long x, int cond, long v)
+{
+  if (cond == 0)
+    return v;
+  return x;
+}
+
+int
+not_int_long (int x, long cond, int v)
+{
+  if (cond == 0)
+    return v;
+  return x;
+}
+
+long
+not_long_long (long x, int cond, long v)
+{
+  if (cond == 0)
+    return v;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mveqz" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-not.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-not.c
new file mode 100644
index 00000000000..f9568bee27f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mveqz-reg-not.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond, int v)
+{
+  if (!cond)
+    return v;
+  return x;
+}
+
+long
+not_long_int (long x, int cond, long v)
+{
+  if (!cond)
+    return v;
+  return x;
+}
+
+int
+not_int_long (int x, long cond, int v)
+{
+  if (!cond)
+    return v;
+  return x;
+}
+
+long
+not_long_long (long x, int cond, long v)
+{
+  if (!cond)
+    return v;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mveqz" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-cond.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-cond.c
new file mode 100644
index 00000000000..8feddbeb79d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-cond.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond)
+{
+  if (cond)
+    return 1025;
+  return x;
+}
+
+long
+not_long_int (long x, int cond)
+{
+  if (cond)
+    return 1025l;
+  return x;
+}
+
+int
+not_int_long (int x, long cond)
+{
+  if (cond)
+    return 1025;
+  return x;
+}
+
+long
+not_long_long (long x, int cond)
+{
+  if (cond)
+    return 1025l;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mvnez" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-nez.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-nez.c
new file mode 100644
index 00000000000..7c08e20c25d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-imm-nez.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond)
+{
+  if (cond != 0)
+    return 1025;
+  return x;
+}
+
+long
+not_long_int (long x, int cond)
+{
+  if (cond != 0)
+    return 1025l;
+  return x;
+}
+
+int
+not_int_long (int x, long cond)
+{
+  if (cond != 0)
+    return 1025;
+  return x;
+}
+
+long
+not_long_long (long x, int cond)
+{
+  if (cond != 0)
+    return 1025l;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mvnez" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-cond.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-cond.c
new file mode 100644
index 00000000000..c1619509af9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-cond.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond, int v)
+{
+  if (cond)
+    return v;
+  return x;
+}
+
+long
+not_long_int (long x, int cond, long v)
+{
+  if (cond)
+    return v;
+  return x;
+}
+
+int
+not_int_long (int x, long cond, int v)
+{
+  if (cond)
+    return v;
+  return x;
+}
+
+long
+not_long_long (long x, int cond, long v)
+{
+  if (cond)
+    return v;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mvnez" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-nez.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-nez.c
new file mode 100644
index 00000000000..ff95a57927a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-mvnez-reg-nez.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+not_int_int (int x, int cond, int v)
+{
+  if (cond != 0)
+    return v;
+  return x;
+}
+
+long
+not_long_int (long x, int cond, long v)
+{
+  if (cond != 0)
+    return v;
+  return x;
+}
+
+int
+not_int_long (int x, long cond, int v)
+{
+  if (cond != 0)
+    return v;
+  return x;
+}
+
+long
+not_long_long (long x, int cond, long v)
+{
+  if (cond != 0)
+    return v;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "th.mvnez" 4 } } */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 09/11] riscv: thead: Add support for XTheadMac ISA extension
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (7 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 08/11] riscv: thead: Add support for XTheadCondMov ISA extensions Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 10/11] riscv: thead: Add support for XTheadFmv " Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 11/11] riscv: thead: Add support for XTheadMemPair " Christoph Muellner
  10 siblings, 0 replies; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

The XTheadMac ISA extension provides multiply-accumulate/subtract
instructions:
* mula/mulaw/mulah
* muls/mulsw/mulsh

To benefit from middle-end passes, we expand the following named
patterns in riscv.md (as they are not T-Head-specific):
* maddhisi4
* msubhisi4

gcc/ChangeLog:

	* config/riscv/riscv.md (maddhisi4): New expand.
	(msubhisi4): New expand.
	* config/riscv/thead.md (*th_mula<mode>): New pattern.
	(*th_mulawsi): New pattern.
	(*th_mulawsi2): New pattern.
	(*th_maddhisi4): New pattern.
	(*th_sextw_maddhisi4): New pattern.
	(*th_muls<mode>): New pattern.
	(*th_mulswsi): New pattern.
	(*th_mulswsi2): New pattern.
	(*th_msubhisi4): New pattern.
	(*th_sextw_msubhisi4): New pattern.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/thead-mula-muls.c: New test.

Co-Developed-by: Xianmiao Qu <cooper.qu@linux.alibaba.com>
Signed-off-by: Xianmiao Qu <cooper.qu@linux.alibaba.com>
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>

Changed in v2:
- Add missing prefix in on INSN
---
 gcc/config/riscv/riscv.md                     |  18 +++
 gcc/config/riscv/thead.md                     | 121 ++++++++++++++++++
 .../gcc.target/riscv/xtheadmac-mula-muls.c    |  43 +++++++
 3 files changed, 182 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmac-mula-muls.c

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 34327bfb01f..20506451e7c 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3086,6 +3086,24 @@ (define_expand "extzv<mode>"
     FAIL;
 })
 
+(define_expand "maddhisi4"
+  [(set (match_operand:SI 0 "register_operand")
+	(plus:SI
+	  (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand"))
+		   (sign_extend:SI (match_operand:HI 2 "register_operand")))
+	  (match_operand:SI 3 "register_operand")))]
+  "TARGET_XTHEADMAC"
+)
+
+(define_expand "msubhisi4"
+  [(set (match_operand:SI 0 "register_operand")
+	(minus:SI
+	  (match_operand:SI 3 "register_operand")
+	  (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand"))
+		   (sign_extend:SI (match_operand:HI 2 "register_operand")))))]
+  "TARGET_XTHEADMAC"
+)
+
 (include "bitmanip.md")
 (include "sync.md")
 (include "peephole.md")
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index 9f03d1d43b4..d9cac15cc5f 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -143,3 +143,124 @@ (define_insn "*th_cond_gpr_mov<GPR:mode><GPR2:mode>"
    th.mveqz\t%0,%z3,%1"
   [(set_attr "type" "condmove")
    (set_attr "mode" "<GPR:MODE>")])
+
+;; XTheadMac
+
+(define_insn "*th_mula<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	      (plus:X (mult:X (match_operand:X 1 "register_operand" "r")
+			      (match_operand:X 2 "register_operand" "r"))
+		      (match_operand:X 3 "register_operand" "0")))]
+  "TARGET_XTHEADMAC"
+  "th.mula\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "<MODE>")]
+)
+
+(define_insn "*th_mulawsi"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(sign_extend:DI
+	  (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+			    (match_operand:SI 2 "register_operand" "r"))
+		   (match_operand:SI 3 "register_operand" "0"))))]
+  "TARGET_XTHEADMAC && TARGET_64BIT"
+  "th.mulaw\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_mulawsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	      (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+				(match_operand:SI 2 "register_operand" "r"))
+		       (match_operand:SI 3 "register_operand" "0")))]
+  "TARGET_XTHEADMAC && TARGET_64BIT"
+  "th.mulaw\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_maddhisi4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	  (plus:SI
+	    (mult:SI
+	      (sign_extend:SI (match_operand:HI 1 "register_operand" " r"))
+	      (sign_extend:SI (match_operand:HI 2 "register_operand" " r")))
+	    (match_operand:SI 3 "register_operand" " 0")))]
+  "TARGET_XTHEADMAC"
+  "th.mulah\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_sextw_maddhisi4"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(sign_extend:DI
+	  (plus:SI
+	    (mult:SI
+	      (sign_extend:SI (match_operand:HI 1 "register_operand" " r"))
+	      (sign_extend:SI (match_operand:HI 2 "register_operand" " r")))
+	    (match_operand:SI 3 "register_operand" " 0"))))]
+  "TARGET_XTHEADMAC && TARGET_64BIT"
+  "th.mulah\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_muls<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	      (minus:X (match_operand:X 3 "register_operand" "0")
+		       (mult:X (match_operand:X 1 "register_operand" "r")
+			       (match_operand:X 2 "register_operand" "r"))))]
+  "TARGET_XTHEADMAC"
+  "th.muls\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "<MODE>")]
+)
+
+(define_insn "*th_mulswsi"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(sign_extend:DI
+	  (minus:SI (match_operand:SI 3 "register_operand" "0")
+		    (mult:SI (match_operand:SI 1 "register_operand" "r")
+			     (match_operand:SI 2 "register_operand" "r")))))]
+  "TARGET_XTHEADMAC && TARGET_64BIT"
+  "th.mulsw\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_mulswsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(minus:SI (match_operand:SI 3 "register_operand" "0")
+		  (mult:SI (match_operand:SI 1 "register_operand" "r")
+			   (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_XTHEADMAC && TARGET_64BIT"
+  "th.mulsw\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_msubhisi4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(minus:SI (match_operand:SI 3 "register_operand" " 0")
+	  (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" " r"))
+	    (sign_extend:SI (match_operand:HI 2 "register_operand" " r")))))]
+  "TARGET_XTHEADMAC"
+  "th.mulsh\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*th_sextw_msubhisi4"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(sign_extend:DI
+	  (minus:SI (match_operand:SI 3 "register_operand" " 0")
+	    (mult:SI
+	      (sign_extend:SI (match_operand:HI 1 "register_operand" " r"))
+	      (sign_extend:SI (match_operand:HI 2 "register_operand" " r"))))))]
+  "TARGET_XTHEADMAC && TARGET_64BIT"
+  "th.mulsh\\t%0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "mode" "SI")]
+)
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmac-mula-muls.c b/gcc/testsuite/gcc.target/riscv/xtheadmac-mula-muls.c
new file mode 100644
index 00000000000..751a4be5091
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmac-mula-muls.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadmac" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadmac" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+long f_mula(long a, long b, long c)
+{
+  return a + b * c;
+}
+
+long f_muls(long a, long b, long c)
+{
+  return a - b * c;
+}
+
+#if __riscv_xlen == 64
+int f_mulaw(int a, int b, int c)
+{
+  return a + b * c;
+}
+
+int f_mulsw(int a, int b, int c)
+{
+  return a - b * c;
+}
+#endif
+
+long f_mulah(int a, unsigned short b, unsigned short c)
+{
+  return a + (int)(short)b * (int)(short)c;
+}
+
+long f_mulsh(int a, unsigned short b, unsigned short c)
+{
+  return a - (int)(short)b * (int)(short)c;
+}
+
+/* { dg-final { scan-assembler-times "th.mula\t" 1 } } */
+/* { dg-final { scan-assembler-times "th.muls\t" 1 } } */
+/* { dg-final { scan-assembler-times "th.mulaw\t" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.mulsw\t" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.mulah\t" 1 } } */
+/* { dg-final { scan-assembler-times "th.mulsh\t" 1 } } */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 10/11] riscv: thead: Add support for XTheadFmv ISA extension
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (8 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 09/11] riscv: thead: Add support for XTheadMac ISA extension Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  2022-12-19  1:08 ` [PATCH v2 11/11] riscv: thead: Add support for XTheadMemPair " Christoph Muellner
  10 siblings, 0 replies; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: Christoph Müllner

From: Christoph Müllner <christoph.muellner@vrull.eu>

The XTheadFmv ISA extension provides instructions to move
data between 32-bit GP registers and 64-bit FP registers.

gcc/ChangeLog:

	* config/riscv/constraints.md (TARGET_XTHEADFMV ? FP_REGS : NO_REGS)
	New constraint "th_f_fmv".
	(TARGET_XTHEADFMV ? GR_REGS : NO_REGS): New constraint
	"th_r_fmv".
	* config/riscv/riscv.cc (riscv_split_doubleword_move):
	Add split code for XTheadFmv.
	(riscv_secondary_memory_needed): XTheadFmv does not need
	secondary memory.
	* config/riscv/riscv.md: Add new UNSPEC_XTHEADFMV and
	UNSPEC_XTHEADFMV_HW. Add support for XTheadFmv to
	movdf_hardfloat_rv32.
	* config/riscv/thead.md (th_fmv_hw_w_x): New INSN.
	(th_fmv_x_w): New INSN.
	(th_fmv_x_hw): New INSN.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadfmv-fmv.c: New test.

Co-Developed-by: Xianmiao Qu <cooper.qu@linux.alibaba.com>
Signed-off-by: Xianmiao Qu <cooper.qu@linux.alibaba.com>
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/constraints.md               |  8 +++++
 gcc/config/riscv/riscv.cc                     | 25 ++++++++++++--
 gcc/config/riscv/riscv.md                     | 11 +++++--
 gcc/config/riscv/thead.md                     | 33 +++++++++++++++++++
 .../gcc.target/riscv/xtheadfmv-fmv.c          | 24 ++++++++++++++
 5 files changed, 95 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 51cffb2bcb6..f3b1af774e1 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -156,3 +156,11 @@ (define_constraint "Wdm"
   "Vector duplicate memory operand"
   (and (match_operand 0 "memory_operand")
        (match_code "reg" "0")))
+
+;; Vendor ISA extension constraints.
+
+(define_register_constraint "th_f_fmv" "TARGET_XTHEADFMV ? FP_REGS : NO_REGS"
+  "A floating-point register for XTheadFmv.")
+
+(define_register_constraint "th_r_fmv" "TARGET_XTHEADFMV ? GR_REGS : NO_REGS"
+  "An integer register for XTheadFmv.")
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 21ec7a6225b..fc18ce2c766 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2754,11 +2754,29 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
 void
 riscv_split_doubleword_move (rtx dest, rtx src)
 {
-  rtx low_dest;
+  /* XTheadFmv has instructions for accessing the upper bits of a double.  */
+  if (!TARGET_64BIT && TARGET_XTHEADFMV)
+    {
+      if (FP_REG_RTX_P (dest))
+	{
+	  rtx low_src = riscv_subword (src, false);
+	  rtx high_src = riscv_subword (src, true);
+	  emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
+	  return;
+	}
+      if (FP_REG_RTX_P (src))
+	{
+	  rtx low_dest = riscv_subword (dest, false);
+	  rtx high_dest = riscv_subword (dest, true);
+	  emit_insn (gen_th_fmv_x_w (low_dest, src));
+	  emit_insn (gen_th_fmv_x_hw (high_dest, src));
+	  return;
+	}
+    }
 
    /* The operation can be split into two normal moves.  Decide in
       which order to do them.  */
-   low_dest = riscv_subword (dest, false);
+   rtx low_dest = riscv_subword (dest, false);
    if (REG_P (low_dest) && reg_overlap_mentioned_p (low_dest, src))
      {
        riscv_emit_move (riscv_subword (dest, true), riscv_subword (src, true));
@@ -5752,7 +5770,8 @@ riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1,
 {
   return (!riscv_v_ext_vector_mode_p (mode)
 	  && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
-	  && (class1 == FP_REGS) != (class2 == FP_REGS));
+	  && (class1 == FP_REGS) != (class2 == FP_REGS)
+	  && !TARGET_XTHEADFMV);
 }
 
 /* Implement TARGET_REGISTER_MOVE_COST.  */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 20506451e7c..ef6ae443059 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -100,6 +100,10 @@ (define_c_enum "unspecv" [
 
   ;; Zihintpause unspec
   UNSPECV_PAUSE
+
+  ;; XTheadFmv unspec
+  UNSPEC_XTHEADFMV
+  UNSPEC_XTHEADFMV_HW
 ])
 
 (define_constants
@@ -1836,16 +1840,17 @@ (define_expand "movdf"
     DONE;
 })
 
+
 ;; In RV32, we lack fmv.x.d and fmv.d.x.  Go through memory instead.
 ;; (However, we can still use fcvt.d.w to zero a floating-point register.)
 (define_insn "*movdf_hardfloat_rv32"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,  *r,*r,*m")
-	(match_operand:DF 1 "move_operand"         " f,G,m,f,G,*r*G,*m,*r"))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*th_f_fmv,*th_r_fmv,  *r,*r,*m")
+	(match_operand:DF 1 "move_operand"         " f,G,m,f,G,*th_r_fmv,*th_f_fmv,*r*G,*m,*r"))]
   "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,move,load,store")
+  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_hardfloat_rv64"
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index d9cac15cc5f..d3e3644c73f 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -144,6 +144,39 @@ (define_insn "*th_cond_gpr_mov<GPR:mode><GPR2:mode>"
   [(set_attr "type" "condmove")
    (set_attr "mode" "<GPR:MODE>")])
 
+;; XTheadFmv
+
+;; In RV32, we lack fmv.x.d and fmv.d.x, but XTheadFmv has instructions
+;; that cover this case.
+
+(define_insn "th_fmv_hw_w_x"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+	(unspec:DF [(match_operand:SI 1 "register_operand" "r")
+                (match_operand:SI 2 "register_operand" "r")]
+     UNSPEC_XTHEADFMV))]
+  "!TARGET_64BIT && TARGET_XTHEADFMV"
+  "fmv.w.x\t%0,%2\n\tth.fmv.hw.x\t%0,%1"
+  [(set_attr "move_type" "move")
+   (set_attr "mode" "DF")])
+
+(define_insn "th_fmv_x_w"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:DF 1 "register_operand" "f")]
+     UNSPEC_XTHEADFMV))]
+  "!TARGET_64BIT && TARGET_XTHEADFMV"
+  "fmv.x.w\t%0,%1"
+  [(set_attr "move_type" "move")
+   (set_attr "mode" "DF")])
+
+(define_insn "th_fmv_x_hw"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:DF 1 "register_operand" "f")]
+     UNSPEC_XTHEADFMV_HW))]
+  "!TARGET_64BIT && TARGET_XTHEADFMV"
+  "th.fmv.x.hw\t%0,%1"
+  [(set_attr "move_type" "move")
+   (set_attr "mode" "DF")])
+
 ;; XTheadMac
 
 (define_insn "*th_mula<mode>"
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c b/gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c
new file mode 100644
index 00000000000..10d035e9e1d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c
@@ -0,0 +1,24 @@
+/* { dg-do compile { target { rv32 } } } */
+/* { dg-options "-march=rv32gc_xtheadfmv" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+double
+ll2d (long long ll)
+{
+  return *(double*)&ll;
+}
+
+long long
+d2ll (double d)
+{
+  return *(long long*)&d;
+}
+
+/* { dg-final { scan-assembler "fmv.w.x" } } */
+/* { dg-final { scan-assembler "th.fmv.hw.x" } } */
+/* { dg-final { scan-assembler "fmv.x.w" } } */
+/* { dg-final { scan-assembler "th.fmv.x.hw" } } */
+/* { dg-final { scan-assembler-not "sw" } } */
+/* { dg-final { scan-assembler-not "fld" } } */
+/* { dg-final { scan-assembler-not "fsd" } } */
+/* { dg-final { scan-assembler-not "lw" } } */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 11/11] riscv: thead: Add support for XTheadMemPair ISA extension
  2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
                   ` (9 preceding siblings ...)
  2022-12-19  1:08 ` [PATCH v2 10/11] riscv: thead: Add support for XTheadFmv " Christoph Muellner
@ 2022-12-19  1:08 ` Christoph Muellner
  10 siblings, 0 replies; 24+ messages in thread
From: Christoph Muellner @ 2022-12-19  1:08 UTC (permalink / raw)
  To: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu
  Cc: moiz.hussain, Christoph Müllner, M . Moiz Hussain

From: "moiz.hussain" <moiz.hussain@vrull.eu>

The XTheadMemPair ISA extension provides load/store pair instructions:
* th.ldd
* th.sdd
* th.lwd
* th.lwud
* th.swd

This patch adds the following unnamed patterns to the peephole.md stage,
which take care of reordering loads/stores appropriately:
* load/store pair patterns for 4 instructions
* load/store pair patterns for 2 instructions

The generation of the load/store-pair instructions (based on ordered
load/store sequences) is inspired by the approaches of other backends.

The CFA expansion (save/restore registers on/from stack) is done quite
late, therefore it needs special-treatment. This patch tries to minimize
the impact for the default case and follows the pattern of other
backends.

gcc/ChangeLog:

	* config/riscv/peephole.md: New load/store pair ordering
	peephole optimizations.
	* config/riscv/predicates.md (reg_or_const_operand): New
	predicate.
	* config/riscv/riscv-protos.h (riscv_load_store_bonding_p_2instr):
	New prototype.
	(riscv_load_store_bonding_p_4instr): Likewise.
	(riscv_ldrstr_offset_compare): Likewise.
	(extract_base_offset_in_addr): Likewise.
	(th_riscv_output_mempair_move): Likewise.
	(th_riscv_gen_adjusted_mempair): Likewise.
	* config/riscv/riscv.cc (extract_base_offset_in_addr): New function.
	(riscv_split_plus): Likewise.
	(th_riscv_output_mempair_move): Likewise.
	(riscv_load_store_bonding_p_4instr): Likewise.
	(riscv_load_store_bonding_p_2instr): Likewise.
	(riscv_ldrstr_offset_compare): Likewise.
	(th_riscv_gen_adjusted_mempair): Likewise.
	(riscv_save_reg): Moved before new uses.
	(riscv_restore_reg): Moved before new uses.
	(riscv_for_each_saved_reg): Adjusted for load/store-pair support
	in CFA expansion.
	* config/riscv/thead.md (th_mov_mempair_<GPR:MODE>): New INSN.
	(th_mov_mempair_di_si_zero_ext): New INSN.
	(th_mov_mempair_di_si_sign_ext): New INSN.
	(th_mov_mempair_si_si_zero_ext): New INSN.
	(th_mov_mempair_si_si_sign_ext): New INSN.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadmempair-1.c: New test.
	* gcc.target/riscv/xtheadmempair-10.c: New test.
	* gcc.target/riscv/xtheadmempair-11.c: New test.
	* gcc.target/riscv/xtheadmempair-12.c: New test.
	* gcc.target/riscv/xtheadmempair-13.c: New test.
	* gcc.target/riscv/xtheadmempair-14.c: New test.
	* gcc.target/riscv/xtheadmempair-15.c: New test.
	* gcc.target/riscv/xtheadmempair-16.c: New test.
	* gcc.target/riscv/xtheadmempair-17.c: New test.
	* gcc.target/riscv/xtheadmempair-18.c: New test.
	* gcc.target/riscv/xtheadmempair-19.c: New test.
	* gcc.target/riscv/xtheadmempair-2.c: New test.
	* gcc.target/riscv/xtheadmempair-20.c: New test.
	* gcc.target/riscv/xtheadmempair-3.c: New test.
	* gcc.target/riscv/xtheadmempair-4.c: New test.
	* gcc.target/riscv/xtheadmempair-5.c: New test.
	* gcc.target/riscv/xtheadmempair-6.c: New test.
	* gcc.target/riscv/xtheadmempair-7.c: New test.
	* gcc.target/riscv/xtheadmempair-8.c: New test.
	* gcc.target/riscv/xtheadmempair-9.c: New test.
	* gcc.target/riscv/xtheadmempair-helper.h: New test.

Co-Developed-by: Christoph Müllner <christoph.muellner@vrull.eu>
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
Signed-off-by: M. Moiz Hussain <muhammad.hussain@vrull.eu>
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/peephole.md                  | 298 ++++++++
 gcc/config/riscv/predicates.md                |   4 +
 gcc/config/riscv/riscv-protos.h               |   9 +
 gcc/config/riscv/riscv.cc                     | 701 +++++++++++++++++-
 gcc/config/riscv/thead.md                     |  86 +++
 .../gcc.target/riscv/xtheadmempair-1.c        |  29 +
 .../gcc.target/riscv/xtheadmempair-10.c       |  36 +
 .../gcc.target/riscv/xtheadmempair-11.c       |  18 +
 .../gcc.target/riscv/xtheadmempair-12.c       |  20 +
 .../gcc.target/riscv/xtheadmempair-13.c       |  23 +
 .../gcc.target/riscv/xtheadmempair-14.c       |  30 +
 .../gcc.target/riscv/xtheadmempair-15.c       |  15 +
 .../gcc.target/riscv/xtheadmempair-16.c       |  18 +
 .../gcc.target/riscv/xtheadmempair-17.c       |  13 +
 .../gcc.target/riscv/xtheadmempair-18.c       |  49 ++
 .../gcc.target/riscv/xtheadmempair-19.c       |  86 +++
 .../gcc.target/riscv/xtheadmempair-2.c        |  26 +
 .../gcc.target/riscv/xtheadmempair-20.c       |  21 +
 .../gcc.target/riscv/xtheadmempair-3.c        |  30 +
 .../gcc.target/riscv/xtheadmempair-4.c        |  20 +
 .../gcc.target/riscv/xtheadmempair-5.c        |  21 +
 .../gcc.target/riscv/xtheadmempair-6.c        |  19 +
 .../gcc.target/riscv/xtheadmempair-7.c        |  22 +
 .../gcc.target/riscv/xtheadmempair-8.c        |  29 +
 .../gcc.target/riscv/xtheadmempair-9.c        |  37 +
 .../gcc.target/riscv/xtheadmempair-helper.h   |  52 ++
 26 files changed, 1680 insertions(+), 32 deletions(-)
 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-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
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadmempair-helper.h

diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md
index d9477f46338..e0f04b09345 100644
--- a/gcc/config/riscv/peephole.md
+++ b/gcc/config/riscv/peephole.md
@@ -38,3 +38,301 @@ (define_peephole2
 {
   operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5]));
 })
+
+;; --- T-HEAD EXTENSION MEMPAIR - 4 instr LOADS -> 2 pairs ---
+;; 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 -> 2 pairs ---
+;; 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 "reg_or_const_operand" ""))
+   (set (match_operand:DI 2 "memory_operand" "")
+	(match_operand:DI 3 "reg_or_const_operand" ""))
+   (set (match_operand:DI 4 "memory_operand" "")
+	(match_operand:DI 5 "reg_or_const_operand" ""))
+   (set (match_operand:DI 6 "memory_operand" "")
+	(match_operand:DI 7 "reg_or_const_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 "reg_or_const_operand" ""))
+   (set (match_operand:SI 2 "memory_operand" "")
+	(match_operand:SI 3 "reg_or_const_operand" ""))
+   (set (match_operand:SI 4 "memory_operand" "")
+	(match_operand:SI 5 "reg_or_const_operand" ""))
+   (set (match_operand:SI 6 "memory_operand" "")
+	(match_operand:SI 7 "reg_or_const_operand" ""))
+   (match_dup 8)]
+  "TARGET_XTHEADMEMPAIR
+  && 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 -> 1 pair ---
+;; 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 -> 1 pair
+;; 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 "reg_or_const_operand" ""))
+   (set (match_operand:DI 2 "memory_operand" "")
+	(match_operand:DI 3 "reg_or_const_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 "reg_or_const_operand" ""))
+   (set (match_operand:SI 2 "memory_operand" "")
+	(match_operand:SI 3 "reg_or_const_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/predicates.md b/gcc/config/riscv/predicates.md
index 5a5a49bf7c0..956a58bf41b 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -59,6 +59,10 @@ (define_predicate "reg_or_0_operand"
   (ior (match_operand 0 "const_0_operand")
        (match_operand 0 "register_operand")))
 
+(define_predicate "reg_or_const_operand"
+  (ior (match_operand 0 "const_int_operand")
+       (match_operand 0 "register_operand")))
+
 ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
 (define_predicate "branch_on_bit_operand"
   (and (match_code "const_int")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 7975bc4f438..b42533574d0 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 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,
+					   bool has_scratch = true);
 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 fc18ce2c766..3ed84619278 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -36,6 +36,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"
@@ -57,6 +58,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"
@@ -2943,6 +2945,570 @@ 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;
+}
+
+/* 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 OR CONST STORE
+  else if ( (which_alternative == 1)
+	 || (which_alternative == 2))
+    {
+	reg1 = copy_rtx (operands[1]);
+	reg2 = copy_rtx (operands[3]);
+	mem1 = copy_rtx (operands[0]);
+	mem2 = copy_rtx (operands[2]);
+    }
+  else
+	abort ();
+
+  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\t%0, %1, (%2), %3, %4",
+			       output_operands);
+	    else if (code == SIGN_EXTEND)
+	      output_asm_insn ("th.lwd\t%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\t%0, %1, (%2), %3, %4", output_operands);
+	  }
+	  break;
+	default:
+	  abort ();
+	}
+    }
+  // STORE OR CONST STORE
+  else if (which_alternative == 1 || which_alternative == 2)
+    {
+      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\t%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\t%z0, %z1, (%2), %3, %4",
+			     output_operands);
+	  }
+	  break;
+	default:
+	  abort ();
+	}
+    }
+  // UNKNOWN
+  else
+    abort ();
+
+  return "";
+}
+
+/* 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,
+			      bool has_scratch)
+{
+  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;
+
+  constexpr int NUM_INSTR_MAX = 4;
+  int NUM_INSTR = 2;
+  if (is_four_insns)
+    NUM_INSTR = 4;
+
+  rtx temp_operands[2*NUM_INSTR_MAX], mem[NUM_INSTR_MAX];
+  bool emit_adjust_insn = false;
+  bool misaligned_offset = false;
+
+  if (has_scratch)
+    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 (has_scratch && 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 (has_scratch && 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 ()
 {
@@ -4916,6 +5482,35 @@ riscv_set_return_address (rtx address, rtx scratch)
   riscv_emit_move (gen_frame_mem (GET_MODE (address), slot_address), address);
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+riscv_save_reg (rtx reg, rtx mem)
+{
+  riscv_emit_move (mem, reg);
+  riscv_set_frame_expr (riscv_frame_set (mem, reg));
+}
+
+/* Restore register REG from MEM.  */
+
+static void
+riscv_restore_reg (rtx reg, rtx mem)
+{
+  rtx insn = riscv_emit_move (reg, mem);
+  rtx dwarf = NULL_RTX;
+  dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+
+  if (epilogue_cfa_sp_offset && REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
+    {
+      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+					 GEN_INT (epilogue_cfa_sp_offset));
+      dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
+    }
+
+  REG_NOTES (insn) = dwarf;
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
 /* A function to save or store a register.  The first argument is the
    register and the second is the stack slot.  */
 typedef void (*riscv_save_restore_fn) (rtx, rtx);
@@ -4985,8 +5580,8 @@ static void
 riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 			  bool epilogue, bool maybe_eh_return)
 {
-  HOST_WIDE_INT offset;
-  unsigned int regno;
+  HOST_WIDE_INT offset, offset2;
+  unsigned int regno, regno2;
   unsigned int start = GP_REG_FIRST;
   unsigned int limit = GP_REG_LAST;
 
@@ -5009,7 +5604,78 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 	  && riscv_is_eh_return_data_register (regno))
 	continue;
 
-      riscv_save_restore_reg (word_mode, regno, offset, fn);
+      if (TARGET_XTHEADMEMPAIR && regno < limit)
+	{
+	  offset2 = offset;
+	  regno2 = riscv_next_saved_reg (regno + 1, limit, &offset2, false);
+	}
+
+      if (TARGET_XTHEADMEMPAIR && regno2 <= limit
+	  && !riscv_is_eh_return_data_register (regno2)
+	  && !cfun->machine->reg_is_wrapped_separately[regno2])
+	{
+	  if ((fn == riscv_save_reg) || (fn == riscv_restore_reg))
+	    {
+	      rtx operands[4], reg1, reg2, mem1, mem2;
+	      HOST_WIDE_INT mem_stride;
+
+	      reg1 = gen_rtx_REG (Pmode, regno);
+	      mem1 = gen_frame_mem (Pmode, plus_constant (Pmode,
+							  stack_pointer_rtx,
+							  offset));
+	      reg2 = gen_rtx_REG (Pmode, regno2);
+	      mem2 = gen_frame_mem (Pmode, plus_constant (Pmode,
+							  stack_pointer_rtx,
+							  offset2));
+
+	      if (fn == riscv_restore_reg)
+		{
+		  operands[0] = copy_rtx (reg1);
+		  operands[1] = copy_rtx (mem1);
+		  operands[2] = copy_rtx (reg2);
+		  operands[3] = copy_rtx (mem2);
+		}
+	      else if (fn == riscv_save_reg)
+		{
+		  operands[0] = copy_rtx (mem1);
+		  operands[1] = copy_rtx (reg1);
+		  operands[2] = copy_rtx (mem2);
+		  operands[3] = copy_rtx (reg2);
+		}
+	      else
+		abort ();
+
+	      /* Sort the mem operands.  */
+	      gcc_stablesort (operands, 2, 2 * sizeof (rtx *),
+			      riscv_ldrstr_offset_compare);
+
+	      mem_stride = abs (offset - offset2);
+
+	      /* Offset alignment should be matching the pair immediate.  */
+	      if ((mem_stride == 8) && (offset % 16))
+		emit_insn (gen_th_mov_mempair_DI (operands[0], operands[1],
+						  operands[2], operands[3]));
+	      else if ((mem_stride == 4) && (offset % 8))
+		emit_insn (gen_th_mov_mempair_SI (operands[0], operands[1],
+						  operands[2], operands[3]));
+	      else
+		{
+		  riscv_save_restore_reg (word_mode, regno, offset, fn);
+		  continue;
+		}
+
+	      offset = offset2;
+	      regno = regno2;
+	    }
+	  else
+	    {
+	      riscv_save_restore_reg (word_mode, regno, offset, fn);
+	    }
+	}
+      else
+	{
+	  riscv_save_restore_reg (word_mode, regno, offset, fn);
+	}
     }
 
   /* This loop must iterate over the same space as its companion in
@@ -5027,35 +5693,6 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
       }
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
-
-static void
-riscv_save_reg (rtx reg, rtx mem)
-{
-  riscv_emit_move (mem, reg);
-  riscv_set_frame_expr (riscv_frame_set (mem, reg));
-}
-
-/* Restore register REG from MEM.  */
-
-static void
-riscv_restore_reg (rtx reg, rtx mem)
-{
-  rtx insn = riscv_emit_move (reg, mem);
-  rtx dwarf = NULL_RTX;
-  dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
-
-  if (epilogue_cfa_sp_offset && REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
-    {
-      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-					 GEN_INT (epilogue_cfa_sp_offset));
-      dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
-    }
-
-  REG_NOTES (insn) = dwarf;
-  RTX_FRAME_RELATED_P (insn) = 1;
-}
-
 /* For stack frames that can't be allocated with a single ADDI instruction,
    compute the best value to initially allocate.  It must at a minimum
    allocate enough space to spill the callee-saved registers.  If TARGET_RVC,
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index d3e3644c73f..b039dd6e2e1 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -297,3 +297,89 @@ (define_insn "*th_sextw_msubhisi4"
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")]
 )
+
+;; XTheadMemPair
+
+;; MEMPAIR load/store 64/32 bit
+(define_insn "th_mov_mempair_<GPR:MODE>"
+  [(set (match_operand:GPR 0 "nonimmediate_operand" "=r, m, m")
+	(match_operand:GPR 1 "move_operand" "m, r, T"))
+   (set (match_operand:GPR 2 "nonimmediate_operand" "=r, m, m")
+	(match_operand:GPR 3 "move_operand" "m, r, T"))]
+  "TARGET_XTHEADMEMPAIR && reload_completed
+   && (register_operand (operands[0], <GPR:MODE>mode)
+   || reg_or_const_operand (operands[1], <GPR:MODE>mode))
+   && (register_operand (operands[2], <GPR:MODE>mode)
+   || reg_or_const_operand (operands[3], <GPR:MODE>mode))"
+  { return th_riscv_output_mempair_move (operands, <GPR:MODE>mode,
+    SIGN_EXTEND); }
+  [(set_attr "move_type" "load, store, const")
+   (set_attr "mode" "<GPR: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_const_operand (operands[1], SImode))
+   && (register_operand (operands[2], DImode)
+   || reg_or_const_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_const_operand (operands[1], SImode))
+   && (register_operand (operands[2], DImode)
+   || reg_or_const_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_const_operand (operands[1], SImode))
+   && (register_operand (operands[2], SImode)
+   || reg_or_const_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_const_operand (operands[1], SImode))
+   && (register_operand (operands[2], SImode)
+   || reg_or_const_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..64085e236a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-1.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os" "-funroll-loops"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+#define A_SIZE 32
+
+unsigned long long array[A_SIZE];
+unsigned long long temp[A_SIZE];
+
+void bar (void);
+
+int
+foo (void)
+{
+  for (int i=0; i<A_SIZE; i++)
+    array[i] = 0xF;
+  
+  bar();
+
+  for (int i=0; i<A_SIZE; i++)
+    temp[i] = array[i];
+
+  return 1;
+}
+/* { dg-final { scan-assembler-times "th.ldd\t" 3 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.sdd\t" 3 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.lwd\t" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-10.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-10.c
new file mode 100644
index 00000000000..9a466cb650b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-10.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+#include <stdint.h>
+
+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)
+{
+  a = b.f3;
+}
+
+/* { 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 "th.sdd\t" 2 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.lwd\t" 5 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 5 { target { rv32 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-11.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-11.c
new file mode 100644
index 00000000000..23c07c8839a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-11.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+int arr[4][4] = {{0, 1, 1, -1}, {-1, -1, 1, -1}, {1, -1, 1, 1}, {1, -1, -1, 0}};
+
+long long
+foo ()
+{
+  long long ll;
+  ll = arr[1][0];
+  ll += arr[1][1];
+  ll += arr[1][2];
+  return ll;
+}
+
+/* { dg-final { scan-assembler-times "th.lwd\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-12.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-12.c
new file mode 100644
index 00000000000..b348dc1884d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-12.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+unsigned int arr[4][4] = {{0, 1, 1, 2}, {2, 2, 1, 2}, {1, 2, 1, 1}, {1, 2, 2, 0}};
+
+unsigned long long
+foo ()
+{
+  unsigned long long ll;
+  ll = arr[1][0];
+  ll += arr[1][1];
+  return ll;
+}
+
+/* { dg-final { scan-assembler-times "th.lwud\t" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.lwd\t" 1 { target { rv32 } } } } */
+
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-13.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-13.c
new file mode 100644
index 00000000000..fcb96c0b622
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-13.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+typedef float __attribute__ ((vector_size (8))) fvec;
+typedef int __attribute__ ((vector_size (8))) ivec;
+
+struct vec_pair
+{
+  fvec a;
+  ivec b;
+};
+
+void
+ldp (fvec *a, ivec *b, struct vec_pair *p)
+{
+  *a = p->a;
+  *b = p->b;
+}
+
+/* { dg-final { scan-assembler-times "th.ldd\t" 1 { target { rv64 } } } } */
+/* { 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..6fa991ee271
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-14.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+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 } } */
+/* { 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 "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..297f86e18ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-15.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+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" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "th.lwd\t" 1 { 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..a65c5526de9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-16.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+void
+store_offset (int *array, int x, int y)
+{
+  array[1085] = x;
+  array[1084] = y;
+
+  array[1086] = y;
+  array[1087] = x;
+}
+
+/* { dg-final { scan-assembler-times "addi\t" 1 } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 2 } } */
+
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..be2162e2f60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-17.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+int
+load (int *arr)
+{
+  return (arr[400] + arr[401] + arr[527] + arr[528]);
+}
+
+/* { dg-final { scan-assembler-times "addi\t" 2 } } */
+/* { 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..75105d2765b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-18.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+#include "xtheadmempair-helper.h"
+#include <stdint.h>
+
+CONST_FN (2, int32_t, 0);
+
+CONST_FN (4, int32_t, 0);
+
+CONST_FN (8, int32_t, 0);
+
+CONST_FN (16, int32_t, 0);
+
+CONST_FN (2, int32_t, 1);
+
+CONST_FN (4, int32_t, 1);
+
+CONST_FN (8, int32_t, 1);
+
+DUP_FN (2, int32_t);
+
+DUP_FN (4, int32_t);
+
+DUP_FN (8, int32_t);
+
+CONS2_FN (1, int32_t);
+
+CONS2_FN (2, int32_t);
+
+CONS2_FN (4, int32_t);
+
+CONS2_FN (8, int32_t);
+
+CONS2_FN (16, int32_t);
+
+CONS4_FN (1, int32_t);
+
+CONS4_FN (2, int32_t);
+
+CONS4_FN (4, int32_t);
+
+CONS4_FN (8, int32_t);
+
+/* { dg-final { scan-assembler-times "th.swd\t" 68 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.sdd\t" 10 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 90 { target { rv32 } } } } */
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..803619291eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-19.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+#include "xtheadmempair-helper.h"
+#include <stdint.h>
+
+CONST_FN (2, int64_t, 0);
+/* "th.sdd\t" 1 target: rv64 */
+/* "th.swd\t" 2 target: rv32 */
+
+CONST_FN (4, int64_t, 0);
+/* "th.sdd\t" 2 target: rv64 */
+/* "th.swd\t" 4 target: rv32 */
+
+CONST_FN (8, int64_t, 0);
+/* "th.sdd\t" 4 target: rv64 */
+/* "th.swd\t" 8 target: rv32 */
+
+CONST_FN (16, int64_t, 0);
+/* "th.sdd\t" 8 target: rv64 */
+/* "th.swd\t" 16 target: rv32 */
+
+CONST_FN (2, int64_t, 1);
+/* "th.sdd\t" 1 target: rv64 */
+/* "th.swd\t" 2 target: rv32 */
+
+CONST_FN (4, int64_t, 1);
+/* "th.sdd\t" 2 target: rv64 */
+/* "th.swd\t" 4 target: rv32 */
+
+CONST_FN (8, int64_t, 1);
+/* "th.sdd\t" 4 target: rv64 */
+/* "th.swd\t" 8 target: rv32 */
+
+DUP_FN (2, int64_t);
+/* "th.sdd\t" 1 target: rv64 */
+/* "th.swd\t" 2 target: rv32 */
+
+DUP_FN (4, int64_t);
+/* "th.sdd\t" 2 target: rv64 */
+/* "th.swd\t" 4 target: rv32 */
+
+DUP_FN (8, int64_t);
+/* "th.sdd\t" 4 target: rv64 */
+/* "th.swd\t" 8 target: rv32 */
+
+CONS2_FN (1, int64_t);
+/* "th.sdd\t" 1 target: rv64 */
+/* "th.swd\t" 2 target: rv32 */
+
+CONS2_FN (2, int64_t);
+/* "th.sdd\t" 2 target: rv64 */
+/* "th.swd\t" 4 target: rv32 */
+
+CONS2_FN (4, int64_t);
+/* "th.sdd\t" 4 target: rv64 */
+/* "th.swd\t" 8 target: rv32 */
+
+CONS2_FN (8, int64_t);
+/* "th.sdd\t" 8 target: rv64 */
+/* "th.swd\t" 16 target: rv32 */
+
+CONS2_FN (16, int64_t);
+/* "th.sdd\t" 16 target: rv64 */
+/* "th.swd\t" 32 target: rv32 */
+
+CONS4_FN (1, int64_t);
+/* "th.sdd\t" 2 target: rv64 */
+/* "th.swd\t" 4 target: rv32 */
+
+CONS4_FN (2, int64_t);
+/* "th.sdd\t" 4 target: rv64 */
+/* "th.swd\t" 8 target: rv32 */
+
+CONS4_FN (4, int64_t);
+/* "th.sdd\t" 8 target: rv64 */
+/* "th.swd\t" 16 target: rv32 */
+
+CONS4_FN (8, int64_t);
+/* "th.sdd\t" 16 target: rv64 */
+/* "th.swd\t" 32 target: rv32 */
+
+/* { dg-final { scan-assembler-times "th.sdd\t" 90 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 180 { 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..85e9ada91c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-2.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+#include <stdint.h>
+
+#if __riscv_xlen == 32
+  uint64_t a;
+  #define XLEN 32
+#else
+  __int128 a;
+  #define XLEN 64
+#endif
+
+void
+foo (int e)
+{
+  a = 25 << 52 + 10 + e;
+  uint64_t c, d;
+  c = a >> XLEN;
+  d = a;
+}
+
+/* { dg-final { scan-assembler-times "th.sdd\t" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 1 { 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..b50ada4e22e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-20.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+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.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-3.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-3.c
new file mode 100644
index 00000000000..73758c85458
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906 --param=sched-autopref-queue-depth=10" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906 --param=sched-autopref-queue-depth=10" { target { rv32 } } } */
+
+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" 5 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 7 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "addi\t" 5 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 7 { target { rv32 } } } } */
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..c6ed5a830f9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+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..29015e09fac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-5.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+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 { target { rv64 } } } } */
+/* { 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-6.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair-6.c
new file mode 100644
index 00000000000..906a4e29650
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-6.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+int x[4] = {-4,-5,6,7};
+
+int
+foo()
+{
+  int a,b,c;
+  
+  a = x[0];
+  b = x[1];
+  c = x[2];
+  return a+b+c;
+}
+
+/* { 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..d1ace43b285
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-7.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+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.lwd\t" 1 } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 1 } } */
+/* { dg-final { scan-assembler-times "addi\t" 5 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "addi\t" 4 { target { rv32 } } } } */
+
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..f0e775e06d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-8.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os" "-funroll-loops"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+typedef int VINT32 __attribute__ ((vector_size((16))));
+
+/* Note: When compiling for RV32, 321r.sched2 changes the ordering of some
+   loads/stores sequences (after the peephole passes), which disables these
+   optimization opportunities.  */
+
+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 "th.lwd\t" 4 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 4 { target { rv32 } } } } */
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..432c7d24fbc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-9.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadmempair -mtune=thead-c906" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadmempair -mtune=thead-c906" { target { rv32 } } } */
+
+#include <stdint.h>
+
+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" 8 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.lwd\t" 2 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "th.swd\t" 3 { target { rv32 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair-helper.h b/gcc/testsuite/gcc.target/riscv/xtheadmempair-helper.h
new file mode 100644
index 00000000000..ef139c6b940
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair-helper.h
@@ -0,0 +1,52 @@
+#ifndef __XTHEADMEMPAIR_HELPER_H
+#define __XTHEADMEMPAIR_HELPER_H
+
+#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;					\
+      }								\
+  }
+
+#endif /* __XTHEADMEMPAIR_HELPER_H */
-- 
2.38.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 01/11] riscv: attr: Synchronize comments with code
  2022-12-19  1:08 ` [PATCH v2 01/11] riscv: attr: Synchronize comments with code Christoph Muellner
@ 2022-12-19  2:48   ` Kito Cheng
  2022-12-27 19:51     ` Philipp Tomsich
  0 siblings, 1 reply; 24+ messages in thread
From: Kito Cheng @ 2022-12-19  2:48 UTC (permalink / raw)
  To: Christoph Muellner
  Cc: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu

LGTM, you can commit this separately if you want :)

On Mon, Dec 19, 2022 at 9:09 AM Christoph Muellner
<christoph.muellner@vrull.eu> wrote:
>
> From: Christoph Müllner <christoph.muellner@vrull.eu>
>
> The comment above the enumeration of existing attributes got out of
> order and a few entries were forgotten.
> This patch synchronizes the comments according to the list.
> This commit does not include any functional change.
>
> gcc/ChangeLog:
>
>         * config/riscv/riscv.md: Sync comments with code.
>
> Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> ---
>  gcc/config/riscv/riscv.md | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index df57e2b0b4a..a8bb331f25c 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -220,7 +220,6 @@ (define_attr "enabled" "no,yes"
>  ;; mfc         transfer from coprocessor
>  ;; const       load constant
>  ;; arith       integer arithmetic instructions
> -;; auipc       integer addition to PC
>  ;; logical      integer logical instructions
>  ;; shift       integer shift instructions
>  ;; slt         set less than instructions
> @@ -236,9 +235,13 @@ (define_attr "enabled" "no,yes"
>  ;; fcvt                floating point convert
>  ;; fsqrt       floating point square root
>  ;; multi       multiword sequence (or user asm statements)
> +;; auipc       integer addition to PC
> +;; sfb_alu  SFB ALU instruction
>  ;; nop         no operation
>  ;; ghost       an instruction that produces no real code
>  ;; bitmanip    bit manipulation instructions
> +;; rotate   rotation instructions
> +;; atomic   atomic instructions
>  ;; Classification of RVV instructions which will be added to each RVV .md pattern and used by scheduler.
>  ;; rdvlenb     vector byte length vlenb csrr read
>  ;; rdvl        vector length vl csrr read
> --
> 2.38.1
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code
  2022-12-19  1:08 ` [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code Christoph Muellner
@ 2022-12-19  6:30   ` Kito Cheng
  2022-12-19  9:21     ` Christoph Müllner
  2022-12-27 19:51     ` Philipp Tomsich
  0 siblings, 2 replies; 24+ messages in thread
From: Kito Cheng @ 2022-12-19  6:30 UTC (permalink / raw)
  To: Christoph Muellner
  Cc: gcc-patches, Jim Wilson, Palmer Dabbelt, Andrew Waterman,
	Philipp Tomsich, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu

just one more nit: Use INVALID_REGNUM as sentinel value for
riscv_next_saved_reg, otherwise LGTM, and feel free to commit that
separately :)

On Mon, Dec 19, 2022 at 9:08 AM Christoph Muellner
<christoph.muellner@vrull.eu> wrote:
>
> From: Christoph Müllner <christoph.muellner@vrull.eu>
>
> This patch restructures the loop over the GP registers
> which saves/restores then as part of the prologue/epilogue.
> No functional change is intended by this patch, but it
> offers the possibility to use load-pair/store-pair instructions.
>
> gcc/ChangeLog:
>
>         * config/riscv/riscv.cc (riscv_next_saved_reg): New function.
>         (riscv_is_eh_return_data_register): New function.
>         (riscv_for_each_saved_reg): Restructure loop.
>
> Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> ---
>  gcc/config/riscv/riscv.cc | 94 +++++++++++++++++++++++++++------------
>  1 file changed, 66 insertions(+), 28 deletions(-)
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 6dd2ab2d11e..a8d5e1dac7f 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -4835,6 +4835,49 @@ riscv_save_restore_reg (machine_mode mode, int regno,
>    fn (gen_rtx_REG (mode, regno), mem);
>  }
>
> +/* Return the next register up from REGNO up to LIMIT for the callee
> +   to save or restore.  OFFSET will be adjusted accordingly.
> +   If INC is set, then REGNO will be incremented first.  */
> +
> +static unsigned int
> +riscv_next_saved_reg (unsigned int regno, unsigned int limit,
> +                     HOST_WIDE_INT *offset, bool inc = true)
> +{
> +  if (inc)
> +    regno++;
> +
> +  while (regno <= limit)
> +    {
> +      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> +       {
> +         *offset = *offset - UNITS_PER_WORD;
> +         break;
> +       }
> +
> +      regno++;
> +    }
> +  return regno;
> +}
> +
> +/* Return TRUE if provided REGNO is eh return data register.  */
> +
> +static bool
> +riscv_is_eh_return_data_register (unsigned int regno)
> +{
> +  unsigned int i, regnum;
> +
> +  if (!crtl->calls_eh_return)
> +    return false;
> +
> +  for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
> +    if (regno == regnum)
> +      {
> +       return true;
> +      }
> +
> +  return false;
> +}
> +
>  /* Call FN for each register that is saved by the current function.
>     SP_OFFSET is the offset of the current stack pointer from the start
>     of the frame.  */
> @@ -4844,36 +4887,31 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
>                           bool epilogue, bool maybe_eh_return)
>  {
>    HOST_WIDE_INT offset;
> +  unsigned int regno;
> +  unsigned int start = GP_REG_FIRST;
> +  unsigned int limit = GP_REG_LAST;
>
>    /* Save the link register and s-registers. */
> -  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ();
> -  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
> -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> -      {
> -       bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
> -
> -       /* If this is a normal return in a function that calls the eh_return
> -          builtin, then do not restore the eh return data registers as that
> -          would clobber the return value.  But we do still need to save them
> -          in the prologue, and restore them for an exception return, so we
> -          need special handling here.  */
> -       if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
> -         {
> -           unsigned int i, regnum;
> -
> -           for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
> -                i++)
> -             if (regno == regnum)
> -               {
> -                 handle_reg = FALSE;
> -                 break;
> -               }
> -         }
> -
> -       if (handle_reg)
> -         riscv_save_restore_reg (word_mode, regno, offset, fn);
> -       offset -= UNITS_PER_WORD;
> -      }
> +  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ()
> +          + UNITS_PER_WORD;
> +  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
> +       regno <= limit;
> +       regno = riscv_next_saved_reg (regno, limit, &offset))
> +    {
> +      if (cfun->machine->reg_is_wrapped_separately[regno])
> +       continue;
> +
> +      /* If this is a normal return in a function that calls the eh_return
> +        builtin, then do not restore the eh return data registers as that
> +        would clobber the return value.  But we do still need to save them
> +        in the prologue, and restore them for an exception return, so we
> +        need special handling here.  */
> +      if (epilogue && !maybe_eh_return
> +         && riscv_is_eh_return_data_register (regno))
> +       continue;
> +
> +      riscv_save_restore_reg (word_mode, regno, offset, fn);
> +    }
>
>    /* This loop must iterate over the same space as its companion in
>       riscv_compute_frame_info.  */
> --
> 2.38.1
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 03/11] riscv: Add basic XThead* vendor extension support
  2022-12-19  1:08 ` [PATCH v2 03/11] riscv: Add basic XThead* vendor extension support Christoph Muellner
@ 2022-12-19  6:32   ` Kito Cheng
  0 siblings, 0 replies; 24+ messages in thread
From: Kito Cheng @ 2022-12-19  6:32 UTC (permalink / raw)
  To: Christoph Muellner
  Cc: gcc-patches, Jim Wilson, Palmer Dabbelt, Andrew Waterman,
	Philipp Tomsich, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu, JojoR

> +  {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadbs", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadcmo", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadcondmov", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadfmemidx", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadfmv", ISA_SPEC_CLASS_NONE, 1, 0},
> +  {"xtheadint", 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},

I don't have strong opinions on version of vendor extensions, but I
would like this could
be align with https://github.com/riscv-non-isa/riscv-toolchain-conventions/pull/27

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 04/11] riscv: riscv-cores.def: Add T-Head XuanTie C906
  2022-12-19  1:08 ` [PATCH v2 04/11] riscv: riscv-cores.def: Add T-Head XuanTie C906 Christoph Muellner
@ 2022-12-19  6:58   ` Kito Cheng
  0 siblings, 0 replies; 24+ messages in thread
From: Kito Cheng @ 2022-12-19  6:58 UTC (permalink / raw)
  To: Christoph Muellner
  Cc: gcc-patches, Jim Wilson, Palmer Dabbelt, Andrew Waterman,
	Philipp Tomsich, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu

LGTM

On Mon, Dec 19, 2022 at 9:08 AM Christoph Muellner
<christoph.muellner@vrull.eu> wrote:
>
> From: Christoph Müllner <christoph.muellner@vrull.eu>
>
> This adds T-Head's XuanTie C906 to the list of known cores as "thead-c906".
> The C906 is shipped for quite some time (it is the core of the Allwinner D1).
> Note, that the tuning struct for the C906 is already part of GCC (it is
> also name "thead-c906").
>
> gcc/ChangeLog:
>
>         * config/riscv/riscv-cores.def (RISCV_CORE): Add "thead-c906".
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/riscv/mcpu-thead-c906.c: New test.
>
> Changes for v2:
> - Enable all supported vendor extensions
>
> Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> ---
>  gcc/config/riscv/riscv-cores.def              |  4 +++
>  .../gcc.target/riscv/mcpu-thead-c906.c        | 28 +++++++++++++++++++
>  2 files changed, 32 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c
>
> diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def
> index 31ad34682c5..307381802fa 100644
> --- a/gcc/config/riscv/riscv-cores.def
> +++ b/gcc/config/riscv/riscv-cores.def
> @@ -73,4 +73,8 @@ RISCV_CORE("sifive-s76",      "rv64imafdc", "sifive-7-series")
>  RISCV_CORE("sifive-u54",      "rv64imafdc", "sifive-5-series")
>  RISCV_CORE("sifive-u74",      "rv64imafdc", "sifive-7-series")
>
> +RISCV_CORE("thead-c906",      "rv64imafdc_xtheadba_xtheadbb_xtheadbs_xtheadcmo_"
> +                             "xtheadcondmov_xtheadfmemidx_xtheadmac_"
> +                             "xtheadmemidx_xtheadmempair_xtheadsync",
> +                             "thead-c906")
>  #undef RISCV_CORE
> diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c b/gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c
> new file mode 100644
> index 00000000000..a71b43a6167
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/mcpu-thead-c906.c
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */
> +/* { dg-options "-mcpu=thead-c906" { target { rv64 } } } */
> +/* T-Head XuanTie C906 => rv64imafdc */
> +
> +#if !((__riscv_xlen == 64)             \
> +      && !defined(__riscv_32e)         \
> +      && defined(__riscv_mul)          \
> +      && defined(__riscv_atomic)       \
> +      && (__riscv_flen == 64)          \
> +      && defined(__riscv_compressed)   \
> +      && defined(__riscv_xtheadba)     \
> +      && defined(__riscv_xtheadbb)     \
> +      && defined(__riscv_xtheadbs)     \
> +      && defined(__riscv_xtheadcmo)    \
> +      && defined(__riscv_xtheadcondmov)        \
> +      && defined(__riscv_xtheadfmemidx)        \
> +      && defined(__riscv_xtheadmac)    \
> +      && defined(__riscv_xtheadmemidx) \
> +      && defined(__riscv_xtheadmempair)        \
> +      && defined(__riscv_xtheadsync))
> +#error "unexpected arch"
> +#endif
> +
> +int main()
> +{
> +  return 0;
> +}
> --
> 2.38.1
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code
  2022-12-19  6:30   ` Kito Cheng
@ 2022-12-19  9:21     ` Christoph Müllner
  2022-12-19  9:26       ` Kito Cheng
  2022-12-27 19:51     ` Philipp Tomsich
  1 sibling, 1 reply; 24+ messages in thread
From: Christoph Müllner @ 2022-12-19  9:21 UTC (permalink / raw)
  To: Kito Cheng
  Cc: gcc-patches, Jim Wilson, Palmer Dabbelt, Andrew Waterman,
	Philipp Tomsich, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu

[-- Attachment #1: Type: text/plain, Size: 6002 bytes --]

On Mon, Dec 19, 2022 at 7:30 AM Kito Cheng <kito.cheng@sifive.com> wrote:

> just one more nit: Use INVALID_REGNUM as sentinel value for
> riscv_next_saved_reg, otherwise LGTM, and feel free to commit that
> separately :)
>

Would this change below be ok?

@@ -5540,7 +5540,7 @@ riscv_next_saved_reg (unsigned int regno, unsigned
int limit,
   if (inc)
     regno++;

-  while (regno <= limit)
+  while (regno <= limit && regno != INVALID_REGNUM)
     {
       if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
        {

Thanks,
Christoph



>
> On Mon, Dec 19, 2022 at 9:08 AM Christoph Muellner
> <christoph.muellner@vrull.eu> wrote:
> >
> > From: Christoph Müllner <christoph.muellner@vrull.eu>
> >
> > This patch restructures the loop over the GP registers
> > which saves/restores then as part of the prologue/epilogue.
> > No functional change is intended by this patch, but it
> > offers the possibility to use load-pair/store-pair instructions.
> >
> > gcc/ChangeLog:
> >
> >         * config/riscv/riscv.cc (riscv_next_saved_reg): New function.
> >         (riscv_is_eh_return_data_register): New function.
> >         (riscv_for_each_saved_reg): Restructure loop.
> >
> > Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> > ---
> >  gcc/config/riscv/riscv.cc | 94 +++++++++++++++++++++++++++------------
> >  1 file changed, 66 insertions(+), 28 deletions(-)
> >
> > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> > index 6dd2ab2d11e..a8d5e1dac7f 100644
> > --- a/gcc/config/riscv/riscv.cc
> > +++ b/gcc/config/riscv/riscv.cc
> > @@ -4835,6 +4835,49 @@ riscv_save_restore_reg (machine_mode mode, int
> regno,
> >    fn (gen_rtx_REG (mode, regno), mem);
> >  }
> >
> > +/* Return the next register up from REGNO up to LIMIT for the callee
> > +   to save or restore.  OFFSET will be adjusted accordingly.
> > +   If INC is set, then REGNO will be incremented first.  */
> > +
> > +static unsigned int
> > +riscv_next_saved_reg (unsigned int regno, unsigned int limit,
> > +                     HOST_WIDE_INT *offset, bool inc = true)
> > +{
> > +  if (inc)
> > +    regno++;
> > +
> > +  while (regno <= limit)
> > +    {
> > +      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > +       {
> > +         *offset = *offset - UNITS_PER_WORD;
> > +         break;
> > +       }
> > +
> > +      regno++;
> > +    }
> > +  return regno;
> > +}
> > +
> > +/* Return TRUE if provided REGNO is eh return data register.  */
> > +
> > +static bool
> > +riscv_is_eh_return_data_register (unsigned int regno)
> > +{
> > +  unsigned int i, regnum;
> > +
> > +  if (!crtl->calls_eh_return)
> > +    return false;
> > +
> > +  for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
> i++)
> > +    if (regno == regnum)
> > +      {
> > +       return true;
> > +      }
> > +
> > +  return false;
> > +}
> > +
> >  /* Call FN for each register that is saved by the current function.
> >     SP_OFFSET is the offset of the current stack pointer from the start
> >     of the frame.  */
> > @@ -4844,36 +4887,31 @@ riscv_for_each_saved_reg (poly_int64 sp_offset,
> riscv_save_restore_fn fn,
> >                           bool epilogue, bool maybe_eh_return)
> >  {
> >    HOST_WIDE_INT offset;
> > +  unsigned int regno;
> > +  unsigned int start = GP_REG_FIRST;
> > +  unsigned int limit = GP_REG_LAST;
> >
> >    /* Save the link register and s-registers. */
> > -  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant
> ();
> > -  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
> > -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > -      {
> > -       bool handle_reg =
> !cfun->machine->reg_is_wrapped_separately[regno];
> > -
> > -       /* If this is a normal return in a function that calls the
> eh_return
> > -          builtin, then do not restore the eh return data registers as
> that
> > -          would clobber the return value.  But we do still need to save
> them
> > -          in the prologue, and restore them for an exception return, so
> we
> > -          need special handling here.  */
> > -       if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
> > -         {
> > -           unsigned int i, regnum;
> > -
> > -           for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) !=
> INVALID_REGNUM;
> > -                i++)
> > -             if (regno == regnum)
> > -               {
> > -                 handle_reg = FALSE;
> > -                 break;
> > -               }
> > -         }
> > -
> > -       if (handle_reg)
> > -         riscv_save_restore_reg (word_mode, regno, offset, fn);
> > -       offset -= UNITS_PER_WORD;
> > -      }
> > +  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant
> ()
> > +          + UNITS_PER_WORD;
> > +  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
> > +       regno <= limit;
> > +       regno = riscv_next_saved_reg (regno, limit, &offset))
> > +    {
> > +      if (cfun->machine->reg_is_wrapped_separately[regno])
> > +       continue;
> > +
> > +      /* If this is a normal return in a function that calls the
> eh_return
> > +        builtin, then do not restore the eh return data registers as
> that
> > +        would clobber the return value.  But we do still need to save
> them
> > +        in the prologue, and restore them for an exception return, so we
> > +        need special handling here.  */
> > +      if (epilogue && !maybe_eh_return
> > +         && riscv_is_eh_return_data_register (regno))
> > +       continue;
> > +
> > +      riscv_save_restore_reg (word_mode, regno, offset, fn);
> > +    }
> >
> >    /* This loop must iterate over the same space as its companion in
> >       riscv_compute_frame_info.  */
> > --
> > 2.38.1
> >
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code
  2022-12-19  9:21     ` Christoph Müllner
@ 2022-12-19  9:26       ` Kito Cheng
  2022-12-19  9:45         ` Christoph Müllner
  0 siblings, 1 reply; 24+ messages in thread
From: Kito Cheng @ 2022-12-19  9:26 UTC (permalink / raw)
  To: Christoph Müllner
  Cc: gcc-patches, Jim Wilson, Palmer Dabbelt, Andrew Waterman,
	Philipp Tomsich, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu

Something like this:

static unsigned int
riscv_next_saved_reg (unsigned int regno, unsigned int limit,
                     HOST_WIDE_INT *offset, bool inc = true)
{
  if (inc)
    regno++;

  while (regno <= limit)
    {
      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
       {
         *offset = *offset - UNITS_PER_WORD;
         break;
       }

      regno++;
    }
  if (regno >= limit)
    return INVALID_REGNUM;
  else
    return regno;
}
...

  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
       regno != INVALID_REGNUM;
       regno = riscv_next_saved_reg (regno, limit, &offset))
    {
...

On Mon, Dec 19, 2022 at 5:21 PM Christoph Müllner
<christoph.muellner@vrull.eu> wrote:
>
>
>
> On Mon, Dec 19, 2022 at 7:30 AM Kito Cheng <kito.cheng@sifive.com> wrote:
>>
>> just one more nit: Use INVALID_REGNUM as sentinel value for
>> riscv_next_saved_reg, otherwise LGTM, and feel free to commit that
>> separately :)
>
>
> Would this change below be ok?
>
> @@ -5540,7 +5540,7 @@ riscv_next_saved_reg (unsigned int regno, unsigned int limit,
>    if (inc)
>      regno++;
>
> -  while (regno <= limit)
> +  while (regno <= limit && regno != INVALID_REGNUM)
>      {
>        if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
>         {
>
> Thanks,
> Christoph
>
>
>>
>>
>> On Mon, Dec 19, 2022 at 9:08 AM Christoph Muellner
>> <christoph.muellner@vrull.eu> wrote:
>> >
>> > From: Christoph Müllner <christoph.muellner@vrull.eu>
>> >
>> > This patch restructures the loop over the GP registers
>> > which saves/restores then as part of the prologue/epilogue.
>> > No functional change is intended by this patch, but it
>> > offers the possibility to use load-pair/store-pair instructions.
>> >
>> > gcc/ChangeLog:
>> >
>> >         * config/riscv/riscv.cc (riscv_next_saved_reg): New function.
>> >         (riscv_is_eh_return_data_register): New function.
>> >         (riscv_for_each_saved_reg): Restructure loop.
>> >
>> > Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
>> > ---
>> >  gcc/config/riscv/riscv.cc | 94 +++++++++++++++++++++++++++------------
>> >  1 file changed, 66 insertions(+), 28 deletions(-)
>> >
>> > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
>> > index 6dd2ab2d11e..a8d5e1dac7f 100644
>> > --- a/gcc/config/riscv/riscv.cc
>> > +++ b/gcc/config/riscv/riscv.cc
>> > @@ -4835,6 +4835,49 @@ riscv_save_restore_reg (machine_mode mode, int regno,
>> >    fn (gen_rtx_REG (mode, regno), mem);
>> >  }
>> >
>> > +/* Return the next register up from REGNO up to LIMIT for the callee
>> > +   to save or restore.  OFFSET will be adjusted accordingly.
>> > +   If INC is set, then REGNO will be incremented first.  */
>> > +
>> > +static unsigned int
>> > +riscv_next_saved_reg (unsigned int regno, unsigned int limit,
>> > +                     HOST_WIDE_INT *offset, bool inc = true)
>> > +{
>> > +  if (inc)
>> > +    regno++;
>> > +
>> > +  while (regno <= limit)
>> > +    {
>> > +      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
>> > +       {
>> > +         *offset = *offset - UNITS_PER_WORD;
>> > +         break;
>> > +       }
>> > +
>> > +      regno++;
>> > +    }
>> > +  return regno;
>> > +}
>> > +
>> > +/* Return TRUE if provided REGNO is eh return data register.  */
>> > +
>> > +static bool
>> > +riscv_is_eh_return_data_register (unsigned int regno)
>> > +{
>> > +  unsigned int i, regnum;
>> > +
>> > +  if (!crtl->calls_eh_return)
>> > +    return false;
>> > +
>> > +  for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
>> > +    if (regno == regnum)
>> > +      {
>> > +       return true;
>> > +      }
>> > +
>> > +  return false;
>> > +}
>> > +
>> >  /* Call FN for each register that is saved by the current function.
>> >     SP_OFFSET is the offset of the current stack pointer from the start
>> >     of the frame.  */
>> > @@ -4844,36 +4887,31 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
>> >                           bool epilogue, bool maybe_eh_return)
>> >  {
>> >    HOST_WIDE_INT offset;
>> > +  unsigned int regno;
>> > +  unsigned int start = GP_REG_FIRST;
>> > +  unsigned int limit = GP_REG_LAST;
>> >
>> >    /* Save the link register and s-registers. */
>> > -  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ();
>> > -  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
>> > -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
>> > -      {
>> > -       bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
>> > -
>> > -       /* If this is a normal return in a function that calls the eh_return
>> > -          builtin, then do not restore the eh return data registers as that
>> > -          would clobber the return value.  But we do still need to save them
>> > -          in the prologue, and restore them for an exception return, so we
>> > -          need special handling here.  */
>> > -       if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
>> > -         {
>> > -           unsigned int i, regnum;
>> > -
>> > -           for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
>> > -                i++)
>> > -             if (regno == regnum)
>> > -               {
>> > -                 handle_reg = FALSE;
>> > -                 break;
>> > -               }
>> > -         }
>> > -
>> > -       if (handle_reg)
>> > -         riscv_save_restore_reg (word_mode, regno, offset, fn);
>> > -       offset -= UNITS_PER_WORD;
>> > -      }
>> > +  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ()
>> > +          + UNITS_PER_WORD;
>> > +  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
>> > +       regno <= limit;
>> > +       regno = riscv_next_saved_reg (regno, limit, &offset))
>> > +    {
>> > +      if (cfun->machine->reg_is_wrapped_separately[regno])
>> > +       continue;
>> > +
>> > +      /* If this is a normal return in a function that calls the eh_return
>> > +        builtin, then do not restore the eh return data registers as that
>> > +        would clobber the return value.  But we do still need to save them
>> > +        in the prologue, and restore them for an exception return, so we
>> > +        need special handling here.  */
>> > +      if (epilogue && !maybe_eh_return
>> > +         && riscv_is_eh_return_data_register (regno))
>> > +       continue;
>> > +
>> > +      riscv_save_restore_reg (word_mode, regno, offset, fn);
>> > +    }
>> >
>> >    /* This loop must iterate over the same space as its companion in
>> >       riscv_compute_frame_info.  */
>> > --
>> > 2.38.1
>> >

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code
  2022-12-19  9:26       ` Kito Cheng
@ 2022-12-19  9:45         ` Christoph Müllner
  0 siblings, 0 replies; 24+ messages in thread
From: Christoph Müllner @ 2022-12-19  9:45 UTC (permalink / raw)
  To: Kito Cheng
  Cc: gcc-patches, Jim Wilson, Palmer Dabbelt, Andrew Waterman,
	Philipp Tomsich, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu

[-- Attachment #1: Type: text/plain, Size: 8784 bytes --]

On Mon, Dec 19, 2022 at 10:26 AM Kito Cheng <kito.cheng@sifive.com> wrote:

> Something like this:
>
> static unsigned int
> riscv_next_saved_reg (unsigned int regno, unsigned int limit,
>                      HOST_WIDE_INT *offset, bool inc = true)
> {
>   if (inc)
>     regno++;
>
>   while (regno <= limit)
>     {
>       if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
>        {
>          *offset = *offset - UNITS_PER_WORD;
>          break;
>        }
>
>       regno++;
>     }
>   if (regno >= limit)
>     return INVALID_REGNUM;
>   else
>     return regno;
> }
> ...
>
>   for (regno = riscv_next_saved_reg (start, limit, &offset, false);
>        regno != INVALID_REGNUM;
>        regno = riscv_next_saved_reg (regno, limit, &offset))
>     {
> ...
>
>
Ok, I see.
I changed it as follows (it will be retested before committing):

@@ -5531,7 +5531,8 @@ riscv_save_restore_reg (machine_mode mode, int regno,

 /* Return the next register up from REGNO up to LIMIT for the callee
    to save or restore.  OFFSET will be adjusted accordingly.
-   If INC is set, then REGNO will be incremented first.  */
+   If INC is set, then REGNO will be incremented first.
+   Returns INVALID_REGNUM if there is no such next register.  */

 static unsigned int
 riscv_next_saved_reg (unsigned int regno, unsigned int limit,
@@ -5545,12 +5546,12 @@ riscv_next_saved_reg (unsigned int regno, unsigned
int limit,
       if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
        {
          *offset = *offset - UNITS_PER_WORD;
-         break;
+         return regno;
        }

       regno++;
     }
-  return regno;
+  return INVALID_REGNUM;
 }

 /* Return TRUE if provided REGNO is eh return data register.  */
@@ -5589,7 +5590,7 @@ riscv_for_each_saved_reg (poly_int64 sp_offset,
riscv_save_restore_fn fn,
   offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant ()
           + UNITS_PER_WORD;
   for (regno = riscv_next_saved_reg (start, limit, &offset, false);
-       regno <= limit;
+       regno != INVALID_REGNUM;

Thanks!



> On Mon, Dec 19, 2022 at 5:21 PM Christoph Müllner
> <christoph.muellner@vrull.eu> wrote:
> >
> >
> >
> > On Mon, Dec 19, 2022 at 7:30 AM Kito Cheng <kito.cheng@sifive.com>
> wrote:
> >>
> >> just one more nit: Use INVALID_REGNUM as sentinel value for
> >> riscv_next_saved_reg, otherwise LGTM, and feel free to commit that
> >> separately :)
> >
> >
> > Would this change below be ok?
> >
> > @@ -5540,7 +5540,7 @@ riscv_next_saved_reg (unsigned int regno, unsigned
> int limit,
> >    if (inc)
> >      regno++;
> >
> > -  while (regno <= limit)
> > +  while (regno <= limit && regno != INVALID_REGNUM)
> >      {
> >        if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> >         {
> >
> > Thanks,
> > Christoph
> >
> >
> >>
> >>
> >> On Mon, Dec 19, 2022 at 9:08 AM Christoph Muellner
> >> <christoph.muellner@vrull.eu> wrote:
> >> >
> >> > From: Christoph Müllner <christoph.muellner@vrull.eu>
> >> >
> >> > This patch restructures the loop over the GP registers
> >> > which saves/restores then as part of the prologue/epilogue.
> >> > No functional change is intended by this patch, but it
> >> > offers the possibility to use load-pair/store-pair instructions.
> >> >
> >> > gcc/ChangeLog:
> >> >
> >> >         * config/riscv/riscv.cc (riscv_next_saved_reg): New function.
> >> >         (riscv_is_eh_return_data_register): New function.
> >> >         (riscv_for_each_saved_reg): Restructure loop.
> >> >
> >> > Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> >> > ---
> >> >  gcc/config/riscv/riscv.cc | 94
> +++++++++++++++++++++++++++------------
> >> >  1 file changed, 66 insertions(+), 28 deletions(-)
> >> >
> >> > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> >> > index 6dd2ab2d11e..a8d5e1dac7f 100644
> >> > --- a/gcc/config/riscv/riscv.cc
> >> > +++ b/gcc/config/riscv/riscv.cc
> >> > @@ -4835,6 +4835,49 @@ riscv_save_restore_reg (machine_mode mode, int
> regno,
> >> >    fn (gen_rtx_REG (mode, regno), mem);
> >> >  }
> >> >
> >> > +/* Return the next register up from REGNO up to LIMIT for the callee
> >> > +   to save or restore.  OFFSET will be adjusted accordingly.
> >> > +   If INC is set, then REGNO will be incremented first.  */
> >> > +
> >> > +static unsigned int
> >> > +riscv_next_saved_reg (unsigned int regno, unsigned int limit,
> >> > +                     HOST_WIDE_INT *offset, bool inc = true)
> >> > +{
> >> > +  if (inc)
> >> > +    regno++;
> >> > +
> >> > +  while (regno <= limit)
> >> > +    {
> >> > +      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> >> > +       {
> >> > +         *offset = *offset - UNITS_PER_WORD;
> >> > +         break;
> >> > +       }
> >> > +
> >> > +      regno++;
> >> > +    }
> >> > +  return regno;
> >> > +}
> >> > +
> >> > +/* Return TRUE if provided REGNO is eh return data register.  */
> >> > +
> >> > +static bool
> >> > +riscv_is_eh_return_data_register (unsigned int regno)
> >> > +{
> >> > +  unsigned int i, regnum;
> >> > +
> >> > +  if (!crtl->calls_eh_return)
> >> > +    return false;
> >> > +
> >> > +  for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
> i++)
> >> > +    if (regno == regnum)
> >> > +      {
> >> > +       return true;
> >> > +      }
> >> > +
> >> > +  return false;
> >> > +}
> >> > +
> >> >  /* Call FN for each register that is saved by the current function.
> >> >     SP_OFFSET is the offset of the current stack pointer from the
> start
> >> >     of the frame.  */
> >> > @@ -4844,36 +4887,31 @@ riscv_for_each_saved_reg (poly_int64
> sp_offset, riscv_save_restore_fn fn,
> >> >                           bool epilogue, bool maybe_eh_return)
> >> >  {
> >> >    HOST_WIDE_INT offset;
> >> > +  unsigned int regno;
> >> > +  unsigned int start = GP_REG_FIRST;
> >> > +  unsigned int limit = GP_REG_LAST;
> >> >
> >> >    /* Save the link register and s-registers. */
> >> > -  offset = (cfun->machine->frame.gp_sp_offset -
> sp_offset).to_constant ();
> >> > -  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST;
> regno++)
> >> > -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> >> > -      {
> >> > -       bool handle_reg =
> !cfun->machine->reg_is_wrapped_separately[regno];
> >> > -
> >> > -       /* If this is a normal return in a function that calls the
> eh_return
> >> > -          builtin, then do not restore the eh return data registers
> as that
> >> > -          would clobber the return value.  But we do still need to
> save them
> >> > -          in the prologue, and restore them for an exception return,
> so we
> >> > -          need special handling here.  */
> >> > -       if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
> >> > -         {
> >> > -           unsigned int i, regnum;
> >> > -
> >> > -           for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) !=
> INVALID_REGNUM;
> >> > -                i++)
> >> > -             if (regno == regnum)
> >> > -               {
> >> > -                 handle_reg = FALSE;
> >> > -                 break;
> >> > -               }
> >> > -         }
> >> > -
> >> > -       if (handle_reg)
> >> > -         riscv_save_restore_reg (word_mode, regno, offset, fn);
> >> > -       offset -= UNITS_PER_WORD;
> >> > -      }
> >> > +  offset = (cfun->machine->frame.gp_sp_offset -
> sp_offset).to_constant ()
> >> > +          + UNITS_PER_WORD;
> >> > +  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
> >> > +       regno <= limit;
> >> > +       regno = riscv_next_saved_reg (regno, limit, &offset))
> >> > +    {
> >> > +      if (cfun->machine->reg_is_wrapped_separately[regno])
> >> > +       continue;
> >> > +
> >> > +      /* If this is a normal return in a function that calls the
> eh_return
> >> > +        builtin, then do not restore the eh return data registers as
> that
> >> > +        would clobber the return value.  But we do still need to
> save them
> >> > +        in the prologue, and restore them for an exception return,
> so we
> >> > +        need special handling here.  */
> >> > +      if (epilogue && !maybe_eh_return
> >> > +         && riscv_is_eh_return_data_register (regno))
> >> > +       continue;
> >> > +
> >> > +      riscv_save_restore_reg (word_mode, regno, offset, fn);
> >> > +    }
> >> >
> >> >    /* This loop must iterate over the same space as its companion in
> >> >       riscv_compute_frame_info.  */
> >> > --
> >> > 2.38.1
> >> >
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension
  2022-12-19  1:08 ` [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension Christoph Muellner
@ 2022-12-19 13:19   ` Kito Cheng
  2022-12-19 18:14     ` Philipp Tomsich
  0 siblings, 1 reply; 24+ messages in thread
From: Kito Cheng @ 2022-12-19 13:19 UTC (permalink / raw)
  To: Christoph Muellner
  Cc: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu

LGTM with a nit:

...
> +  "TARGET_XTHEADBA
> +   && (INTVAL (operands[2]) >= 0) && (INTVAL (operands[2]) <= 3)"

IN_RANGE(INTVAL(operands[2]), 0, 3)

and I am little bit suppress it can be zero

> +  "th.addsl\t%0,%1,%3,%2"
> +  [(set_attr "type" "bitmanip")
> +   (set_attr "mode" "<X:MODE>")])

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 06/11] riscv: thead: Add support for the XTheadBs ISA extension
  2022-12-19  1:08 ` [PATCH v2 06/11] riscv: thead: Add support for the XTheadBs " Christoph Muellner
@ 2022-12-19 14:00   ` Kito Cheng
  0 siblings, 0 replies; 24+ messages in thread
From: Kito Cheng @ 2022-12-19 14:00 UTC (permalink / raw)
  To: Christoph Muellner
  Cc: gcc-patches, Kito Cheng, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Philipp Tomsich, Jeff Law, Cooper Qu,
	Lifang Xia, Yunhai Shang, Zhiwei Liu

LGTM

On Mon, Dec 19, 2022 at 9:12 AM Christoph Muellner
<christoph.muellner@vrull.eu> wrote:
>
> From: Christoph Müllner <christoph.muellner@vrull.eu>
>
> This patch adds support for the XTheadBs ISA extension.
> The new INSN pattern is defined in a new file to separate
> this vendor extension from the standard extensions.
> The cost model adjustment reuses the xbs:bext cost.
>
> gcc/ChangeLog:
>
>         * config/riscv/riscv.cc (riscv_rtx_costs): Add xthead:tst cost.
>         * config/riscv/thead.md (*th_tst): New INSN.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/riscv/xtheadbs-tst.c: New test.
>
> Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> ---
>  gcc/config/riscv/riscv.cc                     |  4 ++--
>  gcc/config/riscv/thead.md                     | 11 +++++++++++
>  gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c | 13 +++++++++++++
>  3 files changed, 26 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index a8d5e1dac7f..537515771c6 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -2400,8 +2400,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
>           *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
>           return true;
>         }
> -      /* bext pattern for zbs.  */
> -      if (TARGET_ZBS && outer_code == SET
> +      /* bit extraction pattern (zbs:bext, xtheadbs:tst).  */
> +      if ((TARGET_ZBS || TARGET_XTHEADBS) && outer_code == SET
>           && GET_CODE (XEXP (x, 1)) == CONST_INT
>           && INTVAL (XEXP (x, 1)) == 1)
>         {
> diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
> index 0257cbfad3e..0e23644ef59 100644
> --- a/gcc/config/riscv/thead.md
> +++ b/gcc/config/riscv/thead.md
> @@ -29,3 +29,14 @@ (define_insn "*th_addsl"
>    "th.addsl\t%0,%1,%3,%2"
>    [(set_attr "type" "bitmanip")
>     (set_attr "mode" "<X:MODE>")])
> +
> +;; XTheadBs
> +
> +(define_insn "*th_tst"
> +  [(set (match_operand:X 0 "register_operand" "=r")
> +       (zero_extract:X (match_operand:X 1 "register_operand" "r")
> +                       (const_int 1)
> +                       (match_operand 2 "immediate_operand" "i")))]
> +  "TARGET_XTHEADBS"
> +  "th.tst\t%0,%1,%2"
> +  [(set_attr "type" "bitmanip")])
> diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c b/gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c
> new file mode 100644
> index 00000000000..674cec09128
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/xtheadbs-tst.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv32gc_xtheadbs" { target { rv32 } } } */
> +/* { dg-options "-march=rv64gc_xtheadbs" { target { rv64 } } } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" } } */
> +
> +long
> +foo1 (long i)
> +{
> +  return 1L & (i >> 20);
> +}
> +
> +/* { dg-final { scan-assembler-times "th.tst\t" 1 } } */
> +/* { dg-final { scan-assembler-not "andi" } } */
> --
> 2.38.1
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension
  2022-12-19 13:19   ` Kito Cheng
@ 2022-12-19 18:14     ` Philipp Tomsich
  0 siblings, 0 replies; 24+ messages in thread
From: Philipp Tomsich @ 2022-12-19 18:14 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Christoph Muellner, gcc-patches, Kito Cheng, Jim Wilson,
	Palmer Dabbelt, Andrew Waterman, Jeff Law, Cooper Qu, Lifang Xia,
	Yunhai Shang, Zhiwei Liu

On Mon, 19 Dec 2022 at 05:20, Kito Cheng <kito.cheng@gmail.com> wrote:
>
> LGTM with a nit:
>
> ...
> > +  "TARGET_XTHEADBA
> > +   && (INTVAL (operands[2]) >= 0) && (INTVAL (operands[2]) <= 3)"
>
> IN_RANGE(INTVAL(operands[2]), 0, 3)
>
> and I am little bit suppress it can be zero

So was I, when reading the specification — and I reconfirmed that bit
by checking with the folks at T-Head.

We discussed this internally before submitting: while this case should
never occur (as other pieces in the compiler are smart enough to
simplify the RTX), we decided to include the 0 as it is an accurate
reflection of the instruction semantics.

Philipp.

>
> > +  "th.addsl\t%0,%1,%3,%2"
> > +  [(set_attr "type" "bitmanip")
> > +   (set_attr "mode" "<X:MODE>")])

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 01/11] riscv: attr: Synchronize comments with code
  2022-12-19  2:48   ` Kito Cheng
@ 2022-12-27 19:51     ` Philipp Tomsich
  0 siblings, 0 replies; 24+ messages in thread
From: Philipp Tomsich @ 2022-12-27 19:51 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Christoph Muellner, gcc-patches, Kito Cheng, Jim Wilson,
	Palmer Dabbelt, Andrew Waterman, Jeff Law, Cooper Qu, Lifang Xia,
	Yunhai Shang, Zhiwei Liu

[-- Attachment #1: Type: text/plain, Size: 2203 bytes --]

Applied to master, thanks!

Philipp.

On Mon, 19 Dec 2022 at 03:49, Kito Cheng <kito.cheng@gmail.com> wrote:

> LGTM, you can commit this separately if you want :)
>
> On Mon, Dec 19, 2022 at 9:09 AM Christoph Muellner
> <christoph.muellner@vrull.eu> wrote:
> >
> > From: Christoph Müllner <christoph.muellner@vrull.eu>
> >
> > The comment above the enumeration of existing attributes got out of
> > order and a few entries were forgotten.
> > This patch synchronizes the comments according to the list.
> > This commit does not include any functional change.
> >
> > gcc/ChangeLog:
> >
> >         * config/riscv/riscv.md: Sync comments with code.
> >
> > Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> > ---
> >  gcc/config/riscv/riscv.md | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> > index df57e2b0b4a..a8bb331f25c 100644
> > --- a/gcc/config/riscv/riscv.md
> > +++ b/gcc/config/riscv/riscv.md
> > @@ -220,7 +220,6 @@ (define_attr "enabled" "no,yes"
> >  ;; mfc         transfer from coprocessor
> >  ;; const       load constant
> >  ;; arith       integer arithmetic instructions
> > -;; auipc       integer addition to PC
> >  ;; logical      integer logical instructions
> >  ;; shift       integer shift instructions
> >  ;; slt         set less than instructions
> > @@ -236,9 +235,13 @@ (define_attr "enabled" "no,yes"
> >  ;; fcvt                floating point convert
> >  ;; fsqrt       floating point square root
> >  ;; multi       multiword sequence (or user asm statements)
> > +;; auipc       integer addition to PC
> > +;; sfb_alu  SFB ALU instruction
> >  ;; nop         no operation
> >  ;; ghost       an instruction that produces no real code
> >  ;; bitmanip    bit manipulation instructions
> > +;; rotate   rotation instructions
> > +;; atomic   atomic instructions
> >  ;; Classification of RVV instructions which will be added to each RVV
> .md pattern and used by scheduler.
> >  ;; rdvlenb     vector byte length vlenb csrr read
> >  ;; rdvl        vector length vl csrr read
> > --
> > 2.38.1
> >
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code
  2022-12-19  6:30   ` Kito Cheng
  2022-12-19  9:21     ` Christoph Müllner
@ 2022-12-27 19:51     ` Philipp Tomsich
  1 sibling, 0 replies; 24+ messages in thread
From: Philipp Tomsich @ 2022-12-27 19:51 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Christoph Muellner, gcc-patches, Jim Wilson, Palmer Dabbelt,
	Andrew Waterman, Jeff Law, Cooper Qu, Lifang Xia, Yunhai Shang,
	Zhiwei Liu

[-- Attachment #1: Type: text/plain, Size: 5722 bytes --]

Applied to master (with the change from the reviews), thanks!

Philipp.

On Mon, 19 Dec 2022 at 07:30, Kito Cheng <kito.cheng@sifive.com> wrote:

> just one more nit: Use INVALID_REGNUM as sentinel value for
> riscv_next_saved_reg, otherwise LGTM, and feel free to commit that
> separately :)
>
> On Mon, Dec 19, 2022 at 9:08 AM Christoph Muellner
> <christoph.muellner@vrull.eu> wrote:
> >
> > From: Christoph Müllner <christoph.muellner@vrull.eu>
> >
> > This patch restructures the loop over the GP registers
> > which saves/restores then as part of the prologue/epilogue.
> > No functional change is intended by this patch, but it
> > offers the possibility to use load-pair/store-pair instructions.
> >
> > gcc/ChangeLog:
> >
> >         * config/riscv/riscv.cc (riscv_next_saved_reg): New function.
> >         (riscv_is_eh_return_data_register): New function.
> >         (riscv_for_each_saved_reg): Restructure loop.
> >
> > Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
> > ---
> >  gcc/config/riscv/riscv.cc | 94 +++++++++++++++++++++++++++------------
> >  1 file changed, 66 insertions(+), 28 deletions(-)
> >
> > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> > index 6dd2ab2d11e..a8d5e1dac7f 100644
> > --- a/gcc/config/riscv/riscv.cc
> > +++ b/gcc/config/riscv/riscv.cc
> > @@ -4835,6 +4835,49 @@ riscv_save_restore_reg (machine_mode mode, int
> regno,
> >    fn (gen_rtx_REG (mode, regno), mem);
> >  }
> >
> > +/* Return the next register up from REGNO up to LIMIT for the callee
> > +   to save or restore.  OFFSET will be adjusted accordingly.
> > +   If INC is set, then REGNO will be incremented first.  */
> > +
> > +static unsigned int
> > +riscv_next_saved_reg (unsigned int regno, unsigned int limit,
> > +                     HOST_WIDE_INT *offset, bool inc = true)
> > +{
> > +  if (inc)
> > +    regno++;
> > +
> > +  while (regno <= limit)
> > +    {
> > +      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > +       {
> > +         *offset = *offset - UNITS_PER_WORD;
> > +         break;
> > +       }
> > +
> > +      regno++;
> > +    }
> > +  return regno;
> > +}
> > +
> > +/* Return TRUE if provided REGNO is eh return data register.  */
> > +
> > +static bool
> > +riscv_is_eh_return_data_register (unsigned int regno)
> > +{
> > +  unsigned int i, regnum;
> > +
> > +  if (!crtl->calls_eh_return)
> > +    return false;
> > +
> > +  for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
> i++)
> > +    if (regno == regnum)
> > +      {
> > +       return true;
> > +      }
> > +
> > +  return false;
> > +}
> > +
> >  /* Call FN for each register that is saved by the current function.
> >     SP_OFFSET is the offset of the current stack pointer from the start
> >     of the frame.  */
> > @@ -4844,36 +4887,31 @@ riscv_for_each_saved_reg (poly_int64 sp_offset,
> riscv_save_restore_fn fn,
> >                           bool epilogue, bool maybe_eh_return)
> >  {
> >    HOST_WIDE_INT offset;
> > +  unsigned int regno;
> > +  unsigned int start = GP_REG_FIRST;
> > +  unsigned int limit = GP_REG_LAST;
> >
> >    /* Save the link register and s-registers. */
> > -  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant
> ();
> > -  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
> > -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > -      {
> > -       bool handle_reg =
> !cfun->machine->reg_is_wrapped_separately[regno];
> > -
> > -       /* If this is a normal return in a function that calls the
> eh_return
> > -          builtin, then do not restore the eh return data registers as
> that
> > -          would clobber the return value.  But we do still need to save
> them
> > -          in the prologue, and restore them for an exception return, so
> we
> > -          need special handling here.  */
> > -       if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
> > -         {
> > -           unsigned int i, regnum;
> > -
> > -           for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) !=
> INVALID_REGNUM;
> > -                i++)
> > -             if (regno == regnum)
> > -               {
> > -                 handle_reg = FALSE;
> > -                 break;
> > -               }
> > -         }
> > -
> > -       if (handle_reg)
> > -         riscv_save_restore_reg (word_mode, regno, offset, fn);
> > -       offset -= UNITS_PER_WORD;
> > -      }
> > +  offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant
> ()
> > +          + UNITS_PER_WORD;
> > +  for (regno = riscv_next_saved_reg (start, limit, &offset, false);
> > +       regno <= limit;
> > +       regno = riscv_next_saved_reg (regno, limit, &offset))
> > +    {
> > +      if (cfun->machine->reg_is_wrapped_separately[regno])
> > +       continue;
> > +
> > +      /* If this is a normal return in a function that calls the
> eh_return
> > +        builtin, then do not restore the eh return data registers as
> that
> > +        would clobber the return value.  But we do still need to save
> them
> > +        in the prologue, and restore them for an exception return, so we
> > +        need special handling here.  */
> > +      if (epilogue && !maybe_eh_return
> > +         && riscv_is_eh_return_data_register (regno))
> > +       continue;
> > +
> > +      riscv_save_restore_reg (word_mode, regno, offset, fn);
> > +    }
> >
> >    /* This loop must iterate over the same space as its companion in
> >       riscv_compute_frame_info.  */
> > --
> > 2.38.1
> >
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2022-12-27 19:52 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-19  1:08 [PATCH v2 00/11] RISC-V: Add XThead* extension support Christoph Muellner
2022-12-19  1:08 ` [PATCH v2 01/11] riscv: attr: Synchronize comments with code Christoph Muellner
2022-12-19  2:48   ` Kito Cheng
2022-12-27 19:51     ` Philipp Tomsich
2022-12-19  1:08 ` [PATCH v2 02/11] riscv: Restructure callee-saved register save/restore code Christoph Muellner
2022-12-19  6:30   ` Kito Cheng
2022-12-19  9:21     ` Christoph Müllner
2022-12-19  9:26       ` Kito Cheng
2022-12-19  9:45         ` Christoph Müllner
2022-12-27 19:51     ` Philipp Tomsich
2022-12-19  1:08 ` [PATCH v2 03/11] riscv: Add basic XThead* vendor extension support Christoph Muellner
2022-12-19  6:32   ` Kito Cheng
2022-12-19  1:08 ` [PATCH v2 04/11] riscv: riscv-cores.def: Add T-Head XuanTie C906 Christoph Muellner
2022-12-19  6:58   ` Kito Cheng
2022-12-19  1:08 ` [PATCH v2 05/11] riscv: thead: Add support for the XTheadBa ISA extension Christoph Muellner
2022-12-19 13:19   ` Kito Cheng
2022-12-19 18:14     ` Philipp Tomsich
2022-12-19  1:08 ` [PATCH v2 06/11] riscv: thead: Add support for the XTheadBs " Christoph Muellner
2022-12-19 14:00   ` Kito Cheng
2022-12-19  1:08 ` [PATCH v2 07/11] riscv: thead: Add support for th XTheadBb " Christoph Muellner
2022-12-19  1:08 ` [PATCH v2 08/11] riscv: thead: Add support for XTheadCondMov ISA extensions Christoph Muellner
2022-12-19  1:08 ` [PATCH v2 09/11] riscv: thead: Add support for XTheadMac ISA extension Christoph Muellner
2022-12-19  1:08 ` [PATCH v2 10/11] riscv: thead: Add support for XTheadFmv " Christoph Muellner
2022-12-19  1:08 ` [PATCH v2 11/11] riscv: thead: Add support for XTheadMemPair " Christoph Muellner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).