S/390: Rework thread pointer handling

Ulrich Weigand uweigand@de.ibm.com
Wed Nov 3 21:37:00 GMT 2004


Hello,

thread pointer support on 64-bit used to be implemented via
get_tp_64 / set_tp_64 patterns that output multiple assembler
instructions.  This is not only ugly, but prevents scheduling.

This reimplements the thread pointer support by providing access
to the %a0 and %a1 access registers as genuine hard regs, allowing
the [gs]et_tp_64 patterns to be split at the insn level.

This is complicated by the fact that on s390x, with word size 64 bit,
access registers are only 32 bit in size, but I still need to store
Pmode (== DImode) values in a pair of them.  This works by having
HARD_REGNO_NREGS return 2 for DImode, even though DImode is word_mode.
To avoid confusing get_lowpart et al by this special situation, we have
to disallow mode changes for access registers.

Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux,
applied to mainline.

Bye,
Ulrich


ChangeLog:

	* config/s390/s390-protos.h (s390_split_access_reg): Add prototype.
	* config/s390/s390.c (s390_split_access_reg): New function.
	(regclass_map): Add access registers.
	(get_thread_pointer): Use access register instead of UNSPEC_TP.
	* config/s390/s390.h (FIRST_PSEUDO_REGISTER): Set to 38.
	(ACCESS_REGNO_P, ACCESS_REG_P): New macros.
	(TP_REGNUM): New define.
	(FIXED_REGISTERS, CALL_USED_REGISTERS, CALL_REALLY_USED_REGISTERS,
	REG_ALLOC_ORDER): Add access registers.
	(HARD_REGNO_NREGS, HARD_REGNO_MODE_OK, CLASS_MAX_NREGS,
	CANNOT_CHANGE_MODE_CLASS): Support access registers.
	(enum reg_class): Add ACCESS_REGS.
	(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Likewise.
	(REG_CLASS_FROM_LETTER): Add 't' constraint.
	(REGISTER_NAMES): Add access registers.
	* config/s390/s390.md (UNSPEC_TP): Remove.
	("*movdi_64"): Add access register alternatives.  Provide splitters
	to split DImode access register <-> GPR moves into SImode moves.
	("*movsi_zarch", "*movsi_esa"): Add access register alternatives.
	("movstrictsi"): Likewise.
	("get_tp_64", "get_tp_31"): Reimplement using access registers.
	("set_tp_64", "set_tp_31"): Likewise.
	("*set_tp"): New insn.


Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.64
diff -c -p -r1.64 s390-protos.h
*** gcc/config/s390/s390-protos.h	11 Oct 2004 14:33:22 -0000	1.64
--- gcc/config/s390/s390-protos.h	3 Nov 2004 16:30:19 -0000
*************** extern void s390_expand_logical_operator
*** 90,95 ****
--- 90,96 ----
  extern bool s390_logical_operator_ok_p (rtx *);
  extern void s390_narrow_logical_operator (enum rtx_code, rtx *, rtx *);
  extern bool s390_pool_operand (rtx);
+ extern void s390_split_access_reg (rtx, rtx *, rtx *);
  
  extern bool s390_output_addr_const_extra (FILE*, rtx);
  extern void print_operand_address (FILE *, rtx);
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.195
diff -c -p -r1.195 s390.c
*** gcc/config/s390/s390.c	1 Nov 2004 18:50:19 -0000	1.195
--- gcc/config/s390/s390.c	3 Nov 2004 16:30:20 -0000
*************** const enum reg_class regclass_map[FIRST_
*** 1355,1361 ****
    FP_REGS,      FP_REGS,   FP_REGS,   FP_REGS,
    FP_REGS,      FP_REGS,   FP_REGS,   FP_REGS,
    FP_REGS,      FP_REGS,   FP_REGS,   FP_REGS,
!   ADDR_REGS,    CC_REGS,   ADDR_REGS, ADDR_REGS
  };
  
  /* Return attribute type of insn.  */
--- 1355,1362 ----
    FP_REGS,      FP_REGS,   FP_REGS,   FP_REGS,
    FP_REGS,      FP_REGS,   FP_REGS,   FP_REGS,
    FP_REGS,      FP_REGS,   FP_REGS,   FP_REGS,
!   ADDR_REGS,    CC_REGS,   ADDR_REGS, ADDR_REGS,
!   ACCESS_REGS,	ACCESS_REGS
  };
  
  /* Return attribute type of insn.  */
*************** store_multiple_operation (rtx op, enum m
*** 2019,2024 ****
--- 2020,2041 ----
    return 1;
  }
  
+ /* Split DImode access register reference REG (on 64-bit) into its constituent
+    low and high parts, and store them into LO and HI.  Note that gen_lowpart/
+    gen_highpart cannot be used as they assume all registers are word-sized,
+    while our access registers have only half that size.  */
+ 
+ void
+ s390_split_access_reg (rtx reg, rtx *lo, rtx *hi)
+ {
+   gcc_assert (TARGET_64BIT);
+   gcc_assert (ACCESS_REG_P (reg));
+   gcc_assert (GET_MODE (reg) == DImode);
+   gcc_assert (!(REGNO (reg) & 1));
+ 
+   *lo = gen_rtx_REG (SImode, REGNO (reg) + 1);
+   *hi = gen_rtx_REG (SImode, REGNO (reg));
+ }
  
  /* Return true if OP contains a symbol reference */
  
*************** legitimize_pic_address (rtx orig, rtx re
*** 3033,3042 ****
  static rtx
  get_thread_pointer (void)
  {
!   rtx tp;
  
!   tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
!   tp = force_reg (Pmode, tp);
    mark_reg_pointer (tp, BITS_PER_WORD);
  
    return tp;
--- 3050,3058 ----
  static rtx
  get_thread_pointer (void)
  {
!   rtx tp = gen_reg_rtx (Pmode);
  
!   emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM));
    mark_reg_pointer (tp, BITS_PER_WORD);
  
    return tp;
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.127
diff -c -p -r1.127 s390.h
*** gcc/config/s390/s390.h	1 Nov 2004 18:50:19 -0000	1.127
--- gcc/config/s390/s390.h	3 Nov 2004 16:30:20 -0000
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 307,319 ****
     GPR 14: Return address register
     GPR 15: Stack pointer
  
!    Registers 32-34 are 'fake' hard registers that do not
     correspond to actual hardware:
     Reg 32: Argument pointer
     Reg 33: Condition code
!    Reg 34: Frame pointer  */
  
! #define FIRST_PSEUDO_REGISTER 36
  
  /* Standard register usage.  */
  #define GENERAL_REGNO_P(N)	((int)(N) >= 0 && (N) < 16)
--- 307,323 ----
     GPR 14: Return address register
     GPR 15: Stack pointer
  
!    Registers 32-35 are 'fake' hard registers that do not
     correspond to actual hardware:
     Reg 32: Argument pointer
     Reg 33: Condition code
!    Reg 34: Frame pointer  
!    Reg 35: Return address pointer
  
!    Registers 36 and 37 are mapped to access registers 
!    0 and 1, used to implement thread-local storage.  */
! 
! #define FIRST_PSEUDO_REGISTER 38
  
  /* Standard register usage.  */
  #define GENERAL_REGNO_P(N)	((int)(N) >= 0 && (N) < 16)
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 321,337 ****
--- 325,344 ----
  #define FP_REGNO_P(N)		((N) >= 16 && (N) < (TARGET_IEEE_FLOAT? 32 : 20))
  #define CC_REGNO_P(N)		((N) == 33)
  #define FRAME_REGNO_P(N)	((N) == 32 || (N) == 34 || (N) == 35)
+ #define ACCESS_REGNO_P(N)	((N) == 36 || (N) == 37)
  
  #define GENERAL_REG_P(X)	(REG_P (X) && GENERAL_REGNO_P (REGNO (X)))
  #define ADDR_REG_P(X)		(REG_P (X) && ADDR_REGNO_P (REGNO (X)))
  #define FP_REG_P(X)		(REG_P (X) && FP_REGNO_P (REGNO (X)))
  #define CC_REG_P(X)		(REG_P (X) && CC_REGNO_P (REGNO (X)))
  #define FRAME_REG_P(X)		(REG_P (X) && FRAME_REGNO_P (REGNO (X)))
+ #define ACCESS_REG_P(X)		(REG_P (X) && ACCESS_REGNO_P (REGNO (X)))
  
  #define SIBCALL_REGNUM 1
  #define BASE_REGNUM 13
  #define RETURN_REGNUM 14
  #define CC_REGNUM 33
+ #define TP_REGNUM 36
  
  /* Set up fixed registers and calling convention:
  
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 342,347 ****
--- 349,355 ----
     GPR 14 is always fixed on S/390 machines (as return address).
     GPR 15 is always fixed (as stack pointer).
     The 'fake' hard registers are call-clobbered and fixed.
+    The access registers are call-saved and fixed.
  
     On 31-bit, FPRs 18-19 are call-clobbered;
     on 64-bit, FPRs 24-31 are call-clobbered.
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 356,362 ****
    0, 0, 0, 0, 					\
    0, 0, 0, 0, 					\
    0, 0, 0, 0, 					\
!   1, 1, 1, 1 }
  
  #define CALL_USED_REGISTERS			\
  { 1, 1, 1, 1, 					\
--- 364,371 ----
    0, 0, 0, 0, 					\
    0, 0, 0, 0, 					\
    0, 0, 0, 0, 					\
!   1, 1, 1, 1,					\
!   1, 1 }
  
  #define CALL_USED_REGISTERS			\
  { 1, 1, 1, 1, 					\
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 367,373 ****
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
!   1, 1, 1, 1 }
  
  #define CALL_REALLY_USED_REGISTERS		\
  { 1, 1, 1, 1, 					\
--- 376,383 ----
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
!   1, 1, 1, 1,					\
!   1, 1 }
  
  #define CALL_REALLY_USED_REGISTERS		\
  { 1, 1, 1, 1, 					\
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 378,384 ****
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
!   1, 1, 1, 1 }
  
  #define CONDITIONAL_REGISTER_USAGE s390_conditional_register_usage ()
  
--- 388,395 ----
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
    1, 1, 1, 1, 					\
!   1, 1, 1, 1,					\
!   0, 0 }
  
  #define CONDITIONAL_REGISTER_USAGE s390_conditional_register_usage ()
  
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 387,393 ****
  {  1, 2, 3, 4, 5, 0, 13, 12, 11, 10, 9, 8, 7, 6, 14,            \
     16, 17, 18, 19, 20, 21, 22, 23,                              \
     24, 25, 26, 27, 28, 29, 30, 31,                              \
!    15, 32, 33, 34, 35 }
  
  
  /* Fitting values into registers.  */
--- 398,404 ----
  {  1, 2, 3, 4, 5, 0, 13, 12, 11, 10, 9, 8, 7, 6, 14,            \
     16, 17, 18, 19, 20, 21, 22, 23,                              \
     24, 25, 26, 27, 28, 29, 30, 31,                              \
!    15, 32, 33, 34, 35, 36, 37 }
  
  
  /* Fitting values into registers.  */
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 411,416 ****
--- 422,429 ----
      (GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) :      \
     GENERAL_REGNO_P(REGNO)?                                      \
      ((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) : \
+    ACCESS_REGNO_P(REGNO)?					\
+     ((GET_MODE_SIZE(MODE)+32-1) / 32) : 			\
     1)
  
  #define HARD_REGNO_MODE_OK(REGNO, MODE)                             \
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 424,429 ****
--- 437,445 ----
       GET_MODE_CLASS (MODE) == MODE_CC :                             \
     FRAME_REGNO_P(REGNO)?                                            \
       (enum machine_mode) (MODE) == Pmode :                          \
+    ACCESS_REGNO_P(REGNO)?					    \
+      (((MODE) == SImode || ((enum machine_mode) (MODE) == Pmode))   \
+       && (HARD_REGNO_NREGS(REGNO, MODE) == 1 || !((REGNO) & 1))) :  \
     0)
  
  #define MODES_TIEABLE_P(MODE1, MODE2)		\
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 435,482 ****
  #define CLASS_MAX_NREGS(CLASS, MODE)   					\
       ((CLASS) == FP_REGS ? 						\
        (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) :  		\
        (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
  
  /* If a 4-byte value is loaded into a FPR, it is placed into the
     *upper* half of the register, not the lower.  Therefore, we
!    cannot use SUBREGs to switch between modes in FP registers.  */
  #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)		\
    (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)			\
!    ? reg_classes_intersect_p (FP_REGS, CLASS) : 0)
  
  /* Register classes.  */
  
  /* We use the following register classes:
     GENERAL_REGS     All general purpose registers
-    CC_REGS          Contains only the condition code register
     ADDR_REGS        All general purpose registers except %r0
                      (These registers can be used in address generation)
-    ADDR_CC_REGS     Union of ADDR_REGS and CC_REGS
-    GENERAL_CC_REGS  Union of GENERAL_REGS and CC_REGS
     FP_REGS          All floating point registers
  
     GENERAL_FP_REGS  Union of GENERAL_REGS and FP_REGS
     ADDR_FP_REGS     Union of ADDR_REGS and FP_REGS
  
     NO_REGS          No registers
     ALL_REGS         All registers
  
     Note that the 'fake' frame pointer and argument pointer registers
!    are included amongst the address registers here.  The condition
!    code register is only included in ALL_REGS.  */
  
  enum reg_class
  {
!   NO_REGS, CC_REGS, ADDR_REGS, GENERAL_REGS, 
    ADDR_CC_REGS, GENERAL_CC_REGS, 
    FP_REGS, ADDR_FP_REGS, GENERAL_FP_REGS,
    ALL_REGS, LIM_REG_CLASSES
  };
  #define N_REG_CLASSES (int) LIM_REG_CLASSES
  
! #define REG_CLASS_NAMES                                                        \
! { "NO_REGS", "CC_REGS", "ADDR_REGS", "GENERAL_REGS", "ADDR_CC_REGS",           \
!   "GENERAL_CC_REGS", "FP_REGS", "ADDR_FP_REGS", "GENERAL_FP_REGS", "ALL_REGS" }
  
  /* Class -> register mapping.  */
  #define REG_CLASS_CONTENTS \
--- 451,504 ----
  #define CLASS_MAX_NREGS(CLASS, MODE)   					\
       ((CLASS) == FP_REGS ? 						\
        (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) :  		\
+       (CLASS) == ACCESS_REGS ?						\
+       (GET_MODE_SIZE (MODE) + 32 - 1) / 32 :				\
        (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
  
  /* If a 4-byte value is loaded into a FPR, it is placed into the
     *upper* half of the register, not the lower.  Therefore, we
!    cannot use SUBREGs to switch between modes in FP registers.
!    Likewise for access registers, since they have only half the
!    word size on 64-bit.  */
  #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)		\
    (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)			\
!    ? reg_classes_intersect_p (FP_REGS, CLASS)			\
!      || reg_classes_intersect_p (ACCESS_REGS, CLASS) : 0)
  
  /* Register classes.  */
  
  /* We use the following register classes:
     GENERAL_REGS     All general purpose registers
     ADDR_REGS        All general purpose registers except %r0
                      (These registers can be used in address generation)
     FP_REGS          All floating point registers
+    CC_REGS          The condition code register
+    ACCESS_REGS      The access registers
  
     GENERAL_FP_REGS  Union of GENERAL_REGS and FP_REGS
     ADDR_FP_REGS     Union of ADDR_REGS and FP_REGS
+    GENERAL_CC_REGS  Union of GENERAL_REGS and CC_REGS
+    ADDR_CC_REGS     Union of ADDR_REGS and CC_REGS
  
     NO_REGS          No registers
     ALL_REGS         All registers
  
     Note that the 'fake' frame pointer and argument pointer registers
!    are included amongst the address registers here.  */
  
  enum reg_class
  {
!   NO_REGS, CC_REGS, ADDR_REGS, GENERAL_REGS, ACCESS_REGS,
    ADDR_CC_REGS, GENERAL_CC_REGS, 
    FP_REGS, ADDR_FP_REGS, GENERAL_FP_REGS,
    ALL_REGS, LIM_REG_CLASSES
  };
  #define N_REG_CLASSES (int) LIM_REG_CLASSES
  
! #define REG_CLASS_NAMES							\
! { "NO_REGS", "CC_REGS", "ADDR_REGS", "GENERAL_REGS", "ACCESS_REGS",	\
!   "ADDR_CC_REGS", "GENERAL_CC_REGS",					\
!   "FP_REGS", "ADDR_FP_REGS", "GENERAL_FP_REGS", "ALL_REGS" }
  
  /* Class -> register mapping.  */
  #define REG_CLASS_CONTENTS \
*************** enum reg_class
*** 485,496 ****
    { 0x00000000, 0x00000002 },	/* CC_REGS */		\
    { 0x0000fffe, 0x0000000d },	/* ADDR_REGS */		\
    { 0x0000ffff, 0x0000000d },	/* GENERAL_REGS */	\
    { 0x0000fffe, 0x0000000f },	/* ADDR_CC_REGS */	\
    { 0x0000ffff, 0x0000000f },	/* GENERAL_CC_REGS */	\
    { 0xffff0000, 0x00000000 },	/* FP_REGS */		\
    { 0xfffffffe, 0x0000000d },	/* ADDR_FP_REGS */	\
    { 0xffffffff, 0x0000000d },	/* GENERAL_FP_REGS */	\
!   { 0xffffffff, 0x0000000f },	/* ALL_REGS */		\
  }
  
  /* Register -> class mapping.  */
--- 507,519 ----
    { 0x00000000, 0x00000002 },	/* CC_REGS */		\
    { 0x0000fffe, 0x0000000d },	/* ADDR_REGS */		\
    { 0x0000ffff, 0x0000000d },	/* GENERAL_REGS */	\
+   { 0x00000000, 0x00000030 },	/* ACCESS_REGS */	\
    { 0x0000fffe, 0x0000000f },	/* ADDR_CC_REGS */	\
    { 0x0000ffff, 0x0000000f },	/* GENERAL_CC_REGS */	\
    { 0xffff0000, 0x00000000 },	/* FP_REGS */		\
    { 0xfffffffe, 0x0000000d },	/* ADDR_FP_REGS */	\
    { 0xffffffff, 0x0000000d },	/* GENERAL_FP_REGS */	\
!   { 0xffffffff, 0x0000003f },	/* ALL_REGS */		\
  }
  
  /* Register -> class mapping.  */
*************** extern const enum reg_class regclass_map
*** 543,549 ****
    ((C) == 'a' ? ADDR_REGS :                                             \
     (C) == 'd' ? GENERAL_REGS :                                          \
     (C) == 'f' ? FP_REGS :                                               \
!    (C) == 'c' ? CC_REGS : NO_REGS)
  
  #define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR)                          \
    s390_const_ok_for_constraint_p ((VALUE), (C), (STR))
--- 566,573 ----
    ((C) == 'a' ? ADDR_REGS :                                             \
     (C) == 'd' ? GENERAL_REGS :                                          \
     (C) == 'f' ? FP_REGS :                                               \
!    (C) == 'c' ? CC_REGS : 						\
!    (C) == 't' ? ACCESS_REGS : NO_REGS)
  
  #define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR)                          \
    s390_const_ok_for_constraint_p ((VALUE), (C), (STR))
*************** extern int flag_pic;
*** 976,982 ****
    "%r8",  "%r9",  "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",	\
    "%f0",  "%f2",  "%f4",  "%f6",  "%f1",  "%f3",  "%f5",  "%f7",	\
    "%f8",  "%f10", "%f12", "%f14", "%f9",  "%f11", "%f13", "%f15",	\
!   "%ap",  "%cc",  "%fp",  "%rp"						\
  }
  
  /* Emit a dtp-relative reference to a TLS variable.  */
--- 1000,1006 ----
    "%r8",  "%r9",  "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",	\
    "%f0",  "%f2",  "%f4",  "%f6",  "%f1",  "%f3",  "%f5",  "%f7",	\
    "%f8",  "%f10", "%f12", "%f14", "%f9",  "%f11", "%f13", "%f15",	\
!   "%ap",  "%cc",  "%fp",  "%rp",  "%a0",  "%a1"				\
  }
  
  /* Emit a dtp-relative reference to a TLS variable.  */
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.138
diff -c -p -r1.138 s390.md
*** gcc/config/s390/s390.md	2 Nov 2004 15:11:43 -0000	1.138
--- gcc/config/s390/s390.md	3 Nov 2004 16:30:20 -0000
***************
*** 112,118 ****
     (UNSPEC_INDNTPOFF            505)
  
     ; TLS support
-    (UNSPEC_TP			510)
     (UNSPEC_TLSLDM_NTPOFF	511)
     (UNSPEC_TLS_LOAD		512)
  
--- 112,117 ----
***************
*** 887,895 ****
  
  (define_insn "*movdi_64"
    [(set (match_operand:DI 0 "nonimmediate_operand"
!                             "=d,d,d,d,d,d,d,d,m,!*f,!*f,!*f,!R,!T,?Q")
          (match_operand:DI 1 "general_operand"
!                             "K,N0HD0,N1HD0,N2HD0,N3HD0,L,d,m,d,*f,R,T,*f,*f,?Q"))]
    "TARGET_64BIT"
    "@
     lghi\t%0,%h1
--- 886,894 ----
  
  (define_insn "*movdi_64"
    [(set (match_operand:DI 0 "nonimmediate_operand"
!                             "=d,d,d,d,d,d,d,d,m,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q")
          (match_operand:DI 1 "general_operand"
!                             "K,N0HD0,N1HD0,N2HD0,N3HD0,L,d,m,d,*f,R,T,*f,*f,t,d,t,Q,?Q"))]
    "TARGET_64BIT"
    "@
     lghi\t%0,%h1
***************
*** 906,915 ****
     ldy\t%0,%1
     std\t%1,%0
     stdy\t%1,%0
     #"
!   [(set_attr "op_type" "RI,RI,RI,RI,RI,RXY,RRE,RXY,RXY,RR,RX,RXY,RX,RXY,SS")
     (set_attr "type" "*,*,*,*,*,la,lr,load,store,floadd,floadd,floadd,
!                      fstored,fstored,cs")])
  
  (define_insn "*movdi_31"
    [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!*f,!R,!T,Q")
--- 905,951 ----
     ldy\t%0,%1
     std\t%1,%0
     stdy\t%1,%0
+    #
+    #
+    stam\t%1,%N1,%S0
+    lam\t%0,%N0,%S1
     #"
!   [(set_attr "op_type" "RI,RI,RI,RI,RI,RXY,RRE,RXY,RXY,RR,RX,RXY,RX,RXY,NN,NN,RS,RS,SS")
     (set_attr "type" "*,*,*,*,*,la,lr,load,store,floadd,floadd,floadd,
!                      fstored,fstored,*,*,*,*,cs")])
! 
! (define_split
!   [(set (match_operand:DI 0 "register_operand" "")
!         (match_operand:DI 1 "register_operand" ""))]
!   "TARGET_64BIT && ACCESS_REG_P (operands[1])"
!   [(set (match_dup 2) (match_dup 3))
!    (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
!    (set (strict_low_part (match_dup 2)) (match_dup 4))]
!   "operands[2] = gen_lowpart (SImode, operands[0]);
!    s390_split_access_reg (operands[1], &operands[4], &operands[3]);")
! 
! (define_split
!   [(set (match_operand:DI 0 "register_operand" "")
!         (match_operand:DI 1 "register_operand" ""))]
!   "TARGET_64BIT && ACCESS_REG_P (operands[0])
!    && dead_or_set_p (insn, operands[1])"
!   [(set (match_dup 3) (match_dup 2))
!    (set (match_dup 1) (lshiftrt:DI (match_dup 1) (const_int 32)))
!    (set (match_dup 4) (match_dup 2))]
!   "operands[2] = gen_lowpart (SImode, operands[1]);
!    s390_split_access_reg (operands[0], &operands[3], &operands[4]);")
! 
! (define_split
!   [(set (match_operand:DI 0 "register_operand" "")
!         (match_operand:DI 1 "register_operand" ""))]
!   "TARGET_64BIT && ACCESS_REG_P (operands[0])
!    && !dead_or_set_p (insn, operands[1])"
!   [(set (match_dup 3) (match_dup 2))
!    (set (match_dup 1) (rotate:DI (match_dup 1) (const_int 32)))
!    (set (match_dup 4) (match_dup 2))
!    (set (match_dup 1) (rotate:DI (match_dup 1) (const_int 32)))]
!   "operands[2] = gen_lowpart (SImode, operands[1]);
!    s390_split_access_reg (operands[0], &operands[3], &operands[4]);")
  
  (define_insn "*movdi_31"
    [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!*f,!R,!T,Q")
***************
*** 1063,1071 ****
  
  (define_insn "*movsi_zarch"
    [(set (match_operand:SI 0 "nonimmediate_operand"
!                             "=d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,?Q")
          (match_operand:SI 1 "general_operand"
!                             "K,N0HS0,N1HS0,L,d,R,T,d,d,*f,R,T,*f,*f,?Q"))]
    "TARGET_ZARCH"
    "@
     lhi\t%0,%h1
--- 1099,1107 ----
  
  (define_insn "*movsi_zarch"
    [(set (match_operand:SI 0 "nonimmediate_operand"
!                             "=d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q")
          (match_operand:SI 1 "general_operand"
!                             "K,N0HS0,N1HS0,L,d,R,T,d,d,*f,R,T,*f,*f,t,d,t,Q,?Q"))]
    "TARGET_ZARCH"
    "@
     lhi\t%0,%h1
***************
*** 1082,1094 ****
     ley\t%0,%1
     ste\t%1,%0
     stey\t%1,%0
     #"
!   [(set_attr "op_type" "RI,RI,RI,RXY,RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,SS")
!    (set_attr "type" "*,*,*,la,lr,load,load,store,store,floads,floads,floads,fstores,fstores,cs")])
  
  (define_insn "*movsi_esa"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,?Q")
!         (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,?Q"))]
    "!TARGET_ZARCH"
    "@
     lhi\t%0,%h1
--- 1118,1134 ----
     ley\t%0,%1
     ste\t%1,%0
     stey\t%1,%0
+    ear\t%0,%1
+    sar\t%0,%1
+    stam\t%1,%1,%S0
+    lam\t%0,%0,%S1
     #"
!   [(set_attr "op_type" "RI,RI,RI,RXY,RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,RRE,RRE,RS,RS,SS")
!    (set_attr "type" "*,*,*,la,lr,load,load,store,store,floads,floads,floads,fstores,fstores,*,*,*,*,cs")])
  
  (define_insn "*movsi_esa"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,d,t,Q,t,?Q")
!         (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,t,d,t,Q,?Q"))]
    "!TARGET_ZARCH"
    "@
     lhi\t%0,%h1
***************
*** 1098,1106 ****
     ler\t%0,%1
     le\t%0,%1
     ste\t%1,%0
     #"
!   [(set_attr "op_type" "RI,RR,RX,RX,RR,RX,RX,SS")
!    (set_attr "type" "*,lr,load,store,floads,floads,fstores,cs")])
  
  (define_peephole2
    [(set (match_operand:SI 0 "register_operand" "")
--- 1138,1150 ----
     ler\t%0,%1
     le\t%0,%1
     ste\t%1,%0
+    ear\t%0,%1
+    sar\t%0,%1
+    stam\t%1,%1,%S0
+    lam\t%0,%0,%S1
     #"
!   [(set_attr "op_type" "RI,RR,RX,RX,RR,RX,RX,RRE,RRE,RS,RS,SS")
!    (set_attr "type" "*,lr,load,store,floads,floads,fstores,*,*,*,*,cs")])
  
  (define_peephole2
    [(set (match_operand:SI 0 "register_operand" "")
***************
*** 1321,1335 ****
  ;
  
  (define_insn "movstrictsi"
!   [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d"))
!                          (match_operand:SI 1 "general_operand" "d,R,T"))]
    "TARGET_64BIT"
    "@
     lr\t%0,%1
     l\t%0,%1
!    ly\t%0,%1"
!   [(set_attr "op_type" "RR,RX,RXY")
!    (set_attr "type" "lr,load,load")])
  
  ;
  ; movdf instruction pattern(s).
--- 1365,1380 ----
  ;
  
  (define_insn "movstrictsi"
!   [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d,d"))
!                          (match_operand:SI 1 "general_operand" "d,R,T,t"))]
    "TARGET_64BIT"
    "@
     lr\t%0,%1
     l\t%0,%1
!    ly\t%0,%1
!    ear\t%0,%1"
!   [(set_attr "op_type" "RR,RX,RXY,RRE")
!    (set_attr "type" "lr,load,load,*")])
  
  ;
  ; movdf instruction pattern(s).
***************
*** 7438,7483 ****
  ;;- Thread-local storage support.
  ;;
  
! (define_insn "get_tp_64"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=??d,Q")
!         (unspec:DI [(const_int 0)] UNSPEC_TP))]
    "TARGET_64BIT"
!   "@
!    ear\t%0,%%a0\;sllg\t%0,%0,32\;ear\t%0,%%a1
!    stam\t%%a0,%%a1,%S0"
!   [(set_attr "op_type" "NN,RS")
!    (set_attr "atype"   "reg,*")
!    (set_attr "type"    "o3,*")
!    (set_attr "length"  "14,*")])
! 
! (define_insn "get_tp_31"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,Q")
!         (unspec:SI [(const_int 0)] UNSPEC_TP))]
    "!TARGET_64BIT"
!   "@
!    ear\t%0,%%a0
!    stam\t%%a0,%%a0,%S0"
!   [(set_attr "op_type" "RRE,RS")])
! 
! (define_insn "set_tp_64"
!   [(unspec_volatile [(match_operand:DI 0 "general_operand" "??d,Q")] UNSPECV_SET_TP)
!    (clobber (match_scratch:SI 1 "=d,X"))]
!   "TARGET_64BIT"
!   "@
!    sar\t%%a1,%0\;srlg\t%1,%0,32\;sar\t%%a0,%1
!    lam\t%%a0,%%a1,%S0"
!   [(set_attr "op_type" "NN,RS")
!    (set_attr "atype"   "reg,*")
!    (set_attr "type"    "o3,*")
!    (set_attr "length"  "14,*")])
  
! (define_insn "set_tp_31"
!   [(unspec_volatile [(match_operand:SI 0 "general_operand" "d,Q")] UNSPECV_SET_TP)]
    "!TARGET_64BIT"
!   "@
!    sar\t%%a0,%0
!    lam\t%%a0,%%a0,%S0"
!   [(set_attr "op_type" "RRE,RS")])
  
  (define_insn "*tls_load_64"
    [(set (match_operand:DI 0 "register_operand" "=d")
--- 7483,7516 ----
  ;;- Thread-local storage support.
  ;;
  
! (define_expand "get_tp_64"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI 36))]
    "TARGET_64BIT"
!   "")
! 
! (define_expand "get_tp_31"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "") (reg:SI 36))]
    "!TARGET_64BIT"
!   "")
! 
! (define_expand "set_tp_64"
!   [(set (reg:DI 36) (match_operand:DI 0 "nonimmediate_operand" ""))
!    (unspec_volatile [(reg:DI 36)] UNSPECV_SET_TP)]
!   "TARGET_64BIT"
!   "")
  
! (define_expand "set_tp_31"
!   [(set (reg:SI 36) (match_operand:SI 0 "nonimmediate_operand" ""))
!    (unspec_volatile [(reg:SI 36)] UNSPECV_SET_TP)]
    "!TARGET_64BIT"
!   "")
! 
! (define_insn "*set_tp"
!   [(unspec_volatile [(reg 36)] UNSPECV_SET_TP)]
!   ""
!   ""
!   [(set_attr "type" "none")
!    (set_attr "length" "0")])
  
  (define_insn "*tls_load_64"
    [(set (match_operand:DI 0 "register_operand" "=d")
-- 
  Dr. Ulrich Weigand
  Linux on zSeries Development
  Ulrich.Weigand@de.ibm.com



More information about the Gcc-patches mailing list