[PATCH] Teach sparc backend about %gsr register and add intrinsics to access it.

David Miller davem@davemloft.net
Sun Sep 25 08:41:00 GMT 2011


As discussed over the past few days.  Committed to trunk.

Hans, thanks again for all of your feedback.  I'll also work
on adding more VIS test cases.

gcc/

	* config/sparc/sparc.h (FIRST_PSEUDO_REGISTER): Bump to 103.
	(SPARC_GSR_REG): Define.
	(FIXED_REGISTERS): Mark GSR as fixed.
	(CALL_USED_REGISTERS): Mark GSR as call used.
	(HARD_REGNO_NREGS): GSR is always 1 register.
	(REG_CLASS_CONTENTS): Add GSR to ALL_REGS.
	(REG_ALLOC_ORDER, REG_LEAF_ALLOC_ORDER): Add GSR to the end.
	(REGISTER_NAMES): Add "%gsr".
	* config/sparc/sparc.md (UNSPEC_ALIGNADDR, UNSPEC_ALIGNADDRL):
	Delete.
	(UNSPEC_WRGSR): New unspec.
	(GSR_REG): New constant.
	(type): Add new insn type 'gsr'.
	(fpack16_vis, fpackfix_vis, fpack32_vis,
	faligndata<V64I:MODE>_vis)): Add use of GSR_REG.
	(wrgsr_vis, *wrgsr_sp64, wrgsr_v8plus, rdgsr_vis, *rdgsr_sp64,
	rdgsr_v8plus): New expanders and insns.
	(alignaddr<P:mode>_vis, alignaddrl<P:mode>_vis): Reimplement
	using patterns which show that this is a plus in addition to a
	modification of GSR_REG, instead of an unspec.
	* config/sparc/ultra1_2.md: Handle 'gsr'.
	* config/sparc/ultra3.md: Likewise.
	* config/sparc/niagara.md: Likewise.
	* config/sparc/niagara2.md: Likewise.
	* config/sparc/sparc.c (leaf_reg_remap, sparc_leaf_regs): Fill out
	end of table.
	(sparc_option_override): Make -mvis imply -mv8plus.
	(hard_32bit_mode_classes, hard_64bit_mode_classes): Add entries
	for %gsr.
	(sparc_vis_init_builtins): Build __builtin_vis_write_gsr and
	__builtin_vis_read_gsr.
	(sparc_expand_buildin): Handle builtins that take one argument and
	return void.
	(sparc_fold_builtin): Never fold writes to %gsr.
	* config/sparc/visintrin.h (__vis_write_gsr, __vis_read_gsr): New.
	* doc/extend.texi: Document new VIS intrinsics.
---
 gcc/ChangeLog                |   39 +++++++++++++
 gcc/config/sparc/niagara.md  |    2 +-
 gcc/config/sparc/niagara2.md |    4 +-
 gcc/config/sparc/sparc.c     |   73 +++++++++++++++++-------
 gcc/config/sparc/sparc.h     |   26 +++++----
 gcc/config/sparc/sparc.md    |  129 ++++++++++++++++++++++++++++++++++++------
 gcc/config/sparc/ultra1_2.md |    2 +-
 gcc/config/sparc/ultra3.md   |    2 +-
 gcc/config/sparc/visintrin.h |   14 +++++
 gcc/doc/extend.texi          |    3 +
 10 files changed, 240 insertions(+), 54 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1ca1113..8e86131 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,42 @@
+2011-09-24  David S. Miller  <davem@davemloft.net>
+
+	* config/sparc/sparc.h (FIRST_PSEUDO_REGISTER): Bump to 103.
+	(SPARC_GSR_REG): Define.
+	(FIXED_REGISTERS): Mark GSR as fixed.
+	(CALL_USED_REGISTERS): Mark GSR as call used.
+	(HARD_REGNO_NREGS): GSR is always 1 register.
+	(REG_CLASS_CONTENTS): Add GSR to ALL_REGS.
+	(REG_ALLOC_ORDER, REG_LEAF_ALLOC_ORDER): Add GSR to the end.
+	(REGISTER_NAMES): Add "%gsr".
+	* config/sparc/sparc.md (UNSPEC_ALIGNADDR, UNSPEC_ALIGNADDRL):
+	Delete.
+	(UNSPEC_WRGSR): New unspec.
+	(GSR_REG): New constant.
+	(type): Add new insn type 'gsr'.
+	(fpack16_vis, fpackfix_vis, fpack32_vis,
+	faligndata<V64I:MODE>_vis)): Add use of GSR_REG.
+	(wrgsr_vis, *wrgsr_sp64, wrgsr_v8plus, rdgsr_vis, *rdgsr_sp64,
+	rdgsr_v8plus): New expanders and insns.
+	(alignaddr<P:mode>_vis, alignaddrl<P:mode>_vis): Reimplement
+	using patterns which show that this is a plus in addition to a
+	modification of GSR_REG, instead of an unspec.
+	* config/sparc/ultra1_2.md: Handle 'gsr'.
+	* config/sparc/ultra3.md: Likewise.
+	* config/sparc/niagara.md: Likewise.
+	* config/sparc/niagara2.md: Likewise.
+	* config/sparc/sparc.c (leaf_reg_remap, sparc_leaf_regs): Fill out
+	end of table.
+	(sparc_option_override): Make -mvis imply -mv8plus.
+	(hard_32bit_mode_classes, hard_64bit_mode_classes): Add entries
+	for %gsr.
+	(sparc_vis_init_builtins): Build __builtin_vis_write_gsr and
+	__builtin_vis_read_gsr.
+	(sparc_expand_buildin): Handle builtins that take one argument and
+	return void.
+	(sparc_fold_builtin): Never fold writes to %gsr.
+	* config/sparc/visintrin.h (__vis_write_gsr, __vis_read_gsr): New.
+	* doc/extend.texi: Document new VIS intrinsics.
+
 2011-09-22  Maxim Kuvyrkov  <maxim@codesourcery.com>
 
 	* ipa-prop.c (ipa_print_node_jump_functions): Fix typos.
diff --git a/gcc/config/sparc/niagara.md b/gcc/config/sparc/niagara.md
index a618b19..3e5a3e5 100644
--- a/gcc/config/sparc/niagara.md
+++ b/gcc/config/sparc/niagara.md
@@ -114,5 +114,5 @@
  */
 (define_insn_reservation "niag_vis" 8
   (and (eq_attr "cpu" "niagara")
-    (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist,edge"))
+    (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist,edge,gsr"))
   "niag_pipe*8")
diff --git a/gcc/config/sparc/niagara2.md b/gcc/config/sparc/niagara2.md
index d53be84..9ea6b04 100644
--- a/gcc/config/sparc/niagara2.md
+++ b/gcc/config/sparc/niagara2.md
@@ -111,10 +111,10 @@
 
 (define_insn_reservation "niag2_vis" 6
   (and (eq_attr "cpu" "niagara2")
-    (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist,edge"))
+    (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist,edge,gsr"))
   "niag2_pipe*6")
 
 (define_insn_reservation "niag3_vis" 9
   (and (eq_attr "cpu" "niagara3")
-    (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist,edge"))
+    (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist,edge,gsr"))
   "niag2_pipe*9")
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index d62d5a1..d648e87 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -329,7 +329,7 @@ char leaf_reg_remap[] =
   72, 73, 74, 75, 76, 77, 78, 79,
   80, 81, 82, 83, 84, 85, 86, 87,
   88, 89, 90, 91, 92, 93, 94, 95,
-  96, 97, 98, 99, 100};
+  96, 97, 98, 99, 100, 101, 102};
 
 /* Vector, indexed by hard register number, which contains 1
    for a register that is allowable in a candidate for leaf
@@ -347,7 +347,7 @@ char sparc_leaf_regs[] =
   1, 1, 1, 1, 1, 1, 1, 1,
   1, 1, 1, 1, 1, 1, 1, 1,
   1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1};
+  1, 1, 1, 1, 1, 1, 1};
 
 struct GTY(()) machine_function
 {
@@ -870,6 +870,10 @@ sparc_option_override (void)
       target_flags &= ~(MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE);
     }
 
+  /* -mvis also implies -mv8plus on 32-bit */
+  if (TARGET_VIS && ! TARGET_ARCH64)
+    target_flags |= MASK_V8PLUS;
+
   /* Use the deprecated v8 insns for sparc64 in 32 bit mode.  */
   if (TARGET_V9 && TARGET_ARCH32)
     target_flags |= MASK_DEPRECATED_V8_INSNS;
@@ -4036,8 +4040,8 @@ static const int hard_32bit_mode_classes[] = {
   /* %fcc[0123] */
   CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
 
-  /* %icc */
-  CC_MODES
+  /* %icc, %sfp, %gsr */
+  CC_MODES, 0, D_MODES
 };
 
 static const int hard_64bit_mode_classes[] = {
@@ -4061,8 +4065,8 @@ static const int hard_64bit_mode_classes[] = {
   /* %fcc[0123] */
   CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
 
-  /* %icc */
-  CC_MODES
+  /* %icc, %sfp, %gsr */
+  CC_MODES, 0, D_MODES
 };
 
 int sparc_mode_class [NUM_MACHINE_MODES];
@@ -9168,6 +9172,10 @@ sparc_vis_init_builtins (void)
 						      v4hi, v4hi, 0);
   tree si_ftype_v2si_v2si = build_function_type_list (intSI_type_node,
 						      v2si, v2si, 0);
+  tree void_ftype_di = build_function_type_list (void_type_node,
+						 intDI_type_node, 0);
+  tree di_ftype_void = build_function_type_list (intDI_type_node,
+						 void_type_node, 0);
 
   /* Packing and expanding vectors.  */
   def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis,
@@ -9206,6 +9214,12 @@ sparc_vis_init_builtins (void)
 	       v2si_ftype_v2si_v2si);
   def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatadi_vis,
 	       di_ftype_di_di);
+
+  def_builtin ("__builtin_vis_write_gsr", CODE_FOR_wrgsr_vis,
+	       void_ftype_di);
+  def_builtin ("__builtin_vis_read_gsr", CODE_FOR_rdgsr_vis,
+	       di_ftype_void);
+
   if (TARGET_ARCH64)
     {
       def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis,
@@ -9289,32 +9303,47 @@ sparc_expand_builtin (tree exp, rtx target,
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int icode = DECL_FUNCTION_CODE (fndecl);
   rtx pat, op[4];
-  enum machine_mode mode[4];
   int arg_count = 0;
+  bool nonvoid;
 
-  mode[0] = insn_data[icode].operand[0].mode;
-  if (!target
-      || GET_MODE (target) != mode[0]
-      || ! (*insn_data[icode].operand[0].predicate) (target, mode[0]))
-    op[0] = gen_reg_rtx (mode[0]);
-  else
-    op[0] = target;
+  nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
 
+  if (nonvoid)
+    {
+      enum machine_mode tmode = insn_data[icode].operand[0].mode;
+      if (!target
+	  || GET_MODE (target) != tmode
+	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+	op[0] = gen_reg_rtx (tmode);
+      else
+	op[0] = target;
+    }
   FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
     {
+      const struct insn_operand_data *insn_op;
+
+      if (arg == error_mark_node)
+	return NULL_RTX;
+
       arg_count++;
-      mode[arg_count] = insn_data[icode].operand[arg_count].mode;
+      insn_op = &insn_data[icode].operand[arg_count - !nonvoid];
       op[arg_count] = expand_normal (arg);
 
       if (! (*insn_data[icode].operand[arg_count].predicate) (op[arg_count],
-							      mode[arg_count]))
-	op[arg_count] = copy_to_mode_reg (mode[arg_count], op[arg_count]);
+							      insn_op->mode))
+	op[arg_count] = copy_to_mode_reg (insn_op->mode, op[arg_count]);
     }
 
   switch (arg_count)
     {
+    case 0:
+      pat = GEN_FCN (icode) (op[0]);
+      break;
     case 1:
-      pat = GEN_FCN (icode) (op[0], op[1]);
+      if (nonvoid)
+	pat = GEN_FCN (icode) (op[0], op[1]);
+      else
+	pat = GEN_FCN (icode) (op[1]);
       break;
     case 2:
       pat = GEN_FCN (icode) (op[0], op[1], op[2]);
@@ -9331,7 +9360,10 @@ sparc_expand_builtin (tree exp, rtx target,
 
   emit_insn (pat);
 
-  return op[0];
+  if (nonvoid)
+    return op[0];
+  else
+    return const0_rtx;
 }
 
 static int
@@ -9416,7 +9448,8 @@ sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
 
   if (ignore
       && icode != CODE_FOR_alignaddrsi_vis
-      && icode != CODE_FOR_alignaddrdi_vis)
+      && icode != CODE_FOR_alignaddrdi_vis
+      && icode != CODE_FOR_wrgsr_vis)
     return build_zero_cst (rtype);
 
   switch (icode)
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index afdca1e..77eff2e 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -691,7 +691,7 @@ extern enum cmodel sparc_cmodel;
    Register 100 is used as the integer condition code register.
    Register 101 is used as the soft frame pointer register.  */
 
-#define FIRST_PSEUDO_REGISTER 102
+#define FIRST_PSEUDO_REGISTER 103
 
 #define SPARC_FIRST_FP_REG     32
 /* Additional V9 fp regs.  */
@@ -704,6 +704,7 @@ extern enum cmodel sparc_cmodel;
 #define SPARC_FCC_REG 96
 /* Integer CC reg.  We don't distinguish %icc from %xcc.  */
 #define SPARC_ICC_REG 100
+#define SPARC_GSR_REG 102
 
 /* Nonzero if REGNO is an fp reg.  */
 #define SPARC_FP_REG_P(REGNO) \
@@ -757,7 +758,7 @@ extern enum cmodel sparc_cmodel;
   0, 0, 0, 0, 0, 0, 0, 0,	\
   0, 0, 0, 0, 0, 0, 0, 0,	\
 				\
-  0, 0, 0, 0, 0, 1}
+  0, 0, 0, 0, 0, 1, 1}
 
 /* 1 for registers not available across function calls.
    These must include the FIXED_REGISTERS and also any
@@ -782,7 +783,7 @@ extern enum cmodel sparc_cmodel;
   1, 1, 1, 1, 1, 1, 1, 1,	\
   1, 1, 1, 1, 1, 1, 1, 1,	\
 				\
-  1, 1, 1, 1, 1, 1}
+  1, 1, 1, 1, 1, 1, 1}
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something of mode MODE.
@@ -796,11 +797,12 @@ extern enum cmodel sparc_cmodel;
    included in the hard register count).  */
 
 #define HARD_REGNO_NREGS(REGNO, MODE) \
-  (TARGET_ARCH64							\
-   ? ((REGNO) < 32 || (REGNO) == FRAME_POINTER_REGNUM			\
-      ? (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD	\
-      : (GET_MODE_SIZE (MODE) + 3) / 4)					\
-   : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+  ((REGNO) == SPARC_GSR_REG ? 1 :					\
+   (TARGET_ARCH64							\
+    ? ((REGNO) < 32 || (REGNO) == FRAME_POINTER_REGNUM			\
+       ? (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD	\
+       : (GET_MODE_SIZE (MODE) + 3) / 4)				\
+    : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
 
 /* Due to the ARCH64 discrepancy above we must override this next
    macro too.  */
@@ -985,7 +987,7 @@ enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
    {0, -1, -1, 0},	/* EXTRA_FP_REGS */		\
    {-1, -1, 0, 0x20},	/* GENERAL_OR_FP_REGS */	\
    {-1, -1, -1, 0x20},	/* GENERAL_OR_EXTRA_FP_REGS */	\
-   {-1, -1, -1, 0x3f}}	/* ALL_REGS */
+   {-1, -1, -1, 0x7f}}	/* ALL_REGS */
 
 /* The same information, inverted:
    Return the class number of the smallest class containing
@@ -1046,7 +1048,7 @@ extern enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
   88, 89, 90, 91, 92, 93, 94, 95,	/* %f56-%f63 */ \
   39, 38, 37, 36, 35, 34, 33, 32,	/* %f7-%f0 */   \
   96, 97, 98, 99,			/* %fcc0-3 */   \
-  100, 0, 14, 30, 101}			/* %icc, %g0, %o6, %i6, %sfp */
+  100, 0, 14, 30, 101, 102 }		/* %icc, %g0, %o6, %i6, %sfp, %gsr */
 
 /* This is the order in which to allocate registers for
    leaf functions.  If all registers can fit in the global and
@@ -1085,7 +1087,7 @@ extern enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
   88, 89, 90, 91, 92, 93, 94, 95,	/* %f56-%f63 */	\
   39, 38, 37, 36, 35, 34, 33, 32,	/* %f7-%f0 */	\
   96, 97, 98, 99,			/* %fcc0-3 */	\
-  100, 0, 14, 30, 31, 101}		/* %icc, %g0, %o6, %i6, %i7, %sfp */
+  100, 0, 14, 30, 31, 101, 102 }	/* %icc, %g0, %o6, %i6, %i7, %sfp, %gsr */
 
 #define ADJUST_REG_ALLOC_ORDER order_regs_for_local_alloc ()
 
@@ -1724,7 +1726,7 @@ do {									   \
  "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",	\
  "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",	\
  "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",	\
- "%fcc0", "%fcc1", "%fcc2", "%fcc3", "%icc", "%sfp" }
+ "%fcc0", "%fcc1", "%fcc2", "%fcc3", "%icc", "%sfp", "%gsr" }
 
 /* Define additional names for use in asm clobbers and asm declarations.  */
 
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 588caf3..e5cf821 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -58,7 +58,7 @@
    (UNSPEC_MUL8UL		46)
    (UNSPEC_MULDUL		47)
    (UNSPEC_ALIGNDATA		48)
-   (UNSPEC_ALIGNADDR		49)
+   (UNSPEC_WRGSR                49)
    (UNSPEC_PDIST		50)
    (UNSPEC_EDGE8		51)
    (UNSPEC_EDGE8L		52)
@@ -66,7 +66,6 @@
    (UNSPEC_EDGE16L		54)
    (UNSPEC_EDGE32		55)
    (UNSPEC_EDGE32L		56)
-   (UNSPEC_ALIGNADDRL		57)
 
    (UNSPEC_SP_SET		60)
    (UNSPEC_SP_TEST		61)
@@ -176,6 +175,7 @@
   (FCC3_REG			99)
   (CC_REG			100)
   (SFP_REG			101)
+  (GSR_REG			102)
  ])
 
 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
@@ -242,7 +242,7 @@
    fpcmp,
    fpmul,fpdivs,fpdivd,
    fpsqrts,fpsqrtd,
-   fga,fgm_pack,fgm_mul,fgm_pdist,fgm_cmp,edge,
+   fga,fgm_pack,fgm_mul,fgm_pdist,fgm_cmp,edge,gsr,
    cmove,
    ialuX,
    multi,savew,flushw,iflush,trap"
@@ -7752,7 +7752,8 @@
 (define_insn "fpack16_vis"
   [(set (match_operand:V4QI 0 "register_operand" "=f")
         (unspec:V4QI [(match_operand:V4HI 1 "register_operand" "e")]
-		      UNSPEC_FPACK16))]
+		      UNSPEC_FPACK16))
+   (use (reg:DI GSR_REG))]
   "TARGET_VIS"
   "fpack16\t%1, %0"
   [(set_attr "type" "fga")
@@ -7761,7 +7762,8 @@
 (define_insn "fpackfix_vis"
   [(set (match_operand:V2HI 0 "register_operand" "=f")
         (unspec:V2HI [(match_operand:V2SI 1 "register_operand" "e")]
-		      UNSPEC_FPACKFIX))]
+		      UNSPEC_FPACKFIX))
+   (use (reg:DI GSR_REG))]
   "TARGET_VIS"
   "fpackfix\t%1, %0"
   [(set_attr "type" "fga")
@@ -7771,7 +7773,8 @@
   [(set (match_operand:V8QI 0 "register_operand" "=e")
         (unspec:V8QI [(match_operand:V2SI 1 "register_operand" "e")
         	      (match_operand:V8QI 2 "register_operand" "e")]
-                     UNSPEC_FPACK32))]
+                     UNSPEC_FPACK32))
+   (use (reg:DI GSR_REG))]
   "TARGET_VIS"
   "fpack32\t%1, %2, %0"
   [(set_attr "type" "fga")
@@ -7871,6 +7874,66 @@
   [(set_attr "type" "fpmul")
    (set_attr "fptype" "double")])
 
+(define_expand "wrgsr_vis"
+  [(set (reg:DI GSR_REG) (unspec:DI [(match_operand:DI 0 "arith_operand" "")]
+                                    UNSPEC_WRGSR))]
+  "TARGET_VIS"
+{
+  if (! TARGET_ARCH64)
+    {
+      emit_insn (gen_wrgsr_v8plus (operands[0]));
+      DONE;
+    }
+})
+
+(define_insn "*wrgsr_sp64"
+  [(set (reg:DI GSR_REG) (unspec:DI [(match_operand:DI 0 "arith_operand" "rI")]
+                                    UNSPEC_WRGSR))]
+  "TARGET_VIS && TARGET_ARCH64"
+  "wr\t%%g0, %0, %%gsr"
+  [(set_attr "type" "gsr")])
+
+(define_insn "wrgsr_v8plus"
+  [(set (reg:DI GSR_REG) (unspec:DI [(match_operand:DI 0 "arith_operand" "I,r")]
+                                    UNSPEC_WRGSR))
+   (clobber (match_scratch:SI 1 "=X,&h"))]
+  "TARGET_VIS && ! TARGET_ARCH64"
+{
+  if (GET_CODE (operands[0]) == CONST_INT
+      || sparc_check_64 (operands[0], insn))
+    return "wr\t%%g0, %0, %%gsr";
+
+  output_asm_insn("srl\t%L0, 0, %L0", operands);
+  return "sllx\t%H0, 32, %1\n\tor\t%L0, %1, %1\n\twr\t%%g0, %1, %%gsr";
+}
+  [(set_attr "type" "multi")])
+
+(define_expand "rdgsr_vis"
+  [(set (match_operand:DI 0 "register_operand" "") (reg:DI GSR_REG))]
+  "TARGET_VIS"
+{
+  if (! TARGET_ARCH64)
+    {
+      emit_insn (gen_rdgsr_v8plus (operands[0]));
+      DONE;
+    }
+})
+
+(define_insn "*rdgsr_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r") (reg:DI GSR_REG))]
+  "TARGET_VIS && TARGET_ARCH64"
+  "rd\t%%gsr, %0"
+  [(set_attr "type" "gsr")])
+
+(define_insn "rdgsr_v8plus"
+  [(set (match_operand:DI 0 "register_operand" "=r") (reg:DI GSR_REG))
+   (clobber (match_scratch:SI 1 "=&h"))]
+  "TARGET_VIS && ! TARGET_ARCH64"
+{
+  return "rd\t%%gsr, %1\n\tsrlx\t%1, 32, %H0\n\tmov %1, %L0";
+}
+  [(set_attr "type" "multi")])
+
 ;; Using faligndata only makes sense after an alignaddr since the choice of
 ;; bytes to take out of each operand is dependent on the results of the last
 ;; alignaddr.
@@ -7878,25 +7941,57 @@
   [(set (match_operand:V64I 0 "register_operand" "=e")
         (unspec:V64I [(match_operand:V64I 1 "register_operand" "e")
                       (match_operand:V64I 2 "register_operand" "e")]
-         UNSPEC_ALIGNDATA))]
+         UNSPEC_ALIGNDATA))
+   (use (reg:SI GSR_REG))]
   "TARGET_VIS"
   "faligndata\t%1, %2, %0"
   [(set_attr "type" "fga")
    (set_attr "fptype" "double")])
 
-(define_insn "alignaddr<P:mode>_vis"
-  [(set (match_operand:P 0 "register_operand" "=r")
-        (unspec:P [(match_operand:P 1 "register_or_zero_operand" "rJ")
-                   (match_operand:P 2 "register_or_zero_operand" "rJ")]
-         UNSPEC_ALIGNADDR))]
+(define_insn "alignaddrsi_vis"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (plus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
+                 (match_operand:SI 2 "register_or_zero_operand" "rJ")))
+   (set (reg:SI GSR_REG)
+        (ior:SI (and:SI (reg:SI GSR_REG) (const_int -8))
+                (and:SI (plus:SI (match_dup 1) (match_dup 2))
+                        (const_int 7))))]
   "TARGET_VIS"
   "alignaddr\t%r1, %r2, %0")
 
-(define_insn "alignaddrl<P:mode>_vis"
-  [(set (match_operand:P 0 "register_operand" "=r")
-        (unspec:P [(match_operand:P 1 "register_or_zero_operand" "rJ")
-                   (match_operand:P 2 "register_or_zero_operand" "rJ")]
-         UNSPEC_ALIGNADDRL))]
+(define_insn "alignaddrdi_vis"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (plus:DI (match_operand:DI 1 "register_or_zero_operand" "rJ")
+                 (match_operand:DI 2 "register_or_zero_operand" "rJ")))
+   (set (reg:SI GSR_REG)
+        (ior:SI (and:SI (reg:SI GSR_REG) (const_int -8))
+                (and:SI (truncate:SI (plus:DI (match_dup 1) (match_dup 2)))
+                        (const_int 7))))]
+  "TARGET_VIS"
+  "alignaddr\t%r1, %r2, %0")
+
+(define_insn "alignaddrlsi_vis"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (plus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
+                 (match_operand:SI 2 "register_or_zero_operand" "rJ")))
+   (set (reg:SI GSR_REG)
+        (ior:SI (and:SI (reg:SI GSR_REG) (const_int -8))
+                (xor:SI (and:SI (plus:SI (match_dup 1) (match_dup 2))
+                                (const_int 7))
+                        (const_int 7))))]
+  "TARGET_VIS"
+  "alignaddrl\t%r1, %r2, %0")
+
+(define_insn "alignaddrldi_vis"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (plus:DI (match_operand:DI 1 "register_or_zero_operand" "rJ")
+                 (match_operand:DI 2 "register_or_zero_operand" "rJ")))
+   (set (reg:SI GSR_REG)
+        (ior:SI (and:SI (reg:SI GSR_REG) (const_int -8))
+                (xor:SI (and:SI (truncate:SI (plus:DI (match_dup 1)
+                                                      (match_dup 2)))
+                                (const_int 7))
+                        (const_int 7))))]
   "TARGET_VIS"
   "alignaddrl\t%r1, %r2, %0")
 
diff --git a/gcc/config/sparc/ultra1_2.md b/gcc/config/sparc/ultra1_2.md
index a24cb81..7f6e8b6 100644
--- a/gcc/config/sparc/ultra1_2.md
+++ b/gcc/config/sparc/ultra1_2.md
@@ -79,7 +79,7 @@
 
 (define_insn_reservation "us1_single" 1
   (and (eq_attr "cpu" "ultrasparc")
-    (eq_attr "type" "multi,savew,flushw,iflush,trap"))
+    (eq_attr "type" "multi,savew,flushw,iflush,trap,gsr"))
   "us1_single_issue")
 
 (define_insn_reservation "us1_simple_ieuN" 1
diff --git a/gcc/config/sparc/ultra3.md b/gcc/config/sparc/ultra3.md
index d438812..ac97099 100644
--- a/gcc/config/sparc/ultra3.md
+++ b/gcc/config/sparc/ultra3.md
@@ -36,7 +36,7 @@
 
 (define_insn_reservation "us3_single" 1
   (and (eq_attr "cpu" "ultrasparc3")
-    (eq_attr "type" "multi,savew,flushw,iflush,trap,edge"))
+    (eq_attr "type" "multi,savew,flushw,iflush,trap,edge,gsr"))
   "us3_single_issue")
 
 (define_insn_reservation "us3_integer" 1
diff --git a/gcc/config/sparc/visintrin.h b/gcc/config/sparc/visintrin.h
index 4c2fa18..e3a5818 100644
--- a/gcc/config/sparc/visintrin.h
+++ b/gcc/config/sparc/visintrin.h
@@ -31,6 +31,20 @@ typedef unsigned char __v8qi __attribute__ ((__vector_size__ (8)));
 typedef unsigned char __v4qi __attribute__ ((__vector_size__ (4)));
 typedef int __i64 __attribute__ ((__mode__ (DI)));
 
+extern __inline void
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_write_gsr (__i64 __A)
+{
+  __builtin_vis_write_gsr (__A);
+}
+
+extern __inline __i64
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_read_gsr (void)
+{
+  return __builtin_vis_read_gsr ();
+}
+
 extern __inline void *
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 __vis_alignaddr (void *__A, long __B)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 1f54ef1..d5106aa 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12935,6 +12935,9 @@ typedef short v2hi __attribute__ ((vector_size (4)));
 typedef unsigned char v8qi __attribute__ ((vector_size (8)));
 typedef unsigned char v4qi __attribute__ ((vector_size (4)));
 
+void __builtin_vis_write_gsr (int64_t);
+int64_t __builtin_vis_read_gsr (void);
+
 void * __builtin_vis_alignaddr (void *, long);
 void * __builtin_vis_alignaddrl (void *, long);
 int64_t __builtin_vis_faligndatadi (int64_t, int64_t);
-- 
1.7.6.401.g6a319



More information about the Gcc-patches mailing list