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