OSDN Git Service

* config/s390/s390-protos.h (s390_split_access_reg): Add prototype.
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 3 Nov 2004 21:39:48 +0000 (21:39 +0000)
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 3 Nov 2004 21:39:48 +0000 (21:39 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@90036 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.h
gcc/config/s390/s390.md

index 3f19c86..425cf0d 100644 (file)
@@ -1,3 +1,29 @@
+2004-11-03  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * 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.
+
 2004-11-03  Kazu Hirata  <kazu@cs.umass.edu>
 
        * tree-phinodes.c (resize_phi_node): Copy only a portion of
index 4b405f2..3b21d03 100644 (file)
@@ -90,6 +90,7 @@ extern void s390_expand_logical_operator (enum rtx_code,
 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 d56624c..8ba78a2 100644 (file)
@@ -1355,7 +1355,8 @@ const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
   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
+  ADDR_REGS,    CC_REGS,   ADDR_REGS, ADDR_REGS,
+  ACCESS_REGS, ACCESS_REGS
 };
 
 /* Return attribute type of insn.  */
@@ -2019,6 +2020,22 @@ store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   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 */
 
@@ -3033,10 +3050,9 @@ legitimize_pic_address (rtx orig, rtx reg)
 static rtx
 get_thread_pointer (void)
 {
-  rtx tp;
+  rtx tp = gen_reg_rtx (Pmode);
 
-  tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
-  tp = force_reg (Pmode, tp);
+  emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM));
   mark_reg_pointer (tp, BITS_PER_WORD);
 
   return tp;
index 013fd93..0116a66 100644 (file)
@@ -307,13 +307,17 @@ if (INTEGRAL_MODE_P (MODE) &&                             \
    GPR 14: Return address register
    GPR 15: Stack pointer
 
-   Registers 32-34 are 'fake' hard registers that do not
+   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 34: Frame pointer  
+   Reg 35: Return address pointer
 
-#define FIRST_PSEUDO_REGISTER 36
+   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)
@@ -321,17 +325,20 @@ if (INTEGRAL_MODE_P (MODE) &&                             \
 #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:
 
@@ -342,6 +349,7 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
    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.
@@ -356,7 +364,8 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
   0, 0, 0, 0,                                  \
   0, 0, 0, 0,                                  \
   0, 0, 0, 0,                                  \
-  1, 1, 1, 1 }
+  1, 1, 1, 1,                                  \
+  1, 1 }
 
 #define CALL_USED_REGISTERS                    \
 { 1, 1, 1, 1,                                  \
@@ -367,7 +376,8 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
   1, 1, 1, 1,                                  \
   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,                                  \
@@ -378,7 +388,8 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
   1, 1, 1, 1,                                  \
   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 ()
 
@@ -387,7 +398,7 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
 {  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 }
+   15, 32, 33, 34, 35, 36, 37 }
 
 
 /* Fitting values into registers.  */
@@ -411,6 +422,8 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
     (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)                             \
@@ -424,6 +437,9 @@ if (INTEGRAL_MODE_P (MODE) &&                               \
      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)          \
@@ -435,48 +451,54 @@ if (INTEGRAL_MODE_P (MODE) &&                             \
 #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.  */
+   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) : 0)
+   ? 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
-   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
+   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.  The condition
-   code register is only included in ALL_REGS.  */
+   are included amongst the address registers here.  */
 
 enum reg_class
 {
-  NO_REGS, CC_REGS, ADDR_REGS, GENERAL_REGS, 
+  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", "ADDR_CC_REGS",           \
-  "GENERAL_CC_REGS", "FP_REGS", "ADDR_FP_REGS", "GENERAL_FP_REGS", "ALL_REGS" }
+#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 \
@@ -485,12 +507,13 @@ enum reg_class
   { 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, 0x0000000f },  /* ALL_REGS */          \
+  { 0xffffffff, 0x0000003f },  /* ALL_REGS */          \
 }
 
 /* Register -> class mapping.  */
@@ -543,7 +566,8 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
   ((C) == 'a' ? ADDR_REGS :                                             \
    (C) == 'd' ? GENERAL_REGS :                                          \
    (C) == 'f' ? FP_REGS :                                               \
-   (C) == 'c' ? CC_REGS : NO_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))
@@ -976,7 +1000,7 @@ extern int flag_pic;
   "%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"                                                \
+  "%ap",  "%cc",  "%fp",  "%rp",  "%a0",  "%a1"                                \
 }
 
 /* Emit a dtp-relative reference to a TLS variable.  */
index 229e3e0..fbce222 100644 (file)
    (UNSPEC_INDNTPOFF            505)
 
    ; TLS support
-   (UNSPEC_TP                  510)
    (UNSPEC_TLSLDM_NTPOFF       511)
    (UNSPEC_TLS_LOAD            512)
 
 
 (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")
+                            "=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,?Q"))]
+                            "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
    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,SS")
+  [(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")])
+                     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")
 
 (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")
+                            "=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,?Q"))]
+                            "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
    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,SS")
-   (set_attr "type" "*,*,*,la,lr,load,load,store,store,floads,floads,floads,fstores,fstores,cs")])
+  [(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,?Q")
-        (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,?Q"))]
+  [(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
    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,SS")
-   (set_attr "type" "*,lr,load,store,floads,floads,fstores,cs")])
+  [(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" "")
 ;
 
 (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"))]
+  [(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"
-  [(set_attr "op_type" "RR,RX,RXY")
-   (set_attr "type" "lr,load,load")])
+   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).
 ;;- 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))]
+(define_expand "get_tp_64"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI 36))]
   "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))]
+(define_expand "get_tp_31"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "") (reg:SI 36))]
   "!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"))]
+(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"
-  "@
-   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)]
+(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"
-  "@
-   sar\t%%a0,%0
-   lam\t%%a0,%%a0,%S0"
-  [(set_attr "op_type" "RRE,RS")])
+  "")
+
+(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")