[PATCH 2/2] RISC-V: Add ldr/str instruction for T-HEAD.

Jojo R rjiejie@linux.alibaba.com
Tue Jun 29 08:11:07 GMT 2021


	gcc/
	* gcc/config/riscv/riscv-opts.h (TARGET_LDR): New.
	(TARGET_LDUR): Likewise.
	* gcc/config/riscv/riscv.h (INDEX_REG_CLASS): Use TARGET_LDR.
	(REGNO_OK_FOR_INDEX_P): Use TARGET_LDR.
	(REG_OK_FOR_INDEX_P): Use REGNO_OK_FOR_INDEX_P.
	* gcc/config/riscv/riscv.c (riscv_address_type): Add ADDRESS_REG_REG,
	ADDRESS_REG_UREG.
	(riscv_address_info): Add shift.
	(riscv_classify_address_index): New.
	(riscv_classify_address): Use riscv_classify_address_index.
	(riscv_legitimize_address_index_p): New.
	(riscv_output_move_index): New.
	(riscv_output_move): Add parameter, Use riscv_output_move_index.
	(riscv_print_operand_address): Use ADDRESS_REG_REG, ADDRESS_REG_UREG.
	* gcc/config/riscv/riscv-protos.h (riscv_output_move): Update riscv_output_move.
	* gcc/config/riscv/riscv.md (zero_extendsidi2): Use riscv_output_move.
	(zero_extendhi<GPR:mode>2): Likewise.
	(zero_extendqi<SUPERQI:mode>2): Likewise.
	(extendsidi2): Likewise.
	(extend<SHORT:mode><SUPERQI:mode>2): Likewise.
	* gcc/config/riscv/predicates.md (sync_memory_operand): New.
	* gcc/config/riscv/sync.md (atomic_store<mode>): Use sync_memory_operand.
	(atomic_<atomic_optab><mode>): Likewise.
	(atomic_fetch_<atomic_optab><mode>): Likewise.
	(atomic_exchange<mode>): Likewise.
	(atomic_cas_value_strong<mode>): Likewise.
	(atomic_compare_and_swap<mode>): Likewise.
	(atomic_test_and_set): Likewise.

	gcc/testsuite/
	* gcc.target/riscv/xthead/riscv-xthead.exp: New.
	* gcc.target/riscv/xthead/ldr.c: Likewise.
---
 gcc/config/riscv/predicates.md                |   4 +
 gcc/config/riscv/riscv-opts.h                 |   3 +
 gcc/config/riscv/riscv-protos.h               |   2 +-
 gcc/config/riscv/riscv.c                      | 234 ++++++++++++++++--
 gcc/config/riscv/riscv.h                      |   7 +-
 gcc/config/riscv/riscv.md                     |  50 ++--
 gcc/config/riscv/sync.md                      |  14 +-
 gcc/testsuite/gcc.target/riscv/xthead/ldr.c   |  34 +++
 .../gcc.target/riscv/xthead/riscv-xthead.exp  |  41 +++
 9 files changed, 348 insertions(+), 41 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xthead/ldr.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp

diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 232115135544..802e7a40e880 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -217,3 +217,7 @@
 {
   return riscv_gpr_save_operation_p (op);
 })
+
+(define_predicate "sync_memory_operand"
+  (and (match_operand 0 "memory_operand")
+       (match_code "reg" "0")))
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index a2d84a66f037..d3163cb2377c 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -76,4 +76,7 @@ enum stack_protector_guard {
 #define MASK_XTHEAD_C (1 << 0)
 #define TARGET_XTHEAD_C ((riscv_x_subext & MASK_XTHEAD_C) != 0)
 
+#define TARGET_LDR (TARGET_XTHEAD_C)
+#define TARGET_LDUR (TARGET_XTHEAD_C)
+
 #endif /* ! GCC_RISCV_OPTS_H */
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 43d7224d6941..3a218f327c42 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -52,9 +52,9 @@ extern bool riscv_legitimize_move (machine_mode, rtx, rtx);
 extern rtx riscv_subword (rtx, bool);
 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 ();
 #ifdef RTX_CODE
+extern const char *riscv_output_move (rtx, rtx, rtx_code outer = UNKNOWN);
 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.c b/gcc/config/riscv/riscv.c
index 576960bb37cb..7d321826f669 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -80,6 +80,12 @@ along with GCC; see the file COPYING3.  If not see
        A natural register + offset address.  The register satisfies
        riscv_valid_base_register_p and the offset is a const_arith_operand.
 
+  ADDRESS_REG_REG
+       A base register indexed by (optionally scaled) register.
+
+  ADDRESS_REG_UREG
+       A base register indexed by (optionally scaled) zero-extended register.
+
    ADDRESS_LO_SUM
        A LO_SUM rtx.  The first operand is a valid base register and
        the second operand is a symbolic address.
@@ -91,6 +97,8 @@ along with GCC; see the file COPYING3.  If not see
        A constant symbolic address.  */
 enum riscv_address_type {
   ADDRESS_REG,
+  ADDRESS_REG_REG,
+  ADDRESS_REG_UREG,
   ADDRESS_LO_SUM,
   ADDRESS_CONST_INT,
   ADDRESS_SYMBOLIC
@@ -175,6 +183,11 @@ struct riscv_arg_info {
    ADDRESS_REG
        REG is the base register and OFFSET is the constant offset.
 
+  ADDRESS_REG_REG
+  ADDRESS_REG_UREG
+       REG is the base register and OFFSET is the indexed register,
+       and SHIFT is scaled value.
+
    ADDRESS_LO_SUM
        REG and OFFSET are the operands to the LO_SUM and SYMBOL_TYPE
        is the type of symbol it references.
@@ -186,6 +199,7 @@ struct riscv_address_info {
   rtx reg;
   rtx offset;
   enum riscv_symbol_type symbol_type;
+  int shift;
 };
 
 /* One stage in a constant building sequence.  These sequences have
@@ -821,6 +835,104 @@ riscv_valid_lo_sum_p (enum riscv_symbol_type sym_type, machine_mode mode,
   return true;
 }
 
+/* Return true if address offset is a valid index.  If it is, fill in INFO
+   appropriately.  STRICT_P is true if REG_OK_STRICT is in effect.  */
+
+bool
+riscv_classify_address_index (struct riscv_address_info *info, rtx x,
+      machine_mode mode, bool strict_p)
+{
+  enum riscv_address_type type = ADDRESS_REG_REG;;
+  rtx index;
+  int shift = 0;
+
+  if (!TARGET_LDR)
+    return false;
+
+  if (FLOAT_MODE_P (mode))
+    return false;
+
+  /* (reg:P) */
+  if ((REG_P (x) || GET_CODE (x) == SUBREG)
+      && GET_MODE (x) == Pmode)
+    {
+      index = x;
+      shift = 0;
+    }
+  /* (zero_extend:DI (reg:SI)) */
+  else if (TARGET_LDUR
+	   && GET_CODE (x) == ZERO_EXTEND
+	   && GET_MODE (x) == DImode
+	   && GET_MODE (XEXP (x, 0)) == SImode)
+    {
+      type = ADDRESS_REG_UREG;
+      index = XEXP (x, 0);
+      shift = 0;
+    }
+  /* (mult:DI (zero_extend:DI (reg:SI)) (const_int scale)) */
+  else if (TARGET_LDUR
+	   && GET_CODE (x) == MULT
+	   && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+	   && GET_MODE (XEXP (x, 0)) == DImode
+	   && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode
+	   && CONST_INT_P (XEXP (x, 1)))
+    {
+      type = ADDRESS_REG_UREG;
+      index = XEXP (XEXP (x, 0), 0);
+      shift = exact_log2 (INTVAL (XEXP (x, 1)));
+    }
+  /* (ashift:DI (zero_extend:DI (reg:SI)) (const_int shift)) */
+  else if (TARGET_LDUR
+	   && GET_CODE (x) == ASHIFT
+	   && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+	   && GET_MODE (XEXP (x, 0)) == DImode
+	   && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode
+	   && CONST_INT_P (XEXP (x, 1)))
+    {
+      type = ADDRESS_REG_UREG;
+      index = XEXP (XEXP (x, 0), 0);
+      shift = INTVAL (XEXP (x, 1));
+    }
+  /* (mult:P (reg:P) (const_int scale)) */
+  else if (GET_CODE (x) == MULT
+	   && GET_MODE (x) == Pmode
+	   && GET_MODE (XEXP (x, 0)) == Pmode
+	   && CONST_INT_P (XEXP (x, 1)))
+    {
+      index = XEXP (x, 0);
+      shift = exact_log2 (INTVAL (XEXP (x, 1)));
+    }
+  /* (ashift:P (reg:P) (const_int shift)) */
+  else if (GET_CODE (x) == ASHIFT
+	   && GET_MODE (x) == Pmode
+	   && GET_MODE (XEXP (x, 0)) == Pmode
+	   && CONST_INT_P (XEXP (x, 1)))
+    {
+      index = XEXP (x, 0);
+      shift = INTVAL (XEXP (x, 1));
+    }
+  else
+    return false;
+
+  if (shift != 0 && !IN_RANGE (shift, 1, 3))
+    return false;
+
+  if (!strict_p
+      && GET_CODE (index) == SUBREG
+      && contains_reg_of_mode[GENERAL_REGS][GET_MODE (SUBREG_REG (index))])
+    index = SUBREG_REG (index);
+
+  if (riscv_valid_base_register_p (index, mode, strict_p))
+    {
+      info->type = type;
+      info->offset = index;
+      info->shift = shift;
+      return true;
+    }
+
+  return false;
+}
+
 /* Return true if X is a valid address for machine mode MODE.  If it is,
    fill in INFO appropriately.  STRICT_P is true if REG_OK_STRICT is in
    effect.  */
@@ -839,6 +951,18 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       return riscv_valid_base_register_p (info->reg, mode, strict_p);
 
     case PLUS:
+      if (riscv_valid_base_register_p (XEXP (x, 0), mode, strict_p)
+	  && riscv_classify_address_index (info, XEXP (x, 1), mode, strict_p))
+	{
+	  info->reg = XEXP (x, 0);
+	  return true;
+	}
+      else if (riscv_valid_base_register_p (XEXP (x, 1), mode, strict_p)
+	       && riscv_classify_address_index (info, XEXP (x, 0), mode, strict_p))
+	{
+	  info->reg = XEXP (x, 1);
+	  return true;
+	}
       info->type = ADDRESS_REG;
       info->reg = XEXP (x, 0);
       info->offset = XEXP (x, 1);
@@ -2047,11 +2171,70 @@ riscv_split_doubleword_move (rtx dest, rtx src)
      }
 }
 
+/* Return TRUE if X is a legitimate address index.  */
+
+bool
+riscv_legitimize_address_index_p (rtx x, machine_mode mode, bool uindex)
+{
+  struct riscv_address_info addr;
+  rtx op0, op1;
+
+  if (GET_CODE (x) != PLUS)
+    return false;
+
+  op0 = XEXP (x, 0);
+  op1 = XEXP (x, 1);
+
+  return ((riscv_valid_base_register_p (op0, mode, false)
+	   && riscv_classify_address_index (&addr, op1, mode, false))
+	  || (riscv_valid_base_register_p (op1, mode, false)
+	      && riscv_classify_address_index (&addr, op0, mode, false)))
+	 && (!uindex || addr.type == ADDRESS_REG_UREG);
+}
+
+/* Return the LDR or STR instructions.  Assume
+   that X is MEM operand.  */
+
+const char *
+riscv_output_move_index (rtx x, machine_mode mode, bool ldr, rtx_code outer)
+{
+  static char buf[128] = {0};
+
+  int index = exact_log2 (GET_MODE_SIZE (mode));
+  if (!IN_RANGE (index, 0, 3))
+    return NULL;
+
+  if (!riscv_legitimize_address_index_p (x, mode, false))
+    return NULL;
+
+  bool uindex = riscv_legitimize_address_index_p (x, mode, true);
+
+  const char *const insn[][4] =
+  {
+    {
+      "s%srb\t%%z1,%%0",
+      "s%srh\t%%z1,%%0",
+      "s%srw\t%%z1,%%0",
+      "s%srd\t%%z1,%%0"
+    },
+    {
+      "l%srbu\t%%0,%%1",
+      "l%srhu\t%%0,%%1",
+      "l%srw%s\t%%0,%%1",
+      "l%srd\t%%0,%%1"
+    }
+  };
+
+  snprintf (buf, sizeof (buf), insn[ldr][index], uindex ? "u" : "", outer == ZERO_EXTEND ? "u" : "");
+
+  return buf;
+}
+
 /* Return the appropriate instructions to move SRC into DEST.  Assume
    that SRC is operand 1 and DEST is operand 0.  */
 
 const char *
-riscv_output_move (rtx dest, rtx src)
+riscv_output_move (rtx dest, rtx src, rtx_code outer)
 {
   enum rtx_code dest_code, src_code;
   machine_mode mode;
@@ -2071,13 +2254,20 @@ riscv_output_move (rtx dest, rtx src)
 	return dbl_p ? "fmv.x.d\t%0,%1" : "fmv.x.w\t%0,%1";
 
       if (src_code == MEM)
-	switch (GET_MODE_SIZE (mode))
-	  {
-	  case 1: return "lbu\t%0,%1";
-	  case 2: return "lhu\t%0,%1";
-	  case 4: return "lw\t%0,%1";
-	  case 8: return "ld\t%0,%1";
-	  }
+	{
+	  const char *insn = NULL;
+	  insn = riscv_output_move_index (XEXP (src, 0), GET_MODE (src), true, outer);
+	  if (insn)
+	    return insn;
+
+	  switch (GET_MODE_SIZE (GET_MODE (src)))
+	    {
+	    case 1: return "lbu\t%0,%1";
+	    case 2: return "lhu\t%0,%1";
+	    case 4: return outer == ZERO_EXTEND ? "lwu\t%0,%1" : "lw\t%0,%1";
+	    case 8: return "ld\t%0,%1";
+	    }
+	}
 
       if (src_code == CONST_INT)
 	return "li\t%0,%1";
@@ -2114,13 +2304,20 @@ riscv_output_move (rtx dest, rtx src)
 	    }
 	}
       if (dest_code == MEM)
-	switch (GET_MODE_SIZE (mode))
-	  {
-	  case 1: return "sb\t%z1,%0";
-	  case 2: return "sh\t%z1,%0";
-	  case 4: return "sw\t%z1,%0";
-	  case 8: return "sd\t%z1,%0";
-	  }
+	{
+	  const char *insn = NULL;
+	  insn = riscv_output_move_index (XEXP (dest, 0), GET_MODE (dest), false, outer);
+	  if (insn)
+	    return insn;
+
+	  switch (GET_MODE_SIZE (mode))
+	    {
+	    case 1: return "sb\t%z1,%0";
+	    case 2: return "sh\t%z1,%0";
+	    case 4: return "sw\t%z1,%0";
+	    case 8: return "sd\t%z1,%0";
+	    }
+	}
     }
   if (src_code == REG && FP_REG_P (REGNO (src)))
     {
@@ -3504,6 +3701,13 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
 	fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
 	return;
 
+      case ADDRESS_REG_REG:
+      case ADDRESS_REG_UREG:
+	fprintf (file, "%s,%s,%u", reg_names[REGNO (addr.reg)],
+				   reg_names[REGNO (addr.offset)],
+				   addr.shift);
+	return;
+
       case ADDRESS_LO_SUM:
 	riscv_print_operand_reloc (file, addr.offset, false);
 	fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index f47d5b40a66a..d54b81270da1 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -492,7 +492,7 @@ enum reg_class
    factor or added to another register (as well as added to a
    displacement).  */
 
-#define INDEX_REG_CLASS NO_REGS
+#define INDEX_REG_CLASS (TARGET_LDR ? GR_REGS : NO_REGS)
 
 /* We generally want to put call-clobbered registers ahead of
    call-saved ones.  (IRA expects this.)  */
@@ -636,7 +636,8 @@ typedef struct {
 
 /* Addressing modes, and classification of registers for them.  */
 
-#define REGNO_OK_FOR_INDEX_P(REGNO) 0
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+  (TARGET_LDR ? riscv_regno_mode_ok_for_base_p (REGNO, VOIDmode, 1) : 0)
 #define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \
   riscv_regno_mode_ok_for_base_p (REGNO, MODE, 1)
 
@@ -659,7 +660,7 @@ typedef struct {
   riscv_regno_mode_ok_for_base_p (REGNO (X), MODE, 1)
 #endif
 
-#define REG_OK_FOR_INDEX_P(X) 0
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
 
 /* Maximum number of registers that can appear in a valid memory address.  */
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index f88877fd5966..5229b00fb76c 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1307,9 +1307,13 @@
 	(zero_extend:DI
 	    (match_operand:SI 1 "nonimmediate_operand" " r,m")))]
   "TARGET_64BIT"
-  "@
-   #
-   lwu\t%0,%1"
+  {
+    switch (which_alternative)
+      {
+      default: return "#";
+      case 1: return riscv_output_move (operands[0], operands[1], ZERO_EXTEND);
+      }
+  }
   "&& reload_completed
    && REG_P (operands[1])
    && !paradoxical_subreg_p (operands[0])"
@@ -1326,9 +1330,13 @@
 	(zero_extend:GPR
 	    (match_operand:HI 1 "nonimmediate_operand" " r,m")))]
   ""
-  "@
-   #
-   lhu\t%0,%1"
+  {
+    switch (which_alternative)
+      {
+      default: return "#";
+      case 1: return riscv_output_move (operands[0], operands[1]);
+      }
+  }
   "&& reload_completed
    && REG_P (operands[1])
    && !paradoxical_subreg_p (operands[0])"
@@ -1348,9 +1356,13 @@
 	(zero_extend:SUPERQI
 	    (match_operand:QI 1 "nonimmediate_operand" " r,m")))]
   ""
-  "@
-   andi\t%0,%1,0xff
-   lbu\t%0,%1"
+  {
+    switch (which_alternative)
+      {
+      default: return "andi\t%0,%1,0xff";
+      case 1: return riscv_output_move (operands[0], operands[1]);
+      }
+  }
   [(set_attr "move_type" "andi,load")
    (set_attr "mode" "<SUPERQI:MODE>")])
 
@@ -1366,9 +1378,13 @@
 	(sign_extend:DI
 	    (match_operand:SI 1 "nonimmediate_operand" " r,m")))]
   "TARGET_64BIT"
-  "@
-   sext.w\t%0,%1
-   lw\t%0,%1"
+  {
+    switch (which_alternative)
+      {
+      default: return "sext.w\t%0,%1";
+      case 1: return riscv_output_move (operands[0], operands[1]);
+      }
+  }
   [(set_attr "move_type" "move,load")
    (set_attr "mode" "DI")])
 
@@ -1377,9 +1393,13 @@
 	(sign_extend:SUPERQI
 	    (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))]
   ""
-  "@
-   #
-   l<SHORT:size>\t%0,%1"
+  {
+    switch (which_alternative)
+      {
+      default: return "#";
+      case 1: return riscv_output_move (operands[0], operands[1]);
+      }
+  }
   "&& reload_completed
    && REG_P (operands[1])
    && !paradoxical_subreg_p (operands[0])"
diff --git a/gcc/config/riscv/sync.md b/gcc/config/riscv/sync.md
index 747a799e2377..5ad1d48a6ce0 100644
--- a/gcc/config/riscv/sync.md
+++ b/gcc/config/riscv/sync.md
@@ -59,7 +59,7 @@
 
 ;; Implement atomic stores with amoswap.  Fall back to fences for atomic loads.
 (define_insn "atomic_store<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "=A")
+  [(set (match_operand:GPR 0 "sync_memory_operand" "=A")
     (unspec_volatile:GPR
       [(match_operand:GPR 1 "reg_or_0_operand" "rJ")
        (match_operand:SI 2 "const_int_operand")]      ;; model
@@ -69,7 +69,7 @@
   [(set (attr "length") (const_int 8))])
 
 (define_insn "atomic_<atomic_optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+A")
+  [(set (match_operand:GPR 0 "sync_memory_operand" "+A")
 	(unspec_volatile:GPR
 	  [(any_atomic:GPR (match_dup 0)
 		     (match_operand:GPR 1 "reg_or_0_operand" "rJ"))
@@ -81,7 +81,7 @@
 
 (define_insn "atomic_fetch_<atomic_optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
-	(match_operand:GPR 1 "memory_operand" "+A"))
+	(match_operand:GPR 1 "sync_memory_operand" "+A"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
 	  [(any_atomic:GPR (match_dup 1)
@@ -95,7 +95,7 @@
 (define_insn "atomic_exchange<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
 	(unspec_volatile:GPR
-	  [(match_operand:GPR 1 "memory_operand" "+A")
+	  [(match_operand:GPR 1 "sync_memory_operand" "+A")
 	   (match_operand:SI 3 "const_int_operand")] ;; model
 	  UNSPEC_SYNC_EXCHANGE))
    (set (match_dup 1)
@@ -106,7 +106,7 @@
 
 (define_insn "atomic_cas_value_strong<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
-	(match_operand:GPR 1 "memory_operand" "+A"))
+	(match_operand:GPR 1 "sync_memory_operand" "+A"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ")
 			      (match_operand:GPR 3 "reg_or_0_operand" "rJ")
@@ -121,7 +121,7 @@
 (define_expand "atomic_compare_and_swap<mode>"
   [(match_operand:SI 0 "register_operand" "")   ;; bool output
    (match_operand:GPR 1 "register_operand" "")  ;; val output
-   (match_operand:GPR 2 "memory_operand" "")    ;; memory
+   (match_operand:GPR 2 "sync_memory_operand" "")    ;; memory
    (match_operand:GPR 3 "reg_or_0_operand" "")  ;; expected value
    (match_operand:GPR 4 "reg_or_0_operand" "")  ;; desired value
    (match_operand:SI 5 "const_int_operand" "")  ;; is_weak
@@ -154,7 +154,7 @@
 
 (define_expand "atomic_test_and_set"
   [(match_operand:QI 0 "register_operand" "")     ;; bool output
-   (match_operand:QI 1 "memory_operand" "+A")    ;; memory
+   (match_operand:QI 1 "sync_memory_operand" "+A")    ;; memory
    (match_operand:SI 2 "const_int_operand" "")]   ;; model
   "TARGET_ATOMIC"
 {
diff --git a/gcc/testsuite/gcc.target/riscv/xthead/ldr.c b/gcc/testsuite/gcc.target/riscv/xthead/ldr.c
new file mode 100644
index 000000000000..bee469392881
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xthead/ldr.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-skip-if "test ldr/str insns" { *-*-* } { "*" } { "-march=*xtheadc* -mabi=lp64*" } } */
+
+void foo_w(int *dest, int *src, int index)
+{
+    dest[index] = src[index];
+}
+
+/* { dg-final { scan-assembler "lrw" } } */
+/* { dg-final { scan-assembler "srw" } } */
+
+void foo_d(long *dest, long *src, int index)
+{
+    dest[index] = src[index];
+}
+
+/* { dg-final { scan-assembler "lrd" } } */
+/* { dg-final { scan-assembler "srd" } } */
+
+void foo_w_ui(int *dest, int *src, unsigned index)
+{
+    dest[index] = src[index];
+}
+
+/* { dg-final { scan-assembler "lurw" } } */
+/* { dg-final { scan-assembler "surw" } } */
+
+void foo_d_ui(long *dest, long *src, unsigned index)
+{
+    dest[index] = src[index];
+}
+
+/* { dg-final { scan-assembler "lurd" } } */
+/* { dg-final { scan-assembler "surd" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp b/gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp
new file mode 100644
index 000000000000..2b83bf9e5a23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xthead/riscv-xthead.exp
@@ -0,0 +1,41 @@
+# Copyright (C) 2017-2021 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't a RISC-V target.
+if ![istarget riscv*-*-*] then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
+	"" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
-- 
2.24.3 (Apple Git-128)



More information about the Gcc-patches mailing list