summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/s390
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2003-07-11 03:40:53 +0000
committerkan <kan@FreeBSD.org>2003-07-11 03:40:53 +0000
commitb2a8872fbe1ec1c49094559ac7b78e6ea4ab7180 (patch)
treef6b0610f4a17fd26aa234354f050080f789861a4 /contrib/gcc/config/s390
parent52e69d78eee5612ac195e0701a5cebe40d1ab0e1 (diff)
downloadFreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.zip
FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.tar.gz
Gcc 3.3.1-pre as of 2003-07-11.
Diffstat (limited to 'contrib/gcc/config/s390')
-rw-r--r--contrib/gcc/config/s390/fixdfdi.h7
-rw-r--r--contrib/gcc/config/s390/libgcc-glibc.ver20
-rw-r--r--contrib/gcc/config/s390/linux.h302
-rw-r--r--contrib/gcc/config/s390/s390-modes.def38
-rw-r--r--contrib/gcc/config/s390/s390-protos.h27
-rw-r--r--contrib/gcc/config/s390/s390.c3534
-rw-r--r--contrib/gcc/config/s390/s390.h1354
-rw-r--r--contrib/gcc/config/s390/s390.md3328
-rw-r--r--contrib/gcc/config/s390/t-crtstuff4
-rw-r--r--contrib/gcc/config/s390/t-linux649
10 files changed, 5509 insertions, 3114 deletions
diff --git a/contrib/gcc/config/s390/fixdfdi.h b/contrib/gcc/config/s390/fixdfdi.h
index 4f1fb35..1f82a9c 100644
--- a/contrib/gcc/config/s390/fixdfdi.h
+++ b/contrib/gcc/config/s390/fixdfdi.h
@@ -43,6 +43,7 @@ union double_long {
UDItype_x ll;
};
+UDItype_x __fixunsdfdi (double a1);
/* convert double to unsigned int */
UDItype_x
@@ -114,6 +115,8 @@ union double_long {
UDItype_x ll;
};
+DItype_x __fixdfdi (double a1);
+
/* convert double to int */
DItype_x
__fixdfdi (double a1)
@@ -184,6 +187,8 @@ union float_long
USItype_x l;
};
+UDItype_x __fixunssfdi (float a1);
+
/* convert float to unsigned int */
UDItype_x
__fixunssfdi (float a1)
@@ -250,6 +255,8 @@ union float_long
USItype_x l;
};
+DItype_x __fixsfdi (float a1);
+
/* convert double to int */
DItype_x
__fixsfdi (float a1)
diff --git a/contrib/gcc/config/s390/libgcc-glibc.ver b/contrib/gcc/config/s390/libgcc-glibc.ver
index 9a42151..1d9e229 100644
--- a/contrib/gcc/config/s390/libgcc-glibc.ver
+++ b/contrib/gcc/config/s390/libgcc-glibc.ver
@@ -8,6 +8,25 @@
# because GLIBC_2.0 does not exist on this architecture, as the first
# ever glibc release on the platform was GLIBC_2.2.
+%ifndef __s390x__
+%inherit GCC_3.0 GLIBC_2.0
+GLIBC_2.0 {
+ __divdi3
+ __moddi3
+ __udivdi3
+ __umoddi3
+
+ __register_frame
+ __register_frame_table
+ __deregister_frame
+ __register_frame_info
+ __deregister_frame_info
+ __frame_state_for
+ __register_frame_info_table
+}
+%endif
+
+%ifdef __s390x__
%inherit GCC_3.0 GLIBC_2.2
GLIBC_2.2 {
__register_frame
@@ -18,4 +37,5 @@ GLIBC_2.2 {
__frame_state_for
__register_frame_info_table
}
+%endif
diff --git a/contrib/gcc/config/s390/linux.h b/contrib/gcc/config/s390/linux.h
index a0336bf..cbb7710 100644
--- a/contrib/gcc/config/s390/linux.h
+++ b/contrib/gcc/config/s390/linux.h
@@ -50,35 +50,22 @@ Boston, MA 02111-1307, USA. */
/* Target specific preprocessor settings. */
-#define NO_BUILTIN_SIZE_TYPE
-#define NO_BUILTIN_PTRDIFF_TYPE
-
-#define CPP_PREDEFINES \
- "-Dunix -Asystem(unix) -D__gnu_linux__ -Dlinux -Asystem(linux) -D__ELF__ \
- -Acpu(s390) -Amachine(s390) -D__s390__"
-
-#define CPP_ARCH31_SPEC \
- "-D__SIZE_TYPE__=long\\ unsigned\\ int -D__PTRDIFF_TYPE__=int"
-#define CPP_ARCH64_SPEC \
- "-D__SIZE_TYPE__=long\\ unsigned\\ int -D__PTRDIFF_TYPE__=long\\ int \
- -D__s390x__ -D__LONG_MAX__=9223372036854775807L"
-
-#ifdef DEFAULT_TARGET_64BIT
-#undef CPP_SPEC
-#define CPP_SPEC "%{m31:%(cpp_arch31)} %{!m31:%(cpp_arch64)}"
-#else
-#undef CPP_SPEC
-#define CPP_SPEC "%{m64:%(cpp_arch64)} %{!m64:%(cpp_arch31)}"
-#endif
-
-
-/* Target specific compiler settings. */
-
-/* ??? -fcaller-saves sometimes doesn't work. Fix this! */
-#undef CC1_SPEC
-#define CC1_SPEC "-fno-caller-saves"
-#undef CC1PLUS_SPEC
-#define CC1PLUS_SPEC "-fno-caller-saves"
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define_std ("linux"); \
+ builtin_define_std ("unix"); \
+ builtin_assert ("system=linux"); \
+ builtin_assert ("system=unix"); \
+ builtin_define ("__ELF__"); \
+ builtin_define ("__gnu_linux__"); \
+ if (flag_pic) \
+ { \
+ builtin_define ("__PIC__"); \
+ builtin_define ("__pic__"); \
+ } \
+ } \
+ while (0)
/* Target specific assembler settings. */
@@ -94,6 +81,12 @@ Boston, MA 02111-1307, USA. */
/* Target specific linker settings. */
+#ifdef DEFAULT_TARGET_64BIT
+#define MULTILIB_DEFAULTS { "m64" }
+#else
+#define MULTILIB_DEFAULTS { "m31" }
+#endif
+
#define LINK_ARCH31_SPEC \
"-m elf_s390 \
%{shared:-shared} \
@@ -126,183 +119,86 @@ Boston, MA 02111-1307, USA. */
is an initializer with a subgrouping for each command option. */
#define EXTRA_SPECS \
- { "cpp_arch31", CPP_ARCH31_SPEC }, \
- { "cpp_arch64", CPP_ARCH64_SPEC }, \
{ "link_arch31", LINK_ARCH31_SPEC }, \
{ "link_arch64", LINK_ARCH64_SPEC }, \
-/* Character to start a comment. */
-
-#define ASM_COMMENT_START "#"
-
-
-/* Assembler pseudos to introduce constants of various size. */
-
-#define ASM_DOUBLE "\t.double"
-
-/* The LOCAL_LABEL_PREFIX variable is used by dbxelf.h. */
-#define LOCAL_LABEL_PREFIX "."
-
-/* Prefix for internally generated assembler labels. */
-#define LPREFIX ".L"
-
-
-/* This is how to output the definition of a user-level label named NAME,
- such as the label on a static function or variable NAME. */
-
-#undef ASM_OUTPUT_LABEL
-#define ASM_OUTPUT_LABEL(FILE, NAME) \
- (assemble_name (FILE, NAME), fputs (":\n", FILE))
-
-/* Store in OUTPUT a string (made with alloca) containing
- an assembler-name for a local static variable named NAME.
- LABELNO is an integer which is different for each call. */
-
-#undef ASM_FORMAT_PRIVATE_NAME
-#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
-( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
- sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
-
-
- /* internal macro to output long */
-#define _ASM_OUTPUT_LONG(FILE, VALUE) \
- fprintf (FILE, "\t.long\t0x%lX\n", VALUE);
-
-
-/* This is how to output an element of a case-vector that is absolute. */
-
-#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
- fprintf (FILE, "%s%s%d\n", integer_asm_op (UNITS_PER_WORD, TRUE), \
- LPREFIX, VALUE)
-
-/* This is how to output an element of a case-vector that is relative. */
-
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
- fprintf (FILE, "%s%s%d-%s%d\n", integer_asm_op (UNITS_PER_WORD, TRUE), \
- LPREFIX, VALUE, LPREFIX, REL)
-
-
-
-/* This is how to output an assembler line
- that says to advance the location counter
- to a multiple of 2**LOG bytes. */
-
-#undef ASM_OUTPUT_ALIGN
-#define ASM_OUTPUT_ALIGN(FILE, LOG) \
- if ((LOG)!=0) fprintf ((FILE), "\t.align\t%d\n", 1<<(LOG))
-
-/* This is how to output an assembler line
- that says to advance the location counter by SIZE bytes. */
-
-#undef ASM_OUTPUT_SKIP
-#define ASM_OUTPUT_SKIP(FILE, SIZE) \
- fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE))
-
-/* This is how to output assembler code to declare an
- uninitialized external linkage data object. */
-
-#undef ASM_OUTPUT_ALIGNED_BSS
-#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
- asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
-
-/* Output before read-only data. */
-
-#define TEXT_SECTION_ASM_OP ".text"
-
-/* Output before writable (initialized) data. */
-
-#define DATA_SECTION_ASM_OP ".data"
-
-/* Output before writable (uninitialized) data. */
-
-#define BSS_SECTION_ASM_OP ".bss"
-
-/* This is how to output a command to make the user-level label named NAME
- defined for reference from other files. */
-
-#define ASM_GLOBALIZE_LABEL(FILE, NAME) \
- (fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE))
-
-/* Select section for constant in constant pool.
- We are in the right section.
- undef for 64 bit mode (linux64.h).
- */
-
-#undef SELECT_RTX_SECTION
-#define SELECT_RTX_SECTION(MODE, X, ALIGN)
-
-
-/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
- Used for C++ multiple inheritance. */
-#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
-do { \
- if (TARGET_64BIT) \
- { \
- if (flag_pic) \
- { \
- fprintf (FILE, "\tlarl 1,0f\n"); \
- fprintf (FILE, "\tagf %d,0(1)\n", \
- aggregate_value_p (TREE_TYPE \
- (TREE_TYPE (FUNCTION))) ? 3 :2 ); \
- fprintf (FILE, "\tlarl 1,"); \
- assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
- fprintf (FILE, "@GOTENT\n"); \
- fprintf (FILE, "\tlg 1,0(1)\n"); \
- fprintf (FILE, "\tbr 1\n"); \
- fprintf (FILE, "0:\t.long "); \
- fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \
- fprintf (FILE, "\n"); \
- } \
- else \
- { \
- fprintf (FILE, "\tlarl 1,0f\n"); \
- fprintf (FILE, "\tagf %d,0(1)\n", \
- aggregate_value_p (TREE_TYPE \
- (TREE_TYPE (FUNCTION))) ? 3 :2 ); \
- fprintf (FILE, "\tjg "); \
- assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
- fprintf (FILE, "\n"); \
- fprintf (FILE, "0:\t.long "); \
- fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \
- fprintf (FILE, "\n"); \
- } \
- } \
- else \
- { \
- if (flag_pic) \
- { \
- fprintf (FILE, "\tbras 1,0f\n"); \
- fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_-.\n"); \
- fprintf (FILE, "\t.long "); \
- assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
- fprintf (FILE, "@GOT\n"); \
- fprintf (FILE, "\t.long "); \
- fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \
- fprintf (FILE, "\n"); \
- fprintf (FILE, "0:\tal %d,8(1)\n", \
- aggregate_value_p (TREE_TYPE \
- (TREE_TYPE (FUNCTION))) ? 3 : 2 ); \
- fprintf (FILE, "\tl 0,4(1)\n"); \
- fprintf (FILE, "\tal 1,0(1)\n"); \
- fprintf (FILE, "\talr 1,0\n"); \
- fprintf (FILE, "\tl 1,0(1)\n"); \
- fprintf (FILE, "\tbr 1\n"); \
- } else { \
- fprintf (FILE, "\tbras 1,0f\n"); \
- fprintf (FILE, "\t.long "); \
- assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
- fprintf (FILE, "-.\n"); \
- fprintf (FILE, "\t.long "); \
- fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, (DELTA)); \
- fprintf (FILE, "\n"); \
- fprintf (FILE, "0:\tal %d,4(1)\n", \
- aggregate_value_p (TREE_TYPE \
- (TREE_TYPE (FUNCTION))) ? 3 : 2 ); \
- fprintf (FILE, "\tal 1,0(1)\n"); \
- fprintf (FILE, "\tbr 1\n"); \
- } \
- } \
-} while (0)
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
+ do { \
+ unsigned char *pc_ = (CONTEXT)->ra; \
+ long new_cfa_; \
+ int i_; \
+ \
+ typedef struct \
+ { \
+ unsigned long psw_mask; \
+ unsigned long psw_addr; \
+ unsigned long gprs[16]; \
+ unsigned int acrs[16]; \
+ unsigned int fpc; \
+ unsigned int __pad; \
+ double fprs[16]; \
+ } __attribute__ ((__aligned__ (8))) sigregs_; \
+ \
+ sigregs_ *regs_; \
+ \
+ /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn */ \
+ if (pc_[0] != 0x0a || (pc_[1] != 119 && pc_[1] != 173)) \
+ break; \
+ \
+ /* New-style RT frame: \
+ retcode + alignment (8 bytes) \
+ siginfo (128 bytes) \
+ ucontext (contains sigregs) */ \
+ if ((CONTEXT)->ra == (CONTEXT)->cfa) \
+ { \
+ struct ucontext_ \
+ { \
+ unsigned long uc_flags; \
+ struct ucontext_ *uc_link; \
+ unsigned long uc_stack[3]; \
+ sigregs_ uc_mcontext; \
+ } *uc_ = (CONTEXT)->cfa + 8 + 128; \
+ \
+ regs_ = &uc_->uc_mcontext; \
+ } \
+ \
+ /* Old-style RT frame and all non-RT frames: \
+ old signal mask (8 bytes) \
+ pointer to sigregs */ \
+ else \
+ { \
+ regs_ = *(sigregs_ **)((CONTEXT)->cfa + 8); \
+ } \
+ \
+ new_cfa_ = regs_->gprs[15] + 16*sizeof(long) + 32; \
+ (FS)->cfa_how = CFA_REG_OFFSET; \
+ (FS)->cfa_reg = 15; \
+ (FS)->cfa_offset = \
+ new_cfa_ - (long) (CONTEXT)->cfa + 16*sizeof(long) + 32; \
+ \
+ for (i_ = 0; i_ < 16; i_++) \
+ { \
+ (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[i_].loc.offset = \
+ (long)&regs_->gprs[i_] - new_cfa_; \
+ } \
+ for (i_ = 0; i_ < 16; i_++) \
+ { \
+ (FS)->regs.reg[16+i_].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[16+i_].loc.offset = \
+ (long)&regs_->fprs[i_] - new_cfa_; \
+ } \
+ \
+ /* Load return addr from PSW into dummy register 32. */ \
+ (FS)->regs.reg[32].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[32].loc.offset = (long)&regs_->psw_addr - new_cfa_; \
+ (FS)->retaddr_column = 32; \
+ \
+ goto SUCCESS; \
+ } while (0)
#endif
diff --git a/contrib/gcc/config/s390/s390-modes.def b/contrib/gcc/config/s390/s390-modes.def
new file mode 100644
index 0000000..9f9d526
--- /dev/null
+++ b/contrib/gcc/config/s390/s390-modes.def
@@ -0,0 +1,38 @@
+/* Definitions of target machine for GNU compiler, for IBM S/390
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Contributed by Hartmut Penner (hpenner@de.ibm.com) and
+ Ulrich Weigand (uweigand@de.ibm.com).
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Add any extra modes needed to represent the condition code. */
+
+CC (CCZ)
+CC (CCA)
+CC (CCAP)
+CC (CCAN)
+CC (CCL)
+CC (CCL1)
+CC (CCL2)
+CC (CCU)
+CC (CCUR)
+CC (CCS)
+CC (CCSR)
+CC (CCT)
+CC (CCT1)
+CC (CCT2)
+CC (CCT3)
diff --git a/contrib/gcc/config/s390/s390-protos.h b/contrib/gcc/config/s390/s390-protos.h
index cd4ac10..1f8b144 100644
--- a/contrib/gcc/config/s390/s390-protos.h
+++ b/contrib/gcc/config/s390/s390-protos.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for IBM S/390.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com)
This file is part of GNU CC.
@@ -24,17 +24,16 @@ Boston, MA 02111-1307, USA. */
extern void optimization_options PARAMS ((int, int));
extern void override_options PARAMS ((void));
extern int s390_arg_frame_offset PARAMS ((void));
-extern void s390_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
-extern void s390_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
extern void s390_emit_prologue PARAMS ((void));
extern void s390_emit_epilogue PARAMS ((void));
extern void s390_function_profiler PARAMS ((FILE *, int));
#ifdef RTX_CODE
+extern int s390_address_cost PARAMS ((rtx));
+extern int q_constraint PARAMS ((rtx));
extern int const0_operand PARAMS ((rtx, enum machine_mode));
extern int consttable_operand PARAMS ((rtx, enum machine_mode));
extern int larl_operand PARAMS ((rtx, enum machine_mode));
-extern int fp_operand PARAMS ((rtx, enum machine_mode));
extern int s_operand PARAMS ((rtx, enum machine_mode));
extern int s_imm_operand PARAMS ((rtx, enum machine_mode));
extern int bras_sym_operand PARAMS ((rtx, enum machine_mode));
@@ -44,12 +43,17 @@ extern int s390_single_hi PARAMS ((rtx, enum machine_mode, int));
extern int s390_extract_hi PARAMS ((rtx, enum machine_mode, int));
extern int s390_single_qi PARAMS ((rtx, enum machine_mode, int));
extern int s390_extract_qi PARAMS ((rtx, enum machine_mode, int));
+extern bool s390_split_ok_p PARAMS ((rtx, rtx, enum machine_mode, int));
+extern int tls_symbolic_operand PARAMS ((rtx));
extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode));
+extern enum machine_mode s390_tm_ccmode PARAMS ((rtx, rtx, int));
extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx));
extern int symbolic_reference_mentioned_p PARAMS ((rtx));
+extern int tls_symbolic_reference_mentioned_p PARAMS ((rtx));
+extern rtx s390_tls_get_offset PARAMS ((void));
extern int legitimate_la_operand_p PARAMS ((rtx));
-extern rtx legitimize_la_operand PARAMS ((rtx));
+extern int preferred_la_operand_p PARAMS ((rtx));
extern int legitimate_pic_operand_p PARAMS ((rtx));
extern int legitimate_constant_p PARAMS ((rtx));
extern int legitimate_reload_constant_p PARAMS ((rtx));
@@ -58,18 +62,25 @@ extern rtx legitimize_pic_address PARAMS ((rtx, rtx));
extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
extern enum reg_class s390_preferred_reload_class PARAMS ((rtx, enum reg_class));
extern enum reg_class s390_secondary_input_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx));
+extern enum reg_class s390_secondary_output_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx));
extern int s390_plus_operand PARAMS ((rtx, enum machine_mode));
extern void s390_expand_plus_operand PARAMS ((rtx, rtx, rtx));
-extern void emit_pic_move PARAMS ((rtx *, enum machine_mode));
+extern void emit_symbolic_move PARAMS ((rtx *));
+extern void s390_load_address PARAMS ((rtx, rtx));
+extern void s390_expand_movstr PARAMS ((rtx, rtx, rtx));
+extern void s390_expand_clrstr PARAMS ((rtx, rtx));
+extern void s390_expand_cmpstr PARAMS ((rtx, rtx, rtx, rtx));
+extern rtx s390_return_addr_rtx PARAMS ((int, rtx));
extern void s390_output_symbolic_const PARAMS ((FILE *, rtx));
extern void print_operand_address PARAMS ((FILE *, rtx));
extern void print_operand PARAMS ((FILE *, rtx, int));
-extern void s390_output_constant_pool PARAMS ((FILE *));
+extern void s390_output_constant_pool PARAMS ((rtx, rtx));
extern void s390_trampoline_template PARAMS ((FILE *));
extern void s390_initialize_trampoline PARAMS ((rtx, rtx, rtx));
extern rtx s390_gen_rtx_const_DI PARAMS ((int, int));
extern rtx s390_simplify_dwarf_addr PARAMS ((rtx));
+extern void s390_machine_dependent_reorg PARAMS ((rtx));
#endif /* RTX_CODE */
#ifdef TREE_CODE
@@ -78,7 +89,7 @@ extern void s390_function_arg_advance PARAMS ((CUMULATIVE_ARGS *, enum machine_m
extern tree s390_build_va_list PARAMS ((void));
#ifdef RTX_CODE
extern rtx s390_function_arg PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int));
-extern void s390_va_start PARAMS ((int, tree, rtx));
+extern void s390_va_start PARAMS ((tree, rtx));
extern rtx s390_va_arg PARAMS ((tree, tree));
#endif /* RTX_CODE */
#endif /* TREE_CODE */
diff --git a/contrib/gcc/config/s390/s390.c b/contrib/gcc/config/s390/s390.c
index 4c96dce..d6fda65 100644
--- a/contrib/gcc/config/s390/s390.c
+++ b/contrib/gcc/config/s390/s390.c
@@ -1,5 +1,5 @@
/* Subroutines used for code generation on IBM S/390 and zSeries
- Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
Ulrich Weigand (uweigand@de.ibm.com).
@@ -45,11 +45,22 @@ Boston, MA 02111-1307, USA. */
#include "target.h"
#include "target-def.h"
#include "debug.h"
-
+#include "langhooks.h"
+#include "optabs.h"
static bool s390_assemble_integer PARAMS ((rtx, unsigned int, int));
static int s390_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int s390_adjust_priority PARAMS ((rtx, int));
+static void s390_select_rtx_section PARAMS ((enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT));
+static void s390_encode_section_info PARAMS ((tree, int));
+static const char *s390_strip_name_encoding PARAMS ((const char *));
+static bool s390_cannot_force_const_mem PARAMS ((rtx));
+static void s390_init_builtins PARAMS ((void));
+static rtx s390_expand_builtin PARAMS ((tree, rtx, rtx,
+ enum machine_mode, int));
+static void s390_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
+ HOST_WIDE_INT, tree));
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
@@ -58,24 +69,43 @@ static int s390_adjust_priority PARAMS ((rtx, int));
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER s390_assemble_integer
-#undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE s390_function_prologue
-
-#undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE s390_function_epilogue
-
#undef TARGET_ASM_OPEN_PAREN
#define TARGET_ASM_OPEN_PAREN ""
#undef TARGET_ASM_CLOSE_PAREN
#define TARGET_ASM_CLOSE_PAREN ""
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define TARGET_ASM_SELECT_RTX_SECTION s390_select_rtx_section
+
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST s390_adjust_cost
#undef TARGET_SCHED_ADJUST_PRIORITY
#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO s390_encode_section_info
+#undef TARGET_STRIP_NAME_ENCODING
+#define TARGET_STRIP_NAME_ENCODING s390_strip_name_encoding
+
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM s390_cannot_force_const_mem
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS s390_init_builtins
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN s390_expand_builtin
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK s390_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+
struct gcc_target targetm = TARGET_INITIALIZER;
extern int reload_completed;
@@ -83,13 +113,13 @@ extern int reload_completed;
/* The alias set for prologue/epilogue register save/restore. */
static int s390_sr_alias_set = 0;
-/* Function count for creating unique internal labels in a compile unit. */
-int s390_function_count = 0;
-
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
rtx s390_compare_op0, s390_compare_op1;
+/* The encoding characters for the four TLS models present in ELF. */
+static char const tls_model_chars[] = " GLil";
+
/* Structure used to hold the components of a S/390 memory
address. A legitimate address on S/390 is of the general
form
@@ -107,19 +137,26 @@ struct s390_address
int pointer;
};
-/* Structure containing information for prologue and epilogue. */
+/* Define the structure for the machine field in struct function. */
-struct s390_frame
+struct machine_function GTY(())
{
- int frame_pointer_p;
- int return_reg_saved_p;
+ /* Label of start of initial literal pool. */
+ rtx literal_pool_label;
+
+ /* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
int save_fprs_p;
+
+ /* Number of first and last gpr to be saved, restored. */
int first_save_gpr;
int first_restore_gpr;
int last_save_gpr;
- int arg_frame_offset;
+ /* Size of stack frame. */
HOST_WIDE_INT frame_size;
+
+ /* Some local-dynamic TLS symbol name. */
+ const char *some_ld_name;
};
static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));
@@ -127,20 +164,29 @@ static int s390_branch_condition_mask PARAMS ((rtx));
static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));
static int check_mode PARAMS ((rtx, enum machine_mode *));
static int general_s_operand PARAMS ((rtx, enum machine_mode, int));
-static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
+static int s390_decompose_address PARAMS ((rtx, struct s390_address *));
+static rtx get_thread_pointer PARAMS ((void));
+static rtx legitimize_tls_address PARAMS ((rtx, rtx));
+static const char *get_some_local_dynamic_name PARAMS ((void));
+static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
static int reg_used_in_mem_p PARAMS ((int, rtx));
static int addr_generation_dependency_p PARAMS ((rtx, rtx));
-static void s390_split_branches PARAMS ((void));
+static int s390_split_branches PARAMS ((rtx, bool *));
static void find_constant_pool_ref PARAMS ((rtx, rtx *));
static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));
-static void s390_chunkify_pool PARAMS ((void));
-static int save_fprs_p PARAMS ((void));
+static int find_base_register_in_addr PARAMS ((struct s390_address *));
+static bool find_base_register_ref PARAMS ((rtx));
+static void replace_base_register_ref PARAMS ((rtx *, rtx));
+static void s390_optimize_prolog PARAMS ((int));
+static bool s390_fixup_clobbered_return_reg PARAMS ((rtx));
static int find_unused_clobbered_reg PARAMS ((void));
-static void s390_frame_info PARAMS ((struct s390_frame *));
+static void s390_frame_info PARAMS ((void));
static rtx save_fpr PARAMS ((rtx, int, int));
static rtx restore_fpr PARAMS ((rtx, int, int));
+static rtx save_gprs PARAMS ((rtx, int, int, int));
+static rtx restore_gprs PARAMS ((rtx, int, int, int));
static int s390_function_arg_size PARAMS ((enum machine_mode, tree));
-
+static struct machine_function * s390_init_machine_status PARAMS ((void));
/* Return true if SET either doesn't set the CC register, or else
the source and destination have matching CC modes and that
@@ -163,19 +209,28 @@ s390_match_ccmode_set (set, req_mode)
switch (set_mode)
{
case CCSmode:
- if (req_mode != CCSmode)
- return 0;
- break;
+ case CCSRmode:
case CCUmode:
- if (req_mode != CCUmode)
- return 0;
- break;
+ case CCURmode:
case CCLmode:
- if (req_mode != CCLmode)
+ case CCL1mode:
+ case CCL2mode:
+ case CCT1mode:
+ case CCT2mode:
+ case CCT3mode:
+ if (req_mode != set_mode)
return 0;
break;
+
case CCZmode:
- if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode)
+ if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode
+ && req_mode != CCSRmode && req_mode != CCURmode)
+ return 0;
+ break;
+
+ case CCAPmode:
+ case CCANmode:
+ if (req_mode != CCAmode)
return 0;
break;
@@ -188,7 +243,8 @@ s390_match_ccmode_set (set, req_mode)
/* Return true if every SET in INSN that sets the CC register
has source and destination with matching CC modes and that
- CC mode is at least as constrained as REQ_MODE. */
+ CC mode is at least as constrained as REQ_MODE.
+ If REQ_MODE is VOIDmode, always return false. */
int
s390_match_ccmode (insn, req_mode)
@@ -197,6 +253,10 @@ s390_match_ccmode (insn, req_mode)
{
int i;
+ /* s390_tm_ccmode returns VOIDmode to indicate failure. */
+ if (req_mode == VOIDmode)
+ return 0;
+
if (GET_CODE (PATTERN (insn)) == SET)
return s390_match_ccmode_set (PATTERN (insn), req_mode);
@@ -212,6 +272,45 @@ s390_match_ccmode (insn, req_mode)
return 1;
}
+/* If a test-under-mask instruction can be used to implement
+ (compare (and ... OP1) OP2), return the CC mode required
+ to do that. Otherwise, return VOIDmode.
+ MIXED is true if the instruction can distinguish between
+ CC1 and CC2 for mixed selected bits (TMxx), it is false
+ if the instruction cannot (TM). */
+
+enum machine_mode
+s390_tm_ccmode (op1, op2, mixed)
+ rtx op1;
+ rtx op2;
+ int mixed;
+{
+ int bit0, bit1;
+
+ /* ??? Fixme: should work on CONST_DOUBLE as well. */
+ if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT)
+ return VOIDmode;
+
+ /* Selected bits all zero: CC0. */
+ if (INTVAL (op2) == 0)
+ return CCTmode;
+
+ /* Selected bits all one: CC3. */
+ if (INTVAL (op2) == INTVAL (op1))
+ return CCT3mode;
+
+ /* Exactly two bits selected, mixed zeroes and ones: CC1 or CC2. */
+ if (mixed)
+ {
+ bit1 = exact_log2 (INTVAL (op2));
+ bit0 = exact_log2 (INTVAL (op1) ^ INTVAL (op2));
+ if (bit0 != -1 && bit1 != -1)
+ return bit0 > bit1 ? CCT1mode : CCT2mode;
+ }
+
+ return VOIDmode;
+}
+
/* Given a comparison code OP (EQ, NE, etc.) and the operands
OP0 and OP1 of a COMPARE, return the mode to be used for the
comparison. */
@@ -226,16 +325,49 @@ s390_select_ccmode (code, op0, op1)
{
case EQ:
case NE:
+ if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op0, 1)), 'K'))
+ return CCAPmode;
if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
|| GET_CODE (op1) == NEG)
return CCLmode;
+ if (GET_CODE (op0) == AND)
+ {
+ /* Check whether we can potentially do it via TM. */
+ enum machine_mode ccmode;
+ ccmode = s390_tm_ccmode (XEXP (op0, 1), op1, 1);
+ if (ccmode != VOIDmode)
+ {
+ /* Relax CCTmode to CCZmode to allow fall-back to AND
+ if that turns out to be beneficial. */
+ return ccmode == CCTmode ? CCZmode : ccmode;
+ }
+ }
+
+ if (register_operand (op0, HImode)
+ && GET_CODE (op1) == CONST_INT
+ && (INTVAL (op1) == -1 || INTVAL (op1) == 65535))
+ return CCT3mode;
+ if (register_operand (op0, QImode)
+ && GET_CODE (op1) == CONST_INT
+ && (INTVAL (op1) == -1 || INTVAL (op1) == 255))
+ return CCT3mode;
+
return CCZmode;
case LE:
case LT:
case GE:
case GT:
+ if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op0, 1)), 'K'))
+ {
+ if (INTVAL (XEXP((op0), 1)) < 0)
+ return CCANmode;
+ else
+ return CCAPmode;
+ }
case UNORDERED:
case ORDERED:
case UNEQ:
@@ -244,12 +376,29 @@ s390_select_ccmode (code, op0, op1)
case UNGE:
case UNGT:
case LTGT:
+ if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
+ && GET_CODE (op1) != CONST_INT)
+ return CCSRmode;
return CCSmode;
- case LEU:
case LTU:
case GEU:
+ if (GET_CODE (op0) == PLUS)
+ return CCL1mode;
+
+ if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
+ && GET_CODE (op1) != CONST_INT)
+ return CCURmode;
+ return CCUmode;
+
+ case LEU:
case GTU:
+ if (GET_CODE (op0) == MINUS)
+ return CCL2mode;
+
+ if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND)
+ && GET_CODE (op1) != CONST_INT)
+ return CCURmode;
return CCUmode;
default:
@@ -286,13 +435,61 @@ s390_branch_condition_mask (code)
}
break;
+ case CCT1mode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC1;
+ case NE: return CC0 | CC2 | CC3;
+ default:
+ abort ();
+ }
+ break;
+
+ case CCT2mode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC2;
+ case NE: return CC0 | CC1 | CC3;
+ default:
+ abort ();
+ }
+ break;
+
+ case CCT3mode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC3;
+ case NE: return CC0 | CC1 | CC2;
+ default:
+ abort ();
+ }
+ break;
+
case CCLmode:
switch (GET_CODE (code))
{
case EQ: return CC0 | CC2;
case NE: return CC1 | CC3;
- case UNORDERED: return CC2 | CC3; /* carry */
- case ORDERED: return CC0 | CC1; /* no carry */
+ default:
+ abort ();
+ }
+ break;
+
+ case CCL1mode:
+ switch (GET_CODE (code))
+ {
+ case LTU: return CC2 | CC3; /* carry */
+ case GEU: return CC0 | CC1; /* no carry */
+ default:
+ abort ();
+ }
+ break;
+
+ case CCL2mode:
+ switch (GET_CODE (code))
+ {
+ case GTU: return CC0 | CC1; /* borrow */
+ case LEU: return CC2 | CC3; /* no borrow */
default:
abort ();
}
@@ -312,6 +509,48 @@ s390_branch_condition_mask (code)
}
break;
+ case CCURmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC2 | CC1 | CC3;
+ case LTU: return CC2;
+ case GTU: return CC1;
+ case LEU: return CC0 | CC2;
+ case GEU: return CC0 | CC1;
+ default:
+ abort ();
+ }
+ break;
+
+ case CCAPmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC1 | CC2 | CC3;
+ case LT: return CC1 | CC3;
+ case GT: return CC2;
+ case LE: return CC0 | CC1 | CC3;
+ case GE: return CC0 | CC2;
+ default:
+ abort ();
+ }
+ break;
+
+ case CCANmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC1 | CC2 | CC3;
+ case LT: return CC1;
+ case GT: return CC2 | CC3;
+ case LE: return CC0 | CC1;
+ case GE: return CC0 | CC2 | CC3;
+ default:
+ abort ();
+ }
+ break;
+
case CCSmode:
switch (GET_CODE (code))
{
@@ -332,6 +571,29 @@ s390_branch_condition_mask (code)
default:
abort ();
}
+ break;
+
+ case CCSRmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC2 | CC1 | CC3;
+ case LT: return CC2;
+ case GT: return CC1;
+ case LE: return CC0 | CC2;
+ case GE: return CC0 | CC1;
+ case UNORDERED: return CC3;
+ case ORDERED: return CC0 | CC2 | CC1;
+ case UNEQ: return CC0 | CC3;
+ case UNLT: return CC2 | CC3;
+ case UNGT: return CC1 | CC3;
+ case UNLE: return CC0 | CC2 | CC3;
+ case UNGE: return CC0 | CC1 | CC3;
+ case LTGT: return CC2 | CC1;
+ default:
+ abort ();
+ }
+ break;
default:
abort ();
@@ -347,7 +609,7 @@ s390_branch_condition_mnemonic (code, inv)
rtx code;
int inv;
{
- static const char *mnemonic[16] =
+ static const char *const mnemonic[16] =
{
NULL, "o", "h", "nle",
"l", "nhe", "lh", "ne",
@@ -379,7 +641,7 @@ s390_single_hi (op, mode, def)
{
if (GET_CODE (op) == CONST_INT)
{
- unsigned HOST_WIDE_INT value;
+ unsigned HOST_WIDE_INT value = 0;
int n_parts = GET_MODE_SIZE (mode) / 2;
int i, part = -1;
@@ -405,7 +667,7 @@ s390_single_hi (op, mode, def)
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode)
{
- unsigned HOST_WIDE_INT value;
+ unsigned HOST_WIDE_INT value = 0;
int n_parts = GET_MODE_SIZE (mode) / 2;
int i, part = -1;
@@ -482,7 +744,7 @@ s390_single_qi (op, mode, def)
{
if (GET_CODE (op) == CONST_INT)
{
- unsigned HOST_WIDE_INT value;
+ unsigned HOST_WIDE_INT value = 0;
int n_parts = GET_MODE_SIZE (mode);
int i, part = -1;
@@ -508,7 +770,7 @@ s390_single_qi (op, mode, def)
else if (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode)
{
- unsigned HOST_WIDE_INT value;
+ unsigned HOST_WIDE_INT value = 0;
int n_parts = GET_MODE_SIZE (mode);
int i, part = -1;
@@ -572,6 +834,42 @@ s390_extract_qi (op, mode, part)
abort ();
}
+/* Check whether we can (and want to) split a double-word
+ move in mode MODE from SRC to DST into two single-word
+ moves, moving the subword FIRST_SUBWORD first. */
+
+bool
+s390_split_ok_p (dst, src, mode, first_subword)
+ rtx dst;
+ rtx src;
+ enum machine_mode mode;
+ int first_subword;
+{
+ /* Floating point registers cannot be split. */
+ if (FP_REG_P (src) || FP_REG_P (dst))
+ return false;
+
+ /* We don't need to split if operands are directly accessable. */
+ if (s_operand (src, mode) || s_operand (dst, mode))
+ return false;
+
+ /* Non-offsettable memory references cannot be split. */
+ if ((GET_CODE (src) == MEM && !offsettable_memref_p (src))
+ || (GET_CODE (dst) == MEM && !offsettable_memref_p (dst)))
+ return false;
+
+ /* Moving the first subword must not clobber a register
+ needed to move the second subword. */
+ if (register_operand (dst, mode))
+ {
+ rtx subreg = operand_subword (dst, first_subword, 0, mode);
+ if (reg_overlap_mentioned_p (subreg, src))
+ return false;
+ }
+
+ return true;
+}
+
/* Change optimizations to be performed, depending on the
optimization level.
@@ -579,18 +877,19 @@ s390_extract_qi (op, mode, part)
LEVEL is the optimization level specified; 2 if `-O2' is
specified, 1 if `-O' is specified, and 0 if neither is specified.
- SIZE is non-zero if `-Os' is specified and zero otherwise. */
+ SIZE is nonzero if `-Os' is specified and zero otherwise. */
void
optimization_options (level, size)
int level ATTRIBUTE_UNUSED;
int size ATTRIBUTE_UNUSED;
{
-#ifdef HAVE_decrement_and_branch_on_count
- /* When optimizing, enable use of BRCT instruction. */
- if (level >= 1)
- flag_branch_on_count_reg = 1;
-#endif
+ /* ??? There are apparently still problems with -fcaller-saves. */
+ flag_caller_saves = 0;
+
+ /* By default, always emit DWARF-2 unwind info. This allows debugging
+ without maintaining a stack frame back-chain. */
+ flag_asynchronous_unwind_tables = 1;
}
void
@@ -598,12 +897,14 @@ override_options ()
{
/* Acquire a unique set number for our register saves and restores. */
s390_sr_alias_set = new_alias_set ();
-}
+ /* Set up function hooks. */
+ init_machine_status = s390_init_machine_status;
+}
/* Map for smallest class containing reg regno. */
-enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
+const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
{ GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
@@ -674,6 +975,8 @@ larl_operand (op, mode)
if (GET_CODE (op) == LABEL_REF)
return 1;
if (GET_CODE (op) == SYMBOL_REF
+ && XSTR (op, 0)[0] != '@'
+ && !tls_symbolic_operand (op)
&& (!flag_pic || SYMBOL_REF_FLAG (op)
|| CONSTANT_POOL_ADDRESS_P (op)))
return 1;
@@ -696,39 +999,27 @@ larl_operand (op, mode)
if (GET_CODE (op) == LABEL_REF)
return 1;
if (GET_CODE (op) == SYMBOL_REF
+ && XSTR (op, 0)[0] != '@'
+ && !tls_symbolic_operand (op)
&& (!flag_pic || SYMBOL_REF_FLAG (op)
|| CONSTANT_POOL_ADDRESS_P (op)))
return 1;
- /* Now we must have a @GOTENT offset or @PLT stub. */
+ /* Now we must have a @GOTENT offset or @PLT stub
+ or an @INDNTPOFF TLS offset. */
if (GET_CODE (op) == UNSPEC
&& XINT (op, 1) == 111)
return 1;
if (GET_CODE (op) == UNSPEC
&& XINT (op, 1) == 113)
return 1;
+ if (GET_CODE (op) == UNSPEC
+ && XINT (op, 1) == UNSPEC_INDNTPOFF)
+ return 1;
return 0;
}
-/* Return true if OP is a valid FP-Register.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-fp_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- register enum rtx_code code = GET_CODE (op);
- if (! check_mode (op, &mode))
- return 0;
- if (code == REG && REGNO_OK_FOR_FP_P (REGNO (op)))
- return 1;
- else
- return 0;
-}
-
/* Helper routine to implement s_operand and s_imm_operand.
OP is the current operation.
MODE is the current operation mode.
@@ -777,7 +1068,7 @@ general_s_operand (op, mode, allow_immediate)
case MEM:
if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
return 1;
- if (s390_decompose_address (XEXP (op, 0), &addr, FALSE)
+ if (s390_decompose_address (XEXP (op, 0), &addr)
&& !addr.indx)
return 1;
break;
@@ -815,6 +1106,41 @@ s_imm_operand (op, mode)
return general_s_operand (op, mode, 1);
}
+/* Return true if OP is a valid operand for a 'Q' constraint.
+ This differs from s_operand in that only memory operands
+ without index register are accepted, nothing else. */
+
+int
+q_constraint (op)
+ register rtx op;
+{
+ struct s390_address addr;
+
+ if (GET_CODE (op) != MEM)
+ return 0;
+
+ if (!s390_decompose_address (XEXP (op, 0), &addr))
+ return 0;
+
+ if (addr.indx)
+ return 0;
+
+ return 1;
+}
+
+/* Return the cost of an address rtx ADDR. */
+
+int
+s390_address_cost (addr)
+ rtx addr;
+{
+ struct s390_address ad;
+ if (!s390_decompose_address (addr, &ad))
+ return 1000;
+
+ return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1);
+}
+
/* Return true if OP is a valid operand for the BRAS instruction.
OP is the current operation.
MODE is the current operation mode. */
@@ -838,6 +1164,23 @@ bras_sym_operand (op, mode)
return 0;
}
+/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
+ otherwise return 0. */
+
+int
+tls_symbolic_operand (op)
+ register rtx op;
+{
+ const char *symbol_str;
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+ symbol_str = XSTR (op, 0);
+
+ if (symbol_str[0] != '%')
+ return 0;
+ return strchr (tls_model_chars, symbol_str[1]) - tls_model_chars;
+}
/* Return true if OP is a load multiple operation. It is known to be a
PARALLEL and the first section will be tested.
@@ -997,6 +1340,37 @@ symbolic_reference_mentioned_p (op)
return 0;
}
+/* Return true if OP contains a reference to a thread-local symbol. */
+
+int
+tls_symbolic_reference_mentioned_p (op)
+ rtx op;
+{
+ register const char *fmt;
+ register int i;
+
+ if (GET_CODE (op) == SYMBOL_REF)
+ return tls_symbolic_operand (op);
+
+ fmt = GET_RTX_FORMAT (GET_CODE (op));
+ for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ register int j;
+
+ for (j = XVECLEN (op, i) - 1; j >= 0; j--)
+ if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
+ return 1;
+ }
+
+ else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
/* Return true if OP is a legitimate general operand when
generating PIC code. It is given that flag_pic is on
@@ -1011,7 +1385,7 @@ legitimate_pic_operand_p (op)
return 1;
/* Reject everything else; must be handled
- via emit_pic_move. */
+ via emit_symbolic_move. */
return 0;
}
@@ -1026,22 +1400,87 @@ legitimate_constant_p (op)
if (!SYMBOLIC_CONST (op))
return 1;
+ /* Accept immediate LARL operands. */
+ if (TARGET_64BIT && larl_operand (op, VOIDmode))
+ return 1;
+
+ /* Thread-local symbols are never legal constants. This is
+ so that emit_call knows that computing such addresses
+ might require a function call. */
+ if (TLS_SYMBOLIC_CONST (op))
+ return 0;
+
/* In the PIC case, symbolic constants must *not* be
forced into the literal pool. We accept them here,
- so that they will be handled by emit_pic_move. */
+ so that they will be handled by emit_symbolic_move. */
if (flag_pic)
return 1;
- /* Even in the non-PIC case, we can accept immediate
- LARL operands here. */
- if (TARGET_64BIT)
- return larl_operand (op, VOIDmode);
-
/* All remaining non-PIC symbolic constants are
forced into the literal pool. */
return 0;
}
+/* Determine if it's legal to put X into the constant pool. This
+ is not possible if X contains the address of a symbol that is
+ not constant (TLS) or not known at final link time (PIC). */
+
+static bool
+s390_cannot_force_const_mem (x)
+ rtx x;
+{
+ switch (GET_CODE (x))
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ /* Accept all non-symbolic constants. */
+ return false;
+
+ case LABEL_REF:
+ /* Labels are OK iff we are non-PIC. */
+ return flag_pic != 0;
+
+ case SYMBOL_REF:
+ /* 'Naked' TLS symbol references are never OK,
+ non-TLS symbols are OK iff we are non-PIC. */
+ if (tls_symbolic_operand (x))
+ return true;
+ else
+ return flag_pic != 0;
+
+ case CONST:
+ return s390_cannot_force_const_mem (XEXP (x, 0));
+ case PLUS:
+ case MINUS:
+ return s390_cannot_force_const_mem (XEXP (x, 0))
+ || s390_cannot_force_const_mem (XEXP (x, 1));
+
+ case UNSPEC:
+ switch (XINT (x, 1))
+ {
+ /* Only lt-relative or GOT-relative UNSPECs are OK. */
+ case 100:
+ case 104:
+ case 112:
+ case 114:
+ case UNSPEC_TLSGD:
+ case UNSPEC_TLSLDM:
+ case UNSPEC_NTPOFF:
+ case UNSPEC_DTPOFF:
+ case UNSPEC_GOTNTPOFF:
+ case UNSPEC_INDNTPOFF:
+ return false;
+
+ default:
+ return true;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+}
+
/* Returns true if the constant value OP is a legitimate general
operand during and after reload. The difference to
legitimate_constant_p is that this function will not accept
@@ -1067,15 +1506,6 @@ legitimate_reload_constant_p (op)
&& larl_operand (op, VOIDmode))
return 1;
- /* If reload is completed, and we do not already have a
- literal pool, and OP must be forced to the literal
- pool, then something must have gone wrong earlier.
- We *cannot* force the constant any more, because the
- prolog generation already decided we don't need to
- set up the base register. */
- if (reload_completed && !regs_ever_live[BASE_REGISTER])
- abort ();
-
/* Everything else cannot be handled without reload. */
return 0;
}
@@ -1097,23 +1527,14 @@ s390_preferred_reload_class (op, class)
switch (GET_CODE (op))
{
/* Constants we cannot reload must be forced into the
- literal pool. For constants we *could* handle directly,
- it might still be preferable to put them in the pool and
- use a memory-to-memory instruction.
-
- However, try to avoid needlessly allocating a literal
- pool in a routine that wouldn't otherwise need any.
- Heuristically, we assume that 64-bit leaf functions
- typically don't need a literal pool, all others do. */
+ literal pool. */
+
case CONST_DOUBLE:
case CONST_INT:
- if (!legitimate_reload_constant_p (op))
- return NO_REGS;
-
- if (TARGET_64BIT && current_function_is_leaf)
+ if (legitimate_reload_constant_p (op))
return class;
-
- return NO_REGS;
+ else
+ return NO_REGS;
/* If a symbolic constant or a PLUS is reloaded,
it is most likely being used as an address, so
@@ -1153,6 +1574,29 @@ s390_secondary_input_reload_class (class, mode, in)
return NO_REGS;
}
+/* Return the register class of a scratch register needed to
+ store a register of class CLASS in MODE into OUT:
+
+ We need a temporary when storing a double-word to a
+ non-offsettable memory address. */
+
+enum reg_class
+s390_secondary_output_reload_class (class, mode, out)
+ enum reg_class class;
+ enum machine_mode mode;
+ rtx out;
+{
+ if ((TARGET_64BIT ? mode == TImode
+ : (mode == DImode || mode == DFmode))
+ && reg_classes_intersect_p (GENERAL_REGS, class)
+ && GET_CODE (out) == MEM
+ && !offsettable_memref_p (out)
+ && !s_operand (out, VOIDmode))
+ return ADDR_REGS;
+
+ return NO_REGS;
+}
+
/* Return true if OP is a PLUS that is not a legitimate
operand for the LA instruction.
OP is the current operation.
@@ -1180,21 +1624,13 @@ s390_plus_operand (op, mode)
SCRATCH may be used as scratch register. */
void
-s390_expand_plus_operand (target, src, scratch_in)
+s390_expand_plus_operand (target, src, scratch)
register rtx target;
register rtx src;
- register rtx scratch_in;
+ register rtx scratch;
{
- rtx sum1, sum2, scratch;
-
- /* ??? reload apparently does not ensure that the scratch register
- and the target do not overlap. We absolutely require this to be
- the case, however. Therefore the reload_in[sd]i patterns ask for
- a double-sized scratch register, and if one part happens to be
- equal to the target, we use the other one. */
- scratch = gen_rtx_REG (Pmode, REGNO (scratch_in));
- if (rtx_equal_p (scratch, target))
- scratch = gen_rtx_REG (Pmode, REGNO (scratch_in) + 1);
+ rtx sum1, sum2;
+ struct s390_address ad;
/* src must be a PLUS; get its two operands. */
if (GET_CODE (src) != PLUS || GET_MODE (src) != Pmode)
@@ -1205,58 +1641,49 @@ s390_expand_plus_operand (target, src, scratch_in)
float registers occur in an address. */
sum1 = find_replacement (&XEXP (src, 0));
sum2 = find_replacement (&XEXP (src, 1));
+ src = gen_rtx_PLUS (Pmode, sum1, sum2);
- /* If one of the two operands is equal to the target,
- make it the first one. If one is a constant, make
- it the second one. */
- if (rtx_equal_p (target, sum2)
- || GET_CODE (sum1) == CONST_INT)
+ /* If the address is already strictly valid, there's nothing to do. */
+ if (!s390_decompose_address (src, &ad)
+ || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
+ || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx)))
{
- rtx tem = sum2;
- sum2 = sum1;
- sum1 = tem;
- }
+ /* Otherwise, one of the operands cannot be an address register;
+ we reload its value into the scratch register. */
+ if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15)
+ {
+ emit_move_insn (scratch, sum1);
+ sum1 = scratch;
+ }
+ if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15)
+ {
+ emit_move_insn (scratch, sum2);
+ sum2 = scratch;
+ }
- /* If the first operand is not an address register,
- we reload it into the target. */
- if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15)
- {
- emit_move_insn (target, sum1);
- sum1 = target;
- }
+ /* According to the way these invalid addresses are generated
+ in reload.c, it should never happen (at least on s390) that
+ *neither* of the PLUS components, after find_replacements
+ was applied, is an address register. */
+ if (sum1 == scratch && sum2 == scratch)
+ {
+ debug_rtx (src);
+ abort ();
+ }
- /* Likewise for the second operand. However, take
- care not to clobber the target if we already used
- it for the first operand. Use the scratch instead.
- Also, allow an immediate offset if it is in range. */
- if ((true_regnum (sum2) < 1 || true_regnum (sum2) > 15)
- && !(GET_CODE (sum2) == CONST_INT
- && INTVAL (sum2) >= 0 && INTVAL (sum2) < 4096))
- {
- if (!rtx_equal_p (target, sum1))
- {
- emit_move_insn (target, sum2);
- sum2 = target;
- }
- else
- {
- emit_move_insn (scratch, sum2);
- sum2 = scratch;
- }
+ src = gen_rtx_PLUS (Pmode, sum1, sum2);
}
/* Emit the LOAD ADDRESS pattern. Note that reload of PLUS
is only ever performed on addresses, so we can mark the
sum as legitimate for LA in any case. */
- src = gen_rtx_PLUS (Pmode, sum1, sum2);
- src = legitimize_la_operand (src);
- emit_insn (gen_rtx_SET (VOIDmode, target, src));
+ s390_load_address (target, src);
}
/* Decompose a RTL expression ADDR for a memory address into
- its components, returned in OUT. The boolean STRICT
- specifies whether strict register checking applies.
+ its components, returned in OUT.
+
Returns 0 if ADDR is not a valid memory address, nonzero
otherwise. If OUT is NULL, don't return the components,
but check for validity only.
@@ -1266,10 +1693,9 @@ s390_expand_plus_operand (target, src, scratch_in)
canonical form so that they will be recognized. */
static int
-s390_decompose_address (addr, out, strict)
+s390_decompose_address (addr, out)
register rtx addr;
struct s390_address *out;
- int strict;
{
rtx base = NULL_RTX;
rtx indx = NULL_RTX;
@@ -1320,6 +1746,22 @@ s390_decompose_address (addr, out, strict)
disp = addr; /* displacement */
+ /* Prefer to use pointer as base, not index. */
+ if (base && indx)
+ {
+ int base_ptr = GET_CODE (base) == UNSPEC
+ || (REG_P (base) && REG_POINTER (base));
+ int indx_ptr = GET_CODE (indx) == UNSPEC
+ || (REG_P (indx) && REG_POINTER (indx));
+
+ if (!base_ptr && indx_ptr)
+ {
+ rtx tmp = base;
+ base = indx;
+ indx = tmp;
+ }
+ }
+
/* Validate base register. */
if (base)
{
@@ -1334,16 +1776,15 @@ s390_decompose_address (addr, out, strict)
if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
return FALSE;
- if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
- || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
- return FALSE;
-
if (REGNO (base) == BASE_REGISTER
|| REGNO (base) == STACK_POINTER_REGNUM
|| REGNO (base) == FRAME_POINTER_REGNUM
|| ((reload_completed || reload_in_progress)
&& frame_pointer_needed
&& REGNO (base) == HARD_FRAME_POINTER_REGNUM)
+ || REGNO (base) == ARG_POINTER_REGNUM
+ || (REGNO (base) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (base) <= LAST_VIRTUAL_REGISTER)
|| (flag_pic
&& REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
pointer = TRUE;
@@ -1363,16 +1804,15 @@ s390_decompose_address (addr, out, strict)
if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
return FALSE;
- if ((strict && ! REG_OK_FOR_BASE_STRICT_P (indx))
- || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (indx)))
- return FALSE;
-
if (REGNO (indx) == BASE_REGISTER
|| REGNO (indx) == STACK_POINTER_REGNUM
|| REGNO (indx) == FRAME_POINTER_REGNUM
|| ((reload_completed || reload_in_progress)
&& frame_pointer_needed
&& REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
+ || REGNO (indx) == ARG_POINTER_REGNUM
+ || (REGNO (indx) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (indx) <= LAST_VIRTUAL_REGISTER)
|| (flag_pic
&& REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
pointer = TRUE;
@@ -1384,15 +1824,27 @@ s390_decompose_address (addr, out, strict)
/* Allow integer constant in range. */
if (GET_CODE (disp) == CONST_INT)
{
- if (INTVAL (disp) < 0 || INTVAL (disp) >= 4096)
- return FALSE;
+ /* If the argument pointer is involved, the displacement will change
+ later anyway as the argument pointer gets eliminated. This could
+ make a valid displacement invalid, but it is more likely to make
+ an invalid displacement valid, because we sometimes access the
+ register save area via negative offsets to the arg pointer.
+ Thus we don't check the displacement for validity here. If after
+ elimination the displacement turns out to be invalid after all,
+ this is fixed up by reload in any case. */
+ if (base != arg_pointer_rtx && indx != arg_pointer_rtx)
+ {
+ if (INTVAL (disp) < 0 || INTVAL (disp) >= 4096)
+ return FALSE;
+ }
}
/* In the small-PIC case, the linker converts @GOT12
- offsets to possible displacements. */
+ and @GOTNTPOFF offsets to possible displacements. */
else if (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (disp, 0)) == UNSPEC
- && XINT (XEXP (disp, 0), 1) == 110)
+ && (XINT (XEXP (disp, 0), 1) == 110
+ || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
{
if (flag_pic != 1)
return FALSE;
@@ -1442,12 +1894,6 @@ s390_decompose_address (addr, out, strict)
|| !CONSTANT_POOL_ADDRESS_P (disp))
return FALSE;
- /* In 64-bit PIC mode we cannot accept symbolic
- constants in the constant pool. */
- if (TARGET_64BIT && flag_pic
- && SYMBOLIC_CONST (get_pool_constant (disp)))
- return FALSE;
-
/* If we have an offset, make sure it does not
exceed the size of the constant pool entry. */
if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp)))
@@ -1497,7 +1943,26 @@ legitimate_address_p (mode, addr, strict)
register rtx addr;
int strict;
{
- return s390_decompose_address (addr, NULL, strict);
+ struct s390_address ad;
+ if (!s390_decompose_address (addr, &ad))
+ return FALSE;
+
+ if (strict)
+ {
+ if (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
+ return FALSE;
+ if (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx))
+ return FALSE;
+ }
+ else
+ {
+ if (ad.base && !REG_OK_FOR_BASE_NONSTRICT_P (ad.base))
+ return FALSE;
+ if (ad.indx && !REG_OK_FOR_INDEX_NONSTRICT_P (ad.indx))
+ return FALSE;
+ }
+
+ return TRUE;
}
/* Return 1 if OP is a valid operand for the LA instruction.
@@ -1509,7 +1974,7 @@ legitimate_la_operand_p (op)
register rtx op;
{
struct s390_address addr;
- if (!s390_decompose_address (op, &addr, FALSE))
+ if (!s390_decompose_address (op, &addr))
return FALSE;
if (TARGET_64BIT || addr.pointer)
@@ -1518,30 +1983,43 @@ legitimate_la_operand_p (op)
return FALSE;
}
-/* Return a modified variant of OP that is guaranteed to
- be accepted by legitimate_la_operand_p. */
-
-rtx
-legitimize_la_operand (op)
+/* Return 1 if OP is a valid operand for the LA instruction,
+ and we prefer to use LA over addition to compute it. */
+
+int
+preferred_la_operand_p (op)
register rtx op;
{
struct s390_address addr;
- if (!s390_decompose_address (op, &addr, FALSE))
- abort ();
+ if (!s390_decompose_address (op, &addr))
+ return FALSE;
- if (TARGET_64BIT || addr.pointer)
- return op;
+ if (!TARGET_64BIT && !addr.pointer)
+ return FALSE;
- if (!addr.base)
- abort ();
+ if (addr.pointer)
+ return TRUE;
- op = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr.base), 101);
- if (addr.indx)
- op = gen_rtx_PLUS (Pmode, op, addr.indx);
- if (addr.disp)
- op = gen_rtx_PLUS (Pmode, op, addr.disp);
+ if ((addr.base && REG_P (addr.base) && REG_POINTER (addr.base))
+ || (addr.indx && REG_P (addr.indx) && REG_POINTER (addr.indx)))
+ return TRUE;
- return op;
+ return FALSE;
+}
+
+/* Emit a forced load-address operation to load SRC into DST.
+ This will use the LOAD ADDRESS instruction even in situations
+ where legitimate_la_operand_p (SRC) returns false. */
+
+void
+s390_load_address (dst, src)
+ rtx dst;
+ rtx src;
+{
+ if (TARGET_64BIT)
+ emit_move_insn (dst, src);
+ else
+ emit_insn (gen_force_la_31 (dst, src));
}
/* Return a legitimate reference for ORIG (an address) using the
@@ -1577,7 +2055,7 @@ legitimize_pic_address (orig, reg)
|| CONSTANT_POOL_ADDRESS_P (addr))))
{
/* This is a local symbol. */
- if (TARGET_64BIT)
+ if (TARGET_64BIT && larl_operand (addr, VOIDmode))
{
/* Access local symbols PC-relative via LARL.
This is the same as in the non-PIC case, so it is
@@ -1589,9 +2067,9 @@ legitimize_pic_address (orig, reg)
rtx temp = reg? reg : gen_reg_rtx (Pmode);
- addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 100);
- addr = gen_rtx_CONST (SImode, addr);
- addr = force_const_mem (SImode, addr);
+ addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 100);
+ addr = gen_rtx_CONST (Pmode, addr);
+ addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
base = gen_rtx_REG (Pmode, BASE_REGISTER);
@@ -1615,7 +2093,8 @@ legitimize_pic_address (orig, reg)
/* Assume GOT offset < 4k. This is handled the same way
in both 31- and 64-bit code (@GOT12). */
- current_function_uses_pic_offset_table = 1;
+ if (reload_in_progress || reload_completed)
+ regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 110);
new = gen_rtx_CONST (Pmode, new);
@@ -1648,11 +2127,12 @@ legitimize_pic_address (orig, reg)
rtx temp = gen_reg_rtx (Pmode);
- current_function_uses_pic_offset_table = 1;
+ if (reload_in_progress || reload_completed)
+ regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
- addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 112);
- addr = gen_rtx_CONST (SImode, addr);
- addr = force_const_mem (SImode, addr);
+ addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 112);
+ addr = gen_rtx_CONST (Pmode, addr);
+ addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
@@ -1678,7 +2158,7 @@ legitimize_pic_address (orig, reg)
case 100:
case 112:
case 114:
- new = force_const_mem (SImode, orig);
+ new = force_const_mem (Pmode, orig);
break;
/* @GOTENT is OK as is. */
@@ -1693,9 +2173,9 @@ legitimize_pic_address (orig, reg)
rtx temp = reg? reg : gen_reg_rtx (Pmode);
addr = XVECEXP (addr, 0, 0);
- addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 114);
- addr = gen_rtx_CONST (SImode, addr);
- addr = force_const_mem (SImode, addr);
+ addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 114);
+ addr = gen_rtx_CONST (Pmode, addr);
+ addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
base = gen_rtx_REG (Pmode, BASE_REGISTER);
@@ -1729,7 +2209,7 @@ legitimize_pic_address (orig, reg)
|| CONSTANT_POOL_ADDRESS_P (op0))))
&& GET_CODE (op1) == CONST_INT)
{
- if (TARGET_64BIT)
+ if (TARGET_64BIT && larl_operand (op0, VOIDmode))
{
if (INTVAL (op1) & 1)
{
@@ -1766,10 +2246,10 @@ legitimize_pic_address (orig, reg)
rtx temp = reg? reg : gen_reg_rtx (Pmode);
- addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, op0), 100);
- addr = gen_rtx_PLUS (SImode, addr, op1);
- addr = gen_rtx_CONST (SImode, addr);
- addr = force_const_mem (SImode, addr);
+ addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 100);
+ addr = gen_rtx_PLUS (Pmode, addr, op1);
+ addr = gen_rtx_CONST (Pmode, addr);
+ addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
base = gen_rtx_REG (Pmode, BASE_REGISTER);
@@ -1795,7 +2275,7 @@ legitimize_pic_address (orig, reg)
if (XINT (op0, 1) != 100)
abort ();
- new = force_const_mem (SImode, orig);
+ new = force_const_mem (Pmode, orig);
}
/* Otherwise, compute the sum. */
@@ -1825,18 +2305,237 @@ legitimize_pic_address (orig, reg)
return new;
}
+/* Load the thread pointer into a register. */
+
+static rtx
+get_thread_pointer ()
+{
+ 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;
+}
+
+/* Construct the SYMBOL_REF for the tls_get_offset function. */
+
+static GTY(()) rtx s390_tls_symbol;
+rtx
+s390_tls_get_offset ()
+{
+ if (!s390_tls_symbol)
+ s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
+
+ return s390_tls_symbol;
+}
+
+/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
+ this (thread-local) address. REG may be used as temporary. */
+
+static rtx
+legitimize_tls_address (addr, reg)
+ rtx addr;
+ rtx reg;
+{
+ rtx new, tls_call, temp, base, r2, insn;
+
+ if (GET_CODE (addr) == SYMBOL_REF)
+ switch (tls_symbolic_operand (addr))
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ start_sequence ();
+ r2 = gen_rtx_REG (Pmode, 2);
+ tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLSGD);
+ new = gen_rtx_CONST (Pmode, tls_call);
+ new = force_const_mem (Pmode, new);
+ emit_move_insn (r2, new);
+ emit_call_insn (gen_call_value_tls (r2, tls_call));
+ insn = get_insns ();
+ end_sequence ();
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF);
+ temp = gen_reg_rtx (Pmode);
+ emit_libcall_block (insn, temp, r2, new);
+
+ new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ if (reg != 0)
+ {
+ s390_load_address (reg, new);
+ new = reg;
+ }
+ break;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ start_sequence ();
+ r2 = gen_rtx_REG (Pmode, 2);
+ tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM);
+ new = gen_rtx_CONST (Pmode, tls_call);
+ new = force_const_mem (Pmode, new);
+ emit_move_insn (r2, new);
+ emit_call_insn (gen_call_value_tls (r2, tls_call));
+ insn = get_insns ();
+ end_sequence ();
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM_NTPOFF);
+ temp = gen_reg_rtx (Pmode);
+ emit_libcall_block (insn, temp, r2, new);
+
+ new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ base = gen_reg_rtx (Pmode);
+ s390_load_address (base, new);
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_DTPOFF);
+ new = gen_rtx_CONST (Pmode, new);
+ new = force_const_mem (Pmode, new);
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+
+ new = gen_rtx_PLUS (Pmode, base, temp);
+ if (reg != 0)
+ {
+ s390_load_address (reg, new);
+ new = reg;
+ }
+ break;
+
+ case TLS_MODEL_INITIAL_EXEC:
+ if (flag_pic == 1)
+ {
+ /* Assume GOT offset < 4k. This is handled the same way
+ in both 31- and 64-bit code. */
+
+ if (reload_in_progress || reload_completed)
+ regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
+ new = gen_rtx_CONST (Pmode, new);
+ new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
+ new = gen_rtx_MEM (Pmode, new);
+ RTX_UNCHANGING_P (new) = 1;
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+ }
+ else if (TARGET_64BIT)
+ {
+ /* If the GOT offset might be >= 4k, we determine the position
+ of the GOT entry via a PC-relative LARL. */
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF);
+ new = gen_rtx_CONST (Pmode, new);
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+
+ new = gen_rtx_MEM (Pmode, temp);
+ RTX_UNCHANGING_P (new) = 1;
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+ }
+ else if (flag_pic)
+ {
+ /* If the GOT offset might be >= 4k, we have to load it
+ from the literal pool. */
+
+ if (reload_in_progress || reload_completed)
+ regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
+ new = gen_rtx_CONST (Pmode, new);
+ new = force_const_mem (Pmode, new);
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+
+ new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
+ new = gen_rtx_MEM (Pmode, new);
+ RTX_UNCHANGING_P (new) = 1;
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD);
+ temp = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (Pmode, temp, new));
+ }
+ else
+ {
+ /* In position-dependent code, load the absolute address of
+ the GOT entry from the literal pool. */
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF);
+ new = gen_rtx_CONST (Pmode, new);
+ new = force_const_mem (Pmode, new);
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+
+ new = temp;
+ new = gen_rtx_MEM (Pmode, new);
+ RTX_UNCHANGING_P (new) = 1;
+
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD);
+ temp = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (Pmode, temp, new));
+ }
+
+ new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ if (reg != 0)
+ {
+ s390_load_address (reg, new);
+ new = reg;
+ }
+ break;
+
+ case TLS_MODEL_LOCAL_EXEC:
+ new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF);
+ new = gen_rtx_CONST (Pmode, new);
+ new = force_const_mem (Pmode, new);
+ temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, new);
+
+ new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ if (reg != 0)
+ {
+ s390_load_address (reg, new);
+ new = reg;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == UNSPEC)
+ {
+ switch (XINT (XEXP (addr, 0), 1))
+ {
+ case UNSPEC_INDNTPOFF:
+ if (TARGET_64BIT)
+ new = addr;
+ else
+ abort ();
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ else
+ abort (); /* for now ... */
+
+ return new;
+}
+
/* Emit insns to move operands[1] into operands[0]. */
void
-emit_pic_move (operands, mode)
+emit_symbolic_move (operands)
rtx *operands;
- enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
- if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
+ if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (Pmode, operands[1]);
- else
+ else if (TLS_SYMBOLIC_CONST (operands[1]))
+ operands[1] = legitimize_tls_address (operands[1], temp);
+ else if (flag_pic)
operands[1] = legitimize_pic_address (operands[1], temp);
}
@@ -1859,7 +2558,14 @@ legitimize_address (x, oldx, mode)
{
rtx constant_term = const0_rtx;
- if (flag_pic)
+ if (TLS_SYMBOLIC_CONST (x))
+ {
+ x = legitimize_tls_address (x, 0);
+
+ if (legitimate_address_p (mode, x, FALSE))
+ return x;
+ }
+ else if (flag_pic)
{
if (SYMBOLIC_CONST (x)
|| (GET_CODE (x) == PLUS
@@ -1873,6 +2579,31 @@ legitimize_address (x, oldx, mode)
x = eliminate_constant_term (x, &constant_term);
+ /* Optimize loading of large displacements by splitting them
+ into the multiple of 4K and the rest; this allows the
+ former to be CSE'd if possible.
+
+ Don't do this if the displacement is added to a register
+ pointing into the stack frame, as the offsets will
+ change later anyway. */
+
+ if (GET_CODE (constant_term) == CONST_INT
+ && (INTVAL (constant_term) < 0
+ || INTVAL (constant_term) >= 4096)
+ && !(REG_P (x) && REGNO_PTR_FRAME_P (REGNO (x))))
+ {
+ HOST_WIDE_INT lower = INTVAL (constant_term) & 0xfff;
+ HOST_WIDE_INT upper = INTVAL (constant_term) ^ lower;
+
+ rtx temp = gen_reg_rtx (Pmode);
+ rtx val = force_operand (GEN_INT (upper), temp);
+ if (val != temp)
+ emit_move_insn (temp, val);
+
+ x = gen_rtx_PLUS (Pmode, x, temp);
+ constant_term = GEN_INT (lower);
+ }
+
if (GET_CODE (x) == PLUS)
{
if (GET_CODE (XEXP (x, 0)) == REG)
@@ -1902,6 +2633,316 @@ legitimize_address (x, oldx, mode)
return x;
}
+/* Emit code to move LEN bytes from DST to SRC. */
+
+void
+s390_expand_movstr (dst, src, len)
+ rtx dst;
+ rtx src;
+ rtx len;
+{
+ rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) =
+ TARGET_64BIT ? gen_movstr_short_64 : gen_movstr_short_31;
+ rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) =
+ TARGET_64BIT ? gen_movstr_long_64 : gen_movstr_long_31;
+
+
+ if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
+ {
+ if (INTVAL (len) > 0)
+ emit_insn ((*gen_short) (dst, src, GEN_INT (INTVAL (len) - 1)));
+ }
+
+ else if (TARGET_MVCLE)
+ {
+ enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
+ enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
+ rtx reg0 = gen_reg_rtx (double_mode);
+ rtx reg1 = gen_reg_rtx (double_mode);
+
+ emit_move_insn (gen_highpart (single_mode, reg0),
+ force_operand (XEXP (dst, 0), NULL_RTX));
+ emit_move_insn (gen_highpart (single_mode, reg1),
+ force_operand (XEXP (src, 0), NULL_RTX));
+
+ convert_move (gen_lowpart (single_mode, reg0), len, 1);
+ convert_move (gen_lowpart (single_mode, reg1), len, 1);
+
+ emit_insn ((*gen_long) (reg0, reg1, reg0, reg1));
+ }
+
+ else
+ {
+ rtx dst_addr, src_addr, count, blocks, temp;
+ rtx end_label = gen_label_rtx ();
+ enum machine_mode mode;
+ tree type;
+
+ mode = GET_MODE (len);
+ if (mode == VOIDmode)
+ mode = word_mode;
+
+ type = (*lang_hooks.types.type_for_mode) (mode, 1);
+ if (!type)
+ abort ();
+
+ dst_addr = gen_reg_rtx (Pmode);
+ src_addr = gen_reg_rtx (Pmode);
+ count = gen_reg_rtx (mode);
+ blocks = gen_reg_rtx (mode);
+
+ convert_move (count, len, 1);
+ emit_cmp_and_jump_insns (count, const0_rtx,
+ EQ, NULL_RTX, mode, 1, end_label);
+
+ emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
+ emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX));
+ dst = change_address (dst, VOIDmode, dst_addr);
+ src = change_address (src, VOIDmode, src_addr);
+
+ temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ if (temp != count)
+ emit_move_insn (count, temp);
+
+ temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
+ if (temp != blocks)
+ emit_move_insn (blocks, temp);
+
+ expand_start_loop (1);
+ expand_exit_loop_top_cond (0, build (NE_EXPR, type,
+ make_tree (type, blocks),
+ make_tree (type, const0_rtx)));
+
+ emit_insn ((*gen_short) (dst, src, GEN_INT (255)));
+ s390_load_address (dst_addr,
+ gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
+ s390_load_address (src_addr,
+ gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256)));
+
+ temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
+ if (temp != blocks)
+ emit_move_insn (blocks, temp);
+
+ expand_end_loop ();
+
+ emit_insn ((*gen_short) (dst, src, convert_to_mode (word_mode, count, 1)));
+ emit_label (end_label);
+ }
+}
+
+/* Emit code to clear LEN bytes at DST. */
+
+void
+s390_expand_clrstr (dst, len)
+ rtx dst;
+ rtx len;
+{
+ rtx (*gen_short) PARAMS ((rtx, rtx)) =
+ TARGET_64BIT ? gen_clrstr_short_64 : gen_clrstr_short_31;
+ rtx (*gen_long) PARAMS ((rtx, rtx, rtx)) =
+ TARGET_64BIT ? gen_clrstr_long_64 : gen_clrstr_long_31;
+
+
+ if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
+ {
+ if (INTVAL (len) > 0)
+ emit_insn ((*gen_short) (dst, GEN_INT (INTVAL (len) - 1)));
+ }
+
+ else if (TARGET_MVCLE)
+ {
+ enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
+ enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
+ rtx reg0 = gen_reg_rtx (double_mode);
+ rtx reg1 = gen_reg_rtx (double_mode);
+
+ emit_move_insn (gen_highpart (single_mode, reg0),
+ force_operand (XEXP (dst, 0), NULL_RTX));
+ convert_move (gen_lowpart (single_mode, reg0), len, 1);
+
+ emit_move_insn (gen_highpart (single_mode, reg1), const0_rtx);
+ emit_move_insn (gen_lowpart (single_mode, reg1), const0_rtx);
+
+ emit_insn ((*gen_long) (reg0, reg1, reg0));
+ }
+
+ else
+ {
+ rtx dst_addr, src_addr, count, blocks, temp;
+ rtx end_label = gen_label_rtx ();
+ enum machine_mode mode;
+ tree type;
+
+ mode = GET_MODE (len);
+ if (mode == VOIDmode)
+ mode = word_mode;
+
+ type = (*lang_hooks.types.type_for_mode) (mode, 1);
+ if (!type)
+ abort ();
+
+ dst_addr = gen_reg_rtx (Pmode);
+ src_addr = gen_reg_rtx (Pmode);
+ count = gen_reg_rtx (mode);
+ blocks = gen_reg_rtx (mode);
+
+ convert_move (count, len, 1);
+ emit_cmp_and_jump_insns (count, const0_rtx,
+ EQ, NULL_RTX, mode, 1, end_label);
+
+ emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
+ dst = change_address (dst, VOIDmode, dst_addr);
+
+ temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ if (temp != count)
+ emit_move_insn (count, temp);
+
+ temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
+ if (temp != blocks)
+ emit_move_insn (blocks, temp);
+
+ expand_start_loop (1);
+ expand_exit_loop_top_cond (0, build (NE_EXPR, type,
+ make_tree (type, blocks),
+ make_tree (type, const0_rtx)));
+
+ emit_insn ((*gen_short) (dst, GEN_INT (255)));
+ s390_load_address (dst_addr,
+ gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256)));
+
+ temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
+ if (temp != blocks)
+ emit_move_insn (blocks, temp);
+
+ expand_end_loop ();
+
+ emit_insn ((*gen_short) (dst, convert_to_mode (word_mode, count, 1)));
+ emit_label (end_label);
+ }
+}
+
+/* Emit code to compare LEN bytes at OP0 with those at OP1,
+ and return the result in TARGET. */
+
+void
+s390_expand_cmpstr (target, op0, op1, len)
+ rtx target;
+ rtx op0;
+ rtx op1;
+ rtx len;
+{
+ rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) =
+ TARGET_64BIT ? gen_cmpstr_short_64 : gen_cmpstr_short_31;
+ rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) =
+ TARGET_64BIT ? gen_cmpstr_long_64 : gen_cmpstr_long_31;
+ rtx (*gen_result) PARAMS ((rtx)) =
+ GET_MODE (target) == DImode ? gen_cmpint_di : gen_cmpint_si;
+
+ op0 = protect_from_queue (op0, 0);
+ op1 = protect_from_queue (op1, 0);
+ len = protect_from_queue (len, 0);
+
+ if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
+ {
+ if (INTVAL (len) > 0)
+ {
+ emit_insn ((*gen_short) (op0, op1, GEN_INT (INTVAL (len) - 1)));
+ emit_insn ((*gen_result) (target));
+ }
+ else
+ emit_move_insn (target, const0_rtx);
+ }
+
+ else /* if (TARGET_MVCLE) */
+ {
+ enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode;
+ enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode;
+ rtx reg0 = gen_reg_rtx (double_mode);
+ rtx reg1 = gen_reg_rtx (double_mode);
+
+ emit_move_insn (gen_highpart (single_mode, reg0),
+ force_operand (XEXP (op0, 0), NULL_RTX));
+ emit_move_insn (gen_highpart (single_mode, reg1),
+ force_operand (XEXP (op1, 0), NULL_RTX));
+
+ convert_move (gen_lowpart (single_mode, reg0), len, 1);
+ convert_move (gen_lowpart (single_mode, reg1), len, 1);
+
+ emit_insn ((*gen_long) (reg0, reg1, reg0, reg1));
+ emit_insn ((*gen_result) (target));
+ }
+
+#if 0
+ /* Deactivate for now as profile code cannot cope with
+ CC being live across basic block boundaries. */
+ else
+ {
+ rtx addr0, addr1, count, blocks, temp;
+ rtx end_label = gen_label_rtx ();
+ enum machine_mode mode;
+ tree type;
+
+ mode = GET_MODE (len);
+ if (mode == VOIDmode)
+ mode = word_mode;
+
+ type = (*lang_hooks.types.type_for_mode) (mode, 1);
+ if (!type)
+ abort ();
+
+ addr0 = gen_reg_rtx (Pmode);
+ addr1 = gen_reg_rtx (Pmode);
+ count = gen_reg_rtx (mode);
+ blocks = gen_reg_rtx (mode);
+
+ convert_move (count, len, 1);
+ emit_cmp_and_jump_insns (count, const0_rtx,
+ EQ, NULL_RTX, mode, 1, end_label);
+
+ emit_move_insn (addr0, force_operand (XEXP (op0, 0), NULL_RTX));
+ emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX));
+ op0 = change_address (op0, VOIDmode, addr0);
+ op1 = change_address (op1, VOIDmode, addr1);
+
+ temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ if (temp != count)
+ emit_move_insn (count, temp);
+
+ temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
+ if (temp != blocks)
+ emit_move_insn (blocks, temp);
+
+ expand_start_loop (1);
+ expand_exit_loop_top_cond (0, build (NE_EXPR, type,
+ make_tree (type, blocks),
+ make_tree (type, const0_rtx)));
+
+ emit_insn ((*gen_short) (op0, op1, GEN_INT (255)));
+ temp = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCSmode, 33), const0_rtx);
+ temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
+ gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx);
+ temp = gen_rtx_SET (VOIDmode, pc_rtx, temp);
+ emit_jump_insn (temp);
+
+ s390_load_address (addr0,
+ gen_rtx_PLUS (Pmode, addr0, GEN_INT (256)));
+ s390_load_address (addr1,
+ gen_rtx_PLUS (Pmode, addr1, GEN_INT (256)));
+
+ temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0);
+ if (temp != blocks)
+ emit_move_insn (blocks, temp);
+
+ expand_end_loop ();
+
+ emit_insn ((*gen_short) (op0, op1, convert_to_mode (word_mode, count, 1)));
+ emit_label (end_label);
+
+ emit_insn ((*gen_result) (target));
+ }
+#endif
+}
+
/* In the name of slightly smaller debug output, and to cater to
general assembler losage, recognize various UNSPEC sequences
and turn them back into a direct symbol reference. */
@@ -1940,6 +2981,48 @@ s390_simplify_dwarf_addr (orig_x)
return orig_x;
}
+/* Locate some local-dynamic symbol still in use by this function
+ so that we can print its name in local-dynamic base patterns. */
+
+static const char *
+get_some_local_dynamic_name ()
+{
+ rtx insn;
+
+ if (cfun->machine->some_ld_name)
+ return cfun->machine->some_ld_name;
+
+ for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+ if (INSN_P (insn)
+ && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+ return cfun->machine->some_ld_name;
+
+ abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *px;
+
+ if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
+ {
+ x = get_pool_constant (x);
+ return for_each_rtx (&x, get_some_local_dynamic_name_1, 0);
+ }
+
+ if (GET_CODE (x) == SYMBOL_REF
+ && tls_symbolic_operand (x) == TLS_MODEL_LOCAL_DYNAMIC)
+ {
+ cfun->machine->some_ld_name = XSTR (x, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
/* Output symbolic constant X in assembler syntax to
stdio stream FILE. */
@@ -1981,8 +3064,15 @@ s390_output_symbolic_const (file, x)
switch (XINT (x, 1))
{
case 100:
+ case 104:
+ s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+ fprintf (file, "-");
+ s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
+ break;
+ case 105:
+ s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
+ fprintf (file, "-");
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "-.LT%X", s390_function_count);
break;
case 110:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
@@ -2002,7 +3092,32 @@ s390_output_symbolic_const (file, x)
break;
case 114:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@PLT-.LT%X", s390_function_count);
+ fprintf (file, "@PLT-");
+ s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
+ break;
+ case UNSPEC_TLSGD:
+ s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+ fprintf (file, "@TLSGD");
+ break;
+ case UNSPEC_TLSLDM:
+ assemble_name (file, get_some_local_dynamic_name ());
+ fprintf (file, "@TLSLDM");
+ break;
+ case UNSPEC_DTPOFF:
+ s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+ fprintf (file, "@DTPOFF");
+ break;
+ case UNSPEC_NTPOFF:
+ s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+ fprintf (file, "@NTPOFF");
+ break;
+ case UNSPEC_GOTNTPOFF:
+ s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+ fprintf (file, "@GOTNTPOFF");
+ break;
+ case UNSPEC_INDNTPOFF:
+ s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
+ fprintf (file, "@INDNTPOFF");
break;
default:
output_operand_lossage ("invalid UNSPEC as operand (2)");
@@ -2026,7 +3141,9 @@ print_operand_address (file, addr)
{
struct s390_address ad;
- if (!s390_decompose_address (addr, &ad, TRUE))
+ if (!s390_decompose_address (addr, &ad)
+ || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
+ || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx)))
output_operand_lossage ("Cannot decompose address.");
if (ad.disp)
@@ -2047,6 +3164,7 @@ print_operand_address (file, addr)
'C': print opcode suffix for branch condition.
'D': print opcode suffix for inverse branch condition.
+ 'J': print tls_load/tls_gdcall/tls_ldcall suffix
'O': print only the displacement of a memory reference.
'R': print only the base register of a memory reference.
'N': print the second word of a DImode operand.
@@ -2072,12 +3190,33 @@ print_operand (file, x, code)
fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
return;
+ case 'J':
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ fprintf (file, "%s", ":tls_load:");
+ output_addr_const (file, x);
+ }
+ else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
+ {
+ fprintf (file, "%s", ":tls_gdcall:");
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ }
+ else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM)
+ {
+ fprintf (file, "%s", ":tls_ldcall:");
+ assemble_name (file, get_some_local_dynamic_name ());
+ }
+ else
+ abort ();
+ return;
+
case 'O':
{
struct s390_address ad;
if (GET_CODE (x) != MEM
- || !s390_decompose_address (XEXP (x, 0), &ad, TRUE)
+ || !s390_decompose_address (XEXP (x, 0), &ad)
+ || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
|| ad.indx)
abort ();
@@ -2093,7 +3232,8 @@ print_operand (file, x, code)
struct s390_address ad;
if (GET_CODE (x) != MEM
- || !s390_decompose_address (XEXP (x, 0), &ad, TRUE)
+ || !s390_decompose_address (XEXP (x, 0), &ad)
+ || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
|| ad.indx)
abort ();
@@ -2248,7 +3388,11 @@ addr_generation_dependency_p (dep_rtx, insn)
if (GET_CODE (dep_rtx) == SET)
{
target = SET_DEST (dep_rtx);
-
+ if (GET_CODE (target) == STRICT_LOW_PART)
+ target = XEXP (target, 0);
+ while (GET_CODE (target) == SUBREG)
+ target = SUBREG_REG (target);
+
if (GET_CODE (target) == REG)
{
int regno = REGNO (target);
@@ -2389,18 +3533,25 @@ s390_adjust_priority (insn, priority)
}
-/* Split all branches that exceed the maximum distance. */
+/* Split all branches that exceed the maximum distance.
+ Returns true if this created a new literal pool entry.
+
+ Code generated by this routine is allowed to use
+ TEMP_REG as temporary scratch register. If this is
+ done, TEMP_USED is set to true. */
-static void
-s390_split_branches (void)
+static int
+s390_split_branches (temp_reg, temp_used)
+ rtx temp_reg;
+ bool *temp_used;
{
- rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
- rtx insn, pat, label, target, jump, tmp;
+ int new_literal = 0;
+ rtx insn, pat, tmp, target;
+ rtx *label;
- /* In 64-bit mode we can jump +- 4GB. */
+ /* We need correct insn addresses. */
- if (TARGET_64BIT)
- return;
+ shorten_branches (get_insns ());
/* Find all branches that exceed 64KB, and split them. */
@@ -2410,61 +3561,66 @@ s390_split_branches (void)
continue;
pat = PATTERN (insn);
- if (GET_CODE (pat) != SET)
+ if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
+ pat = XVECEXP (pat, 0, 0);
+ if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx)
continue;
if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
{
- label = SET_SRC (pat);
+ label = &SET_SRC (pat);
}
else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
{
if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
- label = XEXP (SET_SRC (pat), 1);
+ label = &XEXP (SET_SRC (pat), 1);
else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
- label = XEXP (SET_SRC (pat), 2);
+ label = &XEXP (SET_SRC (pat), 2);
else
continue;
}
else
continue;
- if (get_attr_length (insn) == 4)
+ if (get_attr_length (insn) <= (TARGET_64BIT ? 6 : 4))
continue;
- if (flag_pic)
+ *temp_used = 1;
+
+ if (TARGET_64BIT)
{
- target = gen_rtx_UNSPEC (SImode, gen_rtvec (1, label), 100);
- target = gen_rtx_CONST (SImode, target);
- target = force_const_mem (SImode, target);
- jump = gen_rtx_REG (Pmode, BASE_REGISTER);
- jump = gen_rtx_PLUS (Pmode, jump, temp_reg);
+ tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, *label), insn);
+ INSN_ADDRESSES_NEW (tmp, -1);
+
+ target = temp_reg;
}
- else
+ else if (!flag_pic)
{
- target = force_const_mem (Pmode, label);
- jump = temp_reg;
- }
+ new_literal = 1;
+ tmp = force_const_mem (Pmode, *label);
+ tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
+ INSN_ADDRESSES_NEW (tmp, -1);
- if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
+ target = temp_reg;
+ }
+ else
{
- if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
- jump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (SET_SRC (pat), 0),
- jump, pc_rtx);
- else
- jump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (SET_SRC (pat), 0),
- pc_rtx, jump);
+ new_literal = 1;
+ tmp = gen_rtx_UNSPEC (SImode, gen_rtvec (1, *label), 104);
+ tmp = gen_rtx_CONST (SImode, tmp);
+ tmp = force_const_mem (SImode, tmp);
+ tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
+ INSN_ADDRESSES_NEW (tmp, -1);
+
+ target = gen_rtx_REG (Pmode, BASE_REGISTER);
+ target = gen_rtx_PLUS (Pmode, target, temp_reg);
}
- tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
- INSN_ADDRESSES_NEW (tmp, -1);
-
- tmp = emit_jump_insn_before (gen_rtx_SET (VOIDmode, pc_rtx, jump), insn);
- INSN_ADDRESSES_NEW (tmp, -1);
-
- remove_insn (insn);
- insn = tmp;
+ if (!validate_change (insn, label, target, 0))
+ abort ();
}
+
+ return new_literal;
}
@@ -2582,6 +3738,153 @@ replace_constant_pool_ref (x, ref, addr)
}
}
+/* Check whether ADDR is an address that uses the base register,
+ without actually constituting a literal pool access. (This happens
+ in 31-bit PIC mode, where the base register is used as anchor for
+ relative addressing of local symbols.)
+
+ Returns 1 if the base register occupies the base slot,
+ returns 2 if the base register occupies the index slot,
+ returns 0 if the address is not of this form. */
+
+static int
+find_base_register_in_addr (addr)
+ struct s390_address *addr;
+{
+ /* If DISP is complex, we might have a literal pool reference. */
+ if (addr->disp && GET_CODE (addr->disp) != CONST_INT)
+ return 0;
+
+ if (addr->base && REG_P (addr->base) && REGNO (addr->base) == BASE_REGISTER)
+ return 1;
+
+ if (addr->indx && REG_P (addr->indx) && REGNO (addr->indx) == BASE_REGISTER)
+ return 2;
+
+ return 0;
+}
+
+/* Return true if X contains an address that uses the base register,
+ without actually constituting a literal pool access. */
+
+static bool
+find_base_register_ref (x)
+ rtx x;
+{
+ bool retv = FALSE;
+ struct s390_address addr;
+ int i, j;
+ const char *fmt;
+
+ /* Addresses can only occur inside a MEM ... */
+ if (GET_CODE (x) == MEM)
+ {
+ if (s390_decompose_address (XEXP (x, 0), &addr)
+ && find_base_register_in_addr (&addr))
+ return TRUE;
+ }
+
+ /* ... or a load-address type pattern. */
+ if (GET_CODE (x) == SET && GET_CODE (SET_DEST (x)) == REG)
+ {
+ if (s390_decompose_address (SET_SRC (x), &addr)
+ && find_base_register_in_addr (&addr))
+ return TRUE;
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ retv |= find_base_register_ref (XEXP (x, i));
+ }
+ else if (fmt[i] == 'E')
+ {
+ for (j = 0; j < XVECLEN (x, i); j++)
+ retv |= find_base_register_ref (XVECEXP (x, i, j));
+ }
+ }
+
+ return retv;
+}
+
+/* If X contains an address that uses the base register,
+ without actually constituting a literal pool access,
+ replace the base register with REPL in all such cases.
+
+ Handles both MEMs and load address patterns. */
+
+static void
+replace_base_register_ref (x, repl)
+ rtx *x;
+ rtx repl;
+{
+ struct s390_address addr;
+ rtx new_addr;
+ int i, j, pos;
+ const char *fmt;
+
+ /* Addresses can only occur inside a MEM ... */
+ if (GET_CODE (*x) == MEM)
+ {
+ if (s390_decompose_address (XEXP (*x, 0), &addr)
+ && (pos = find_base_register_in_addr (&addr)))
+ {
+ if (pos == 1)
+ addr.base = repl;
+ else
+ addr.indx = repl;
+
+ new_addr = addr.base;
+ if (addr.indx)
+ new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx);
+ if (addr.disp)
+ new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp);
+
+ *x = replace_equiv_address (*x, new_addr);
+ return;
+ }
+ }
+
+ /* ... or a load-address type pattern. */
+ if (GET_CODE (*x) == SET && GET_CODE (SET_DEST (*x)) == REG)
+ {
+ if (s390_decompose_address (SET_SRC (*x), &addr)
+ && (pos = find_base_register_in_addr (&addr)))
+ {
+ if (pos == 1)
+ addr.base = repl;
+ else
+ addr.indx = repl;
+
+ new_addr = addr.base;
+ if (addr.indx)
+ new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx);
+ if (addr.disp)
+ new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp);
+
+ SET_SRC (*x) = new_addr;
+ return;
+ }
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (*x));
+ for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ replace_base_register_ref (&XEXP (*x, i), repl);
+ }
+ else if (fmt[i] == 'E')
+ {
+ for (j = 0; j < XVECLEN (*x, i); j++)
+ replace_base_register_ref (&XVECEXP (*x, i, j), repl);
+ }
+ }
+}
+
+
/* We keep a list of constants we which we have to add to internal
constant tables in the middle of large functions. */
@@ -2613,17 +3916,26 @@ struct constant_pool
{
struct constant_pool *next;
rtx first_insn;
- rtx last_insn;
+ rtx pool_insn;
+ bitmap insns;
struct constant *constants[NR_C_MODES];
rtx label;
int size;
+ bool anchor;
};
+static struct constant_pool * s390_chunkify_start PARAMS ((rtx, bool *));
+static void s390_chunkify_finish PARAMS ((struct constant_pool *, rtx));
+static void s390_chunkify_cancel PARAMS ((struct constant_pool *));
+
static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx));
static void s390_end_pool PARAMS ((struct constant_pool *, rtx));
+static void s390_add_pool_insn PARAMS ((struct constant_pool *, rtx));
static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx));
-static rtx s390_add_pool PARAMS ((struct constant_pool *, rtx, enum machine_mode));
+static void s390_add_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode));
+static rtx s390_find_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode));
+static void s390_add_anchor PARAMS ((struct constant_pool *));
static rtx s390_dump_pool PARAMS ((struct constant_pool *));
static void s390_free_pool PARAMS ((struct constant_pool *));
@@ -2645,9 +3957,11 @@ s390_start_pool (pool_list, insn)
pool->label = gen_label_rtx ();
pool->first_insn = insn;
- pool->last_insn = NULL_RTX;
+ pool->pool_insn = NULL_RTX;
+ pool->insns = BITMAP_XMALLOC ();
pool->size = 0;
-
+ pool->anchor = FALSE;
+
for (prev = pool_list; *prev; prev = &(*prev)->next)
;
*prev = pool;
@@ -2655,14 +3969,31 @@ s390_start_pool (pool_list, insn)
return pool;
}
-/* End range of instructions covered by POOL at INSN. */
+/* End range of instructions covered by POOL at INSN and emit
+ placeholder insn representing the pool. */
static void
s390_end_pool (pool, insn)
struct constant_pool *pool;
rtx insn;
{
- pool->last_insn = insn;
+ rtx pool_size = GEN_INT (pool->size + 8 /* alignment slop */);
+
+ if (!insn)
+ insn = get_last_insn ();
+
+ pool->pool_insn = emit_insn_after (gen_pool (pool_size), insn);
+ INSN_ADDRESSES_NEW (pool->pool_insn, -1);
+}
+
+/* Add INSN to the list of insns covered by POOL. */
+
+static void
+s390_add_pool_insn (pool, insn)
+ struct constant_pool *pool;
+ rtx insn;
+{
+ bitmap_set_bit (pool->insns, INSN_UID (insn));
}
/* Return pool out of POOL_LIST that covers INSN. */
@@ -2672,33 +4003,24 @@ s390_find_pool (pool_list, insn)
struct constant_pool *pool_list;
rtx insn;
{
- int addr = INSN_ADDRESSES (INSN_UID (insn));
struct constant_pool *pool;
- if (addr == -1)
- return NULL;
-
for (pool = pool_list; pool; pool = pool->next)
- if (INSN_ADDRESSES (INSN_UID (pool->first_insn)) <= addr
- && (pool->last_insn == NULL_RTX
- || INSN_ADDRESSES (INSN_UID (pool->last_insn)) > addr))
+ if (bitmap_bit_p (pool->insns, INSN_UID (insn)))
break;
return pool;
}
-/* Add constant VAL of mode MODE to the constant pool POOL.
- Return an RTX describing the distance from the start of
- the pool to the location of the new constant. */
+/* Add constant VAL of mode MODE to the constant pool POOL. */
-static rtx
-s390_add_pool (pool, val, mode)
+static void
+s390_add_constant (pool, val, mode)
struct constant_pool *pool;
rtx val;
enum machine_mode mode;
{
struct constant *c;
- rtx offset;
int i;
for (i = 0; i < NR_C_MODES; i++)
@@ -2720,13 +4042,54 @@ s390_add_pool (pool, val, mode)
pool->constants[i] = c;
pool->size += GET_MODE_SIZE (mode);
}
+}
- offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
- gen_rtx_LABEL_REF (Pmode, pool->label));
+/* Find constant VAL of mode MODE in the constant pool POOL.
+ Return an RTX describing the distance from the start of
+ the pool to the location of the new constant. */
+
+static rtx
+s390_find_constant (pool, val, mode)
+ struct constant_pool *pool;
+ rtx val;
+ enum machine_mode mode;
+{
+ struct constant *c;
+ rtx offset;
+ int i;
+
+ for (i = 0; i < NR_C_MODES; i++)
+ if (constant_modes[i] == mode)
+ break;
+ if (i == NR_C_MODES)
+ abort ();
+
+ for (c = pool->constants[i]; c != NULL; c = c->next)
+ if (rtx_equal_p (val, c->value))
+ break;
+
+ if (c == NULL)
+ abort ();
+
+ offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
+ gen_rtx_LABEL_REF (Pmode, pool->label));
offset = gen_rtx_CONST (Pmode, offset);
return offset;
}
+/* Set 'anchor' flag in POOL. */
+
+static void
+s390_add_anchor (pool)
+ struct constant_pool *pool;
+{
+ if (!pool->anchor)
+ {
+ pool->anchor = TRUE;
+ pool->size += 4;
+ }
+}
+
/* Dump out the constants in POOL. */
static rtx
@@ -2737,31 +4100,47 @@ s390_dump_pool (pool)
rtx insn;
int i;
- /* Select location to put literal pool. */
- if (TARGET_64BIT)
- insn = get_last_insn ();
- else
- insn = pool->last_insn? pool->last_insn : get_last_insn ();
-
/* Pool start insn switches to proper section
and guarantees necessary alignment. */
if (TARGET_64BIT)
- insn = emit_insn_after (gen_pool_start_64 (), insn);
+ insn = emit_insn_after (gen_pool_start_64 (), pool->pool_insn);
else
- insn = emit_insn_after (gen_pool_start_31 (), insn);
+ insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn);
INSN_ADDRESSES_NEW (insn, -1);
insn = emit_label_after (pool->label, insn);
INSN_ADDRESSES_NEW (insn, -1);
+ /* Emit anchor if we need one. */
+ if (pool->anchor)
+ {
+ rtx anchor = gen_rtx_LABEL_REF (VOIDmode, pool->label);
+ anchor = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, anchor), 105);
+ anchor = gen_rtx_CONST (VOIDmode, anchor);
+ insn = emit_insn_after (gen_consttable_si (anchor), insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+ }
+
/* Dump constants in descending alignment requirement order,
ensuring proper alignment for every constant. */
for (i = 0; i < NR_C_MODES; i++)
for (c = pool->constants[i]; c; c = c->next)
{
+ /* Convert 104 unspecs to pool-relative references. */
+ rtx value = c->value;
+ if (GET_CODE (value) == CONST
+ && GET_CODE (XEXP (value, 0)) == UNSPEC
+ && XINT (XEXP (value, 0), 1) == 104
+ && XVECLEN (XEXP (value, 0), 0) == 1)
+ {
+ value = gen_rtx_MINUS (Pmode, XVECEXP (XEXP (value, 0), 0, 0),
+ gen_rtx_LABEL_REF (VOIDmode, pool->label));
+ value = gen_rtx_CONST (VOIDmode, value);
+ }
+
insn = emit_label_after (c->label, insn);
INSN_ADDRESSES_NEW (insn, -1);
- insn = emit_insn_after (gen_consttable[i] (c->value), insn);
+ insn = emit_insn_after (gen_consttable[i] (value), insn);
INSN_ADDRESSES_NEW (insn, -1);
}
@@ -2776,6 +4155,9 @@ s390_dump_pool (pool)
insn = emit_barrier_after (insn);
INSN_ADDRESSES_NEW (insn, -1);
+ /* Remove placeholder insn. */
+ remove_insn (pool->pool_insn);
+
return insn;
}
@@ -2798,57 +4180,86 @@ s390_free_pool (pool)
}
}
+ BITMAP_XFREE (pool->insns);
free (pool);
}
-/* Used in s390.md for branch length calculation. */
-int s390_pool_overflow = 0;
-/* Chunkify the literal pool if required. */
+/* Chunkify the literal pool if required.
+
+ Code generated by this routine is allowed to use
+ TEMP_REG as temporary scratch register. If this is
+ done, TEMP_USED is set to true. */
#define S390_POOL_CHUNK_MIN 0xc00
#define S390_POOL_CHUNK_MAX 0xe00
-static void
-s390_chunkify_pool (void)
+static struct constant_pool *
+s390_chunkify_start (temp_reg, temp_used)
+ rtx temp_reg;
+ bool *temp_used;
{
- rtx base_reg = gen_rtx_REG (Pmode,
- TARGET_64BIT? BASE_REGISTER : RETURN_REGNUM);
+ rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
int extra_size = 0;
bitmap far_labels;
rtx insn;
+ rtx (*gen_reload_base) PARAMS ((rtx, rtx)) =
+ TARGET_64BIT? gen_reload_base_64 : gen_reload_base_31;
+
+
/* Do we need to chunkify the literal pool? */
if (get_pool_size () < S390_POOL_CHUNK_MAX)
- return;
+ return NULL;
+
+ /* We need correct insn addresses. */
+
+ shorten_branches (get_insns ());
/* Scan all insns and move literals to pool chunks.
- Replace all occurrances of literal pool references
- by explicit references to pool chunk entries. */
+ Also, emit anchor reload insns before every insn that uses
+ the literal pool base register as anchor pointer. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == INSN)
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
{
- rtx addr, pool_ref = NULL_RTX;
+ rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
if (pool_ref)
{
if (!curr_pool)
curr_pool = s390_start_pool (&pool_list, insn);
- addr = s390_add_pool (curr_pool, get_pool_constant (pool_ref),
- get_pool_mode (pool_ref));
+ s390_add_constant (curr_pool, get_pool_constant (pool_ref),
+ get_pool_mode (pool_ref));
+ s390_add_pool_insn (curr_pool, insn);
+ }
- addr = gen_rtx_PLUS (Pmode, base_reg, addr);
- replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
- INSN_CODE (insn) = -1;
+ else if (!TARGET_64BIT && flag_pic
+ && find_base_register_ref (PATTERN (insn)))
+ {
+ rtx new = gen_reload_anchor (temp_reg, base_reg);
+ new = emit_insn_before (new, insn);
+ INSN_ADDRESSES_NEW (new, INSN_ADDRESSES (INSN_UID (insn)));
+ extra_size += 8;
+ *temp_used = 1;
+
+ if (!curr_pool)
+ curr_pool = s390_start_pool (&pool_list, new);
+
+ s390_add_anchor (curr_pool);
+ s390_add_pool_insn (curr_pool, insn);
}
}
+ if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL)
+ if (curr_pool)
+ s390_add_pool_insn (curr_pool, insn);
+
if (!curr_pool
|| INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
|| INSN_ADDRESSES (INSN_UID (insn)) == -1)
@@ -2859,7 +4270,7 @@ s390_chunkify_pool (void)
if (curr_pool->size < S390_POOL_CHUNK_MAX)
continue;
- s390_end_pool (curr_pool, insn);
+ s390_end_pool (curr_pool, NULL_RTX);
curr_pool = NULL;
}
else
@@ -2872,11 +4283,8 @@ s390_chunkify_pool (void)
Those will have an effect on code size, which we need to
consider here. This calculation makes rather pessimistic
worst-case assumptions. */
- if (GET_CODE (insn) == CODE_LABEL
- || GET_CODE (insn) == JUMP_INSN)
+ if (GET_CODE (insn) == CODE_LABEL)
extra_size += 6;
- else if (GET_CODE (insn) == CALL_INSN)
- extra_size += 4;
if (chunk_size < S390_POOL_CHUNK_MIN
&& curr_pool->size < S390_POOL_CHUNK_MIN)
@@ -2892,12 +4300,22 @@ s390_chunkify_pool (void)
/* ... so if we don't find one in time, create one. */
else if ((chunk_size > S390_POOL_CHUNK_MAX
- || curr_pool->size > S390_POOL_CHUNK_MAX)
- && (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN))
+ || curr_pool->size > S390_POOL_CHUNK_MAX))
{
- int addr = INSN_ADDRESSES (INSN_UID (insn));
rtx label, jump, barrier;
+ /* We can insert the barrier only after a 'real' insn. */
+ if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
+ continue;
+ if (get_attr_length (insn) == 0)
+ continue;
+
+ /* Don't separate insns created by s390_split_branches. */
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SET
+ && rtx_equal_p (SET_DEST (PATTERN (insn)), temp_reg))
+ continue;
+
label = gen_label_rtx ();
jump = emit_jump_insn_after (gen_jump (label), insn);
barrier = emit_barrier_after (jump);
@@ -2905,8 +4323,8 @@ s390_chunkify_pool (void)
JUMP_LABEL (jump) = label;
LABEL_NUSES (label) = 1;
- INSN_ADDRESSES_NEW (jump, addr+1);
- INSN_ADDRESSES_NEW (barrier, addr+1);
+ INSN_ADDRESSES_NEW (jump, -1);
+ INSN_ADDRESSES_NEW (barrier, -1);
INSN_ADDRESSES_NEW (insn, -1);
s390_end_pool (curr_pool, barrier);
@@ -2916,10 +4334,8 @@ s390_chunkify_pool (void)
}
}
- /* Dump out all literal pools. */
-
- for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
- s390_dump_pool (curr_pool);
+ if (curr_pool)
+ s390_end_pool (curr_pool, NULL_RTX);
/* Find all labels that are branched into
@@ -2953,22 +4369,12 @@ s390_chunkify_pool (void)
else if (GET_CODE (insn) == JUMP_INSN)
{
rtx pat = PATTERN (insn);
+ if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
+ pat = XVECEXP (pat, 0, 0);
+
if (GET_CODE (pat) == SET)
{
- rtx label = 0;
-
- if (GET_CODE (SET_SRC (pat)) == LABEL_REF)
- {
- label = XEXP (SET_SRC (pat), 0);
- }
- else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
- {
- if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF)
- label = XEXP (XEXP (SET_SRC (pat), 1), 0);
- else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF)
- label = XEXP (XEXP (SET_SRC (pat), 2), 0);
- }
-
+ rtx label = JUMP_LABEL (insn);
if (label)
{
if (s390_find_pool (pool_list, label)
@@ -3009,19 +4415,11 @@ s390_chunkify_pool (void)
/* Insert base register reload insns before every pool. */
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
- if (TARGET_64BIT)
- {
- rtx pool_ref = gen_rtx_LABEL_REF (Pmode, curr_pool->label);
- rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
- rtx insn = curr_pool->first_insn;
- INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
- }
- else
- {
- rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
- rtx insn = curr_pool->first_insn;
- INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
- }
+ {
+ rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
+ rtx insn = curr_pool->first_insn;
+ INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
+ }
/* Insert base register reload insns at every far label. */
@@ -3032,60 +4430,137 @@ s390_chunkify_pool (void)
struct constant_pool *pool = s390_find_pool (pool_list, insn);
if (pool)
{
- if (TARGET_64BIT)
- {
- rtx pool_ref = gen_rtx_LABEL_REF (Pmode, pool->label);
- rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
- INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
- }
- else
- {
- rtx new_insn = gen_reload_base (base_reg, pool->label);
- INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
- }
+ rtx new_insn = gen_reload_base (base_reg, pool->label);
+ INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
}
}
- /* Insert base register reload insns after every call if necessary. */
-
- if (REGNO (base_reg) == RETURN_REGNUM)
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == CALL_INSN)
- {
- struct constant_pool *pool = s390_find_pool (pool_list, insn);
- if (pool)
- {
- rtx new_insn = gen_reload_base2 (base_reg, pool->label);
- INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
- }
- }
+
+ BITMAP_XFREE (far_labels);
/* Recompute insn addresses. */
- s390_pool_overflow = 1;
init_insn_lengths ();
shorten_branches (get_insns ());
- s390_pool_overflow = 0;
- /* Insert base register reload insns after far branches. */
+ return pool_list;
+}
- if (!TARGET_64BIT)
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) == SET
- && get_attr_length (insn) >= 12)
- {
- struct constant_pool *pool = s390_find_pool (pool_list, insn);
- if (pool)
+/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
+ After we have decided to use this list, finish implementing
+ all changes to the current function as required.
+
+ Code generated by this routine is allowed to use
+ TEMP_REG as temporary scratch register. */
+
+static void
+s390_chunkify_finish (pool_list, temp_reg)
+ struct constant_pool *pool_list;
+ rtx temp_reg;
+{
+ rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
+ struct constant_pool *curr_pool = NULL;
+ rtx insn;
+
+
+ /* Replace all literal pool references. */
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ curr_pool = s390_find_pool (pool_list, insn);
+ if (!curr_pool)
+ continue;
+
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+ {
+ rtx addr, pool_ref = NULL_RTX;
+ find_constant_pool_ref (PATTERN (insn), &pool_ref);
+ if (pool_ref)
+ {
+ addr = s390_find_constant (curr_pool, get_pool_constant (pool_ref),
+ get_pool_mode (pool_ref));
+ addr = gen_rtx_PLUS (Pmode, base_reg, addr);
+ replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
+ INSN_CODE (insn) = -1;
+ }
+
+ else if (!TARGET_64BIT && flag_pic
+ && find_base_register_ref (PATTERN (insn)))
{
- rtx new_insn = gen_reload_base (base_reg, pool->label);
- INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
+ replace_base_register_ref (&PATTERN (insn), temp_reg);
}
+ }
+ }
+
+ /* Dump out all literal pools. */
+
+ for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
+ s390_dump_pool (curr_pool);
+
+ /* Free pool list. */
+
+ while (pool_list)
+ {
+ struct constant_pool *next = pool_list->next;
+ s390_free_pool (pool_list);
+ pool_list = next;
+ }
+}
+
+/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
+ We have decided we cannot use this list, so revert all changes
+ to the current function that were done by s390_chunkify_start. */
+
+static void
+s390_chunkify_cancel (pool_list)
+ struct constant_pool *pool_list;
+{
+ struct constant_pool *curr_pool = NULL;
+ rtx insn;
+
+ /* Remove all pool placeholder insns. */
+
+ for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
+ {
+ /* Did we insert an extra barrier? Remove it. */
+ rtx barrier = PREV_INSN (curr_pool->pool_insn);
+ rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX;
+ rtx label = NEXT_INSN (curr_pool->pool_insn);
+
+ if (jump && GET_CODE (jump) == JUMP_INSN
+ && barrier && GET_CODE (barrier) == BARRIER
+ && label && GET_CODE (label) == CODE_LABEL
+ && GET_CODE (PATTERN (jump)) == SET
+ && SET_DEST (PATTERN (jump)) == pc_rtx
+ && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
+ && XEXP (SET_SRC (PATTERN (jump)), 0) == label)
+ {
+ remove_insn (jump);
+ remove_insn (barrier);
+ remove_insn (label);
}
+ remove_insn (curr_pool->pool_insn);
+ }
- /* Free all memory. */
+ /* Remove all base/anchor register reload insns. */
+
+ for (insn = get_insns (); insn; )
+ {
+ rtx next_insn = NEXT_INSN (insn);
+
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
+ && (XINT (SET_SRC (PATTERN (insn)), 1) == 210
+ || XINT (SET_SRC (PATTERN (insn)), 1) == 211))
+ remove_insn (insn);
+
+ insn = next_insn;
+ }
+
+ /* Free pool list. */
while (pool_list)
{
@@ -3093,8 +4568,6 @@ s390_chunkify_pool (void)
s390_free_pool (pool_list);
pool_list = next;
}
-
- BITMAP_XFREE (far_labels);
}
@@ -3108,54 +4581,359 @@ int s390_nr_constants;
/* Output main constant pool to stdio stream FILE. */
void
-s390_output_constant_pool (file)
- FILE *file;
+s390_output_constant_pool (start_label, end_label)
+ rtx start_label;
+ rtx end_label;
{
- /* Output constant pool. */
- if (s390_nr_constants)
+ if (TARGET_64BIT)
{
- if (TARGET_64BIT)
+ readonly_data_section ();
+ ASM_OUTPUT_ALIGN (asm_out_file, 3);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (start_label));
+ }
+ else
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (start_label));
+ ASM_OUTPUT_ALIGN (asm_out_file, 2);
+ }
+
+ s390_pool_count = 0;
+ output_constant_pool (current_function_name, current_function_decl);
+ s390_pool_count = -1;
+ if (TARGET_64BIT)
+ function_section (current_function_decl);
+ else
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file, 1);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (end_label));
+ }
+}
+
+/* Rework the prolog/epilog to avoid saving/restoring
+ registers unnecessarily. If TEMP_REGNO is nonnegative,
+ it specifies the number of a caller-saved register used
+ as temporary scratch register by code emitted during
+ machine dependent reorg. */
+
+static void
+s390_optimize_prolog (temp_regno)
+ int temp_regno;
+{
+ int save_first, save_last, restore_first, restore_last;
+ int i, j;
+ rtx insn, new_insn, next_insn;
+
+ /* Recompute regs_ever_live data for special registers. */
+ regs_ever_live[BASE_REGISTER] = 0;
+ regs_ever_live[RETURN_REGNUM] = 0;
+ regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
+
+ /* If there is (possibly) any pool entry, we need to
+ load the base register.
+ ??? FIXME: this should be more precise. */
+ if (get_pool_size ())
+ regs_ever_live[BASE_REGISTER] = 1;
+
+ /* In non-leaf functions, the prolog/epilog code relies
+ on RETURN_REGNUM being saved in any case. */
+ if (!current_function_is_leaf)
+ regs_ever_live[RETURN_REGNUM] = 1;
+
+ /* We need to save/restore the temporary register. */
+ if (temp_regno >= 0)
+ regs_ever_live[temp_regno] = 1;
+
+
+ /* Find first and last gpr to be saved. */
+
+ for (i = 6; i < 16; i++)
+ if (regs_ever_live[i])
+ if (!global_regs[i]
+ || i == STACK_POINTER_REGNUM
+ || i == RETURN_REGNUM
+ || i == BASE_REGISTER
+ || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
+ break;
+
+ for (j = 15; j > i; j--)
+ if (regs_ever_live[j])
+ if (!global_regs[j]
+ || j == STACK_POINTER_REGNUM
+ || j == RETURN_REGNUM
+ || j == BASE_REGISTER
+ || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM))
+ break;
+
+ if (i == 16)
+ {
+ /* Nothing to save/restore. */
+ save_first = restore_first = -1;
+ save_last = restore_last = -1;
+ }
+ else
+ {
+ /* Save/restore from i to j. */
+ save_first = restore_first = i;
+ save_last = restore_last = j;
+ }
+
+ /* Varargs functions need to save gprs 2 to 6. */
+ if (current_function_stdarg)
+ {
+ save_first = 2;
+ if (save_last < 6)
+ save_last = 6;
+ }
+
+
+ /* If all special registers are in fact used, there's nothing we
+ can do, so no point in walking the insn list. */
+ if (i <= BASE_REGISTER && j >= BASE_REGISTER
+ && i <= RETURN_REGNUM && j >= RETURN_REGNUM)
+ return;
+
+
+ /* Search for prolog/epilog insns and replace them. */
+
+ for (insn = get_insns (); insn; insn = next_insn)
+ {
+ int first, last, off;
+ rtx set, base, offset;
+
+ next_insn = NEXT_INSN (insn);
+
+ if (GET_CODE (insn) != INSN)
+ continue;
+ if (GET_CODE (PATTERN (insn)) != PARALLEL)
+ continue;
+
+ if (store_multiple_operation (PATTERN (insn), VOIDmode))
{
- fprintf (file, "\tlarl\t%s,.LT%X\n", reg_names[BASE_REGISTER],
- s390_function_count);
- readonly_data_section ();
- ASM_OUTPUT_ALIGN (file, 3);
+ set = XVECEXP (PATTERN (insn), 0, 0);
+ first = REGNO (SET_SRC (set));
+ last = first + XVECLEN (PATTERN (insn), 0) - 1;
+ offset = const0_rtx;
+ base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
+ off = INTVAL (offset) - first * UNITS_PER_WORD;
+
+ if (GET_CODE (base) != REG || off < 0)
+ continue;
+ if (first > BASE_REGISTER && first > RETURN_REGNUM)
+ continue;
+ if (last < BASE_REGISTER && last < RETURN_REGNUM)
+ continue;
+
+ if (save_first != -1)
+ {
+ new_insn = save_gprs (base, off, save_first, save_last);
+ new_insn = emit_insn_before (new_insn, insn);
+ INSN_ADDRESSES_NEW (new_insn, -1);
+ }
+
+ remove_insn (insn);
}
- else
+
+ if (load_multiple_operation (PATTERN (insn), VOIDmode))
{
- fprintf (file, "\tbras\t%s,.LTN%X\n", reg_names[BASE_REGISTER],
- s390_function_count);
+ set = XVECEXP (PATTERN (insn), 0, 0);
+ first = REGNO (SET_DEST (set));
+ last = first + XVECLEN (PATTERN (insn), 0) - 1;
+ offset = const0_rtx;
+ base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
+ off = INTVAL (offset) - first * UNITS_PER_WORD;
+
+ if (GET_CODE (base) != REG || off < 0)
+ continue;
+ if (first > BASE_REGISTER && first > RETURN_REGNUM)
+ continue;
+ if (last < BASE_REGISTER && last < RETURN_REGNUM)
+ continue;
+
+ if (restore_first != -1)
+ {
+ new_insn = restore_gprs (base, off, restore_first, restore_last);
+ new_insn = emit_insn_before (new_insn, insn);
+ INSN_ADDRESSES_NEW (new_insn, -1);
+ }
+
+ remove_insn (insn);
}
- fprintf (file, ".LT%X:\n", s390_function_count);
+ }
+}
- s390_pool_count = 0;
- output_constant_pool (current_function_name, current_function_decl);
- s390_pool_count = -1;
+/* Check whether any insn in the function makes use of the original
+ value of RETURN_REG (e.g. for __builtin_return_address).
+ If so, insert an insn reloading that value.
- if (TARGET_64BIT)
- function_section (current_function_decl);
+ Return true if any such insn was found. */
+
+static bool
+s390_fixup_clobbered_return_reg (return_reg)
+ rtx return_reg;
+{
+ bool replacement_done = 0;
+ rtx insn;
+
+ /* If we never called __builtin_return_address, register 14
+ might have been used as temp during the prolog; we do
+ not want to touch those uses. */
+ if (!has_hard_reg_initial_val (Pmode, REGNO (return_reg)))
+ return false;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ rtx reg, off, new_insn;
+
+ if (GET_CODE (insn) != INSN)
+ continue;
+ if (!reg_referenced_p (return_reg, PATTERN (insn)))
+ continue;
+ if (GET_CODE (PATTERN (insn)) == PARALLEL
+ && store_multiple_operation (PATTERN (insn), VOIDmode))
+ continue;
+
+ if (frame_pointer_needed)
+ reg = hard_frame_pointer_rtx;
else
- fprintf (file, ".LTN%X:\n", s390_function_count);
+ reg = stack_pointer_rtx;
+
+ off = GEN_INT (cfun->machine->frame_size + REGNO (return_reg) * UNITS_PER_WORD);
+ if (INTVAL (off) >= 4096)
+ {
+ off = force_const_mem (Pmode, off);
+ new_insn = gen_rtx_SET (Pmode, return_reg, off);
+ new_insn = emit_insn_before (new_insn, insn);
+ INSN_ADDRESSES_NEW (new_insn, -1);
+ off = return_reg;
+ }
+
+ new_insn = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, reg, off));
+ new_insn = gen_rtx_SET (Pmode, return_reg, new_insn);
+ new_insn = emit_insn_before (new_insn, insn);
+ INSN_ADDRESSES_NEW (new_insn, -1);
+
+ replacement_done = 1;
}
-}
+ return replacement_done;
+}
-/* Return true if floating point registers need to be saved. */
+/* Perform machine-dependent processing. */
-static int
-save_fprs_p ()
+void
+s390_machine_dependent_reorg (first)
+ rtx first ATTRIBUTE_UNUSED;
{
- int i;
- if (!TARGET_64BIT)
- return 0;
- for (i=24; i<=31; i++)
+ bool fixed_up_clobbered_return_reg = 0;
+ rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
+ bool temp_used = 0;
+
+ /* Make sure all splits have been performed; splits after
+ machine_dependent_reorg might confuse insn length counts. */
+ split_all_insns_noflow ();
+
+
+ /* There are two problematic situations we need to correct:
+
+ - the literal pool might be > 4096 bytes in size, so that
+ some of its elements cannot be directly accessed
+
+ - a branch target might be > 64K away from the branch, so that
+ it is not possible to use a PC-relative instruction.
+
+ To fix those, we split the single literal pool into multiple
+ pool chunks, reloading the pool base register at various
+ points throughout the function to ensure it always points to
+ the pool chunk the following code expects, and / or replace
+ PC-relative branches by absolute branches.
+
+ However, the two problems are interdependent: splitting the
+ literal pool can move a branch further away from its target,
+ causing the 64K limit to overflow, and on the other hand,
+ replacing a PC-relative branch by an absolute branch means
+ we need to put the branch target address into the literal
+ pool, possibly causing it to overflow.
+
+ So, we loop trying to fix up both problems until we manage
+ to satisfy both conditions at the same time. Note that the
+ loop is guaranteed to terminate as every pass of the loop
+ strictly decreases the total number of PC-relative branches
+ in the function. (This is not completely true as there
+ might be branch-over-pool insns introduced by chunkify_start.
+ Those never need to be split however.) */
+
+ for (;;)
{
- if (regs_ever_live[i] == 1)
- return 1;
+ struct constant_pool *pool_list;
+
+ /* Try to chunkify the literal pool. */
+ pool_list = s390_chunkify_start (temp_reg, &temp_used);
+
+ /* Split out-of-range branches. If this has created new
+ literal pool entries, cancel current chunk list and
+ recompute it. */
+ if (s390_split_branches (temp_reg, &temp_used))
+ {
+ if (pool_list)
+ s390_chunkify_cancel (pool_list);
+
+ continue;
+ }
+
+ /* Check whether we have clobbered a use of the return
+ register (e.g. for __builtin_return_address). If so,
+ add insns reloading the register where necessary. */
+ if (temp_used && !fixed_up_clobbered_return_reg
+ && s390_fixup_clobbered_return_reg (temp_reg))
+ {
+ fixed_up_clobbered_return_reg = 1;
+
+ /* The fixup insns might have caused a jump to overflow. */
+ if (pool_list)
+ s390_chunkify_cancel (pool_list);
+
+ continue;
+ }
+
+ /* If we made it up to here, both conditions are satisfied.
+ Finish up pool chunkification if required. */
+ if (pool_list)
+ s390_chunkify_finish (pool_list, temp_reg);
+
+ break;
}
- return 0;
+
+ s390_optimize_prolog (temp_used? RETURN_REGNUM : -1);
}
+
+/* Return an RTL expression representing the value of the return address
+ for the frame COUNT steps up from the current frame. FRAME is the
+ frame pointer of that frame. */
+
+rtx
+s390_return_addr_rtx (count, frame)
+ int count;
+ rtx frame;
+{
+ rtx addr;
+
+ /* For the current frame, we use the initial value of RETURN_REGNUM.
+ This works both in leaf and non-leaf functions. */
+
+ if (count == 0)
+ return get_hard_reg_initial_val (Pmode, RETURN_REGNUM);
+
+ /* For frames farther back, we read the stack slot where the
+ corresponding RETURN_REGNUM value was saved. */
+
+ addr = plus_constant (frame, RETURN_REGNUM * UNITS_PER_WORD);
+ addr = memory_address (Pmode, addr);
+ return gen_rtx_MEM (Pmode, addr);
+}
+
/* Find first call clobbered register unsused in a function.
This could be used as base register in a leaf function
or for holding the return address before epilogue. */
@@ -3173,9 +4951,9 @@ find_unused_clobbered_reg ()
/* Fill FRAME with info about frame of current function. */
static void
-s390_frame_info (frame)
- struct s390_frame *frame;
+s390_frame_info ()
{
+ char gprs_ever_live[16];
int i, j;
HOST_WIDE_INT fsize = get_frame_size ();
@@ -3183,79 +4961,59 @@ s390_frame_info (frame)
fatal_error ("Total size of local variables exceeds architecture limit.");
/* fprs 8 - 15 are caller saved for 64 Bit ABI. */
- frame->save_fprs_p = save_fprs_p ();
+ cfun->machine->save_fprs_p = 0;
+ if (TARGET_64BIT)
+ for (i = 24; i < 32; i++)
+ if (regs_ever_live[i] && !global_regs[i])
+ {
+ cfun->machine->save_fprs_p = 1;
+ break;
+ }
- frame->frame_size = fsize + frame->save_fprs_p * 64;
+ cfun->machine->frame_size = fsize + cfun->machine->save_fprs_p * 64;
/* Does function need to setup frame and save area. */
if (! current_function_is_leaf
- || frame->frame_size > 0
+ || cfun->machine->frame_size > 0
|| current_function_calls_alloca
- || current_function_stdarg
- || current_function_varargs)
- frame->frame_size += STARTING_FRAME_OFFSET;
-
- /* If we need to allocate a frame, the stack pointer is changed. */
+ || current_function_stdarg)
+ cfun->machine->frame_size += STARTING_FRAME_OFFSET;
- if (frame->frame_size > 0)
- regs_ever_live[STACK_POINTER_REGNUM] = 1;
+ /* Find first and last gpr to be saved. Note that at this point,
+ we assume the return register and the base register always
+ need to be saved. This is done because the usage of these
+ register might change even after the prolog was emitted.
+ If it turns out later that we really don't need them, the
+ prolog/epilog code is modified again. */
- /* If the literal pool might overflow, the return register might
- be used as temp literal pointer. */
-
- if (!TARGET_64BIT && get_pool_size () >= S390_POOL_CHUNK_MAX / 2)
- regs_ever_live[RETURN_REGNUM] = 1;
+ for (i = 0; i < 16; i++)
+ gprs_ever_live[i] = regs_ever_live[i] && !global_regs[i];
- /* If there is (possibly) any pool entry, we need to
- load base register. */
-
- if (get_pool_size ()
- || !CONST_OK_FOR_LETTER_P (frame->frame_size, 'K')
- || (!TARGET_64BIT && current_function_uses_pic_offset_table))
- regs_ever_live[BASE_REGISTER] = 1;
-
- /* If we need the GOT pointer, remember to save/restore it. */
-
- if (current_function_uses_pic_offset_table)
- regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
-
- /* Frame pointer needed. */
-
- frame->frame_pointer_p = frame_pointer_needed;
-
- /* Find first and last gpr to be saved. */
+ if (flag_pic)
+ gprs_ever_live[PIC_OFFSET_TABLE_REGNUM] =
+ regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
+ gprs_ever_live[BASE_REGISTER] = 1;
+ gprs_ever_live[RETURN_REGNUM] = 1;
+ gprs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
for (i = 6; i < 16; i++)
- if (regs_ever_live[i])
+ if (gprs_ever_live[i])
break;
for (j = 15; j > i; j--)
- if (regs_ever_live[j])
+ if (gprs_ever_live[j])
break;
-
- if (i == 16)
- {
- /* Nothing to save / restore. */
- frame->first_save_gpr = -1;
- frame->first_restore_gpr = -1;
- frame->last_save_gpr = -1;
- frame->return_reg_saved_p = 0;
- }
- else
- {
- /* Save / Restore from gpr i to j. */
- frame->first_save_gpr = i;
- frame->first_restore_gpr = i;
- frame->last_save_gpr = j;
- frame->return_reg_saved_p = (j >= RETURN_REGNUM && i <= RETURN_REGNUM);
- }
- if (current_function_stdarg || current_function_varargs)
- {
- /* Varargs function need to save from gpr 2 to gpr 15. */
- frame->first_save_gpr = 2;
- }
+
+ /* Save / Restore from gpr i to j. */
+ cfun->machine->first_save_gpr = i;
+ cfun->machine->first_restore_gpr = i;
+ cfun->machine->last_save_gpr = j;
+
+ /* Varargs functions need to save gprs 2 to 6. */
+ if (current_function_stdarg)
+ cfun->machine->first_save_gpr = 2;
}
/* Return offset between argument pointer and frame pointer
@@ -3264,13 +5022,29 @@ s390_frame_info (frame)
int
s390_arg_frame_offset ()
{
- struct s390_frame frame;
+ HOST_WIDE_INT fsize = get_frame_size ();
+ int save_fprs_p, i;
- /* Compute frame_info. */
+ /* fprs 8 - 15 are caller saved for 64 Bit ABI. */
+ save_fprs_p = 0;
+ if (TARGET_64BIT)
+ for (i = 24; i < 32; i++)
+ if (regs_ever_live[i] && !global_regs[i])
+ {
+ save_fprs_p = 1;
+ break;
+ }
- s390_frame_info (&frame);
+ fsize = fsize + save_fprs_p * 64;
- return frame.frame_size + STACK_POINTER_OFFSET;
+ /* Does function need to setup frame and save area. */
+
+ if (! current_function_is_leaf
+ || fsize > 0
+ || current_function_calls_alloca
+ || current_function_stdarg)
+ fsize += STARTING_FRAME_OFFSET;
+ return fsize + STACK_POINTER_OFFSET;
}
/* Emit insn to save fpr REGNUM at offset OFFSET relative
@@ -3305,30 +5079,118 @@ restore_fpr (base, offset, regnum)
return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr);
}
-/* Output the function prologue assembly code to the
- stdio stream FILE. The local frame size is passed
- in LSIZE. */
+/* Generate insn to save registers FIRST to LAST into
+ the register save area located at offset OFFSET
+ relative to register BASE. */
-void
-s390_function_prologue (file, lsize)
- FILE *file ATTRIBUTE_UNUSED;
- HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
+static rtx
+save_gprs (base, offset, first, last)
+ rtx base;
+ int offset;
+ int first;
+ int last;
{
- s390_chunkify_pool ();
- s390_split_branches ();
+ rtx addr, insn, note;
+ int i;
+
+ addr = plus_constant (base, offset + first * UNITS_PER_WORD);
+ addr = gen_rtx_MEM (Pmode, addr);
+ set_mem_alias_set (addr, s390_sr_alias_set);
+
+ /* Special-case single register. */
+ if (first == last)
+ {
+ if (TARGET_64BIT)
+ insn = gen_movdi (addr, gen_rtx_REG (Pmode, first));
+ else
+ insn = gen_movsi (addr, gen_rtx_REG (Pmode, first));
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ return insn;
+ }
+
+
+ insn = gen_store_multiple (addr,
+ gen_rtx_REG (Pmode, first),
+ GEN_INT (last - first + 1));
+
+
+ /* We need to set the FRAME_RELATED flag on all SETs
+ inside the store-multiple pattern.
+
+ However, we must not emit DWARF records for registers 2..5
+ if they are stored for use by variable arguments ...
+
+ ??? Unfortunately, it is not enough to simply not the the
+ FRAME_RELATED flags for those SETs, because the first SET
+ of the PARALLEL is always treated as if it had the flag
+ set, even if it does not. Therefore we emit a new pattern
+ without those registers as REG_FRAME_RELATED_EXPR note. */
+
+ if (first >= 6)
+ {
+ rtx pat = PATTERN (insn);
+
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
+ RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else if (last >= 6)
+ {
+ addr = plus_constant (base, offset + 6 * UNITS_PER_WORD);
+ note = gen_store_multiple (gen_rtx_MEM (Pmode, addr),
+ gen_rtx_REG (Pmode, 6),
+ GEN_INT (last - 6 + 1));
+ note = PATTERN (note);
+
+ REG_NOTES (insn) =
+ gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ note, REG_NOTES (insn));
+
+ for (i = 0; i < XVECLEN (note, 0); i++)
+ if (GET_CODE (XVECEXP (note, 0, i)) == SET)
+ RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ return insn;
}
-/* Output the function epilogue assembly code to the
- stdio stream FILE. The local frame size is passed
- in LSIZE. */
+/* Generate insn to restore registers FIRST to LAST from
+ the register save area located at offset OFFSET
+ relative to register BASE. */
-void
-s390_function_epilogue (file, lsize)
- FILE *file ATTRIBUTE_UNUSED;
- HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
+static rtx
+restore_gprs (base, offset, first, last)
+ rtx base;
+ int offset;
+ int first;
+ int last;
{
- current_function_uses_pic_offset_table = 0;
- s390_function_count++;
+ rtx addr, insn;
+
+ addr = plus_constant (base, offset + first * UNITS_PER_WORD);
+ addr = gen_rtx_MEM (Pmode, addr);
+ set_mem_alias_set (addr, s390_sr_alias_set);
+
+ /* Special-case single register. */
+ if (first == last)
+ {
+ if (TARGET_64BIT)
+ insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
+ else
+ insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
+
+ return insn;
+ }
+
+ insn = gen_load_multiple (gen_rtx_REG (Pmode, first),
+ addr,
+ GEN_INT (last - first + 1));
+ return insn;
}
/* Expand the prologue into a bunch of separate insns. */
@@ -3336,18 +5198,18 @@ s390_function_epilogue (file, lsize)
void
s390_emit_prologue ()
{
- struct s390_frame frame;
rtx insn, addr;
rtx temp_reg;
+ rtx pool_start_label, pool_end_label;
int i;
/* Compute frame_info. */
- s390_frame_info (&frame);
+ s390_frame_info ();
/* Choose best register to use for temp use within prologue. */
- if (frame.return_reg_saved_p
+ if (!current_function_is_leaf
&& !has_hard_reg_initial_val (Pmode, RETURN_REGNUM)
&& get_pool_size () < S390_POOL_CHUNK_MAX / 2)
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
@@ -3356,75 +5218,26 @@ s390_emit_prologue ()
/* Save call saved gprs. */
- if (frame.first_save_gpr != -1)
- {
- addr = plus_constant (stack_pointer_rtx,
- frame.first_save_gpr * UNITS_PER_WORD);
- addr = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (addr, s390_sr_alias_set);
-
- if (frame.first_save_gpr != frame.last_save_gpr )
- {
- insn = emit_insn (gen_store_multiple (addr,
- gen_rtx_REG (Pmode, frame.first_save_gpr),
- GEN_INT (frame.last_save_gpr
- - frame.first_save_gpr + 1)));
-
- /* We need to set the FRAME_RELATED flag on all SETs
- inside the store-multiple pattern.
+ insn = save_gprs (stack_pointer_rtx, 0,
+ cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
+ emit_insn (insn);
- However, we must not emit DWARF records for registers 2..5
- if they are stored for use by variable arguments ...
+ /* Dump constant pool and set constant pool register. */
- ??? Unfortunately, it is not enough to simply not the the
- FRAME_RELATED flags for those SETs, because the first SET
- of the PARALLEL is always treated as if it had the flag
- set, even if it does not. Therefore we emit a new pattern
- without those registers as REG_FRAME_RELATED_EXPR note. */
-
- if (frame.first_save_gpr >= 6)
- {
- rtx pat = PATTERN (insn);
-
- for (i = 0; i < XVECLEN (pat, 0); i++)
- if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
- RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
-
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- else if (frame.last_save_gpr >= 6)
- {
- rtx note, naddr;
- naddr = plus_constant (stack_pointer_rtx, 6 * UNITS_PER_WORD);
- note = gen_store_multiple (gen_rtx_MEM (Pmode, naddr),
- gen_rtx_REG (Pmode, 6),
- GEN_INT (frame.last_save_gpr - 6 + 1));
- REG_NOTES (insn) =
- gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- note, REG_NOTES (insn));
-
- for (i = 0; i < XVECLEN (note, 0); i++)
- if (GET_CODE (XVECEXP (note, 0, i)) == SET)
- RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
-
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- }
- else
- {
- insn = emit_move_insn (addr,
- gen_rtx_REG (Pmode, frame.first_save_gpr));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
- }
-
- /* Dump constant pool and set constant pool register (13). */
-
- insn = emit_insn (gen_lit ());
+ pool_start_label = gen_label_rtx();
+ pool_end_label = gen_label_rtx();
+ cfun->machine->literal_pool_label = pool_start_label;
+
+ if (TARGET_64BIT)
+ insn = emit_insn (gen_literal_pool_64 (gen_rtx_REG (Pmode, BASE_REGISTER),
+ pool_start_label, pool_end_label));
+ else
+ insn = emit_insn (gen_literal_pool_31 (gen_rtx_REG (Pmode, BASE_REGISTER),
+ pool_start_label, pool_end_label));
/* Save fprs for variable args. */
- if (current_function_stdarg || current_function_varargs)
+ if (current_function_stdarg)
{
/* Save fpr 0 and 2. */
@@ -3445,12 +5258,12 @@ s390_emit_prologue ()
if (!TARGET_64BIT)
{
/* Save fpr 4 and 6. */
- if (regs_ever_live[18])
+ if (regs_ever_live[18] && !global_regs[18])
{
insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18);
RTX_FRAME_RELATED_P (insn) = 1;
}
- if (regs_ever_live[19])
+ if (regs_ever_live[19] && !global_regs[19])
{
insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19);
RTX_FRAME_RELATED_P (insn) = 1;
@@ -3459,21 +5272,21 @@ s390_emit_prologue ()
/* Decrement stack pointer. */
- if (frame.frame_size > 0)
+ if (cfun->machine->frame_size > 0)
{
- rtx frame_off = GEN_INT (-frame.frame_size);
+ rtx frame_off = GEN_INT (-cfun->machine->frame_size);
/* Save incoming stack pointer into temp reg. */
- if (TARGET_BACKCHAIN || frame.save_fprs_p)
+ if (TARGET_BACKCHAIN || cfun->machine->save_fprs_p)
{
insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
}
/* Substract frame size from stack pointer. */
- frame_off = GEN_INT (-frame.frame_size);
- if (!CONST_OK_FOR_LETTER_P (-frame.frame_size, 'K'))
+ frame_off = GEN_INT (-cfun->machine->frame_size);
+ if (!CONST_OK_FOR_LETTER_P (-cfun->machine->frame_size, 'K'))
frame_off = force_const_mem (Pmode, frame_off);
insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
@@ -3482,7 +5295,7 @@ s390_emit_prologue ()
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (-frame.frame_size))),
+ GEN_INT (-cfun->machine->frame_size))),
REG_NOTES (insn));
/* Set backchain. */
@@ -3493,19 +5306,29 @@ s390_emit_prologue ()
set_mem_alias_set (addr, s390_sr_alias_set);
insn = emit_insn (gen_move_insn (addr, temp_reg));
}
+
+ /* If we support asynchronous exceptions (e.g. for Java),
+ we need to make sure the backchain pointer is set up
+ before any possibly trapping memory access. */
+
+ if (TARGET_BACKCHAIN && flag_non_call_exceptions)
+ {
+ addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, addr));
+ }
}
/* Save fprs 8 - 15 (64 bit ABI). */
- if (frame.save_fprs_p)
+ if (cfun->machine->save_fprs_p)
{
insn = emit_insn (gen_add2_insn (temp_reg, GEN_INT(-64)));
for (i = 24; i < 32; i++)
- if (regs_ever_live[i])
+ if (regs_ever_live[i] && !global_regs[i])
{
rtx addr = plus_constant (stack_pointer_rtx,
- frame.frame_size - 64 + (i-24)*8);
+ cfun->machine->frame_size - 64 + (i-24)*8);
insn = save_fpr (temp_reg, (i-24)*8, i);
RTX_FRAME_RELATED_P (insn) = 1;
@@ -3520,7 +5343,7 @@ s390_emit_prologue ()
/* Set frame pointer, if needed. */
- if (frame.frame_pointer_p)
+ if (frame_pointer_needed)
{
insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
@@ -3528,7 +5351,7 @@ s390_emit_prologue ()
/* Set up got pointer, if needed. */
- if (current_function_uses_pic_offset_table)
+ if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
{
rtx got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
SYMBOL_REF_FLAG (got_symbol) = 1;
@@ -3553,8 +5376,10 @@ s390_emit_prologue ()
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
- insn = emit_insn (gen_add2_insn (pic_offset_table_rtx,
- gen_rtx_REG (Pmode, BASE_REGISTER)));
+ got_symbol = gen_rtx_REG (Pmode, BASE_REGISTER);
+ got_symbol = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol), 101);
+ got_symbol = gen_rtx_PLUS (Pmode, got_symbol, pic_offset_table_rtx);
+ insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
@@ -3566,26 +5391,21 @@ s390_emit_prologue ()
void
s390_emit_epilogue ()
{
- struct s390_frame frame;
rtx frame_pointer, return_reg;
- int area_bottom, area_top, offset;
+ int area_bottom, area_top, offset = 0;
rtvec p;
- /* Compute frame_info. */
-
- s390_frame_info (&frame);
-
/* Check whether to use frame or stack pointer for restore. */
- frame_pointer = frame.frame_pointer_p ?
+ frame_pointer = frame_pointer_needed ?
hard_frame_pointer_rtx : stack_pointer_rtx;
/* Compute which parts of the save area we need to access. */
- if (frame.first_restore_gpr != -1)
+ if (cfun->machine->first_restore_gpr != -1)
{
- area_bottom = frame.first_restore_gpr * UNITS_PER_WORD;
- area_top = (frame.last_save_gpr + 1) * UNITS_PER_WORD;
+ area_bottom = cfun->machine->first_restore_gpr * UNITS_PER_WORD;
+ area_top = (cfun->machine->last_save_gpr + 1) * UNITS_PER_WORD;
}
else
{
@@ -3595,7 +5415,7 @@ s390_emit_epilogue ()
if (TARGET_64BIT)
{
- if (frame.save_fprs_p)
+ if (cfun->machine->save_fprs_p)
{
if (area_bottom > -64)
area_bottom = -64;
@@ -3605,14 +5425,14 @@ s390_emit_epilogue ()
}
else
{
- if (regs_ever_live[18])
+ if (regs_ever_live[18] && !global_regs[18])
{
if (area_bottom > STACK_POINTER_OFFSET - 16)
area_bottom = STACK_POINTER_OFFSET - 16;
if (area_top < STACK_POINTER_OFFSET - 8)
area_top = STACK_POINTER_OFFSET - 8;
}
- if (regs_ever_live[19])
+ if (regs_ever_live[19] && !global_regs[19])
{
if (area_bottom > STACK_POINTER_OFFSET - 8)
area_bottom = STACK_POINTER_OFFSET - 8;
@@ -3628,18 +5448,18 @@ s390_emit_epilogue ()
{
/* Nothing to restore. */
}
- else if (frame.frame_size + area_bottom >= 0
- && frame.frame_size + area_top <= 4096)
+ else if (cfun->machine->frame_size + area_bottom >= 0
+ && cfun->machine->frame_size + area_top <= 4096)
{
/* Area is in range. */
- offset = frame.frame_size;
+ offset = cfun->machine->frame_size;
}
else
{
rtx insn, frame_off;
offset = area_bottom < 0 ? -area_bottom : 0;
- frame_off = GEN_INT (frame.frame_size - offset);
+ frame_off = GEN_INT (cfun->machine->frame_size - offset);
if (!CONST_OK_FOR_LETTER_P (INTVAL (frame_off), 'K'))
frame_off = force_const_mem (Pmode, frame_off);
@@ -3653,7 +5473,7 @@ s390_emit_epilogue ()
{
int i;
- if (frame.save_fprs_p)
+ if (cfun->machine->save_fprs_p)
for (i = 24; i < 32; i++)
if (regs_ever_live[i] && !global_regs[i])
restore_fpr (frame_pointer,
@@ -3673,16 +5493,16 @@ s390_emit_epilogue ()
/* Restore call saved gprs. */
- if (frame.first_restore_gpr != -1)
+ if (cfun->machine->first_restore_gpr != -1)
{
- rtx addr;
+ rtx insn, addr;
int i;
/* Check for global register and save them
to stack location from where they get restored. */
- for (i = frame.first_restore_gpr;
- i <= frame.last_save_gpr;
+ for (i = cfun->machine->first_restore_gpr;
+ i <= cfun->machine->last_save_gpr;
i++)
{
/* These registers are special and need to be
@@ -3690,7 +5510,7 @@ s390_emit_epilogue ()
if (i == STACK_POINTER_REGNUM
|| i == RETURN_REGNUM
|| i == BASE_REGISTER
- || (flag_pic && i == PIC_OFFSET_TABLE_REGNUM))
+ || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
continue;
if (global_regs[i])
@@ -3706,8 +5526,7 @@ s390_emit_epilogue ()
/* Fetch return address from stack before load multiple,
this will do good for scheduling. */
- if (frame.last_save_gpr >= RETURN_REGNUM
- && frame.first_restore_gpr < RETURN_REGNUM)
+ if (!current_function_is_leaf)
{
int return_regnum = find_unused_clobbered_reg();
if (!return_regnum)
@@ -3727,23 +5546,10 @@ s390_emit_epilogue ()
emit_insn (gen_blockage());
- addr = plus_constant (frame_pointer,
- offset + frame.first_restore_gpr * UNITS_PER_WORD);
- addr = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (addr, s390_sr_alias_set);
-
- if (frame.first_restore_gpr != frame.last_save_gpr)
- {
- emit_insn (gen_load_multiple (
- gen_rtx_REG (Pmode, frame.first_restore_gpr),
- addr,
- GEN_INT (frame.last_save_gpr - frame.first_restore_gpr + 1)));
- }
- else
- {
- emit_move_insn (gen_rtx_REG (Pmode, frame.first_restore_gpr),
- addr);
- }
+ insn = restore_gprs (frame_pointer, offset,
+ cfun->machine->first_restore_gpr,
+ cfun->machine->last_save_gpr);
+ emit_insn (insn);
}
/* Return to caller. */
@@ -3906,7 +5712,7 @@ s390_build_va_list ()
{
tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
- record = make_lang_type (RECORD_TYPE);
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
type_decl =
build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
@@ -3939,9 +5745,8 @@ s390_build_va_list ()
}
/* Implement va_start by filling the va_list structure VALIST.
- STDARG_P is true if implementing __builtin_stdarg_va_start,
- false if implementing __builtin_varargs_va_start. NEXTARG
- points to the first anonymous stack argument.
+ STDARG_P is always true, and ignored.
+ NEXTARG points to the first anonymous stack argument.
The following global variables are used to initialize
the va_list structure:
@@ -3953,8 +5758,7 @@ s390_build_va_list ()
(relative to the virtual arg pointer). */
void
-s390_va_start (stdarg_p, valist, nextarg)
- int stdarg_p;
+s390_va_start (valist, nextarg)
tree valist;
rtx nextarg ATTRIBUTE_UNUSED;
{
@@ -3992,8 +5796,6 @@ s390_va_start (stdarg_p, valist, nextarg)
off = INTVAL (current_function_arg_offset_rtx);
off = off < 0 ? 0 : off;
- if (! stdarg_p)
- off = off > 0 ? off - UNITS_PER_WORD : off;
if (TARGET_DEBUG_ARG)
fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n",
(int)n_gpr, (int)n_fpr, off);
@@ -4200,6 +6002,134 @@ s390_va_arg (valist, type)
}
+/* Builtins. */
+
+enum s390_builtin
+{
+ S390_BUILTIN_THREAD_POINTER,
+ S390_BUILTIN_SET_THREAD_POINTER,
+
+ S390_BUILTIN_max
+};
+
+static unsigned int const code_for_builtin_64[S390_BUILTIN_max] = {
+ CODE_FOR_get_tp_64,
+ CODE_FOR_set_tp_64
+};
+
+static unsigned int const code_for_builtin_31[S390_BUILTIN_max] = {
+ CODE_FOR_get_tp_31,
+ CODE_FOR_set_tp_31
+};
+
+static void
+s390_init_builtins ()
+{
+ tree ftype;
+
+ ftype = build_function_type (ptr_type_node, void_list_node);
+ builtin_function ("__builtin_thread_pointer", ftype,
+ S390_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
+ NULL, NULL_TREE);
+
+ ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+ builtin_function ("__builtin_set_thread_pointer", ftype,
+ S390_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
+ NULL, NULL_TREE);
+}
+
+/* Expand an expression EXP that calls a built-in function,
+ with result going to TARGET if that's convenient
+ (and in mode MODE if that's convenient).
+ SUBTARGET may be used as the target for computing one of EXP's operands.
+ IGNORE is nonzero if the value is to be ignored. */
+
+static rtx
+s390_expand_builtin (exp, target, subtarget, mode, ignore)
+ tree exp;
+ rtx target;
+ rtx subtarget ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ int ignore ATTRIBUTE_UNUSED;
+{
+#define MAX_ARGS 2
+
+ unsigned int const *code_for_builtin =
+ TARGET_64BIT ? code_for_builtin_64 : code_for_builtin_31;
+
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ tree arglist = TREE_OPERAND (exp, 1);
+ enum insn_code icode;
+ rtx op[MAX_ARGS], pat;
+ int arity;
+ bool nonvoid;
+
+ if (fcode >= S390_BUILTIN_max)
+ internal_error ("bad builtin fcode");
+ icode = code_for_builtin[fcode];
+ if (icode == 0)
+ internal_error ("bad builtin fcode");
+
+ nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+
+ for (arglist = TREE_OPERAND (exp, 1), arity = 0;
+ arglist;
+ arglist = TREE_CHAIN (arglist), arity++)
+ {
+ const struct insn_operand_data *insn_op;
+
+ tree arg = TREE_VALUE (arglist);
+ if (arg == error_mark_node)
+ return NULL_RTX;
+ if (arity > MAX_ARGS)
+ return NULL_RTX;
+
+ insn_op = &insn_data[icode].operand[arity + nonvoid];
+
+ op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0);
+
+ if (!(*insn_op->predicate) (op[arity], insn_op->mode))
+ op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
+ }
+
+ 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))
+ target = gen_reg_rtx (tmode);
+ }
+
+ switch (arity)
+ {
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ if (nonvoid)
+ pat = GEN_FCN (icode) (target, op[0]);
+ else
+ pat = GEN_FCN (icode) (op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ default:
+ abort ();
+ }
+ if (!pat)
+ return NULL_RTX;
+ emit_insn (pat);
+
+ if (nonvoid)
+ return target;
+ else
+ return const0_rtx;
+}
+
+
/* Output assembly code for the trampoline template to
stdio stream FILE.
@@ -4285,7 +6215,7 @@ s390_function_profiler (file, labelno)
rtx op[7];
char label[128];
- sprintf (label, "%sP%d", LPREFIX, labelno);
+ ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
fprintf (file, "# function profiler \n");
@@ -4344,3 +6274,353 @@ s390_function_profiler (file, labelno)
}
}
+/* Select section for constant in constant pool. In 32-bit mode,
+ constants go in the function section; in 64-bit mode in .rodata. */
+
+static void
+s390_select_rtx_section (mode, x, align)
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx x ATTRIBUTE_UNUSED;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ if (TARGET_64BIT)
+ readonly_data_section ();
+ else
+ function_section (current_function_decl);
+}
+
+/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF
+ into its name and SYMBOL_REF_FLAG. */
+
+static void
+s390_encode_section_info (decl, first)
+ tree decl;
+ int first ATTRIBUTE_UNUSED;
+{
+ bool local_p = (*targetm.binds_local_p) (decl);
+ rtx rtl, symbol;
+
+ rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl);
+ if (GET_CODE (rtl) != MEM)
+ return;
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ /* When using PIC, SYMBOL_REF_FLAG marks non-global symbols
+ that can be accessed directly. */
+ if (flag_pic)
+ SYMBOL_REF_FLAG (symbol) = local_p;
+
+ /* Encode thread-local data with %[GLil] for "global dynamic",
+ "local dynamic", "initial exec" or "local exec" TLS models,
+ respectively. */
+
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ {
+ const char *symbol_str = XSTR (symbol, 0);
+ char *newstr;
+ size_t len;
+ enum tls_model kind = decl_tls_model (decl);
+
+ if (!flag_pic)
+ {
+ /* We don't allow non-pic code for shared libraries,
+ so don't generate GD/LD TLS models for non-pic code. */
+ switch (kind)
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ kind = TLS_MODEL_INITIAL_EXEC; break;
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ kind = TLS_MODEL_LOCAL_EXEC; break;
+ default:
+ break;
+ }
+ }
+
+ if (symbol_str[0] == '%')
+ {
+ if (symbol_str[1] == tls_model_chars[kind])
+ return;
+ symbol_str += 2;
+ }
+ len = strlen (symbol_str) + 1;
+ newstr = alloca (len + 2);
+
+ newstr[0] = '%';
+ newstr[1] = tls_model_chars[kind];
+ memcpy (newstr + 2, symbol_str, len);
+
+ XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1);
+ }
+
+ /* If a variable has a forced alignment to < 2 bytes, mark it
+ with '@' to prevent it from being used as LARL operand. */
+
+ else if (TREE_CODE (decl) == VAR_DECL
+ && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16
+ && XSTR (symbol, 0)[0] != '@')
+ {
+ const char *symbol_str = XSTR (symbol, 0);
+ size_t len = strlen (symbol_str) + 1;
+ char *newstr = alloca (len + 1);
+
+ newstr[0] = '@';
+ memcpy (newstr + 1, symbol_str, len);
+
+ XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 1 - 1);
+ }
+}
+
+/* Undo the above when printing symbol names. */
+
+static const char *
+s390_strip_name_encoding (str)
+ const char *str;
+{
+ if (str[0] == '%')
+ str += 2;
+ if (str[0] == '@')
+ str += 1;
+ if (str[0] == '*')
+ str += 1;
+ return str;
+}
+
+/* Output thunk to FILE that implements a C++ virtual function call (with
+ multiple inheritance) to FUNCTION. The thunk adjusts the this pointer
+ by DELTA, and unless VCALL_OFFSET is zero, applies an additional adjustment
+ stored at VCALL_OFFSET in the vtable whose address is located at offset 0
+ relative to the resulting this pointer. */
+
+static void
+s390_output_mi_thunk (file, thunk, delta, vcall_offset, function)
+ FILE *file;
+ tree thunk ATTRIBUTE_UNUSED;
+ HOST_WIDE_INT delta;
+ HOST_WIDE_INT vcall_offset;
+ tree function;
+{
+ rtx op[10];
+ int nonlocal = 0;
+
+ /* Operand 0 is the target function. */
+ op[0] = XEXP (DECL_RTL (function), 0);
+ if (flag_pic && !SYMBOL_REF_FLAG (op[0]))
+ {
+ nonlocal = 1;
+ op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]),
+ TARGET_64BIT ? 113 : flag_pic == 2 ? 112 : 110);
+ op[0] = gen_rtx_CONST (Pmode, op[0]);
+ }
+
+ /* Operand 1 is the 'this' pointer. */
+ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+ op[1] = gen_rtx_REG (Pmode, 3);
+ else
+ op[1] = gen_rtx_REG (Pmode, 2);
+
+ /* Operand 2 is the delta. */
+ op[2] = GEN_INT (delta);
+
+ /* Operand 3 is the vcall_offset. */
+ op[3] = GEN_INT (vcall_offset);
+
+ /* Operand 4 is the temporary register. */
+ op[4] = gen_rtx_REG (Pmode, 1);
+
+ /* Operands 5 to 8 can be used as labels. */
+ op[5] = NULL_RTX;
+ op[6] = NULL_RTX;
+ op[7] = NULL_RTX;
+ op[8] = NULL_RTX;
+
+ /* Operand 9 can be used for temporary register. */
+ op[9] = NULL_RTX;
+
+ /* Generate code. */
+ if (TARGET_64BIT)
+ {
+ /* Setup literal pool pointer if required. */
+ if (!CONST_OK_FOR_LETTER_P (delta, 'K')
+ || !CONST_OK_FOR_LETTER_P (vcall_offset, 'K'))
+ {
+ op[5] = gen_label_rtx ();
+ output_asm_insn ("larl\t%4,%5", op);
+ }
+
+ /* Add DELTA to this pointer. */
+ if (delta)
+ {
+ if (CONST_OK_FOR_LETTER_P (delta, 'J'))
+ output_asm_insn ("la\t%1,%2(%1)", op);
+ else if (CONST_OK_FOR_LETTER_P (delta, 'K'))
+ output_asm_insn ("aghi\t%1,%2", op);
+ else
+ {
+ op[6] = gen_label_rtx ();
+ output_asm_insn ("agf\t%1,%6-%5(%4)", op);
+ }
+ }
+
+ /* Perform vcall adjustment. */
+ if (vcall_offset)
+ {
+ if (CONST_OK_FOR_LETTER_P (vcall_offset, 'J'))
+ {
+ output_asm_insn ("lg\t%4,0(%1)", op);
+ output_asm_insn ("ag\t%1,%3(%4)", op);
+ }
+ else if (CONST_OK_FOR_LETTER_P (vcall_offset, 'K'))
+ {
+ output_asm_insn ("lghi\t%4,%3", op);
+ output_asm_insn ("ag\t%4,0(%1)", op);
+ output_asm_insn ("ag\t%1,0(%4)", op);
+ }
+ else
+ {
+ op[7] = gen_label_rtx ();
+ output_asm_insn ("llgf\t%4,%7-%5(%4)", op);
+ output_asm_insn ("ag\t%4,0(%1)", op);
+ output_asm_insn ("ag\t%1,0(%4)", op);
+ }
+ }
+
+ /* Jump to target. */
+ output_asm_insn ("jg\t%0", op);
+
+ /* Output literal pool if required. */
+ if (op[5])
+ {
+ output_asm_insn (".align\t4", op);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5]));
+ }
+ if (op[6])
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6]));
+ output_asm_insn (".long\t%2", op);
+ }
+ if (op[7])
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[7]));
+ output_asm_insn (".long\t%3", op);
+ }
+ }
+ else
+ {
+ /* Setup base pointer if required. */
+ if (!vcall_offset
+ || !CONST_OK_FOR_LETTER_P (delta, 'K')
+ || !CONST_OK_FOR_LETTER_P (vcall_offset, 'K'))
+ {
+ op[5] = gen_label_rtx ();
+ output_asm_insn ("basr\t%4,0", op);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5]));
+ }
+
+ /* Add DELTA to this pointer. */
+ if (delta)
+ {
+ if (CONST_OK_FOR_LETTER_P (delta, 'J'))
+ output_asm_insn ("la\t%1,%2(%1)", op);
+ else if (CONST_OK_FOR_LETTER_P (delta, 'K'))
+ output_asm_insn ("ahi\t%1,%2", op);
+ else
+ {
+ op[6] = gen_label_rtx ();
+ output_asm_insn ("a\t%1,%6-%5(%4)", op);
+ }
+ }
+
+ /* Perform vcall adjustment. */
+ if (vcall_offset)
+ {
+ if (CONST_OK_FOR_LETTER_P (vcall_offset, 'J'))
+ {
+ output_asm_insn ("lg\t%4,0(%1)", op);
+ output_asm_insn ("a\t%1,%3(%4)", op);
+ }
+ else if (CONST_OK_FOR_LETTER_P (vcall_offset, 'K'))
+ {
+ output_asm_insn ("lhi\t%4,%3", op);
+ output_asm_insn ("a\t%4,0(%1)", op);
+ output_asm_insn ("a\t%1,0(%4)", op);
+ }
+ else
+ {
+ op[7] = gen_label_rtx ();
+ output_asm_insn ("l\t%4,%7-%5(%4)", op);
+ output_asm_insn ("a\t%4,0(%1)", op);
+ output_asm_insn ("a\t%1,0(%4)", op);
+ }
+
+ /* We had to clobber the base pointer register.
+ Re-setup the base pointer (with a different base). */
+ op[5] = gen_label_rtx ();
+ output_asm_insn ("basr\t%4,0", op);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5]));
+ }
+
+ /* Jump to target. */
+ op[8] = gen_label_rtx ();
+
+ if (!flag_pic)
+ output_asm_insn ("l\t%4,%8-%5(%4)", op);
+ else if (!nonlocal)
+ output_asm_insn ("a\t%4,%8-%5(%4)", op);
+ /* We cannot call through .plt, since .plt requires %r12 loaded. */
+ else if (flag_pic == 1)
+ {
+ output_asm_insn ("a\t%4,%8-%5(%4)", op);
+ output_asm_insn ("l\t%4,%0(%4)", op);
+ }
+ else if (flag_pic == 2)
+ {
+ op[9] = gen_rtx_REG (Pmode, 0);
+ output_asm_insn ("l\t%9,%8-4-%5(%4)", op);
+ output_asm_insn ("a\t%4,%8-%5(%4)", op);
+ output_asm_insn ("ar\t%4,%9", op);
+ output_asm_insn ("l\t%4,0(%4)", op);
+ }
+
+ output_asm_insn ("br\t%4", op);
+
+ /* Output literal pool. */
+ output_asm_insn (".align\t4", op);
+
+ if (nonlocal && flag_pic == 2)
+ output_asm_insn (".long\t%0", op);
+ if (nonlocal)
+ {
+ op[0] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+ SYMBOL_REF_FLAG (op[0]) = 1;
+ }
+
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[8]));
+ if (!flag_pic)
+ output_asm_insn (".long\t%0", op);
+ else
+ output_asm_insn (".long\t%0-%5", op);
+
+ if (op[6])
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6]));
+ output_asm_insn (".long\t%2", op);
+ }
+ if (op[7])
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[7]));
+ output_asm_insn (".long\t%3", op);
+ }
+ }
+}
+
+/* How to allocate a 'struct machine_function'. */
+
+static struct machine_function *
+s390_init_machine_status ()
+{
+ return ggc_alloc_cleared (sizeof (struct machine_function));
+}
+
+#include "gt-s390.h"
diff --git a/contrib/gcc/config/s390/s390.h b/contrib/gcc/config/s390/s390.h
index f3218e9..c3dad68 100644
--- a/contrib/gcc/config/s390/s390.h
+++ b/contrib/gcc/config/s390/s390.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for IBM S/390
- Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
Ulrich Weigand (uweigand@de.ibm.com).
This file is part of GNU CC.
@@ -22,13 +22,29 @@ Boston, MA 02111-1307, USA. */
#ifndef _S390_H
#define _S390_H
-extern int flag_pic;
+/* Override the __fixdfdi etc. routines when building libgcc2.
+ ??? This should be done in a cleaner way ... */
+#if defined (IN_LIBGCC2) && !defined (__s390x__)
+#include <s390/fixdfdi.h>
+#endif
-/* Run-time compilation parameters selecting different hardware subsets. */
-extern int target_flags;
+/* Run-time target specification. */
-/* Target macros checked at runtime of compiler. */
+/* Target CPU builtins. */
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_assert ("cpu=s390"); \
+ builtin_assert ("machine=s390"); \
+ builtin_define ("__s390__"); \
+ if (TARGET_64BIT) \
+ builtin_define ("__s390x__"); \
+ } \
+ while (0)
+
+/* Optional target features. */
+extern int target_flags;
#define TARGET_HARD_FLOAT (target_flags & 1)
#define TARGET_SOFT_FLOAT (!(target_flags & 1))
@@ -38,26 +54,22 @@ extern int target_flags;
#define TARGET_64BIT (target_flags & 16)
#define TARGET_MVCLE (target_flags & 32)
+/* ??? Once this actually works, it could be made a runtime option. */
+#define TARGET_IBM_FLOAT 0
+#define TARGET_IEEE_FLOAT 1
+
#ifdef DEFAULT_TARGET_64BIT
#define TARGET_DEFAULT 0x13
-#define TARGET_VERSION fprintf (stderr, " (zSeries)");
#else
#define TARGET_DEFAULT 0x3
-#define TARGET_VERSION fprintf (stderr, " (S/390)");
#endif
-
-/* Macro to define tables used to set the flags. This is a list in braces
- of pairs in braces, each pair being { "NAME", VALUE }
- where VALUE is the bits to set or minus the bits to clear.
- An empty string NAME is used to identify the default VALUE. */
-
#define TARGET_SWITCHES \
{ { "hard-float", 1, N_("Use hardware fp")}, \
{ "soft-float", -1, N_("Don't use hardware fp")}, \
{ "backchain", 2, N_("Set backchain")}, \
{ "no-backchain", -2, N_("Don't set backchain (faster, but debug harder")}, \
- { "small-exec", 4, N_("Use bras for execucable < 64k")}, \
+ { "small-exec", 4, N_("Use bras for executable < 64k")}, \
{ "no-small-exec",-4, N_("Don't use bras")}, \
{ "debug", 8, N_("Additional debug prints")}, \
{ "no-debug", -8, N_("Don't print additional debug prints")}, \
@@ -67,97 +79,50 @@ extern int target_flags;
{ "no-mvcle", -32, N_("mvc&ex")}, \
{ "", TARGET_DEFAULT, 0 } }
-/* Define this to change the optimizations performed by default. */
-#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options(LEVEL, SIZE)
+/* Target version string. Overridden by the OS header. */
+#ifdef DEFAULT_TARGET_64BIT
+#define TARGET_VERSION fprintf (stderr, " (zSeries)");
+#else
+#define TARGET_VERSION fprintf (stderr, " (S/390)");
+#endif
-/* Sometimes certain combinations of command options do not make sense
- on a particular target machine. You can define a macro
- `OVERRIDE_OPTIONS' to take account of this. This macro, if
- defined, is executed once just after all the command options have
- been parsed. */
+/* Hooks to override options. */
+#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options(LEVEL, SIZE)
#define OVERRIDE_OPTIONS override_options ()
+/* Frame pointer is not used for debugging. */
+#define CAN_DEBUG_WITHOUT_FP
-/* Defines for REAL_ARITHMETIC. */
-#define IEEE_FLOAT 1
-#define TARGET_IBM_FLOAT 0
-#define TARGET_IEEE_FLOAT 1
-
-/* The current function count for create unique internal labels. */
-
-extern int s390_function_count;
-/* The amount of space used for outgoing arguments. */
+/* In libgcc2, determine target settings as compile-time constants. */
+#ifdef IN_LIBGCC2
+#undef TARGET_64BIT
+#ifdef __s390x__
+#define TARGET_64BIT 1
+#else
+#define TARGET_64BIT 0
+#endif
+#endif
-extern int current_function_outgoing_args_size;
/* Target machine storage layout. */
-/* Define this if most significant bit is lowest numbered in instructions
- that operate on numbered bit-fields. */
-
+/* Everything is big-endian. */
#define BITS_BIG_ENDIAN 1
-
-/* Define this if most significant byte of a word is the lowest numbered. */
-
#define BYTES_BIG_ENDIAN 1
-
-/* Define this if MS word of a multiword is the lowest numbered. */
-
#define WORDS_BIG_ENDIAN 1
-/* Number of bits in an addressable storage unit. */
-
-#define BITS_PER_UNIT 8
-
-/* Width in bits of a "word", which is the contents of a machine register. */
-
-#define BITS_PER_WORD (TARGET_64BIT ? 64 : 32)
-#define MAX_BITS_PER_WORD 64
-
/* Width of a word, in units (bytes). */
-
#define UNITS_PER_WORD (TARGET_64BIT ? 8 : 4)
+#ifndef IN_LIBGCC2
#define MIN_UNITS_PER_WORD 4
+#endif
+#define MAX_BITS_PER_WORD 64
-/* Width in bits of a pointer. See also the macro `Pmode' defined below. */
-
-#define POINTER_SIZE (TARGET_64BIT ? 64 : 32)
-
-/* A C expression for the size in bits of the type `short' on the
- target machine. If you don't define this, the default is half a
- word. (If this would be less than one storage unit, it is
- rounded up to one unit.) */
-#define SHORT_TYPE_SIZE 16
-
-/* A C expression for the size in bits of the type `int' on the
- target machine. If you don't define this, the default is one
- word. */
-#define INT_TYPE_SIZE 32
-
-/* A C expression for the size in bits of the type `long' on the
- target machine. If you don't define this, the default is one
- word. */
-#define LONG_TYPE_SIZE (TARGET_64BIT ? 64 : 32)
-#define MAX_LONG_TYPE_SIZE 64
-
-/* A C expression for the size in bits of the type `long long' on the
- target machine. If you don't define this, the default is two
- words. */
-#define LONG_LONG_TYPE_SIZE 64
-
-/* Right now we only support two floating point formats, the
- 32 and 64 bit ieee formats. */
-
-#define FLOAT_TYPE_SIZE 32
-#define DOUBLE_TYPE_SIZE 64
-#define LONG_DOUBLE_TYPE_SIZE 64
-
-/* Define this macro if it is advisable to hold scalars in registers
- in a wider mode than that declared by the program. In such cases,
- the value is constrained to be within the bounds of the declared
- type, but kept valid in the wider mode. The signedness of the
- extension may differ from that of the type. */
+/* Function arguments and return values are promoted to word size. */
+#define PROMOTE_FUNCTION_ARGS
+#define PROMOTE_FUNCTION_RETURN
+#define PROMOTE_FOR_CALL_ONLY
#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
if (INTEGRAL_MODE_P (MODE) && \
@@ -165,109 +130,109 @@ if (INTEGRAL_MODE_P (MODE) && \
(MODE) = Pmode; \
}
-/* Defining PROMOTE_FUNCTION_ARGS eliminates some unnecessary zero/sign
- extensions applied to char/short functions arguments. Defining
- PROMOTE_FUNCTION_RETURN does the same for function returns. */
-
-#define PROMOTE_FUNCTION_ARGS
-#define PROMOTE_FUNCTION_RETURN
-#define PROMOTE_FOR_CALL_ONLY
-
-/* Allocation boundary (in *bits*) for storing pointers in memory. */
-
-#define POINTER_BOUNDARY 32
-
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
-
#define PARM_BOUNDARY (TARGET_64BIT ? 64 : 32)
/* Boundary (in *bits*) on which stack pointer should be aligned. */
-
#define STACK_BOUNDARY 64
/* Allocation boundary (in *bits*) for the code of a function. */
-
#define FUNCTION_BOUNDARY 32
/* There is no point aligning anything to a rounder boundary than this. */
-
#define BIGGEST_ALIGNMENT 64
/* Alignment of field after `int : 0' in a structure. */
-
#define EMPTY_FIELD_BOUNDARY 32
/* Alignment on even addresses for LARL instruction. */
-
#define CONSTANT_ALIGNMENT(EXP, ALIGN) (ALIGN) < 16 ? 16 : (ALIGN)
-
#define DATA_ALIGNMENT(TYPE, ALIGN) (ALIGN) < 16 ? 16 : (ALIGN)
-/* Define this if move instructions will actually fail to work when given
- unaligned data. */
-
+/* Alignment is not required by the hardware. */
#define STRICT_ALIGNMENT 0
-/* real arithmetic */
-
-#define REAL_ARITHMETIC
+/* Mode of stack savearea.
+ FUNCTION is VOIDmode because calling convention maintains SP.
+ BLOCK needs Pmode for SP.
+ NONLOCAL needs twice Pmode to maintain both backchain and SP. */
+#define STACK_SAVEAREA_MODE(LEVEL) \
+ (LEVEL == SAVE_FUNCTION ? VOIDmode \
+ : LEVEL == SAVE_NONLOCAL ? (TARGET_64BIT ? TImode : DImode) : Pmode)
/* Define target floating point format. */
+#define TARGET_FLOAT_FORMAT \
+ (TARGET_IEEE_FLOAT? IEEE_FLOAT_FORMAT : IBM_FLOAT_FORMAT)
-#undef TARGET_FLOAT_FORMAT
-#ifdef IEEE_FLOAT
-#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
-#else
-#define TARGET_FLOAT_FORMAT IBM_FLOAT_FORMAT
-#endif
-/* Define if special allocation order desired. */
+/* Type layout. */
-#define REG_ALLOC_ORDER \
-{ 1, 2, 3, 4, 5, 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, \
- 16, 17, 18, 19, 20, 21, 22, 23, \
- 24, 25, 26, 27, 28, 29, 30, 31, \
- 15, 32, 33, 34 }
+/* Sizes in bits of the source language data types. */
+#define SHORT_TYPE_SIZE 16
+#define INT_TYPE_SIZE 32
+#define LONG_TYPE_SIZE (TARGET_64BIT ? 64 : 32)
+#define MAX_LONG_TYPE_SIZE 64
+#define LONG_LONG_TYPE_SIZE 64
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE 64 /* ??? Should support extended format. */
-/* Standard register usage. */
-
-#define INT_REGNO_P(N) ( (int)(N) >= 0 && (N) < 16 )
-#ifdef IEEE_FLOAT
-#define FLOAT_REGNO_P(N) ( (N) >= 16 && (N) < 32 )
-#else
-#define FLOAT_REGNO_P(N) ( (N) >= 16 && (N) < 20 )
-#endif
-#define CC_REGNO_P(N) ( (N) == 33 )
-
-/* Number of actual hardware registers. The hardware registers are
- assigned numbers for the compiler from 0 to just below
- FIRST_PSEUDO_REGISTER.
- All registers that the compiler knows about must be given numbers,
- even those that are not normally considered general registers.
- For the 390, we give the data registers numbers 0-15,
- and the floating point registers numbers 16-19.
- G5 and following have 16 IEEE floating point register,
- which get numbers 16-31. */
+/* We use "unsigned char" as default. */
+#define DEFAULT_SIGNED_CHAR 0
-#define FIRST_PSEUDO_REGISTER 35
-/* Number of hardware registers that go into the DWARF-2 unwind info.
- If not defined, equals FIRST_PSEUDO_REGISTER. */
+/* Register usage. */
-#define DWARF_FRAME_REGISTERS 34
+/* We have 16 general purpose registers (registers 0-15),
+ and 16 floating point registers (registers 16-31).
+ (On non-IEEE machines, we have only 4 fp registers.)
+
+ Amongst the general purpose registers, some are used
+ for specific purposes:
+ GPR 11: Hard frame pointer (if needed)
+ GPR 12: Global offset table pointer (if needed)
+ GPR 13: Literal pool base register
+ 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 */
-/* The following register have a fix usage
- GPR 12: GOT register points to the GOT, setup in prologue,
- GOT contains pointer to variables in shared libraries
- GPR 13: Base register setup in prologue to point to the
- literal table of each function
- GPR 14: Return registers holds the return address
- GPR 15: Stack pointer */
+#define FIRST_PSEUDO_REGISTER 35
+
+/* Standard register usage. */
+#define GENERAL_REGNO_P(N) ((int)(N) >= 0 && (N) < 16)
+#define ADDR_REGNO_P(N) ((N) >= 1 && (N) < 16)
+#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)
+
+#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 PIC_OFFSET_TABLE_REGNUM (flag_pic ? 12 : INVALID_REGNUM)
#define BASE_REGISTER 13
#define RETURN_REGNUM 14
-#define STACK_POINTER_REGNUM 15
+#define CC_REGNUM 33
+
+/* Set up fixed registers and calling convention:
+
+ GPRs 0-5 are always call-clobbered,
+ GPRs 6-15 are always call-saved.
+ GPR 12 is fixed if used as GOT pointer.
+ GPR 13 is always fixed (as literal pool pointer).
+ GPR 14 is always fixed (as return address).
+ GPR 15 is always fixed (as stack pointer).
+ The 'fake' hard registers are call-clobbered and fixed.
+
+ On 31-bit, FPRs 18-19 are call-clobbered;
+ on 64-bit, FPRs 24-31 are call-clobbered.
+ The remaining FPRs are call-saved. */
#define FIXED_REGISTERS \
{ 0, 0, 0, 0, \
@@ -280,12 +245,6 @@ if (INTEGRAL_MODE_P (MODE) && \
0, 0, 0, 0, \
1, 1, 1 }
-/* 1 for registers not available across function calls. These must include
- the FIXED_REGISTERS and also any registers that can be used without being
- saved.
- The latter must include the registers where values are returned
- and the register where structure-value addresses are passed. */
-
#define CALL_USED_REGISTERS \
{ 1, 1, 1, 1, \
1, 1, 0, 0, \
@@ -297,10 +256,6 @@ if (INTEGRAL_MODE_P (MODE) && \
1, 1, 1, 1, \
1, 1, 1 }
-/* Like `CALL_USED_REGISTERS' except this macro doesn't require that
- the entire set of `FIXED_REGISTERS' be included.
- (`CALL_USED_REGISTERS' must be a superset of `FIXED_REGISTERS'). */
-
#define CALL_REALLY_USED_REGISTERS \
{ 1, 1, 1, 1, \
1, 1, 0, 0, \
@@ -312,8 +267,6 @@ if (INTEGRAL_MODE_P (MODE) && \
1, 1, 1, 1, \
1, 1, 1 }
-/* Macro to conditionally modify fixed_regs/call_used_regs. */
-
#define CONDITIONAL_REGISTER_USAGE \
do \
{ \
@@ -336,160 +289,85 @@ do \
} \
} while (0)
-/* The following register have a special usage
- GPR 11: Frame pointer if needed to point to automatic variables.
- GPR 32: In functions with more the 5 args this register
- points to that arguments, it is always eliminated
- with stack- or frame-pointer.
- GPR 33: Condition code 'register' */
-
-#define HARD_FRAME_POINTER_REGNUM 11
-#define FRAME_POINTER_REGNUM 34
-
-#define ARG_POINTER_REGNUM 32
-
-#define CC_REGNUM 33
-
-/* We use the register %r0 to pass the static chain to a nested function.
-
- Note: It is assumed that this register is call-clobbered!
- We can't use any of the function-argument registers either,
- and register 1 is needed by the trampoline code, so we have
- no other choice but using this one ... */
+/* Preferred register allocation order. */
+#define REG_ALLOC_ORDER \
+{ 1, 2, 3, 4, 5, 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, \
+ 16, 17, 18, 19, 20, 21, 22, 23, \
+ 24, 25, 26, 27, 28, 29, 30, 31, \
+ 15, 32, 33, 34 }
-#define STATIC_CHAIN_REGNUM 0
-/* Return number of consecutive hard regs needed starting at reg REGNO
- to hold something of mode MODE.
- This is ordinarily the length in words of a value of mode MODE
- but can be less for certain modes in special long registers. */
+/* Fitting values into registers. */
+
+/* Integer modes <= word size fit into any GPR.
+ Integer modes > word size fit into successive GPRs, starting with
+ an even-numbered register.
+ SImode and DImode fit into FPRs as well.
+
+ Floating point modes <= word size fit into any FPR or GPR.
+ Floating point modes > word size (i.e. DFmode on 32-bit) fit
+ into any FPR, or an even-odd GPR pair.
+
+ Complex floating point modes fit either into two FPRs, or into
+ successive GPRs (again starting with an even number).
+
+ Condition code modes fit only into the CC register. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
- (FLOAT_REGNO_P(REGNO)? \
+ (FP_REGNO_P(REGNO)? \
(GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) : \
- INT_REGNO_P(REGNO)? \
+ GENERAL_REGNO_P(REGNO)? \
((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) : \
1)
-/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
- The gprs can hold QI, HI, SI, SF, DF, SC and DC.
- Even gprs can hold DI.
- The floating point registers can hold DF, SF, DC and SC. */
-
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
- (FLOAT_REGNO_P(REGNO)? \
- (GET_MODE_CLASS(MODE) == MODE_FLOAT || \
- GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT || \
- (MODE) == SImode || (MODE) == DImode) : \
- INT_REGNO_P(REGNO)? \
+ (FP_REGNO_P(REGNO)? \
+ ((MODE) == SImode || (MODE) == DImode || \
+ GET_MODE_CLASS(MODE) == MODE_FLOAT || \
+ GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT) : \
+ GENERAL_REGNO_P(REGNO)? \
(HARD_REGNO_NREGS(REGNO, MODE) == 1 || !((REGNO) & 1)) : \
CC_REGNO_P(REGNO)? \
GET_MODE_CLASS (MODE) == MODE_CC : \
+ FRAME_REGNO_P(REGNO)? \
+ (enum machine_mode) (MODE) == Pmode : \
0)
-/* Value is 1 if it is a good idea to tie two pseudo registers when one has
- mode MODE1 and one has mode MODE2.
- If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
- for any hard reg, then this must be 0 for correct output. */
-
#define MODES_TIEABLE_P(MODE1, MODE2) \
(((MODE1) == SFmode || (MODE1) == DFmode) \
== ((MODE2) == SFmode || (MODE2) == DFmode))
-/* If defined, gives a class of registers that cannot be used as the
- operand of a SUBREG that changes the mode of the object illegally. */
-
-#define CLASS_CANNOT_CHANGE_MODE FP_REGS
-
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
-
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
-
-/* Define this macro if references to a symbol must be treated
- differently depending on something about the variable or
- function named by the symbol (such as what section it is in).
-
- On s390, if using PIC, mark a SYMBOL_REF for a non-global symbol
- so that we may access it directly in the GOT. */
-
-#define ENCODE_SECTION_INFO(DECL) \
-do \
- { \
- if (flag_pic) \
- { \
- rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
- ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \
- \
- if (GET_CODE (rtl) == MEM) \
- { \
- SYMBOL_REF_FLAG (XEXP (rtl, 0)) \
- = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
- || ! TREE_PUBLIC (DECL)); \
- } \
- } \
- } \
-while (0)
-
-
-/* This is an array of structures. Each structure initializes one pair
- of eliminable registers. The "from" register number is given first,
- followed by "to". Eliminations of the same "from" register are listed
- in order of preference. */
-
-#define ELIMINABLE_REGS \
-{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
- { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
-
-#define CAN_ELIMINATE(FROM, TO) (1)
-
-#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
-{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
- { (OFFSET) = 0; } \
- else if ((FROM) == FRAME_POINTER_REGNUM \
- && (TO) == HARD_FRAME_POINTER_REGNUM) \
- { (OFFSET) = 0; } \
- else if ((FROM) == ARG_POINTER_REGNUM \
- && (TO) == HARD_FRAME_POINTER_REGNUM) \
- { (OFFSET) = s390_arg_frame_offset (); } \
- else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
- { (OFFSET) = s390_arg_frame_offset (); } \
- else \
- abort(); \
-}
-
-#define CAN_DEBUG_WITHOUT_FP
-
-/* Value should be nonzero if functions must have frame pointers.
- Zero means the frame pointer need not be set up (and parms may be
- accessed via the stack pointer) in functions that seem suitable.
- This is computed in `reload', in reload1.c. */
+/* Maximum number of registers to represent a value of mode MODE
+ in a register of class CLASS. */
+#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)
-#define FRAME_POINTER_REQUIRED 0
+/* 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)
-/* Define the classes of registers for register constraints in the
- machine description. Also define ranges of constants.
-
- One of the classes must always be named ALL_REGS and include all hard regs.
- If there is more than one class, another class must be named NO_REGS
- and contain no registers.
+/* Register classes. */
- The name GENERAL_REGS must be the name of a class (or an alias for
- another name such as ALL_REGS). This is the class of registers
- that is allowed by "g" or "r" in a register constraint.
- Also, registers outside this class are allocated only when
- instructions express preferences for them.
-
- The classes must be numbered in nondecreasing order; that is,
- a larger-numbered class must never be contained completely
- in a smaller-numbered class.
-
- For any two classes, it is very desirable that there be another
- class that represents their union. */
-
-/*#define SMALL_REGISTER_CLASSES 1*/
+/* 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
+
+ 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
{
@@ -497,19 +375,13 @@ enum reg_class
FP_REGS, ADDR_FP_REGS, GENERAL_FP_REGS,
ALL_REGS, LIM_REG_CLASSES
};
-
#define N_REG_CLASSES (int) LIM_REG_CLASSES
-/* Give names of register classes as strings for dump file. */
-
#define REG_CLASS_NAMES \
{ "NO_REGS", "ADDR_REGS", "GENERAL_REGS", \
"FP_REGS", "ADDR_FP_REGS", "GENERAL_FP_REGS", "ALL_REGS" }
-/* Define which registers fit in which classes. This is an initializer for
- a vector of HARD_REG_SET of length N_REG_CLASSES.
- G5 and latter have 16 register and support IEEE floating point operations. */
-
+/* Class -> register mapping. */
#define REG_CLASS_CONTENTS \
{ \
{ 0x00000000, 0x00000000 }, /* NO_REGS */ \
@@ -521,105 +393,102 @@ enum reg_class
{ 0xffffffff, 0x00000007 }, /* ALL_REGS */ \
}
+/* Register -> class mapping. */
+extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
+#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
-/* The same information, inverted:
- Return the class number of the smallest class containing
- reg number REGNO. This could be a conditional expression
- or could index an array. */
+/* ADDR_REGS can be used as base or index register. */
+#define INDEX_REG_CLASS ADDR_REGS
+#define BASE_REG_CLASS ADDR_REGS
-#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
+/* Check whether REGNO is a hard register of the suitable class
+ or a pseudo register currently allocated to one such. */
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ (((REGNO) < FIRST_PSEUDO_REGISTER \
+ && REGNO_REG_CLASS ((REGNO)) == ADDR_REGS) \
+ || (reg_renumber[REGNO] > 0 && reg_renumber[REGNO] < 16))
+#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_INDEX_P (REGNO)
-extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; /* smalled class containing REGNO */
-/* The class value for index registers, and the one for base regs. */
+/* Given an rtx X being reloaded into a reg required to be in class CLASS,
+ return the class of reg to actually use. */
+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
+ s390_preferred_reload_class ((X), (CLASS))
-#define INDEX_REG_CLASS ADDR_REGS
-#define BASE_REG_CLASS ADDR_REGS
+/* We need a secondary reload when loading a PLUS which is
+ not a valid operand for LOAD ADDRESS. */
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \
+ s390_secondary_input_reload_class ((CLASS), (MODE), (IN))
+
+/* We need a secondary reload when storing a double-word
+ to a non-offsettable memory address. */
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, OUT) \
+ s390_secondary_output_reload_class ((CLASS), (MODE), (OUT))
-/* Get reg_class from a letter such as appears in the machine description. */
+/* We need secondary memory to move data between GPRs and FPRs. */
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
+ ((CLASS1) != (CLASS2) && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS))
+
+/* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on 64bit
+ because the movsi and movsf patterns don't handle r/f moves. */
+#define SECONDARY_MEMORY_NEEDED_MODE(MODE) \
+ (GET_MODE_BITSIZE (MODE) < 32 \
+ ? mode_for_size (32, GET_MODE_CLASS (MODE), 0) \
+ : MODE)
+
+
+/* Define various machine-dependent constraint letters. */
#define REG_CLASS_FROM_LETTER(C) \
((C) == 'a' ? ADDR_REGS : \
(C) == 'd' ? GENERAL_REGS : \
(C) == 'f' ? FP_REGS : NO_REGS)
-/* The letters I, J, K, L and M in a register constraint string can be used
- to stand for particular ranges of immediate operands.
- This macro defines what the ranges are.
- C is the letter, and VALUE is a constant value.
- Return 1 if VALUE is in the range specified by C. */
-
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? (unsigned long) (VALUE) < 256 : \
(C) == 'J' ? (unsigned long) (VALUE) < 4096 : \
(C) == 'K' ? (VALUE) >= -32768 && (VALUE) < 32768 : \
(C) == 'L' ? (unsigned long) (VALUE) < 65536 : 0)
-/* Similar, but for floating constants, and defining letters G and H.
- Here VALUE is the CONST_DOUBLE rtx itself. */
-
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1
-/* 'Q' means a memory-reference for a S-type operand. */
-
#define EXTRA_CONSTRAINT(OP, C) \
- ((C) == 'Q' ? s_operand (OP, GET_MODE (OP)) : \
+ ((C) == 'Q' ? q_constraint (OP) : \
(C) == 'S' ? larl_operand (OP, GET_MODE (OP)) : 0)
-/* Given an rtx X being reloaded into a reg required to be in class CLASS,
- return the class of reg to actually use. In general this is just CLASS;
- but on some machines in some cases it is preferable to use a more
- restrictive class. */
-
-#define PREFERRED_RELOAD_CLASS(X, CLASS) \
- s390_preferred_reload_class ((X), (CLASS))
-
-/* Return the maximum number of consecutive registers needed to represent
- mode MODE in a register of class CLASS. */
-
-#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)
-
-/* We need a secondary reload when loading a PLUS which is
- not a valid operand for LOAD ADDRESS. */
-
-#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \
- s390_secondary_input_reload_class ((CLASS), (MODE), (IN))
+#define EXTRA_MEMORY_CONSTRAINT(C) ((C) == 'Q')
-/* If we are copying between FP registers and anything else, we need a memory
- location. */
-#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
- ((CLASS1) != (CLASS2) && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS))
-
-/* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on 64bit
- because the movsi and movsf patterns don't handle r/f moves. */
+/* Stack layout and calling conventions. */
+
+/* Our stack grows from higher to lower addresses. However, local variables
+ are accessed by positive offsets, and function arguments are stored at
+ increasing addresses. */
+#define STACK_GROWS_DOWNWARD
+/* #undef FRAME_GROWS_DOWNWARD */
+/* #undef ARGS_GROW_DOWNWARD */
-#define SECONDARY_MEMORY_NEEDED_MODE(MODE) \
- (GET_MODE_BITSIZE (MODE) < 32 \
- ? mode_for_size (32, GET_MODE_CLASS (MODE), 0) \
- : MODE)
+/* The basic stack layout looks like this: the stack pointer points
+ to the register save area for called functions. Above that area
+ is the location to place outgoing arguments. Above those follow
+ dynamic allocations (alloca), and finally the local variables. */
+/* Offset from stack-pointer to first location of outgoing args. */
+#define STACK_POINTER_OFFSET (TARGET_64BIT ? 160 : 96)
-/* A C expression whose value is nonzero if pseudos that have been
- assigned to registers of class CLASS would likely be spilled
- because registers of CLASS are needed for spill registers.
+/* Offset within stack frame to start allocating local variables at. */
+extern int current_function_outgoing_args_size;
+#define STARTING_FRAME_OFFSET \
+ (STACK_POINTER_OFFSET + current_function_outgoing_args_size)
- The default value of this macro returns 1 if CLASS has exactly one
- register and zero otherwise. On most machines, this default
- should be used. Only define this macro to some other expression
- if pseudo allocated by `local-alloc.c' end up in memory because
- their hard registers were needed for spill registers. If this
- macro returns nonzero for those classes, those pseudos will only
- be allocated by `global.c', which knows how to reallocate the
- pseudo to another register. If there would not be another
- register available for reallocation, you should not change the
- definition of this macro since the only effect of such a
- definition would be to slow down register allocation. */
+/* Offset from the stack pointer register to an item dynamically
+ allocated on the stack, e.g., by `alloca'. */
+#define STACK_DYNAMIC_OFFSET(FUNDECL) (STARTING_FRAME_OFFSET)
-/* Stack layout; function entry, exit and calling. */
+/* Offset of first parameter from the argument pointer register value.
+ We have a fake argument pointer register that points directly to
+ the argument area. */
+#define FIRST_PARM_OFFSET(FNDECL) 0
/* The return address of the current frame is retrieved
from the initial value of register RETURN_REGNUM.
@@ -631,108 +500,91 @@ extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; /* smalled class cont
plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET))
#define RETURN_ADDR_RTX(COUNT, FRAME) \
- ((COUNT) == 0 ? get_hard_reg_initial_val (Pmode, RETURN_REGNUM) : \
- gen_rtx_MEM (Pmode, \
- memory_address (Pmode, \
- plus_constant (DYNAMIC_CHAIN_ADDRESS ((FRAME)), \
- RETURN_REGNUM * UNITS_PER_WORD))))
-
-/* The following macros will turn on dwarf2 exception hndling
- Other code location for this exception handling are
- in s390.md (eh_return insn) and in linux.c in the prologue. */
-
-#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, RETURN_REGNUM)
-
-/* We have 31 bit mode. */
+ s390_return_addr_rtx ((COUNT), DYNAMIC_CHAIN_ADDRESS ((FRAME)))
+/* In 31-bit mode, we need to mask off the high bit of return addresses. */
#define MASK_RETURN_ADDR (TARGET_64BIT ? GEN_INT (-1) : GEN_INT (0x7fffffff))
-/* The offset from the incoming value of %sp to the top of the stack frame
- for the current function. */
+/* Exception handling. */
+
+/* Describe calling conventions for DWARF-2 exception handling. */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, RETURN_REGNUM)
#define INCOMING_FRAME_SP_OFFSET STACK_POINTER_OFFSET
-
-/* Location, from where return address to load. */
-
#define DWARF_FRAME_RETURN_COLUMN 14
/* Describe how we implement __builtin_eh_return. */
#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 6 : INVALID_REGNUM)
-#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 10)
#define EH_RETURN_HANDLER_RTX \
gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, \
TARGET_64BIT? -48 : -40))
-/* Define this if pushing a word on the stack makes the stack pointer a
- smaller address. */
-
-#define STACK_GROWS_DOWNWARD
-
-/* Define this if the nominal address of the stack frame is at the
- high-address end of the local variables; that is, each additional local
- variable allocated goes at a more negative offset in the frame. */
-
-/* #define FRAME_GROWS_DOWNWARD */
-
-/* Offset from stack-pointer to first location of outgoing args. */
+/* Select a format to encode pointers in exception handling data. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \
+ (flag_pic \
+ ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4 \
+ : DW_EH_PE_absptr)
-#define STACK_POINTER_OFFSET (TARGET_64BIT ? 160 : 96)
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
+/* Frame registers. */
-#define STARTING_FRAME_OFFSET \
- (STACK_POINTER_OFFSET + current_function_outgoing_args_size)
+#define STACK_POINTER_REGNUM 15
+#define FRAME_POINTER_REGNUM 34
+#define HARD_FRAME_POINTER_REGNUM 11
+#define ARG_POINTER_REGNUM 32
-#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 0
+/* The static chain must be call-clobbered, but not used for
+ function argument passing. As register 1 is clobbered by
+ the trampoline code, we only have one option. */
+#define STATIC_CHAIN_REGNUM 0
-/* If we generate an insn to push BYTES bytes, this says how many the stack
- pointer really advances by. On S/390, we have no push instruction. */
+/* Number of hardware registers that go into the DWARF-2 unwind info.
+ To avoid ABI incompatibility, this number must not change even as
+ 'fake' hard registers are added or removed. */
+#define DWARF_FRAME_REGISTERS 34
-/* #define PUSH_ROUNDING(BYTES) */
-/* Accumulate the outgoing argument count so we can request the right
- DSA size and determine stack offset. */
+/* Frame pointer and argument pointer elimination. */
-#define ACCUMULATE_OUTGOING_ARGS 1
+#define FRAME_POINTER_REQUIRED 0
-/* Offset from the stack pointer register to an item dynamically
- allocated on the stack, e.g., by `alloca'.
+#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 0
- The default value for this macro is `STACK_POINTER_OFFSET' plus the
- length of the outgoing arguments. The default is correct for most
- machines. See `function.c' for details. */
-#define STACK_DYNAMIC_OFFSET(FUNDECL) (STARTING_FRAME_OFFSET)
+#define ELIMINABLE_REGS \
+{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
-/* Offset of first parameter from the argument pointer register value.
- On the S/390, we define the argument pointer to the start of the fixed
- area. */
-#define FIRST_PARM_OFFSET(FNDECL) 0
+#define CAN_ELIMINATE(FROM, TO) (1)
-/* Define this if stack space is still allocated for a parameter passed
- in a register. The value is the number of bytes allocated to this
- area. */
-/* #define REG_PARM_STACK_SPACE(FNDECL) 32 */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+ { (OFFSET) = 0; } \
+ else if ((FROM) == FRAME_POINTER_REGNUM \
+ && (TO) == HARD_FRAME_POINTER_REGNUM) \
+ { (OFFSET) = 0; } \
+ else if ((FROM) == ARG_POINTER_REGNUM \
+ && (TO) == HARD_FRAME_POINTER_REGNUM) \
+ { (OFFSET) = s390_arg_frame_offset (); } \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+ { (OFFSET) = s390_arg_frame_offset (); } \
+ else \
+ abort(); \
+}
-/* Define this if the above stack space is to be considered part of the
- space allocated by the caller. */
-/* #define OUTGOING_REG_PARM_STACK_SPACE */
-/* 1 if N is a possible register number for function argument passing.
- On S390, general registers 2 - 6 and floating point register 0 and 2
- are used in this way. */
+/* Stack arguments. */
+
+/* We need current_function_outgoing_args to be valid. */
+#define ACCUMULATE_OUTGOING_ARGS 1
-#define FUNCTION_ARG_REGNO_P(N) (((N) >=2 && (N) <7) || \
- (N) == 16 || (N) == 17)
+/* Return doesn't modify the stack. */
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0
-/* Define a data type for recording info about an argument list during
- the scan of that argument list. This data type should hold all
- necessary information about the function itself and about the args
- processed so far, enough to enable macros such as FUNCTION_ARG to
- determine where the next arg should go. */
+/* Register arguments. */
+
typedef struct s390_arg_structure
{
int gprs; /* gpr so far */
@@ -740,84 +592,30 @@ typedef struct s390_arg_structure
}
CUMULATIVE_ARGS;
-
-/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to
- a function whose data type is FNTYPE.
- For a library call, FNTYPE is 0. */
-
#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, NN) \
((CUM).gprs=0, (CUM).fprs=0)
-/* Update the data in CUM to advance over an argument of mode MODE and
- data type TYPE. (TYPE is null for libcalls where that information
- may not be available.) */
-
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
s390_function_arg_advance (&CUM, MODE, TYPE, NAMED)
-/* Define where to put the arguments to a function. Value is zero to push
- the argument on the stack, or a hard register in which to store the
- argument. */
-
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
s390_function_arg (&CUM, MODE, TYPE, NAMED)
-/* Define where to expect the arguments of a function. Value is zero, if
- the argument is on the stack, or a hard register in which the argument
- is stored. It is the same like FUNCTION_ARG, except for unnamed args
- That means, that all in case of varargs used, the arguments are expected
- from the stack.
- S/390 has already space on the stack for args coming in registers,
- they are pushed in prologue, if needed. */
-
-
-/* Define the `__builtin_va_list' type. */
-
-#define BUILD_VA_LIST_TYPE(VALIST) \
- (VALIST) = s390_build_va_list ()
-
-/* Implement `va_start' for varargs and stdarg. */
-
-#define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
- s390_va_start (stdarg, valist, nextarg)
-
-/* Implement `va_arg'. */
-
-#define EXPAND_BUILTIN_VA_ARG(valist, type) \
- s390_va_arg (valist, type)
-
-/* For an arg passed partly in registers and partly in memory, this is the
- number of registers used. For args passed entirely in registers or
- entirely in memory, zero. */
-
-#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
-
-
-/* Define if returning from a function call automatically pops the
- arguments described by the number-of-args field in the call. */
-
-#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0
-
-
-/* Define how to find the value returned by a function. VALTYPE is the
- data type of the value (as a tree).
- If the precise function being called is known, FUNC is its FUNCTION_DECL;
- otherwise, FUNC is 15. */
-
-#define RET_REG(MODE) ((GET_MODE_CLASS (MODE) == MODE_INT \
- || TARGET_SOFT_FLOAT ) ? 2 : 16)
-
-
-/* for structs the address is passed, and the Callee makes a
- copy, only if needed */
-
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
s390_function_arg_pass_by_reference (MODE, TYPE)
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
-/* Register 2 (and 3) for integral values
- or floating point register 0 (and 2) for fp values are used. */
+/* Arguments can be placed in general registers 2 to 6,
+ or in floating point registers 0 and 2. */
+#define FUNCTION_ARG_REGNO_P(N) (((N) >=2 && (N) <7) || \
+ (N) == 16 || (N) == 17)
+
+/* Scalar return values. */
+
+/* We return scalars in general purpose register 2 for integral values,
+ and floating point register 0 for fp values. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG ((INTEGRAL_TYPE_P (VALTYPE) \
&& TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
@@ -827,133 +625,77 @@ CUMULATIVE_ARGS;
/* Define how to find the value returned by a library function assuming
the value has mode MODE. */
-
+#define RET_REG(MODE) ((GET_MODE_CLASS (MODE) == MODE_INT \
+ || TARGET_SOFT_FLOAT ) ? 2 : 16)
#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, RET_REG (MODE))
-/* 1 if N is a possible register number for a function value. */
-
+/* Only gpr 2 and fpr 0 are ever used as return registers. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16)
+
+/* Aggregate return values. */
+
/* The definition of this macro implies that there are cases where
a scalar value cannot be returned in registers. */
-
#define RETURN_IN_MEMORY(type) \
(TYPE_MODE (type) == BLKmode || \
GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_INT || \
GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT)
-/* Mode of stack savearea.
- FUNCTION is VOIDmode because calling convention maintains SP.
- BLOCK needs Pmode for SP.
- NONLOCAL needs twice Pmode to maintain both backchain and SP. */
-
-#define STACK_SAVEAREA_MODE(LEVEL) \
- (LEVEL == SAVE_FUNCTION ? VOIDmode \
- : LEVEL == SAVE_NONLOCAL ? (TARGET_64BIT ? TImode : DImode) : Pmode)
-
/* Structure value address is passed as invisible first argument (gpr 2). */
-
#define STRUCT_VALUE 0
-/* This macro definition sets up a default value for `main' to return. */
-
-#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
-
-/* Length in units of the trampoline for entering a nested function. */
-
-#define TRAMPOLINE_SIZE (TARGET_64BIT ? 36 : 20)
-
-/* Initialize the dynamic part of trampoline. */
-
-#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT) \
- s390_initialize_trampoline ((ADDR), (FNADDR), (CXT))
-/* Template for constant part of trampoline. */
+/* Function entry and exit. */
+
+/* When returning from a function, the stack pointer does not matter. */
+#define EXIT_IGNORE_STACK 1
-#define TRAMPOLINE_TEMPLATE(FILE) \
- s390_trampoline_template (FILE)
-/* Output assembler code to FILE to increment profiler label # LABELNO
- for profiling a function entry. */
+/* Profiling. */
#define FUNCTION_PROFILER(FILE, LABELNO) \
- s390_function_profiler ((FILE), ((LABELNO)))
+ s390_function_profiler ((FILE), ((LABELNO)))
#define PROFILE_BEFORE_PROLOGUE 1
-/* Define EXIT_IGNORE_STACK if, when returning from a function, the stack
- pointer does not matter (provided there is a frame pointer). */
-
-#define EXIT_IGNORE_STACK 1
-
-/* Addressing modes, and classification of registers for them. */
-
-/* #define HAVE_POST_INCREMENT */
-/* #define HAVE_POST_DECREMENT */
-/* #define HAVE_PRE_DECREMENT */
-/* #define HAVE_PRE_INCREMENT */
+/* Implementing the varargs macros. */
-/* These assume that REGNO is a hard or pseudo reg number. They give
- nonzero only if REGNO is a hard reg of the suitable class or a pseudo
- reg currently allocated to a suitable hard reg.
- These definitions are NOT overridden anywhere. */
-
-#define REGNO_OK_FOR_INDEX_P(REGNO) \
- (((REGNO) < FIRST_PSEUDO_REGISTER \
- && REGNO_REG_CLASS ((REGNO)) == ADDR_REGS) \
- || (reg_renumber[REGNO] > 0 && reg_renumber[REGNO] < 16))
-
-#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_INDEX_P (REGNO)
+#define BUILD_VA_LIST_TYPE(VALIST) \
+ (VALIST) = s390_build_va_list ()
-#define REGNO_OK_FOR_DATA_P(REGNO) \
- ((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16)
+#define EXPAND_BUILTIN_VA_START(valist, nextarg) \
+ s390_va_start (valist, nextarg)
-#define REGNO_OK_FOR_FP_P(REGNO) \
- FLOAT_REGNO_P (REGNO)
+#define EXPAND_BUILTIN_VA_ARG(valist, type) \
+ s390_va_arg (valist, type)
-/* Now macros that check whether X is a register and also,
- strictly, whether it is in a specified class. */
-/* 1 if X is a data register. */
+/* Trampolines for nested functions. */
-#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X)))
+#define TRAMPOLINE_SIZE (TARGET_64BIT ? 36 : 20)
-/* 1 if X is an fp register. */
+#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT) \
+ s390_initialize_trampoline ((ADDR), (FNADDR), (CXT))
-#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X)))
+#define TRAMPOLINE_TEMPLATE(FILE) \
+ s390_trampoline_template (FILE)
-/* 1 if X is an address register. */
-#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X)))
+/* Library calls. */
+
+/* We should use memcpy, not bcopy. */
+#define TARGET_MEM_FUNCTIONS
-/* Maximum number of registers that can appear in a valid memory address. */
-#define MAX_REGS_PER_ADDRESS 2
+/* Addressing modes, and classification of registers for them. */
/* Recognize any constant value that is a valid address. */
-
#define CONSTANT_ADDRESS_P(X) 0
-#define SYMBOLIC_CONST(X) \
-(GET_CODE (X) == SYMBOL_REF \
- || GET_CODE (X) == LABEL_REF \
- || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
-
-/* General operand is everything except SYMBOL_REF, CONST and CONST_DOUBLE
- they have to be forced to constant pool
- CONST_INT have to be forced into constant pool, if greater than
- 64k. Depending on the insn they have to be force into constant pool
- for smaller value; in this case we have to work with nonimmediate operand. */
-
-#define LEGITIMATE_PIC_OPERAND_P(X) \
- legitimate_pic_operand_p (X)
-
-/* Nonzero if the constant value X is a legitimate general operand.
- It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-
-#define LEGITIMATE_CONSTANT_P(X) \
- legitimate_constant_p (X)
+/* Maximum number of registers that can appear in a valid memory address. */
+#define MAX_REGS_PER_ADDRESS 2
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check
its validity for a certain class. We have two alternate definitions
@@ -966,32 +708,19 @@ CUMULATIVE_ARGS;
Some source files that are used after register allocation
need to be strict. */
-/*
- * Nonzero if X is a hard reg that can be used as an index or if it is
- * a pseudo reg.
- */
-
#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \
((GET_MODE (X) == Pmode) && \
((REGNO (X) >= FIRST_PSEUDO_REGISTER) \
|| REGNO_REG_CLASS (REGNO (X)) == ADDR_REGS))
-/* Nonzero if X is a hard reg that can be used as a base reg or if it is
- a pseudo reg. */
-
#define REG_OK_FOR_BASE_NONSTRICT_P(X) REG_OK_FOR_INDEX_NONSTRICT_P (X)
-/* Nonzero if X is a hard reg that can be used as an index. */
-
#define REG_OK_FOR_INDEX_STRICT_P(X) \
((GET_MODE (X) == Pmode) && (REGNO_OK_FOR_INDEX_P (REGNO (X))))
-/* Nonzero if X is a hard reg that can be used as a base reg. */
-
#define REG_OK_FOR_BASE_STRICT_P(X) \
((GET_MODE (X) == Pmode) && (REGNO_OK_FOR_BASE_P (REGNO (X))))
-
#ifndef REG_OK_STRICT
#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X)
#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X)
@@ -1000,15 +729,13 @@ CUMULATIVE_ARGS;
#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P(X)
#endif
+/* S/390 has no mode dependent addresses. */
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a
valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
- that wants to use this address.
-
- The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
- except for CONSTANT_ADDRESS_P which is actually machine-independent. */
-
+ that wants to use this address. */
#ifdef REG_OK_STRICT
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ \
@@ -1023,15 +750,9 @@ CUMULATIVE_ARGS;
}
#endif
-
-/* S/390 has no mode dependent addresses. */
-
-#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
-
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c. */
-
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
{ \
(X) = legitimize_address (X, OLDX, MODE); \
@@ -1039,73 +760,35 @@ CUMULATIVE_ARGS;
goto WIN; \
}
-/* Specify the machine mode that this machine uses for the index in the
- tablejump instruction. */
-
-#define CASE_VECTOR_MODE (TARGET_64BIT ? DImode : SImode)
-
-/* Define this if the tablejump instruction expects the table to contain
- offsets from the address of the table.
- Do not define this if the table should contain absolute addresses. */
-
-/* #define CASE_VECTOR_PC_RELATIVE */
-
-/* Load from integral MODE < SI from memory into register makes sign_extend
- or zero_extend
- In our case sign_extension happens for Halfwords, other no extension. */
-
-#define LOAD_EXTEND_OP(MODE) \
-(TARGET_64BIT ? ((MODE) == QImode ? ZERO_EXTEND : \
- (MODE) == HImode ? SIGN_EXTEND : NIL) \
- : ((MODE) == HImode ? SIGN_EXTEND : NIL))
-
-/* Define this if fixuns_trunc is the same as fix_trunc. */
-
-/* #define FIXUNS_TRUNC_LIKE_FIX_TRUNC */
-
-/* We use "unsigned char" as default. */
-
-#define DEFAULT_SIGNED_CHAR 0
-
-/* Max number of bytes we can move from memory to memory in one reasonably
- fast instruction. */
-
-#define MOVE_MAX 256
-
-/* Nonzero if access to memory by bytes is slow and undesirable. */
-
-#define SLOW_BYTE_ACCESS 1
-
-/* Define if shifts truncate the shift count which implies one can omit
- a sign-extension or zero-extension of a shift count. */
-
-/* #define SHIFT_COUNT_TRUNCATED */
-
-/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
- is done just by pretending it is already truncated. */
-
-#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
-
-/* We assume that the store-condition-codes instructions store 0 for false
- and some other value for true. This is the value stored for true. */
-
-/* #define STORE_FLAG_VALUE -1 */
+/* Nonzero if the constant value X is a legitimate general operand.
+ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+#define LEGITIMATE_CONSTANT_P(X) \
+ legitimate_constant_p (X)
-/* Don't perform CSE on function addresses. */
+/* Helper macro for s390.c and s390.md to check for symbolic constants. */
+#define SYMBOLIC_CONST(X) \
+(GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == LABEL_REF \
+ || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
-#define NO_FUNCTION_CSE
+#define TLS_SYMBOLIC_CONST(X) \
+((GET_CODE (X) == SYMBOL_REF && tls_symbolic_operand (X)) \
+ || (GET_CODE (X) == CONST && tls_symbolic_reference_mentioned_p (X)))
-/* Specify the machine mode that pointers have.
- After generation of rtl, the compiler makes no further distinction
- between pointers and any other objects of this machine mode. */
-#define Pmode ((enum machine_mode) (TARGET_64BIT ? DImode : SImode))
+/* Condition codes. */
-/* A function address in a call instruction is a byte address (for
- indexing purposes) so give the MEM rtx a byte's mode. */
+/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
+ return the mode to be used for the comparison. */
+#define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
+
+/* Define the information needed to generate branch and scc insns. This is
+ stored from the compare operation. Note that we can't use "rtx" here
+ since it hasn't been defined! */
+extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
-#define FUNCTION_MODE QImode
+/* Relative costs of operations. */
/* A part of a C `switch' statement that describes the relative costs
of constant RTL expressions. It must contain `case' labels for
@@ -1126,7 +809,6 @@ CUMULATIVE_ARGS;
than a short. Because of that we give an addition of greater
constants a cost of 3 (reload1.c 10096). */
-
#define CONST_COSTS(RTX, CODE, OUTER_CODE) \
case CONST: \
if ((GET_CODE (XEXP (RTX, 0)) == MINUS) && \
@@ -1148,10 +830,7 @@ CUMULATIVE_ARGS;
instruction is. In writing this macro, you can use the construct
`COSTS_N_INSNS (N)' to specify a cost equal to N fast
instructions. OUTER_CODE is the code of the expression in which X
- is contained.
-
- This macro is optional; do not define it if the default cost
- assumptions are adequate for the target machine. */
+ is contained. */
#define RTX_COSTS(X, CODE, OUTER_CODE) \
case ASHIFT: \
@@ -1164,155 +843,72 @@ CUMULATIVE_ARGS;
case MINUS: \
case NEG: \
case NOT: \
- return 1; \
+ return COSTS_N_INSNS (1); \
case MULT: \
if (GET_MODE (XEXP (X, 0)) == DImode) \
- return 40; \
- else \
- return 7; \
+ return COSTS_N_INSNS (40); \
+ else \
+ return COSTS_N_INSNS (7); \
case DIV: \
case UDIV: \
case MOD: \
case UMOD: \
- return 33;
+ return COSTS_N_INSNS (33);
/* An expression giving the cost of an addressing mode that contains
ADDRESS. If not defined, the cost is computed from the ADDRESS
- expression and the `CONST_COSTS' values.
-
- For most CISC machines, the default cost is a good approximation
- of the true cost of the addressing mode. However, on RISC
- machines, all instructions normally have the same length and
- execution time. Hence all addresses will have equal costs.
-
- In cases where more than one form of an address is known, the form
- with the lowest cost will be used. If multiple forms have the
- same, lowest, cost, the one that is the most complex will be used.
-
- For example, suppose an address that is equal to the sum of a
- register and a constant is used twice in the same basic block.
- When this macro is not defined, the address will be computed in a
- register and memory references will be indirect through that
- register. On machines where the cost of the addressing mode
- containing the sum is no higher than that of a simple indirect
- reference, this will produce an additional instruction and
- possibly require an additional register. Proper specification of
- this macro eliminates this overhead for such machines.
-
- Similar use of this macro is made in strength reduction of loops.
-
- ADDRESS need not be valid as an address. In such a case, the cost
- is not relevant and can be any value; invalid addresses need not be
- assigned a different cost.
-
- On machines where an address involving more than one register is as
- cheap as an address computation involving only one register,
- defining `ADDRESS_COST' to reflect this can cause two registers to
- be live over a region of code where only one would have been if
- `ADDRESS_COST' were not defined in that manner. This effect should
- be considered in the definition of this macro. Equivalent costs
- should probably only be given to addresses with different numbers
- of registers on machines with lots of registers.
-
- This macro will normally either not be defined or be defined as a
- constant.
-
- On s390 symbols are expensive if compiled with fpic
- lifetimes. */
-
-#define ADDRESS_COST(RTX) \
- ((flag_pic && GET_CODE (RTX) == SYMBOL_REF) ? 2 : 1)
+ expression and the `CONST_COSTS' values. */
+#define ADDRESS_COST(RTX) s390_address_cost ((RTX))
/* On s390, copy between fprs and gprs is expensive. */
-
#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
(( ( reg_classes_intersect_p ((CLASS1), GENERAL_REGS) \
&& reg_classes_intersect_p ((CLASS2), FP_REGS)) \
|| ( reg_classes_intersect_p ((CLASS1), FP_REGS) \
&& reg_classes_intersect_p ((CLASS2), GENERAL_REGS))) ? 10 : 1)
-
/* A C expression for the cost of moving data of mode M between a
register and memory. A value of 2 is the default; this cost is
- relative to those in `REGISTER_MOVE_COST'.
-
- If moving between registers and memory is more expensive than
- between two registers, you should define this macro to express the
- relative cost. */
-
+ relative to those in `REGISTER_MOVE_COST'. */
#define MEMORY_MOVE_COST(M, C, I) 1
/* A C expression for the cost of a branch instruction. A value of 1
is the default; other values are interpreted relative to that. */
-
#define BRANCH_COST 1
-/* Add any extra modes needed to represent the condition code. */
-#define EXTRA_CC_MODES \
- CC (CCZmode, "CCZ") \
- CC (CCAmode, "CCA") \
- CC (CCLmode, "CCL") \
- CC (CCUmode, "CCU") \
- CC (CCSmode, "CCS") \
- CC (CCTmode, "CCT")
-
-/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
- return the mode to be used for the comparison. */
-
-#define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
-
-
-/* Define the information needed to generate branch and scc insns. This is
- stored from the compare operation. Note that we can't use "rtx" here
- since it hasn't been defined! */
-
-extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
-
-
-/* How to refer to registers in assembler output. This sequence is
- indexed by compiler's hard-register-number (see above). */
-
-#define REGISTER_NAMES \
-{ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \
- "%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" \
-}
+/* Nonzero if access to memory by bytes is slow and undesirable. */
+#define SLOW_BYTE_ACCESS 1
-/* implicit call of memcpy, not bcopy */
+/* The maximum number of bytes that a single instruction can move quickly
+ between memory and registers or between two memory locations. */
+#define MOVE_MAX (TARGET_64BIT ? 16 : 8)
+#define MAX_MOVE_MAX 16
-#define TARGET_MEM_FUNCTIONS
+/* Determine whether to use move_by_pieces or block move insn. */
+#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
+ ( (SIZE) == 1 || (SIZE) == 2 || (SIZE) == 4 \
+ || (TARGET_64BIT && (SIZE) == 8) )
-/* Either simplify a location expression, or return the original. */
+/* Determine whether to use clear_by_pieces or block clear insn. */
+#define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
+ ( (SIZE) == 1 || (SIZE) == 2 || (SIZE) == 4 \
+ || (TARGET_64BIT && (SIZE) == 8) )
-#define ASM_SIMPLIFY_DWARF_ADDR(X) \
- s390_simplify_dwarf_addr (X)
-
-/* Print operand X (an rtx) in assembler syntax to file FILE.
- CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
- For `%' followed by punctuation, CODE is the punctuation and X is null. */
-
-#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
+/* Don't perform CSE on function addresses. */
+#define NO_FUNCTION_CSE
-#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+/* Sections. */
-/* Define the codes that are matched by predicates in aux-output.c. */
+/* Output before read-only data. */
+#define TEXT_SECTION_ASM_OP ".text"
-#define PREDICATE_CODES \
- {"s_operand", { SUBREG, MEM }}, \
- {"s_imm_operand", { CONST_INT, CONST_DOUBLE, SUBREG, MEM }}, \
- {"bras_sym_operand",{ SYMBOL_REF, CONST }}, \
- {"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \
- {"load_multiple_operation", {PARALLEL}}, \
- {"store_multiple_operation", {PARALLEL}}, \
- {"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
- {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, \
- CONST_INT, CONST_DOUBLE }}, \
- {"s390_plus_operand", { PLUS }},
+/* Output before writable (initialized) data. */
+#define DATA_SECTION_ASM_OP ".data"
+/* Output before writable (uninitialized) data. */
+#define BSS_SECTION_ASM_OP ".bss"
/* S/390 constant pool breaks the devices in crtstuff.c to control section
in where code resides. We have to write it as asm code. */
@@ -1326,12 +922,97 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
.previous");
#endif
+
+/* Position independent code. */
+
+extern int flag_pic;
+
+#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 12 : INVALID_REGNUM)
+
+#define LEGITIMATE_PIC_OPERAND_P(X) legitimate_pic_operand_p (X)
+
+
+/* Assembler file format. */
+
+/* Character to start a comment. */
+#define ASM_COMMENT_START "#"
+
+/* Declare an uninitialized external linkage data object. */
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP ".globl "
+
+/* Advance the location counter to a multiple of 2**LOG bytes. */
+#define ASM_OUTPUT_ALIGN(FILE, LOG) \
+ if ((LOG)) fprintf ((FILE), "\t.align\t%d\n", 1 << (LOG))
+
+/* Advance the location counter by SIZE bytes. */
+#define ASM_OUTPUT_SKIP(FILE, SIZE) \
+ fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE))
+
+/* Output a reference to a user-level label named NAME. */
+#define ASM_OUTPUT_LABELREF(FILE, NAME) \
+ asm_fprintf ((FILE), "%U%s", (*targetm.strip_name_encoding) (NAME))
+
+/* Store in OUTPUT a string (made with alloca) containing
+ an assembler-name for a local static variable named NAME.
+ LABELNO is an integer which is different for each call. */
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+ ((OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
+ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+
+/* The LOCAL_LABEL_PREFIX variable is used by dbxelf.h. */
+#define LOCAL_LABEL_PREFIX "."
+
+/* Either simplify a location expression, or return the original. */
+#define ASM_SIMPLIFY_DWARF_ADDR(X) \
+ s390_simplify_dwarf_addr (X)
+
+/* How to refer to registers in assembler output. This sequence is
+ indexed by compiler's hard-register-number (see above). */
+#define REGISTER_NAMES \
+{ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \
+ "%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" \
+}
+
+/* Print operand X (an rtx) in assembler syntax to file FILE. */
+#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+
+/* Output an element of a case-vector that is absolute. */
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+do { \
+ char buf[32]; \
+ fputs (integer_asm_op (UNITS_PER_WORD, TRUE), (FILE)); \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", (VALUE)); \
+ assemble_name ((FILE), buf); \
+ fputc ('\n', (FILE)); \
+} while (0)
+
+/* Output an element of a case-vector that is relative. */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+do { \
+ char buf[32]; \
+ fputs (integer_asm_op (UNITS_PER_WORD, TRUE), (FILE)); \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", (VALUE)); \
+ assemble_name ((FILE), buf); \
+ fputc ('-', (FILE)); \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", (REL)); \
+ assemble_name ((FILE), buf); \
+ fputc ('\n', (FILE)); \
+} while (0)
+
+
/* Constant Pool for all symbols operands which are changed with
force_const_mem during insn generation (expand_insn). */
extern int s390_pool_count;
extern int s390_nr_constants;
-extern int s390_pool_overflow;
#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size) \
{ \
@@ -1357,16 +1038,15 @@ extern int s390_pool_overflow;
if (GET_CODE (EXP) != CONST_DOUBLE) \
abort (); \
\
- memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (EXP), sizeof u); \
- assemble_real (u.d, MODE, ALIGN); \
+ REAL_VALUE_FROM_CONST_DOUBLE (r, EXP); \
+ assemble_real (r, MODE, ALIGN); \
break; \
\
case MODE_INT: \
case MODE_PARTIAL_INT: \
- if (flag_pic \
- && (GET_CODE (EXP) == CONST \
- || GET_CODE (EXP) == SYMBOL_REF \
- || GET_CODE (EXP) == LABEL_REF )) \
+ if (GET_CODE (EXP) == CONST \
+ || GET_CODE (EXP) == SYMBOL_REF \
+ || GET_CODE (EXP) == LABEL_REF) \
{ \
fputs (integer_asm_op (UNITS_PER_WORD, TRUE), FILE); \
s390_output_symbolic_const (FILE, EXP); \
@@ -1386,4 +1066,54 @@ extern int s390_pool_overflow;
goto WIN; \
}
+
+/* Miscellaneous parameters. */
+
+/* Define the codes that are matched by predicates in aux-output.c. */
+#define PREDICATE_CODES \
+ {"s_operand", { SUBREG, MEM }}, \
+ {"s_imm_operand", { CONST_INT, CONST_DOUBLE, SUBREG, MEM }}, \
+ {"bras_sym_operand",{ SYMBOL_REF, CONST }}, \
+ {"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \
+ {"load_multiple_operation", {PARALLEL}}, \
+ {"store_multiple_operation", {PARALLEL}}, \
+ {"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
+ {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, \
+ CONST_INT, CONST_DOUBLE }}, \
+ {"s390_plus_operand", { PLUS }},
+
+/* Specify the machine mode that this machine uses for the index in the
+ tablejump instruction. */
+#define CASE_VECTOR_MODE (TARGET_64BIT ? DImode : SImode)
+
+/* Load from integral MODE < SI from memory into register makes sign_extend
+ or zero_extend
+ In our case sign_extension happens for Halfwords, other no extension. */
+#define LOAD_EXTEND_OP(MODE) \
+(TARGET_64BIT ? ((MODE) == QImode ? ZERO_EXTEND : \
+ (MODE) == HImode ? SIGN_EXTEND : NIL) \
+ : ((MODE) == HImode ? SIGN_EXTEND : NIL))
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+ is done just by pretending it is already truncated. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* Specify the machine mode that pointers have.
+ After generation of rtl, the compiler makes no further distinction
+ between pointers and any other objects of this machine mode. */
+#define Pmode ((enum machine_mode) (TARGET_64BIT ? DImode : SImode))
+
+/* A function address in a call instruction is a byte address (for
+ indexing purposes) so give the MEM rtx a byte's mode. */
+#define FUNCTION_MODE QImode
+
+/* This macro definition sets up a default value for `main' to return. */
+#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
+
+/* In rare cases, correct code generation requires extra machine dependent
+ processing between the second jump optimization pass and delayed branch
+ scheduling. On those machines, define this macro as a C statement to act on
+ the code starting at INSN. */
+#define MACHINE_DEPENDENT_REORG(INSN) s390_machine_dependent_reorg (INSN)
+
#endif
diff --git a/contrib/gcc/config/s390/s390.md b/contrib/gcc/config/s390/s390.md
index 2742638..8178516 100644
--- a/contrib/gcc/config/s390/s390.md
+++ b/contrib/gcc/config/s390/s390.md
@@ -1,5 +1,5 @@
;;- Machine description for GNU compiler -- S/390 / zSeries version.
-;; Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
;; Ulrich Weigand (uweigand@de.ibm.com).
;; This file is part of GNU CC.
@@ -44,6 +44,34 @@
;; s_operand -- Matches a valid S operand in a RS, SI or SS type instruction.
;;
+;;
+;; UNSPEC usage
+;;
+
+(define_constants
+ [; TLS relocation specifiers
+ (UNSPEC_TLSGD 500)
+ (UNSPEC_TLSLDM 501)
+ (UNSPEC_NTPOFF 502)
+ (UNSPEC_DTPOFF 503)
+ (UNSPEC_GOTNTPOFF 504)
+ (UNSPEC_INDNTPOFF 505)
+
+ ; TLS support
+ (UNSPEC_TP 510)
+ (UNSPEC_TLSLDM_NTPOFF 511)
+ (UNSPEC_TLS_LOAD 512)
+ ])
+
+;;
+;; UNSPEC_VOLATILE usage
+;;
+
+(define_constants
+ [; TLS support
+ (UNSPECV_SET_TP 500)
+ ])
+
;; Define an insn type attribute. This is used in function unit delay
;; computations.
@@ -191,30 +219,6 @@
DONE;
}")
-;(define_expand "cmphi"
-; [(set (reg:CC 33)
-; (compare:CC (match_operand:HI 0 "register_operand" "")
-; (match_operand:HI 1 "general_operand" "")))]
-; ""
-; "
-;{
-; s390_compare_op0 = operands[0];
-; s390_compare_op1 = operands[1];
-; DONE;
-;}")
-
-;(define_expand "cmpqi"
-; [(set (reg:CC 33)
-; (compare:CC (match_operand:QI 0 "register_operand" "")
-; (match_operand:QI 1 "general_operand" "")))]
-; ""
-; "
-;{
-; s390_compare_op0 = operands[0];
-; s390_compare_op1 = operands[1];
-; DONE;
-;}")
-
(define_expand "cmpdf"
[(set (reg:CC 33)
(compare:CC (match_operand:DF 0 "register_operand" "")
@@ -240,9 +244,9 @@
}")
-; DI instructions
+; Test-under-Mask (zero_extract) instructions
-(define_insn "*cmpdi_tm2"
+(define_insn "*tmdi_ext"
[(set (reg 33)
(compare (zero_extract:DI (match_operand:DI 0 "register_operand" "d")
(match_operand:DI 1 "const_int_operand" "n")
@@ -272,35 +276,63 @@
}"
[(set_attr "op_type" "RI")])
-(define_insn "*cmpdi_tm_reg"
+(define_insn "*tmsi_ext"
[(set (reg 33)
- (compare (and:DI (match_operand:DI 0 "register_operand" "%d")
- (match_operand:DI 1 "immediate_operand" "n"))
+ (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "const_int_operand" "n")
+ (match_operand:SI 2 "const_int_operand" "n"))
(const_int 0)))]
- "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT
- && s390_single_hi (operands[1], DImode, 0) >= 0"
+ "s390_match_ccmode(insn, CCTmode)
+ && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
+ && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
+ && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4
+ == INTVAL (operands[2]) >> 4"
"*
{
- int part = s390_single_hi (operands[1], DImode, 0);
- operands[1] = GEN_INT (s390_extract_hi (operands[1], DImode, part));
+ int part = INTVAL (operands[2]) >> 4;
+ int block = (1 << INTVAL (operands[1])) - 1;
+ int shift = 16 - INTVAL (operands[1]) - (INTVAL (operands[2]) & 15);
+
+ operands[2] = GEN_INT (block << shift);
switch (part)
{
- case 0: return \"tmhh\\t%0,%x1\";
- case 1: return \"tmhl\\t%0,%x1\";
- case 2: return \"tmlh\\t%0,%x1\";
- case 3: return \"tmll\\t%0,%x1\";
+ case 0: return \"tmh\\t%0,%x2\";
+ case 1: return \"tml\\t%0,%x2\";
default: abort ();
}
}"
[(set_attr "op_type" "RI")])
-(define_insn "*cmpdi_tm_mem"
+(define_insn "*tmqi_ext"
[(set (reg 33)
- (compare (and:DI (match_operand:DI 0 "s_operand" "%Qo")
- (match_operand:DI 1 "immediate_operand" "n"))
+ (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q")
+ (match_operand:SI 1 "const_int_operand" "n")
+ (match_operand:SI 2 "const_int_operand" "n"))
(const_int 0)))]
- "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT
+ "s390_match_ccmode(insn, CCTmode)
+ && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
+ && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8"
+ "*
+{
+ int block = (1 << INTVAL (operands[1])) - 1;
+ int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]);
+
+ operands[2] = GEN_INT (block << shift);
+ return \"tm\\t%0,%b2\";
+}"
+ [(set_attr "op_type" "SI")
+ (set_attr "atype" "mem")])
+
+; Test-under-Mask instructions
+
+(define_insn "*tmdi_mem"
+ [(set (reg 33)
+ (compare (and:DI (match_operand:DI 0 "memory_operand" "Q")
+ (match_operand:DI 1 "immediate_operand" "n"))
+ (match_operand:DI 2 "immediate_operand" "n")))]
+ "TARGET_64BIT
+ && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
&& s390_single_qi (operands[1], DImode, 0) >= 0"
"*
{
@@ -314,100 +346,84 @@
[(set_attr "op_type" "SI")
(set_attr "atype" "mem")])
-(define_insn "*ltgr"
+(define_insn "*tmsi_mem"
[(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "const0_operand" "")))
- (set (match_operand:DI 2 "register_operand" "=d")
- (match_dup 0))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "ltgr\\t%2,%0"
- [(set_attr "op_type" "RRE")])
+ (compare (and:SI (match_operand:SI 0 "memory_operand" "Q")
+ (match_operand:SI 1 "immediate_operand" "n"))
+ (match_operand:SI 2 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
+ && s390_single_qi (operands[1], SImode, 0) >= 0"
+ "*
+{
+ int part = s390_single_qi (operands[1], SImode, 0);
+ operands[1] = GEN_INT (s390_extract_qi (operands[1], SImode, part));
-(define_insn "*cmpdi_ccs_0_64"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "ltgr\\t%0,%0"
- [(set_attr "op_type" "RRE")])
+ operands[0] = gen_rtx_MEM (QImode,
+ plus_constant (XEXP (operands[0], 0), part));
+ return \"tm\\t%0,%b1\";
+}"
+ [(set_attr "op_type" "SI")
+ (set_attr "atype" "mem")])
-(define_insn "*cmpdi_ccs_0_31"
+(define_insn "*tmhi_mem"
[(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCSmode)"
- "srda\\t%0,0"
- [(set_attr "op_type" "RS")])
+ (compare (and:SI (subreg:SI (match_operand:HI 0 "memory_operand" "Q") 0)
+ (match_operand:SI 1 "immediate_operand" "n"))
+ (match_operand:SI 2 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
+ && s390_single_qi (operands[1], HImode, 0) >= 0"
+ "*
+{
+ int part = s390_single_qi (operands[1], HImode, 0);
+ operands[1] = GEN_INT (s390_extract_qi (operands[1], HImode, part));
-(define_insn "*cmpdi_ccs"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d,d,d")
- (match_operand:DI 1 "general_operand" "d,K,m")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "@
- cgr\\t%0,%1
- cghi\\t%0,%c1
- cg\\t%0,%1"
- [(set_attr "op_type" "RRE,RI,RXE")
- (set_attr "atype" "reg,reg,mem")])
-
-(define_insn "*cmpdi_ccu"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d,d")
- (match_operand:DI 1 "general_operand" "d,m")))]
- "s390_match_ccmode(insn, CCUmode) && TARGET_64BIT"
- "@
- clgr\\t%0,%1
- clg\\t%0,%1"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "atype" "reg,mem")])
+ operands[0] = gen_rtx_MEM (QImode,
+ plus_constant (XEXP (operands[0], 0), part));
+ return \"tm\\t%0,%b1\";
+}"
+ [(set_attr "op_type" "SI")
+ (set_attr "atype" "mem")])
-(define_insn "*cmpdi_ccu_mem"
+(define_insn "*tmqi_mem"
[(set (reg 33)
- (compare (match_operand:DI 0 "s_operand" "oQ")
- (match_operand:DI 1 "s_imm_operand" "oQ")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")
+ (compare (and:SI (subreg:SI (match_operand:QI 0 "memory_operand" "Q") 0)
+ (match_operand:SI 1 "immediate_operand" "n"))
+ (match_operand:SI 2 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))"
+ "tm\\t%0,%b1"
+ [(set_attr "op_type" "SI")
(set_attr "atype" "mem")])
-; SI instructions
-
-(define_insn "*cmpsi_tm2"
+(define_insn "*tmdi_reg"
[(set (reg 33)
- (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
- (match_operand:SI 1 "const_int_operand" "n")
- (match_operand:SI 2 "const_int_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)
- && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
- && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
- && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4
- == INTVAL (operands[2]) >> 4"
+ (compare (and:DI (match_operand:DI 0 "nonimmediate_operand" "d")
+ (match_operand:DI 1 "immediate_operand" "n"))
+ (match_operand:DI 2 "immediate_operand" "n")))]
+ "TARGET_64BIT
+ && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 1))
+ && s390_single_hi (operands[1], DImode, 0) >= 0"
"*
{
- int part = INTVAL (operands[2]) >> 4;
- int block = (1 << INTVAL (operands[1])) - 1;
- int shift = 16 - INTVAL (operands[1]) - (INTVAL (operands[2]) & 15);
-
- operands[2] = GEN_INT (block << shift);
+ int part = s390_single_hi (operands[1], DImode, 0);
+ operands[1] = GEN_INT (s390_extract_hi (operands[1], DImode, part));
switch (part)
{
- case 0: return \"tmh\\t%0,%x2\";
- case 1: return \"tml\\t%0,%x2\";
+ case 0: return \"tmhh\\t%0,%x1\";
+ case 1: return \"tmhl\\t%0,%x1\";
+ case 2: return \"tmlh\\t%0,%x1\";
+ case 3: return \"tmll\\t%0,%x1\";
default: abort ();
}
}"
[(set_attr "op_type" "RI")])
-(define_insn "*cmpsi_tm_reg"
+(define_insn "*tmsi_reg"
[(set (reg 33)
- (compare (and:SI (match_operand:SI 0 "register_operand" "%d")
+ (compare (and:SI (match_operand:SI 0 "nonimmediate_operand" "d")
(match_operand:SI 1 "immediate_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)
+ (match_operand:SI 2 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 1))
&& s390_single_hi (operands[1], SImode, 0) >= 0"
"*
{
@@ -423,57 +439,88 @@
}"
[(set_attr "op_type" "RI")])
-(define_insn "*cmpsi_tm_mem"
+(define_insn "*tmhi_full"
[(set (reg 33)
- (compare (and:SI (match_operand:SI 0 "s_operand" "%Qo")
- (match_operand:SI 1 "immediate_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)
- && s390_single_qi (operands[1], SImode, 0) >= 0"
- "*
-{
- int part = s390_single_qi (operands[1], SImode, 0);
- operands[1] = GEN_INT (s390_extract_qi (operands[1], SImode, part));
+ (compare (match_operand:HI 0 "register_operand" "d")
+ (match_operand:HI 1 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, s390_tm_ccmode (GEN_INT (-1), operands[1], 1))"
+ "tml\\t%0,65535"
+ [(set_attr "op_type" "RX")])
+
+(define_insn "*tmqi_full"
+ [(set (reg 33)
+ (compare (match_operand:QI 0 "register_operand" "d")
+ (match_operand:QI 1 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, s390_tm_ccmode (GEN_INT (-1), operands[1], 1))"
+ "tml\\t%0,255"
+ [(set_attr "op_type" "RI")])
- operands[0] = gen_rtx_MEM (QImode,
- plus_constant (XEXP (operands[0], 0), part));
- return \"tm\\t%0,%b1\";
-}"
- [(set_attr "op_type" "SI")
- (set_attr "atype" "mem")])
-(define_insn "*ltr"
+; Load-and-Test instructions
+
+(define_insn "*tstdi_sign"
[(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d")
- (match_operand:SI 1 "const0_operand" "")))
- (set (match_operand:SI 2 "register_operand" "=d")
+ (compare (ashiftrt:DI (ashift:DI (subreg:DI (match_operand:SI 0 "register_operand" "d") 0)
+ (const_int 32)) (const_int 32))
+ (match_operand:DI 1 "const0_operand" "")))
+ (set (match_operand:DI 2 "register_operand" "=d")
+ (sign_extend:DI (match_dup 0)))]
+ "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
+ "ltgfr\\t%2,%0"
+ [(set_attr "op_type" "RRE")])
+
+(define_insn "*tstdi"
+ [(set (reg 33)
+ (compare (match_operand:DI 0 "register_operand" "d")
+ (match_operand:DI 1 "const0_operand" "")))
+ (set (match_operand:DI 2 "register_operand" "=d")
(match_dup 0))]
- "s390_match_ccmode(insn, CCSmode)"
- "ltr\\t%2,%0"
- [(set_attr "op_type" "RR")])
+ "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
+ "ltgr\\t%2,%0"
+ [(set_attr "op_type" "RRE")])
-(define_insn "*icm15"
+(define_insn "*tstdi_cconly"
[(set (reg 33)
- (compare (match_operand:SI 0 "s_operand" "Qo")
+ (compare (match_operand:DI 0 "register_operand" "d")
+ (match_operand:DI 1 "const0_operand" "")))]
+ "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
+ "ltgr\\t%0,%0"
+ [(set_attr "op_type" "RRE")])
+
+(define_insn "*tstdi_cconly_31"
+ [(set (reg 33)
+ (compare (match_operand:DI 0 "register_operand" "d")
+ (match_operand:DI 1 "const0_operand" "")))]
+ "s390_match_ccmode(insn, CCSmode) && !TARGET_64BIT"
+ "srda\\t%0,0"
+ [(set_attr "op_type" "RS")])
+
+(define_insn "*tstsi"
+ [(set (reg 33)
+ (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q")
(match_operand:SI 1 "const0_operand" "")))
- (set (match_operand:SI 2 "register_operand" "=d")
+ (set (match_operand:SI 2 "register_operand" "=d,d")
(match_dup 0))]
"s390_match_ccmode(insn, CCSmode)"
- "icm\\t%2,15,%0"
- [(set_attr "op_type" "RS")
- (set_attr "atype" "mem")])
+ "@
+ ltr\\t%2,%0
+ icm\\t%2,15,%0"
+ [(set_attr "op_type" "RR,RS")
+ (set_attr "atype" "reg,mem")])
-(define_insn "*icm15_cconly"
+(define_insn "*tstsi_cconly"
[(set (reg 33)
- (compare (match_operand:SI 0 "s_operand" "Qo")
+ (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q")
(match_operand:SI 1 "const0_operand" "")))
- (clobber (match_scratch:SI 2 "=d"))]
+ (clobber (match_scratch:SI 2 "=X,d"))]
"s390_match_ccmode(insn, CCSmode)"
- "icm\\t%2,15,%0"
- [(set_attr "op_type" "RS")
- (set_attr "atype" "mem")])
+ "@
+ ltr\\t%0,%0
+ icm\\t%2,15,%0"
+ [(set_attr "op_type" "RR,RS")
+ (set_attr "atype" "reg,mem")])
-(define_insn "*cmpsi_ccs_0"
+(define_insn "*tstsi_cconly2"
[(set (reg 33)
(compare (match_operand:SI 0 "register_operand" "d")
(match_operand:SI 1 "const0_operand" "")))]
@@ -481,72 +528,34 @@
"ltr\\t%0,%0"
[(set_attr "op_type" "RR")])
-(define_insn "*cmpsidi_ccs"
- [(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d")
- (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
- "s390_match_ccmode(insn, CCSmode)"
- "ch\\t%0,%1"
- [(set_attr "op_type" "RR")
- (set_attr "atype" "mem")])
-
-(define_insn "*cmpsi_ccs"
- [(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d,d,d")
- (match_operand:SI 1 "general_operand" "d,K,m")))]
- "s390_match_ccmode(insn, CCSmode)"
- "@
- cr\\t%0,%1
- chi\\t%0,%c1
- c\\t%0,%1"
- [(set_attr "op_type" "RR,RI,RX")
- (set_attr "atype" "reg,reg,mem")])
-
-(define_insn "*cmpsi_ccu"
+(define_insn "*tsthiCCT"
[(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d,d")
- (match_operand:SI 1 "general_operand" "d,m")))]
- "s390_match_ccmode(insn, CCUmode)"
+ (compare (match_operand:HI 0 "nonimmediate_operand" "?Q,d")
+ (match_operand:HI 1 "const0_operand" "")))
+ (set (match_operand:HI 2 "register_operand" "=d,0")
+ (match_dup 0))]
+ "s390_match_ccmode(insn, CCTmode)"
"@
- clr\\t%0,%1
- cl\\t%0,%1"
- [(set_attr "op_type" "RR,RX")
- (set_attr "atype" "reg,mem")])
+ icm\\t%2,3,%0
+ tml\\t%0,65535"
+ [(set_attr "op_type" "RS,RI")
+ (set_attr "atype" "mem,reg")])
-(define_insn "*cmpsi_ccu_mem"
+(define_insn "*tsthiCCT_cconly"
[(set (reg 33)
- (compare (match_operand:SI 0 "s_operand" "oQ")
- (match_operand:SI 1 "s_imm_operand" "oQ")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")])
-
-
-; HI instructions
-
-(define_insn "*cmphi_tm_sub"
- [(set (reg 33)
- (compare (and:SI (subreg:SI (match_operand:HI 0 "s_operand" "%Qo") 0)
- (match_operand:SI 1 "immediate_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)
- && s390_single_qi (operands[1], HImode, 0) >= 0"
- "*
-{
- int part = s390_single_qi (operands[1], HImode, 0);
- operands[1] = GEN_INT (s390_extract_qi (operands[1], HImode, part));
-
- operands[0] = gen_rtx_MEM (QImode,
- plus_constant (XEXP (operands[0], 0), part));
- return \"tm\\t%0,%b1\";
-}"
- [(set_attr "op_type" "SI")
- (set_attr "atype" "mem")])
+ (compare (match_operand:HI 0 "nonimmediate_operand" "Q,d")
+ (match_operand:HI 1 "const0_operand" "")))
+ (clobber (match_scratch:HI 2 "=d,X"))]
+ "s390_match_ccmode(insn, CCTmode)"
+ "@
+ icm\\t%2,3,%0
+ tml\\t%0,65535"
+ [(set_attr "op_type" "RS,RI")
+ (set_attr "atype" "mem,reg")])
-(define_insn "*icm3"
+(define_insn "*tsthi"
[(set (reg 33)
- (compare (match_operand:HI 0 "s_operand" "Qo")
+ (compare (match_operand:HI 0 "s_operand" "Q")
(match_operand:HI 1 "const0_operand" "")))
(set (match_operand:HI 2 "register_operand" "=d")
(match_dup 0))]
@@ -555,17 +564,9 @@
[(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
-(define_insn "*cmphi_cct_0"
+(define_insn "*tsthi_cconly"
[(set (reg 33)
- (compare (match_operand:HI 0 "register_operand" "d")
- (match_operand:HI 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCTmode)"
- "tml\\t%0,65535"
- [(set_attr "op_type" "RX")])
-
-(define_insn "*cmphi_ccs_0"
- [(set (reg 33)
- (compare (match_operand:HI 0 "s_operand" "Qo")
+ (compare (match_operand:HI 0 "s_operand" "Q")
(match_operand:HI 1 "const0_operand" "")))
(clobber (match_scratch:HI 2 "=d"))]
"s390_match_ccmode(insn, CCSmode)"
@@ -573,141 +574,192 @@
[(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
-(define_insn "*cmphi_ccu"
+(define_insn "*tstqiCCT"
[(set (reg 33)
- (compare (match_operand:HI 0 "register_operand" "d")
- (match_operand:HI 1 "s_imm_operand" "Qo")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clm\\t%0,3,%1"
+ (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,d")
+ (match_operand:QI 1 "const0_operand" "")))
+ (set (match_operand:QI 2 "register_operand" "=d,0")
+ (match_dup 0))]
+ "s390_match_ccmode(insn, CCTmode)"
+ "@
+ icm\\t%2,1,%0
+ tml\\t%0,255"
+ [(set_attr "op_type" "RS,RI")
+ (set_attr "atype" "mem,reg")])
+
+(define_insn "*tstqiCCT_cconly"
+ [(set (reg 33)
+ (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,d")
+ (match_operand:QI 1 "const0_operand" "")))]
+ "s390_match_ccmode(insn, CCTmode)"
+ "@
+ cli\\t%0,0
+ tml\\t%0,255"
+ [(set_attr "op_type" "SI,RI")
+ (set_attr "atype" "mem,reg")])
+
+(define_insn "*tstqi"
+ [(set (reg 33)
+ (compare (match_operand:QI 0 "s_operand" "Q")
+ (match_operand:QI 1 "const0_operand" "")))
+ (set (match_operand:QI 2 "register_operand" "=d")
+ (match_dup 0))]
+ "s390_match_ccmode(insn, CCSmode)"
+ "icm\\t%2,1,%0"
[(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
-(define_insn "*cmphi_ccu_mem"
+(define_insn "*tstqi_cconly"
[(set (reg 33)
- (compare (match_operand:HI 0 "s_operand" "oQ")
- (match_operand:HI 1 "s_imm_operand" "oQ")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")
+ (compare (match_operand:QI 0 "s_operand" "Q")
+ (match_operand:QI 1 "const0_operand" "")))
+ (clobber (match_scratch:QI 2 "=d"))]
+ "s390_match_ccmode(insn, CCSmode)"
+ "icm\\t%2,1,%0"
+ [(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
-; QI instructions
+; Compare (signed) instructions
-(define_insn "*cmpqi_tm2"
+(define_insn "*cmpdi_ccs_sign"
[(set (reg 33)
- (compare (zero_extract:SI (match_operand:QI 0 "s_operand" "Qo")
- (match_operand:SI 1 "const_int_operand" "n")
- (match_operand:SI 2 "const_int_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)
- && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
- && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8"
- "*
-{
- int block = (1 << INTVAL (operands[1])) - 1;
- int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]);
-
- operands[2] = GEN_INT (block << shift);
- return \"tm\\t%0,%b2\";
-}"
- [(set_attr "op_type" "SI")
- (set_attr "atype" "mem")])
-
-(define_insn "*cmpqi_tm"
- [(set (reg 33)
- (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "%d,Q")
- (match_operand:QI 1 "immediate_operand" "n,n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)"
+ (compare (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m"))
+ (match_operand:DI 0 "register_operand" "d,d")))]
+ "s390_match_ccmode(insn, CCSRmode) && TARGET_64BIT"
"@
- tml\\t%0,%b1
- tm\\t%0,%b1"
- [(set_attr "op_type" "RI,SI")
+ cgfr\\t%0,%1
+ cgf\\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
(set_attr "atype" "reg,mem")])
-(define_insn "*cmpqi_tm_sub"
+(define_insn "*cmpdi_ccs"
[(set (reg 33)
- (compare (and:SI (subreg:SI (match_operand:QI 0 "s_operand" "%Qo") 0)
- (match_operand:SI 1 "immediate_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)"
- "tm\\t%0,%b1"
- [(set_attr "op_type" "SI")
+ (compare (match_operand:DI 0 "register_operand" "d,d,d")
+ (match_operand:DI 1 "general_operand" "d,K,m")))]
+ "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
+ "@
+ cgr\\t%0,%1
+ cghi\\t%0,%c1
+ cg\\t%0,%1"
+ [(set_attr "op_type" "RRE,RI,RXE")
+ (set_attr "atype" "reg,reg,mem")])
+
+(define_insn "*cmpsi_ccs_sign"
+ [(set (reg 33)
+ (compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
+ (match_operand:SI 0 "register_operand" "d")))]
+ "s390_match_ccmode(insn, CCSRmode)"
+ "ch\\t%0,%1"
+ [(set_attr "op_type" "RX")
(set_attr "atype" "mem")])
-(define_insn "*icm1"
+(define_insn "*cmpsi_ccs"
[(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Qo")
- (match_operand:QI 1 "const0_operand" "")))
- (set (match_operand:QI 2 "register_operand" "=d")
- (match_dup 0))]
+ (compare (match_operand:SI 0 "register_operand" "d,d,d")
+ (match_operand:SI 1 "general_operand" "d,K,m")))]
"s390_match_ccmode(insn, CCSmode)"
- "icm\\t%2,1,%0"
- [(set_attr "op_type" "RS")
- (set_attr "atype" "mem")])
+ "@
+ cr\\t%0,%1
+ chi\\t%0,%c1
+ c\\t%0,%1"
+ [(set_attr "op_type" "RR,RI,RX")
+ (set_attr "atype" "reg,reg,mem")])
+
-(define_insn "*tm_0"
+; Compare (unsigned) instructions
+
+(define_insn "*cmpdi_ccu_zero"
[(set (reg 33)
- (compare (zero_extend:SI (and:QI (match_operand:QI 0 "s_operand" "Qo")
- (match_operand:QI 1 "immediate_operand" "")))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode) &&
- INTVAL(operands[1]) >= 0 && INTVAL(operands[1]) < 256"
- "tm\\t%0,%1"
- [(set_attr "op_type" "RI")
- (set_attr "atype" "mem")])
+ (compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m"))
+ (match_operand:DI 0 "register_operand" "d,d")))]
+ "s390_match_ccmode(insn, CCURmode) && TARGET_64BIT"
+ "@
+ clgfr\\t%0,%1
+ clgf\\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
-(define_insn "*cmpqi_cct_0"
+(define_insn "*cmpdi_ccu"
[(set (reg 33)
- (compare (match_operand:QI 0 "register_operand" "d")
- (match_operand:QI 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCTmode)"
- "tml\\t%0,255"
- [(set_attr "op_type" "RI")])
+ (compare (match_operand:DI 0 "register_operand" "d,d")
+ (match_operand:DI 1 "general_operand" "d,m")))]
+ "s390_match_ccmode(insn, CCUmode) && TARGET_64BIT"
+ "@
+ clgr\\t%0,%1
+ clg\\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
-(define_insn "*cmpqi_ccs_0"
+(define_insn "*cmpsi_ccu"
[(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Qo")
- (match_operand:QI 1 "const0_operand" "")))
- (clobber (match_scratch:QI 2 "=d"))]
- "s390_match_ccmode(insn, CCSmode)"
- "icm\\t%2,1,%0"
- [(set_attr "op_type" "RS")
- (set_attr "atype" "mem")])
+ (compare (match_operand:SI 0 "register_operand" "d,d")
+ (match_operand:SI 1 "general_operand" "d,m")))]
+ "s390_match_ccmode(insn, CCUmode)"
+ "@
+ clr\\t%0,%1
+ cl\\t%0,%1"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
-(define_insn "*cmpqi_ccu_0"
+(define_insn "*cmphi_ccu"
[(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Qo")
- (match_operand:QI 1 "const0_operand" "")))]
+ (compare (match_operand:HI 0 "register_operand" "d")
+ (match_operand:HI 1 "s_imm_operand" "Q")))]
"s390_match_ccmode(insn, CCUmode)"
- "cli\\t%0,0"
- [(set_attr "op_type" "SI")
+ "clm\\t%0,3,%1"
+ [(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
(define_insn "*cmpqi_ccu"
[(set (reg 33)
(compare (match_operand:QI 0 "register_operand" "d")
- (match_operand:QI 1 "s_imm_operand" "Qo")))]
+ (match_operand:QI 1 "s_imm_operand" "Q")))]
"s390_match_ccmode(insn, CCUmode)"
"clm\\t%0,1,%1"
[(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
-(define_insn "*cmpqi_ccu_immed"
+(define_insn "*cli"
[(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Qo")
- (match_operand:QI 1 "const_int_operand" "n")))]
- "s390_match_ccmode(insn, CCUmode) &&
- INTVAL(operands[1]) >= 0 && INTVAL(operands[1]) < 256"
- "cli\\t%0,%1"
+ (compare (match_operand:QI 0 "memory_operand" "Q")
+ (match_operand:QI 1 "immediate_operand" "n")))]
+ "s390_match_ccmode (insn, CCUmode)"
+ "cli\\t%0,%b1"
[(set_attr "op_type" "SI")
(set_attr "atype" "mem")])
+(define_insn "*cmpdi_ccu_mem"
+ [(set (reg 33)
+ (compare (match_operand:DI 0 "s_operand" "Q")
+ (match_operand:DI 1 "s_imm_operand" "Q")))]
+ "s390_match_ccmode(insn, CCUmode)"
+ "clc\\t%O0(8,%R0),%1"
+ [(set_attr "op_type" "SS")
+ (set_attr "atype" "mem")])
+
+(define_insn "*cmpsi_ccu_mem"
+ [(set (reg 33)
+ (compare (match_operand:SI 0 "s_operand" "Q")
+ (match_operand:SI 1 "s_imm_operand" "Q")))]
+ "s390_match_ccmode(insn, CCUmode)"
+ "clc\\t%O0(4,%R0),%1"
+ [(set_attr "op_type" "SS")
+ (set_attr "atype" "mem")])
+
+(define_insn "*cmphi_ccu_mem"
+ [(set (reg 33)
+ (compare (match_operand:HI 0 "s_operand" "Q")
+ (match_operand:HI 1 "s_imm_operand" "Q")))]
+ "s390_match_ccmode(insn, CCUmode)"
+ "clc\\t%O0(2,%R0),%1"
+ [(set_attr "op_type" "SS")
+ (set_attr "atype" "mem")])
+
(define_insn "*cmpqi_ccu_mem"
[(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "oQ")
- (match_operand:QI 1 "s_imm_operand" "oQ")))]
+ (compare (match_operand:QI 0 "s_operand" "Q")
+ (match_operand:QI 1 "s_imm_operand" "Q")))]
"s390_match_ccmode(insn, CCUmode)"
"clc\\t%O0(1,%R0),%1"
[(set_attr "op_type" "SS")
@@ -804,94 +856,91 @@
; movti instruction pattern(s).
;
-(define_insn "*movti_ss"
- [(set (match_operand:TI 0 "s_operand" "=Qo")
- (match_operand:TI 1 "s_imm_operand" "Qo"))]
- ""
- "mvc\\t%O0(16,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")])
-
(define_insn "movti"
- [(set (match_operand:TI 0 "nonimmediate_operand" "=d,Q,d,m")
- (match_operand:TI 1 "general_operand" "Q,d,dKm,d"))]
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=d,Q,d,o,Q")
+ (match_operand:TI 1 "general_operand" "Q,d,dKm,d,Q"))]
"TARGET_64BIT"
"@
lmg\\t%0,%N0,%1
stmg\\t%1,%N1,%0
#
- #"
- [(set_attr "op_type" "RSE,RSE,NN,NN")
+ #
+ mvc\\t%O0(16,%R0),%1"
+ [(set_attr "op_type" "RSE,RSE,NN,NN,SS")
(set_attr "atype" "mem")])
(define_split
[(set (match_operand:TI 0 "nonimmediate_operand" "")
(match_operand:TI 1 "general_operand" ""))]
"TARGET_64BIT && reload_completed
- && !s_operand (operands[0], VOIDmode)
- && !s_operand (operands[1], VOIDmode)
- && (register_operand (operands[0], VOIDmode)
- || register_operand (operands[1], VOIDmode))
- && (!register_operand (operands[0], VOIDmode)
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, TImode),
- operands[1])
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, TImode),
- operands[1]))"
+ && s390_split_ok_p (operands[0], operands[1], TImode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
- "
{
- if (!register_operand (operands[0], VOIDmode)
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, TImode),
- operands[1]))
- {
- operands[2] = operand_subword (operands[0], 0, 0, TImode);
- operands[3] = operand_subword (operands[0], 1, 0, TImode);
- operands[4] = operand_subword (operands[1], 0, 0, TImode);
- operands[5] = operand_subword (operands[1], 1, 0, TImode);
- }
- else
- {
- operands[2] = operand_subword (operands[0], 1, 0, TImode);
- operands[3] = operand_subword (operands[0], 0, 0, TImode);
- operands[4] = operand_subword (operands[1], 1, 0, TImode);
- operands[5] = operand_subword (operands[1], 0, 0, TImode);
- }
-}")
+ operands[2] = operand_subword (operands[0], 0, 0, TImode);
+ operands[3] = operand_subword (operands[0], 1, 0, TImode);
+ operands[4] = operand_subword (operands[1], 0, 0, TImode);
+ operands[5] = operand_subword (operands[1], 1, 0, TImode);
+})
+
+(define_split
+ [(set (match_operand:TI 0 "nonimmediate_operand" "")
+ (match_operand:TI 1 "general_operand" ""))]
+ "TARGET_64BIT && reload_completed
+ && s390_split_ok_p (operands[0], operands[1], TImode, 1)"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+{
+ operands[2] = operand_subword (operands[0], 1, 0, TImode);
+ operands[3] = operand_subword (operands[0], 0, 0, TImode);
+ operands[4] = operand_subword (operands[1], 1, 0, TImode);
+ operands[5] = operand_subword (operands[1], 0, 0, TImode);
+})
(define_split
[(set (match_operand:TI 0 "register_operand" "")
(match_operand:TI 1 "memory_operand" ""))]
"TARGET_64BIT && reload_completed
&& !s_operand (operands[1], VOIDmode)"
- [(set (match_dup 2) (match_dup 3))
- (set (match_dup 0) (mem:TI (match_dup 2)))]
- "operands[2] = operand_subword (operands[0], 1, 0, TImode);
- operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
+ [(set (match_dup 0) (match_dup 1))]
+{
+ rtx addr = operand_subword (operands[0], 1, 0, TImode);
+ s390_load_address (addr, XEXP (operands[1], 0));
+ operands[1] = replace_equiv_address (operands[1], addr);
+})
+
+(define_expand "reload_outti"
+ [(parallel [(match_operand:TI 0 "memory_operand" "")
+ (match_operand:TI 1 "register_operand" "d")
+ (match_operand:DI 2 "register_operand" "=&a")])]
+ "TARGET_64BIT"
+{
+ s390_load_address (operands[2], XEXP (operands[0], 0));
+ operands[0] = replace_equiv_address (operands[0], operands[2]);
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
;
; movdi instruction pattern(s).
;
-;; If generating PIC code and operands[1] is a symbolic CONST, emit a
-;; move to get the address of the symbolic object from the GOT.
-
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
"
{
- /* Handle PIC symbolic constants. */
- if (TARGET_64BIT && flag_pic && SYMBOLIC_CONST (operands[1]))
- emit_pic_move (operands, DImode);
+ /* Handle symbolic constants. */
+ if (TARGET_64BIT && SYMBOLIC_CONST (operands[1]))
+ emit_symbolic_move (operands);
/* During and after reload, we need to force constants
to the literal pool ourselves, if necessary. */
if ((reload_in_progress || reload_completed)
&& CONSTANT_P (operands[1])
&& (!legitimate_reload_constant_p (operands[1])
- || fp_operand (operands[0], VOIDmode)))
+ || FP_REG_P (operands[0])))
operands[1] = force_const_mem (DImode, operands[1]);
}")
@@ -901,7 +950,7 @@
"TARGET_64BIT
&& GET_CODE (operands[1]) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K')
- && !fp_operand (operands[0], VOIDmode)"
+ && !FP_REG_P (operands[0])"
"lghi\\t%0,%h1"
[(set_attr "op_type" "RI")
(set_attr "atype" "reg")])
@@ -910,7 +959,7 @@
[(set (match_operand:DI 0 "register_operand" "=d")
(match_operand:DI 1 "immediate_operand" "n"))]
"TARGET_64BIT && s390_single_hi (operands[1], DImode, 0) >= 0
- && !fp_operand (operands[0], VOIDmode)"
+ && !FP_REG_P (operands[0])"
"*
{
int part = s390_single_hi (operands[1], DImode, 0);
@@ -932,23 +981,15 @@
[(set (match_operand:DI 0 "register_operand" "=d")
(match_operand:DI 1 "larl_operand" "X"))]
"TARGET_64BIT
- && !fp_operand (operands[0], VOIDmode)"
+ && !FP_REG_P (operands[0])"
"larl\\t%0,%1"
[(set_attr "op_type" "RIL")
(set_attr "atype" "reg")
(set_attr "type" "la")])
-(define_insn "*movdi_ss"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
- (match_operand:DI 1 "s_imm_operand" "Qo"))]
- ""
- "mvc\\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")])
-
(define_insn "*movdi_64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,m,!*f,!*f,!m")
- (match_operand:DI 1 "general_operand" "d,m,d,*f,m,*f"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,m,!*f,!*f,!m,?Q")
+ (match_operand:DI 1 "general_operand" "d,m,d,*f,m,*f,?Q"))]
"TARGET_64BIT"
"@
lgr\\t%0,%1
@@ -956,13 +997,14 @@
stg\\t%1,%0
ldr\\t%0,%1
ld\\t%0,%1
- std\\t%1,%0"
- [(set_attr "op_type" "RRE,RXE,RXE,RR,RX,RX")
- (set_attr "atype" "reg,mem,mem,reg,mem,mem")])
+ std\\t%1,%0
+ mvc\\t%O0(8,%R0),%1"
+ [(set_attr "op_type" "RRE,RXE,RXE,RR,RX,RX,SS")
+ (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")])
(define_insn "*movdi_31"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,m,!*f,!*f,!m")
- (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,m,*f"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!m,Q")
+ (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,m,*f,Q"))]
"!TARGET_64BIT"
"@
lm\\t%0,%N0,%1
@@ -971,75 +1013,89 @@
#
ldr\\t%0,%1
ld\\t%0,%1
- std\\t%1,%0"
- [(set_attr "op_type" "RS,RS,NN,NN,RR,RX,RX")
- (set_attr "atype" "mem,mem,*,*,reg,mem,mem")])
+ std\\t%1,%0
+ mvc\\t%O0(8,%R0),%1"
+ [(set_attr "op_type" "RS,RS,NN,NN,RR,RX,RX,SS")
+ (set_attr "atype" "mem,mem,*,*,reg,mem,mem,mem")])
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
"!TARGET_64BIT && reload_completed
- && !fp_operand (operands[0], VOIDmode)
- && !fp_operand (operands[1], VOIDmode)
- && !s_operand (operands[0], VOIDmode)
- && !s_operand (operands[1], VOIDmode)
- && (register_operand (operands[0], VOIDmode)
- || register_operand (operands[1], VOIDmode))
- && (!register_operand (operands[0], VOIDmode)
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DImode),
- operands[1])
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, DImode),
- operands[1]))"
+ && s390_split_ok_p (operands[0], operands[1], DImode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
- "
{
- if (!register_operand (operands[0], VOIDmode)
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DImode),
- operands[1]))
- {
- operands[2] = operand_subword (operands[0], 0, 0, DImode);
- operands[3] = operand_subword (operands[0], 1, 0, DImode);
- operands[4] = operand_subword (operands[1], 0, 0, DImode);
- operands[5] = operand_subword (operands[1], 1, 0, DImode);
- }
- else
- {
- operands[2] = operand_subword (operands[0], 1, 0, DImode);
- operands[3] = operand_subword (operands[0], 0, 0, DImode);
- operands[4] = operand_subword (operands[1], 1, 0, DImode);
- operands[5] = operand_subword (operands[1], 0, 0, DImode);
- }
-}")
+ operands[2] = operand_subword (operands[0], 0, 0, DImode);
+ operands[3] = operand_subword (operands[0], 1, 0, DImode);
+ operands[4] = operand_subword (operands[1], 0, 0, DImode);
+ operands[5] = operand_subword (operands[1], 1, 0, DImode);
+})
+
+(define_split
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ "!TARGET_64BIT && reload_completed
+ && s390_split_ok_p (operands[0], operands[1], DImode, 1)"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+{
+ operands[2] = operand_subword (operands[0], 1, 0, DImode);
+ operands[3] = operand_subword (operands[0], 0, 0, DImode);
+ operands[4] = operand_subword (operands[1], 1, 0, DImode);
+ operands[5] = operand_subword (operands[1], 0, 0, DImode);
+})
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "memory_operand" ""))]
"!TARGET_64BIT && reload_completed
- && !fp_operand (operands[0], VOIDmode)
- && !fp_operand (operands[1], VOIDmode)
+ && !FP_REG_P (operands[0])
&& !s_operand (operands[1], VOIDmode)"
- [(set (match_dup 2) (match_dup 3))
- (set (match_dup 0) (mem:DI (match_dup 2)))]
- "operands[2] = operand_subword (operands[0], 1, 0, DImode);
- operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
+ [(set (match_dup 0) (match_dup 1))]
+{
+ rtx addr = operand_subword (operands[0], 1, 0, DImode);
+ s390_load_address (addr, XEXP (operands[1], 0));
+ operands[1] = replace_equiv_address (operands[1], addr);
+})
+
+(define_expand "reload_outdi"
+ [(parallel [(match_operand:DI 0 "memory_operand" "")
+ (match_operand:DI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "=&a")])]
+ "!TARGET_64BIT"
+{
+ s390_load_address (operands[2], XEXP (operands[0], 0));
+ operands[0] = replace_equiv_address (operands[0], operands[2]);
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mem:DI (match_operand 1 "address_operand" "")))]
+ "TARGET_64BIT
+ && !FP_REG_P (operands[0])
+ && GET_CODE (operands[1]) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (operands[1])
+ && get_pool_mode (operands[1]) == DImode
+ && legitimate_reload_constant_p (get_pool_constant (operands[1]))"
+ [(set (match_dup 0) (match_dup 2))]
+ "operands[2] = get_pool_constant (operands[1]);")
;
; movsi instruction pattern(s).
;
-;; If generating PIC code and operands[1] is a symbolic CONST, emit a
-;; move to get the address of the symbolic object from the GOT.
-
(define_expand "movsi"
[(set (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
"
{
- /* Handle PIC symbolic constants. */
- if (!TARGET_64BIT && flag_pic && SYMBOLIC_CONST (operands[1]))
- emit_pic_move (operands, SImode);
+ /* Handle symbolic constants. */
+ if (!TARGET_64BIT && SYMBOLIC_CONST (operands[1]))
+ emit_symbolic_move (operands);
/* expr.c tries to load an effective address using
force_reg. This fails because we don't have a
@@ -1059,7 +1115,7 @@
if ((reload_in_progress || reload_completed)
&& CONSTANT_P (operands[1])
&& (!legitimate_reload_constant_p (operands[1])
- || fp_operand (operands[0], VOIDmode)))
+ || FP_REG_P (operands[0])))
operands[1] = force_const_mem (SImode, operands[1]);
}")
@@ -1068,7 +1124,7 @@
(match_operand:SI 1 "immediate_operand" "K"))]
"GET_CODE (operands[1]) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K')
- && !fp_operand (operands[0], VOIDmode)"
+ && !FP_REG_P (operands[0])"
"lhi\\t%0,%h1"
[(set_attr "op_type" "RI")])
@@ -1076,7 +1132,7 @@
[(set (match_operand:SI 0 "register_operand" "=d")
(match_operand:SI 1 "immediate_operand" "n"))]
"TARGET_64BIT && s390_single_hi (operands[1], SImode, 0) >= 0
- && !fp_operand (operands[0], VOIDmode)"
+ && !FP_REG_P (operands[0])"
"*
{
int part = s390_single_hi (operands[1], SImode, 0);
@@ -1091,17 +1147,9 @@
}"
[(set_attr "op_type" "RI")])
-(define_insn "*movsi_ss"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
- (match_operand:SI 1 "s_imm_operand" "Qo"))]
- ""
- "mvc\\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")])
-
(define_insn "*movsi"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,m,!*f,!*f,!m")
- (match_operand:SI 1 "general_operand" "d,m,d,*f,m,*f"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,m,!*f,!*f,!m,?Q")
+ (match_operand:SI 1 "general_operand" "d,m,d,*f,m,*f,?Q"))]
""
"@
lr\\t%0,%1
@@ -1109,62 +1157,94 @@
st\\t%1,%0
ler\\t%0,%1
le\\t%0,%1
- ste\\t%1,%0"
- [(set_attr "op_type" "RR,RX,RX,RR,RX,RX")
- (set_attr "atype" "reg,mem,mem,reg,mem,mem")])
+ ste\\t%1,%0
+ mvc\\t%O0(4,%R0),%1"
+ [(set_attr "op_type" "RR,RX,RX,RR,RX,RX,SS")
+ (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")])
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mem:SI (match_operand 1 "address_operand" "")))]
+ "!FP_REG_P (operands[0])
+ && GET_CODE (operands[1]) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (operands[1])
+ && get_pool_mode (operands[1]) == SImode
+ && legitimate_reload_constant_p (get_pool_constant (operands[1]))"
+ [(set (match_dup 0) (match_dup 2))]
+ "operands[2] = get_pool_constant (operands[1]);")
;
; movhi instruction pattern(s).
;
(define_insn "movhi"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m")
- (match_operand:HI 1 "general_operand" "d,n,m,d"))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,?Q")
+ (match_operand:HI 1 "general_operand" "d,n,m,d,?Q"))]
""
"@
lr\\t%0,%1
lhi\\t%0,%h1
lh\\t%0,%1
- sth\\t%1,%0"
- [(set_attr "op_type" "RR,RI,RX,RX")
- (set_attr "atype" "reg,reg,mem,mem")])
+ sth\\t%1,%0
+ mvc\\t%O0(2,%R0),%1"
+ [(set_attr "op_type" "RR,RI,RX,RX,SS")
+ (set_attr "atype" "reg,reg,mem,mem,mem")])
+(define_peephole2
+ [(set (match_operand:HI 0 "register_operand" "")
+ (mem:HI (match_operand 1 "address_operand" "")))]
+ "GET_CODE (operands[1]) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (operands[1])
+ && get_pool_mode (operands[1]) == HImode
+ && GET_CODE (get_pool_constant (operands[1])) == CONST_INT"
+ [(set (match_dup 0) (match_dup 2))]
+ "operands[2] = get_pool_constant (operands[1]);")
;
; movqi instruction pattern(s).
;
(define_insn "movqi_64"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,Q")
- (match_operand:QI 1 "general_operand" "d,n,m,d,n"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,Q,?Q")
+ (match_operand:QI 1 "general_operand" "d,n,m,d,n,?Q"))]
"TARGET_64BIT"
"@
lr\\t%0,%1
lhi\\t%0,%b1
llgc\\t%0,%1
stc\\t%1,%0
- mvi\\t%0,%b1"
- [(set_attr "op_type" "RR,RI,RXE,RX,SI")
- (set_attr "atype" "reg,reg,mem,mem,mem")])
+ mvi\\t%0,%b1
+ mvc\\t%O0(1,%R0),%1"
+ [(set_attr "op_type" "RR,RI,RXE,RX,SI,SS")
+ (set_attr "atype" "reg,reg,mem,mem,mem,mem")])
(define_insn "movqi"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,Q")
- (match_operand:QI 1 "general_operand" "d,n,m,d,n"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,Q,?Q")
+ (match_operand:QI 1 "general_operand" "d,n,m,d,n,?Q"))]
""
"@
lr\\t%0,%1
lhi\\t%0,%b1
ic\\t%0,%1
stc\\t%1,%0
- mvi\\t%0,%b1"
- [(set_attr "op_type" "RR,RI,RX,RX,SI")
- (set_attr "atype" "reg,reg,mem,mem,mem")])
+ mvi\\t%0,%b1
+ mvc\\t%O0(1,%R0),%1"
+ [(set_attr "op_type" "RR,RI,RX,RX,SI,SS")
+ (set_attr "atype" "reg,reg,mem,mem,mem,mem")])
+(define_peephole2
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (mem:QI (match_operand 1 "address_operand" "")))]
+ "GET_CODE (operands[1]) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (operands[1])
+ && get_pool_mode (operands[1]) == QImode
+ && GET_CODE (get_pool_constant (operands[1])) == CONST_INT"
+ [(set (match_dup 0) (match_dup 2))]
+ "operands[2] = get_pool_constant (operands[1]);")
;
-; moveqstrictqi instruction pattern(s).
+; movstrictqi instruction pattern(s).
;
(define_insn "*movstrictqi"
@@ -1181,7 +1261,7 @@
(define_insn "*movstricthi"
[(set (strict_low_part (match_operand:HI 0 "register_operand" "+d"))
- (match_operand:HI 1 "s_imm_operand" "Qo"))
+ (match_operand:HI 1 "s_imm_operand" "Q"))
(clobber (reg:CC 33))]
""
"icm\\t%0,3,%1"
@@ -1193,7 +1273,7 @@
; movstrictsi instruction pattern(s).
;
-(define_insn "movestrictsi"
+(define_insn "movstrictsi"
[(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d"))
(match_operand:SI 1 "general_operand" "d,m"))]
"TARGET_64BIT"
@@ -1221,17 +1301,9 @@
operands[1] = force_const_mem (DFmode, operands[1]);
}")
-(define_insn "*movdf_ss"
- [(set (match_operand:DF 0 "s_operand" "=Qo")
- (match_operand:DF 1 "s_imm_operand" "Qo"))]
- ""
- "mvc\\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")])
-
(define_insn "*movdf_64"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,d,d,m")
- (match_operand:DF 1 "general_operand" "f,m,f,d,m,d"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,d,d,m,?Q")
+ (match_operand:DF 1 "general_operand" "f,m,f,d,m,d,?Q"))]
"TARGET_64BIT"
"@
ldr\\t%0,%1
@@ -1239,13 +1311,14 @@
std\\t%1,%0
lgr\\t%0,%1
lg\\t%0,%1
- stg\\t%1,%0"
- [(set_attr "op_type" "RR,RX,RX,RRE,RXE,RXE")
- (set_attr "atype" "reg,mem,mem,reg,mem,mem")])
+ stg\\t%1,%0
+ mvc\\t%O0(8,%R0),%1"
+ [(set_attr "op_type" "RR,RX,RX,RRE,RXE,RXE,SS")
+ (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")])
(define_insn "*movdf_31"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,d,Q,d,m")
- (match_operand:DF 1 "general_operand" "f,m,f,Q,d,dKm,d"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,d,Q,d,o,Q")
+ (match_operand:DF 1 "general_operand" "f,m,f,Q,d,dKm,d,Q"))]
"!TARGET_64BIT"
"@
ldr\\t%0,%1
@@ -1254,58 +1327,63 @@
lm\\t%0,%N0,%1
stm\\t%1,%N1,%0
#
- #"
- [(set_attr "op_type" "RR,RX,RX,RS,RS,NN,NN")
- (set_attr "atype" "reg,mem,mem,mem,mem,*,*")])
+ #
+ mvc\\t%O0(8,%R0),%1"
+ [(set_attr "op_type" "RR,RX,RX,RS,RS,NN,NN,SS")
+ (set_attr "atype" "reg,mem,mem,mem,mem,*,*,mem")])
(define_split
[(set (match_operand:DF 0 "nonimmediate_operand" "")
(match_operand:DF 1 "general_operand" ""))]
"!TARGET_64BIT && reload_completed
- && !fp_operand (operands[0], VOIDmode)
- && !fp_operand (operands[1], VOIDmode)
- && !s_operand (operands[0], VOIDmode)
- && !s_operand (operands[1], VOIDmode)
- && (register_operand (operands[0], VOIDmode)
- || register_operand (operands[1], VOIDmode))
- && (!register_operand (operands[0], VOIDmode)
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DFmode),
- operands[1])
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 1, 0, DFmode),
- operands[1]))"
+ && s390_split_ok_p (operands[0], operands[1], DFmode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
- "
{
- if (!register_operand (operands[0], VOIDmode)
- || !reg_overlap_mentioned_p (operand_subword (operands[0], 0, 0, DFmode),
- operands[1]))
- {
- operands[2] = operand_subword (operands[0], 0, 0, DFmode);
- operands[3] = operand_subword (operands[0], 1, 0, DFmode);
- operands[4] = operand_subword (operands[1], 0, 0, DFmode);
- operands[5] = operand_subword (operands[1], 1, 0, DFmode);
- }
- else
- {
- operands[2] = operand_subword (operands[0], 1, 0, DFmode);
- operands[3] = operand_subword (operands[0], 0, 0, DFmode);
- operands[4] = operand_subword (operands[1], 1, 0, DFmode);
- operands[5] = operand_subword (operands[1], 0, 0, DFmode);
- }
-}")
+ operands[2] = operand_subword (operands[0], 0, 0, DFmode);
+ operands[3] = operand_subword (operands[0], 1, 0, DFmode);
+ operands[4] = operand_subword (operands[1], 0, 0, DFmode);
+ operands[5] = operand_subword (operands[1], 1, 0, DFmode);
+})
+
+(define_split
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ "!TARGET_64BIT && reload_completed
+ && s390_split_ok_p (operands[0], operands[1], DFmode, 1)"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+{
+ operands[2] = operand_subword (operands[0], 1, 0, DFmode);
+ operands[3] = operand_subword (operands[0], 0, 0, DFmode);
+ operands[4] = operand_subword (operands[1], 1, 0, DFmode);
+ operands[5] = operand_subword (operands[1], 0, 0, DFmode);
+})
(define_split
[(set (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "memory_operand" ""))]
"!TARGET_64BIT && reload_completed
- && !fp_operand (operands[0], VOIDmode)
- && !fp_operand (operands[1], VOIDmode)
+ && !FP_REG_P (operands[0])
&& !s_operand (operands[1], VOIDmode)"
- [(set (match_dup 2) (match_dup 3))
- (set (match_dup 0) (mem:DI (match_dup 2)))]
- "operands[2] = operand_subword (operands[0], 1, 0, DFmode);
- operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
+ [(set (match_dup 0) (match_dup 1))]
+{
+ rtx addr = operand_subword (operands[0], 1, 0, DFmode);
+ s390_load_address (addr, XEXP (operands[1], 0));
+ operands[1] = replace_equiv_address (operands[1], addr);
+})
+
+(define_expand "reload_outdf"
+ [(parallel [(match_operand:DF 0 "memory_operand" "")
+ (match_operand:DF 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "=&a")])]
+ "!TARGET_64BIT"
+{
+ s390_load_address (operands[2], XEXP (operands[0], 0));
+ operands[0] = replace_equiv_address (operands[0], operands[2]);
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
;
; movsf instruction pattern(s).
@@ -1324,17 +1402,9 @@
operands[1] = force_const_mem (SFmode, operands[1]);
}")
-(define_insn "*movsf_ss"
- [(set (match_operand:SF 0 "s_operand" "=Qo")
- (match_operand:SF 1 "s_imm_operand" "Qo"))]
- ""
- "mvc\\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")])
-
(define_insn "*movsf"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,m,d,d,m")
- (match_operand:SF 1 "general_operand" "f,m,f,d,m,d"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,m,d,d,m,?Q")
+ (match_operand:SF 1 "general_operand" "f,m,f,d,m,d,?Q"))]
""
"@
ler\\t%0,%1
@@ -1342,9 +1412,10 @@
ste\\t%1,%0
lr\\t%0,%1
l\\t%0,%1
- st\\t%1,%0"
- [(set_attr "op_type" "RR,RX,RX,RR,RX,RX")
- (set_attr "atype" "reg,mem,mem,reg,mem,mem")])
+ st\\t%1,%0
+ mvc\\t%O0(4,%R0),%1"
+ [(set_attr "op_type" "RR,RX,RX,RR,RX,RX,SS")
+ (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")])
;
; load_multiple pattern(s).
@@ -1413,7 +1484,7 @@
(define_insn "*load_multiple_di"
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:DI 1 "register_operand" "=r")
- (match_operand:DI 2 "s_operand" "oQ"))])]
+ (match_operand:DI 2 "s_operand" "Q"))])]
""
"*
{
@@ -1432,7 +1503,7 @@
(define_insn "*load_multiple_si"
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:SI 1 "register_operand" "=r")
- (match_operand:SI 2 "s_operand" "oQ"))])]
+ (match_operand:SI 2 "s_operand" "Q"))])]
""
"*
{
@@ -1516,7 +1587,7 @@
(define_insn "*store_multiple_di"
[(match_parallel 0 "store_multiple_operation"
- [(set (match_operand:DI 1 "s_operand" "=oQ")
+ [(set (match_operand:DI 1 "s_operand" "=Q")
(match_operand:DI 2 "register_operand" "r"))])]
""
"*
@@ -1536,7 +1607,7 @@
(define_insn "*store_multiple_si"
[(match_parallel 0 "store_multiple_operation"
- [(set (match_operand:SI 1 "s_operand" "=oQ")
+ [(set (match_operand:SI 1 "s_operand" "=Q")
(match_operand:SI 2 "register_operand" "r"))])]
""
"*
@@ -1558,172 +1629,31 @@
;;
;
-; movstrdi instruction pattern(s).
+; movstrM instruction pattern(s).
;
(define_expand "movstrdi"
- [(set (match_operand:BLK 0 "general_operand" "")
- (match_operand:BLK 1 "general_operand" ""))
- (use (match_operand:DI 2 "general_operand" ""))
- (match_operand 3 "" "")]
- "TARGET_64BIT"
- "
-{
- rtx addr0, addr1;
-
- addr0 = force_operand (XEXP (operands[0], 0), NULL_RTX);
- addr1 = force_operand (XEXP (operands[1], 0), NULL_RTX);
-
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) <= 256)
- {
- operands[0] = change_address (operands[0], VOIDmode, addr0);
- operands[1] = change_address (operands[1], VOIDmode, addr1);
- operands[2] = GEN_INT (INTVAL (operands[2]) - 1);
-
- emit_insn (gen_movstrdi_short (operands[0], operands[1], operands[2]));
- DONE;
- }
- else
- {
- if (TARGET_MVCLE)
- {
- /* implementation suggested by Richard Henderson <rth@cygnus.com> */
- rtx reg0 = gen_reg_rtx (TImode);
- rtx reg1 = gen_reg_rtx (TImode);
- rtx len = operands[2];
-
- if (! CONSTANT_P (len))
- len = force_reg (DImode, len);
-
- /* Load up the address+length pairs. */
-
- emit_move_insn (gen_highpart (DImode, reg0), addr0);
- emit_move_insn (gen_lowpart (DImode, reg0), len);
-
- emit_move_insn (gen_highpart (DImode, reg1), addr1);
- emit_move_insn (gen_lowpart (DImode, reg1), len);
-
- /* MOVE */
- emit_insn (gen_movstrdi_64 (reg0, reg1, reg0, reg1));
- DONE;
- }
- else
- {
- rtx label1 = gen_label_rtx ();
- rtx label2 = gen_label_rtx ();
- rtx reg0, reg1, len, blocks;
-
- reg0 = gen_reg_rtx (DImode);
- reg1 = gen_reg_rtx (DImode);
- len = gen_reg_rtx (DImode);
- blocks = gen_reg_rtx (DImode);
-
- emit_move_insn (len, operands[2]);
- emit_insn (gen_cmpdi (len, const0_rtx));
- emit_jump_insn (gen_beq (label1));
- emit_move_insn (reg0, addr0);
- emit_move_insn (reg1, addr1);
- emit_insn (gen_adddi3 (len, len, constm1_rtx));
- emit_insn (gen_ashrdi3 (blocks, len, GEN_INT (8)));
- emit_insn (gen_cmpdi (blocks, const0_rtx));
- emit_jump_insn (gen_beq (label2));
- emit_insn (gen_movstrdi_long (reg0, reg1, reg0, reg1, blocks, blocks));
- emit_label (label2);
- operands[0] = change_address (operands[0], VOIDmode, reg0);
- operands[1] = change_address (operands[1], VOIDmode, reg1);
- emit_insn (gen_movstrdi_short (operands[0], operands[1], len));
- emit_label (label1);
- DONE;
- }
- }
-}")
-
-;
-; movstrsi instruction pattern(s).
-;
+ [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (use (match_operand:DI 2 "general_operand" ""))
+ (match_operand 3 "" "")]
+ "TARGET_64BIT"
+ "s390_expand_movstr (operands[0], operands[1], operands[2]); DONE;")
(define_expand "movstrsi"
- [(set (match_operand:BLK 0 "general_operand" "")
- (match_operand:BLK 1 "general_operand" ""))
- (use (match_operand:SI 2 "general_operand" ""))
- (match_operand 3 "" "")]
- "!TARGET_64BIT"
- "
-{
- rtx addr0 = force_operand (XEXP (operands[0], 0), NULL_RTX);
- rtx addr1 = force_operand (XEXP (operands[1], 0), NULL_RTX);
-
- if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) <= 256)
- {
- operands[0] = change_address (operands[0], VOIDmode, addr0);
- operands[1] = change_address (operands[1], VOIDmode, addr1);
- operands[2] = GEN_INT (INTVAL (operands[2]) - 1);
-
- emit_insn (gen_movstrsi_short (operands[0], operands[1], operands[2]));
- DONE;
- }
- else
- {
- if (TARGET_MVCLE)
- {
- /* implementation suggested by Richard Henderson <rth@cygnus.com> */
- rtx reg0 = gen_reg_rtx (DImode);
- rtx reg1 = gen_reg_rtx (DImode);
- rtx len = operands[2];
-
-
- if (! CONSTANT_P (len))
- len = force_reg (SImode, len);
-
- /* Load up the address+length pairs. */
-
- emit_move_insn (gen_highpart (SImode, reg0), addr0);
- emit_move_insn (gen_lowpart (SImode, reg0), len);
-
- emit_move_insn (gen_highpart (SImode, reg1), addr1);
- emit_move_insn (gen_lowpart (SImode, reg1), len);
-
- /* MOVE */
- emit_insn (gen_movstrsi_31 (reg0, reg1, reg0, reg1));
- DONE;
- }
- else
- {
- rtx label1 = gen_label_rtx ();
- rtx label2 = gen_label_rtx ();
- rtx reg0, reg1, len, blocks;
-
- reg0 = gen_reg_rtx (SImode);
- reg1 = gen_reg_rtx (SImode);
- len = gen_reg_rtx (SImode);
- blocks = gen_reg_rtx (SImode);
-
- emit_move_insn (len, operands[2]);
- emit_insn (gen_cmpsi (len, const0_rtx));
- emit_jump_insn (gen_beq (label1));
- emit_move_insn (reg0, addr0);
- emit_move_insn (reg1, addr1);
- emit_insn (gen_addsi3 (len, len, constm1_rtx));
- emit_insn (gen_ashrsi3 (blocks, len, GEN_INT (8)));
- emit_insn (gen_cmpsi (blocks, const0_rtx));
- emit_jump_insn (gen_beq (label2));
- emit_insn (gen_movstrsi_long (reg0, reg1, reg0, reg1, blocks, blocks));
- emit_label (label2);
- operands[0] = change_address (operands[0], VOIDmode, reg0);
- operands[1] = change_address (operands[1], VOIDmode, reg1);
- emit_insn (gen_movstrsi_short (operands[0], operands[1], len));
- emit_label (label1);
- DONE;
- }
- }
-}")
+ [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (use (match_operand:SI 2 "general_operand" ""))
+ (match_operand 3 "" "")]
+ ""
+ "s390_expand_movstr (operands[0], operands[1], operands[2]); DONE;")
; Move a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
-(define_insn "movstrdi_short"
- [(set (match_operand:BLK 0 "s_operand" "=oQ,oQ")
- (match_operand:BLK 1 "s_operand" "oQ,oQ"))
+(define_insn "movstr_short_64"
+ [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
+ (match_operand:BLK 1 "memory_operand" "Q,Q"))
(use (match_operand:DI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:DI 3 "=X,&a"))]
"TARGET_64BIT"
@@ -1744,12 +1674,13 @@
}
}"
[(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
-(define_insn "movstrsi_short"
- [(set (match_operand:BLK 0 "s_operand" "=oQ,oQ")
- (match_operand:BLK 1 "s_operand" "oQ,oQ"))
+(define_insn "movstr_short_31"
+ [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
+ (match_operand:BLK 1 "memory_operand" "Q,Q"))
(use (match_operand:SI 2 "nonmemory_operand" "n,a"))
(clobber (match_scratch:SI 3 "=X,&a"))]
"!TARGET_64BIT"
@@ -1770,64 +1701,13 @@
}
}"
[(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
(set_attr "atype" "mem,mem")
(set_attr "length" "*,14")])
-; Move a block that is a multiple of 256 bytes in length
+; Move a block of arbitrary length.
-(define_insn "movstrdi_long"
- [(set (match_operand:DI 4 "register_operand" "=d")
- (const_int 0))
- (set (match_operand:DI 0 "register_operand" "=a")
- (plus:DI (match_operand:DI 2 "register_operand" "0")
- (ashift:DI (match_operand:DI 5 "register_operand" "4")
- (const_int 8))))
- (set (match_operand:DI 1 "register_operand" "=a")
- (plus:DI (match_operand:DI 3 "register_operand" "1")
- (ashift:DI (match_dup 5) (const_int 8))))
- (set (mem:BLK (match_dup 2))
- (mem:BLK (match_dup 3)))
- (use (match_dup 5))]
- "TARGET_64BIT"
- "*
-{
- output_asm_insn (\"mvc\\t0(256,%0),0(%1)\", operands);
- output_asm_insn (\"la\\t%0,256(%0)\", operands);
- output_asm_insn (\"la\\t%1,256(%1)\", operands);
- return \"brct\\t%4,.-14\";
-}"
- [(set_attr "op_type" "NN")
- (set_attr "atype" "mem")
- (set_attr "length" "18")])
-
-(define_insn "movstrsi_long"
- [(set (match_operand:SI 4 "register_operand" "=d")
- (const_int 0))
- (set (match_operand:SI 0 "register_operand" "=a")
- (plus:SI (match_operand:SI 2 "register_operand" "0")
- (ashift:SI (match_operand:SI 5 "register_operand" "4")
- (const_int 8))))
- (set (match_operand:SI 1 "register_operand" "=a")
- (plus:SI (match_operand:SI 3 "register_operand" "1")
- (ashift:SI (match_dup 5) (const_int 8))))
- (set (mem:BLK (match_dup 2))
- (mem:BLK (match_dup 3)))
- (use (match_dup 5))]
- "!TARGET_64BIT"
- "*
-{
- output_asm_insn (\"mvc\\t0(256,%0),0(%1)\", operands);
- output_asm_insn (\"la\\t%0,256(%0)\", operands);
- output_asm_insn (\"la\\t%1,256(%1)\", operands);
- return \"brct\\t%4,.-14\";
-}"
- [(set_attr "op_type" "NN")
- (set_attr "atype" "mem")
- (set_attr "length" "18")])
-
-; Move a block that is larger than 255 bytes in length.
-
-(define_insn "movstrdi_64"
+(define_insn "movstr_long_64"
[(set (match_operand:TI 0 "register_operand" "=d")
(ashift:TI (plus:TI (match_operand:TI 2 "register_operand" "0")
(lshiftrt:TI (match_dup 2) (const_int 64)))
@@ -1842,10 +1722,11 @@
"TARGET_64BIT"
"mvcle\\t%0,%1,0\;jo\\t.-4"
[(set_attr "op_type" "NN")
+ (set_attr "type" "vs")
(set_attr "atype" "mem")
(set_attr "length" "8")])
-(define_insn "movstrsi_31"
+(define_insn "movstr_long_31"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (plus:DI (match_operand:DI 2 "register_operand" "0")
(lshiftrt:DI (match_dup 2) (const_int 32)))
@@ -1859,112 +1740,93 @@
(clobber (reg:CC 33))]
"!TARGET_64BIT"
"mvcle\\t%0,%1,0\;jo\\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "atype" "mem")
- (set_attr "length" "8")])
+ [(set_attr "op_type" "NN")
+ (set_attr "type" "vs")
+ (set_attr "atype" "mem")
+ (set_attr "length" "8")])
;
-; clrstrdi instruction pattern(s).
+; clrstrM instruction pattern(s).
;
(define_expand "clrstrdi"
- [(set (match_operand:BLK 0 "general_operand" "")
+ [(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:DI 1 "general_operand" ""))
(match_operand 2 "" "")]
"TARGET_64BIT"
- "
-{
- rtx addr = force_operand (XEXP (operands[0], 0), NULL_RTX);
-
- operands[0] = change_address (operands[0], VOIDmode, addr);
-
- if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 256)
- {
- emit_insn (gen_clrstrsico (operands[0], operands[1]));
- DONE;
- }
- else
- {
- rtx reg0 = gen_reg_rtx (TImode);
- rtx reg1 = gen_reg_rtx (TImode);
- rtx len = operands[1];
-
- if (! CONSTANT_P (len))
- len = force_reg (DImode, len);
-
- /* Load up the address+length pairs. */
-
- emit_move_insn (gen_highpart (DImode, reg0), addr);
- emit_move_insn (gen_lowpart (DImode, reg0), len);
-
- emit_move_insn (gen_lowpart (DImode, reg1), const0_rtx);
-
- /* Clear! */
- emit_insn (gen_clrstrsi_64 (reg0, reg1, reg0));
- DONE;
- }
-}")
-
-;
-; clrstrsi instruction pattern(s).
-;
+ "s390_expand_clrstr (operands[0], operands[1]); DONE;")
(define_expand "clrstrsi"
- [(set (match_operand:BLK 0 "general_operand" "")
+ [(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:SI 1 "general_operand" ""))
(match_operand 2 "" "")]
- "!TARGET_64BIT"
- "
-{
- rtx addr = force_operand (XEXP (operands[0], 0), NULL_RTX);
-
- operands[0] = change_address (operands[0], VOIDmode, addr);
-
- if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 256)
- {
- emit_insn (gen_clrstrsico (operands[0], operands[1]));
- DONE;
- }
- else
- {
- rtx reg0 = gen_reg_rtx (DImode);
- rtx reg1 = gen_reg_rtx (DImode);
- rtx len = operands[1];
-
- if (! CONSTANT_P (len))
- len = force_reg (SImode, len);
+ ""
+ "s390_expand_clrstr (operands[0], operands[1]); DONE;")
- /* Load up the address+length pairs. */
+; Clear a block that is up to 256 bytes in length.
+; The block length is taken as (operands[2] % 256) + 1.
- emit_move_insn (gen_highpart (SImode, reg0), addr);
- emit_move_insn (gen_lowpart (SImode, reg0), len);
+(define_insn "clrstr_short_64"
+ [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
+ (const_int 0))
+ (use (match_operand:DI 1 "nonmemory_operand" "n,a"))
+ (clobber (match_scratch:DI 2 "=X,&a"))
+ (clobber (reg:CC 33))]
+ "TARGET_64BIT"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"xc\\t%O0(%b1+1,%R0),%0\";
- emit_move_insn (gen_lowpart (SImode, reg1), const0_rtx);
-
- /* CLear! */
- emit_insn (gen_clrstrsi_31 (reg0, reg1, reg0));
- DONE;
- }
-}")
+ case 1:
+ output_asm_insn (\"bras\\t%2,.+10\", operands);
+ output_asm_insn (\"xc\\t%O0(1,%R0),%0\", operands);
+ return \"ex\\t%1,0(%2)\";
-; Clear memory with length less than 256 bytes
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
+ (set_attr "atype" "mem,mem")
+ (set_attr "length" "*,14")])
-(define_insn "clrstrsico"
- [(set (match_operand:BLK 0 "s_operand" "=Qo")
+(define_insn "clrstr_short_31"
+ [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
(const_int 0))
- (use (match_operand 1 "immediate_operand" "I"))
+ (use (match_operand:SI 1 "nonmemory_operand" "n,a"))
+ (clobber (match_scratch:SI 2 "=X,&a"))
(clobber (reg:CC 33))]
- ""
- "xc\\t%O0(%1,%R0),%0"
- [(set_attr "op_type" "RS")
- (set_attr "type" "cs")
- (set_attr "atype" "mem")])
+ "!TARGET_64BIT"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"xc\\t%O0(%b1+1,%R0),%0\";
+
+ case 1:
+ output_asm_insn (\"bras\\t%2,.+10\", operands);
+ output_asm_insn (\"xc\\t%O0(1,%R0),%0\", operands);
+ return \"ex\\t%1,0(%2)\";
+
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
+ (set_attr "atype" "mem,mem")
+ (set_attr "length" "*,14")])
-; Clear memory with length greater 256 bytes or lenght not constant
+; Clear a block of arbitrary length.
-(define_insn "clrstrsi_64"
+(define_insn "clrstr_long_64"
[(set (match_operand:TI 0 "register_operand" "=d")
(ashift:TI (plus:TI (match_operand:TI 2 "register_operand" "0")
(lshiftrt:TI (match_dup 2) (const_int 64)))
@@ -1980,7 +1842,7 @@
(set_attr "type" "vs")
(set_attr "length" "8")])
-(define_insn "clrstrsi_31"
+(define_insn "clrstr_long_31"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (plus:DI (match_operand:DI 2 "register_operand" "0")
(lshiftrt:DI (match_dup 2) (const_int 32)))
@@ -1997,171 +1859,112 @@
(set_attr "length" "8")])
;
-; cmpstrdi instruction pattern(s).
+; cmpstrM instruction pattern(s).
;
(define_expand "cmpstrdi"
- [(set (match_operand:DI 0 "register_operand" "")
- (compare:DI (match_operand:BLK 1 "s_operand" "")
- (match_operand:BLK 2 "s_operand" "") ) )
- (use (match_operand:DI 3 "general_operand" ""))
- (use (match_operand:DI 4 "" ""))]
- "TARGET_64BIT"
- "
-{
- rtx addr0, addr1;
+ [(set (match_operand:DI 0 "register_operand" "")
+ (compare:DI (match_operand:BLK 1 "memory_operand" "")
+ (match_operand:BLK 2 "memory_operand" "") ) )
+ (use (match_operand:DI 3 "general_operand" ""))
+ (use (match_operand:DI 4 "" ""))]
+ "TARGET_64BIT"
+ "s390_expand_cmpstr (operands[0], operands[1],
+ operands[2], operands[3]); DONE;")
- /* for pre/post increment */
- operands[1] = protect_from_queue (operands[1], 0);
- operands[2] = protect_from_queue (operands[2], 0);
- operands[3] = protect_from_queue (operands[3], 0);
+(define_expand "cmpstrsi"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (compare:SI (match_operand:BLK 1 "memory_operand" "")
+ (match_operand:BLK 2 "memory_operand" "") ) )
+ (use (match_operand:SI 3 "general_operand" ""))
+ (use (match_operand:SI 4 "" ""))]
+ ""
+ "s390_expand_cmpstr (operands[0], operands[1],
+ operands[2], operands[3]); DONE;")
- addr0 = force_operand (XEXP (operands[1], 0), NULL_RTX);
- addr1 = force_operand (XEXP (operands[2], 0), NULL_RTX);
+; Compare a block that is up to 256 bytes in length.
+; The block length is taken as (operands[2] % 256) + 1.
- if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256)
+(define_insn "cmpstr_short_64"
+ [(set (reg:CCS 33)
+ (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q")
+ (match_operand:BLK 1 "memory_operand" "Q,Q")))
+ (use (match_operand:DI 2 "nonmemory_operand" "n,a"))
+ (clobber (match_scratch:DI 3 "=X,&a"))]
+ "TARGET_64BIT"
+ "*
+{
+ switch (which_alternative)
{
- if (INTVAL (operands[3]) == 0) {
- emit_move_insn (operands[0], operands[3]);
- DONE;
- }
-
- operands[1] = change_address (operands[1], VOIDmode, addr0);
- operands[2] = change_address (operands[2], VOIDmode, addr1);
-
- emit_insn (gen_cmpstr_const (operands[1], operands[2], operands[3]));
- emit_insn (gen_cmpint_di (operands[0]));
- DONE;
- }
- else
- {
- /* implementation suggested by Richard Henderson <rth@cygnus.com> */
- rtx reg0 = gen_reg_rtx (TImode);
- rtx reg1 = gen_reg_rtx (TImode);
- rtx len = operands[3];
-
- if (! CONSTANT_P (len))
- len = force_reg (DImode, len);
-
- /* Load up the address+length pairs. */
- emit_move_insn (gen_highpart (DImode, reg0), addr0);
- emit_move_insn (gen_lowpart (DImode, reg0), len);
+ case 0:
+ return \"clc\\t%O0(%b2+1,%R0),%1\";
- emit_move_insn (gen_highpart (DImode, reg1), addr1);
- emit_move_insn (gen_lowpart (DImode, reg1), len);
+ case 1:
+ output_asm_insn (\"bras\\t%3,.+10\", operands);
+ output_asm_insn (\"clc\\t%O0(1,%R0),%1\", operands);
+ return \"ex\\t%2,0(%3)\";
- /* Compare! */
- emit_insn (gen_cmpstr_64 (reg0, reg1, reg0, reg1));
- emit_insn (gen_cmpint_di (operands[0]));
- DONE;
+ default:
+ abort ();
}
-}")
-
-;
-; cmpstrsi instruction pattern(s).
-;
+}"
+ [(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
+ (set_attr "atype" "mem,mem")
+ (set_attr "length" "*,14")])
-(define_expand "cmpstrsi"
- [(set (match_operand:SI 0 "register_operand" "")
- (compare:SI (match_operand:BLK 1 "s_operand" "")
- (match_operand:BLK 2 "s_operand" "") ) )
- (use (match_operand:SI 3 "general_operand" ""))
- (use (match_operand:SI 4 "" ""))]
- ""
- "
+(define_insn "cmpstr_short_31"
+ [(set (reg:CCS 33)
+ (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q")
+ (match_operand:BLK 1 "memory_operand" "Q,Q")))
+ (use (match_operand:SI 2 "nonmemory_operand" "n,a"))
+ (clobber (match_scratch:SI 3 "=X,&a"))]
+ "!TARGET_64BIT"
+ "*
{
- rtx addr0, addr1;
-
- /* for pre/post increment */
- operands[1] = protect_from_queue (operands[1], 0);
- operands[2] = protect_from_queue (operands[2], 0);
- operands[3] = protect_from_queue (operands[3], 0);
-
- addr0 = force_operand (XEXP (operands[1], 0), NULL_RTX);
- addr1 = force_operand (XEXP (operands[2], 0), NULL_RTX);
-
- if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256)
+ switch (which_alternative)
{
- if (INTVAL (operands[3]) == 0) {
- emit_move_insn (operands[0], operands[3]);
- DONE;
- }
-
- operands[1] = change_address (operands[1], VOIDmode, addr0);
- operands[2] = change_address (operands[2], VOIDmode, addr1);
-
- emit_insn (gen_cmpstr_const (operands[1], operands[2], operands[3]));
- emit_insn (gen_cmpint_si (operands[0]));
- DONE;
- }
- else
- {
- /* implementation suggested by Richard Henderson <rth@cygnus.com> */
- rtx reg0, reg1;
- rtx len = operands[3];
-
- if (TARGET_64BIT)
- {
- reg0 = gen_reg_rtx (TImode);
- reg1 = gen_reg_rtx (TImode);
- }
- else
- {
- reg0 = gen_reg_rtx (DImode);
- reg1 = gen_reg_rtx (DImode);
- }
-
- /* Load up the address+length pairs. */
- emit_move_insn (gen_highpart (Pmode, reg0), addr0);
- convert_move (gen_lowpart (Pmode, reg0), len, 1);
-
- emit_move_insn (gen_highpart (Pmode, reg1), addr1);
- convert_move (gen_lowpart (Pmode, reg1), len, 1);
+ case 0:
+ return \"clc\\t%O0(%b2+1,%R0),%1\";
- /* Compare! */
- if (TARGET_64BIT)
- emit_insn (gen_cmpstr_64 (reg0, reg1, reg0, reg1));
- else
- emit_insn (gen_cmpstr_31 (reg0, reg1, reg0, reg1));
+ case 1:
+ output_asm_insn (\"bras\\t%3,.+10\", operands);
+ output_asm_insn (\"clc\\t%O0(1,%R0),%1\", operands);
+ return \"ex\\t%2,0(%3)\";
- emit_insn (gen_cmpint_si (operands[0]));
- DONE;
+ default:
+ abort ();
}
-}")
-
-; Compare a block that is less than 256 bytes in length.
-
-(define_insn "cmpstr_const"
- [(set (reg:CCS 33)
- (compare:CCS (match_operand:BLK 0 "s_operand" "oQ")
- (match_operand:BLK 1 "s_operand" "oQ")))
- (use (match_operand 2 "immediate_operand" "I"))]
- "(unsigned) INTVAL (operands[2]) < 256"
- "clc\\t%O0(%c2,%R0),%1"
- [(set_attr "op_type" "SS")
- (set_attr "atype" "mem")
- (set_attr "type" "cs")])
+}"
+ [(set_attr "op_type" "SS,NN")
+ (set_attr "type" "cs,cs")
+ (set_attr "atype" "mem,mem")
+ (set_attr "length" "*,14")])
-; Compare a block that is larger than 255 bytes in length.
+; Compare a block of arbitrary length.
-(define_insn "cmpstr_64"
+(define_insn "cmpstr_long_64"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(clobber (match_operand:TI 1 "register_operand" "=d"))
(set (reg:CCS 33)
(compare:CCS (mem:BLK (subreg:DI (match_operand:TI 2 "register_operand" "0") 0))
- (mem:BLK (subreg:DI (match_operand:TI 3 "register_operand" "1") 0))))]
+ (mem:BLK (subreg:DI (match_operand:TI 3 "register_operand" "1") 0))))
+ (use (match_dup 2))
+ (use (match_dup 3))]
"TARGET_64BIT"
"clcl\\t%0,%1"
[(set_attr "op_type" "RR")
(set_attr "atype" "mem")
(set_attr "type" "vs")])
-(define_insn "cmpstr_31"
+(define_insn "cmpstr_long_31"
[(clobber (match_operand:DI 0 "register_operand" "=d"))
(clobber (match_operand:DI 1 "register_operand" "=d"))
(set (reg:CCS 33)
(compare:CCS (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "0") 0))
- (mem:BLK (subreg:SI (match_operand:DI 3 "register_operand" "1") 0))))]
+ (mem:BLK (subreg:SI (match_operand:DI 3 "register_operand" "1") 0))))
+ (use (match_dup 2))
+ (use (match_dup 3))]
"!TARGET_64BIT"
"clcl\\t%0,%1"
[(set_attr "op_type" "RR")
@@ -2211,7 +2014,7 @@
(define_insn "*sethighqisi"
[(set (match_operand:SI 0 "register_operand" "=d")
- (unspec:SI [(match_operand:QI 1 "s_operand" "Qo")] 10))
+ (unspec:SI [(match_operand:QI 1 "s_operand" "Q")] 10))
(clobber (reg:CC 33))]
""
"icm\\t%0,8,%1"
@@ -2220,7 +2023,7 @@
(define_insn "*sethighhisi"
[(set (match_operand:SI 0 "register_operand" "=d")
- (unspec:SI [(match_operand:HI 1 "s_operand" "Qo")] 10))
+ (unspec:SI [(match_operand:HI 1 "s_operand" "Q")] 10))
(clobber (reg:CC 33))]
""
"icm\\t%0,12,%1"
@@ -2229,7 +2032,7 @@
(define_insn "*sethighqidi_64"
[(set (match_operand:DI 0 "register_operand" "=d")
- (unspec:DI [(match_operand:QI 1 "s_operand" "Qo")] 10))
+ (unspec:DI [(match_operand:QI 1 "s_operand" "Q")] 10))
(clobber (reg:CC 33))]
"TARGET_64BIT"
"icmh\\t%0,8,%1"
@@ -2238,20 +2041,23 @@
(define_insn "*sethighqidi_31"
[(set (match_operand:DI 0 "register_operand" "=d")
- (unspec:DI [(match_operand:QI 1 "s_operand" "Qo")] 10))
+ (unspec:DI [(match_operand:QI 1 "s_operand" "Q")] 10))
(clobber (reg:CC 33))]
"!TARGET_64BIT"
"icm\\t%0,8,%1"
[(set_attr "op_type" "RS")
(set_attr "atype" "mem")])
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extract:SI (match_operand:QI 1 "s_operand" "")
- (match_operand 2 "const_int_operand" "")
- (const_int 0)))]
- "!TARGET_64BIT && !reload_completed
+(define_insn_and_split "*extractqi"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
+ (match_operand 2 "const_int_operand" "n")
+ (const_int 0)))
+ (clobber (reg:CC 33))]
+ "!TARGET_64BIT
&& INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 8"
+ "#"
+ "&& reload_completed"
[(parallel
[(set (match_dup 0) (unspec:SI [(match_dup 1)] 10))
(clobber (reg:CC 33))])
@@ -2260,15 +2066,19 @@
{
operands[2] = GEN_INT (32 - INTVAL (operands[2]));
operands[1] = change_address (operands[1], QImode, 0);
-}")
+}"
+ [(set_attr "atype" "mem")])
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extract:SI (match_operand:QI 1 "s_operand" "")
- (match_operand 2 "const_int_operand" "")
- (const_int 0)))]
- "!TARGET_64BIT && !reload_completed
+(define_insn_and_split "*extracthi"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
+ (match_operand 2 "const_int_operand" "n")
+ (const_int 0)))
+ (clobber (reg:CC 33))]
+ "!TARGET_64BIT
&& INTVAL (operands[2]) >= 8 && INTVAL (operands[2]) < 16"
+ "#"
+ "&& reload_completed"
[(parallel
[(set (match_dup 0) (unspec:SI [(match_dup 1)] 10))
(clobber (reg:CC 33))])
@@ -2277,7 +2087,8 @@
{
operands[2] = GEN_INT (32 - INTVAL (operands[2]));
operands[1] = change_address (operands[1], HImode, 0);
-}")
+}"
+ [(set_attr "atype" "mem")])
;
; extendsidi2 instruction pattern(s).
@@ -2566,6 +2377,20 @@
"llgh\\t%0,%1"
[(set_attr "op_type" "RXE")
(set_attr "atype" "mem")])
+
+(define_insn_and_split "*zero_extendhisi2_31"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "Q")))
+ (clobber (reg:CC 33))]
+ "!TARGET_64BIT"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (const_int 0))
+ (parallel
+ [(set (strict_low_part (match_dup 2)) (match_dup 1))
+ (clobber (reg:CC 33))])]
+ "operands[2] = gen_lowpart (HImode, operands[0]);"
+ [(set_attr "atype" "mem")])
;
; zero_extendqisi2 instruction pattern(s).
@@ -2590,6 +2415,17 @@
"llgc\\t%0,%1"
[(set_attr "op_type" "RXE")
(set_attr "atype" "mem")])
+
+(define_insn_and_split "*zero_extendqisi2_31"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ "!TARGET_64BIT"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (const_int 0))
+ (set (strict_low_part (match_dup 2)) (match_dup 1))]
+ "operands[2] = gen_lowpart (QImode, operands[0]);"
+ [(set_attr "atype" "mem")])
;
; zero_extendqihi2 instruction pattern(s).
@@ -2609,13 +2445,24 @@
(define_insn "*zero_extendqihi2_64"
[(set (match_operand:HI 0 "register_operand" "=d")
- (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))
- (clobber (reg:CC 33))]
+ (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
"TARGET_64BIT"
"llgc\\t%0,%1"
[(set_attr "op_type" "RXE")
(set_attr "atype" "mem")])
+(define_insn_and_split "*zero_extendqihi2_31"
+ [(set (match_operand:HI 0 "register_operand" "=&d")
+ (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ "!TARGET_64BIT"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (const_int 0))
+ (set (strict_low_part (match_dup 2)) (match_dup 1))]
+ "operands[2] = gen_lowpart (QImode, operands[0]);"
+ [(set_attr "atype" "mem")])
+
+
;
; fixuns_truncdfdi2 and fix_truncdfsi2 instruction pattern(s).
;
@@ -3062,24 +2909,113 @@
; adddi3 instruction pattern(s).
;
-(define_insn "addaddr_esame"
- [(set (match_operand:DI 0 "register_operand" "=a,a")
- (plus:DI (match_operand:DI 1 "register_operand" "%a,a")
- (match_operand:DI 2 "nonmemory_operand" "J,a")))]
- "TARGET_64BIT && (((REGNO (operands[1]) == STACK_POINTER_REGNUM ) ||
- (REGNO (operands[1]) == BASE_REGISTER)) &&
- (GET_CODE (operands[2]) == REG ||
- CONST_OK_FOR_LETTER_P (INTVAL (operands[2]),'J')))"
+(define_insn "*adddi3_sign"
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (plus:DI (sign_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
+ (match_operand:DI 1 "register_operand" "0,0")))
+ (clobber (reg:CC 33))]
+ "TARGET_64BIT"
"@
- la\\t%0,%c2(,%1)
- la\\t%0,0(%1,%2)"
- [(set_attr "op_type" "RX")
- (set_attr "atype" "mem")
- (set_attr "type" "la")])
+ agfr\\t%0,%2
+ agf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*adddi3_zero_cc"
+ [(set (reg 33)
+ (compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
+ (match_operand:DI 1 "register_operand" "0,0"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=d,d")
+ (plus:DI (zero_extend:DI (match_dup 2)) (match_dup 1)))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ "@
+ algfr\\t%0,%2
+ algf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
-(define_insn "adddi3_64"
+(define_insn "*adddi3_zero_cconly"
+ [(set (reg 33)
+ (compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
+ (match_operand:DI 1 "register_operand" "0,0"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 0 "=d,d"))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ "@
+ algfr\\t%0,%2
+ algf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*adddi3_zero"
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
+ (match_operand:DI 1 "register_operand" "0,0")))
+ (clobber (reg:CC 33))]
+ "TARGET_64BIT"
+ "@
+ algfr\\t%0,%2
+ algf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*adddi3_imm_cc"
+ [(set (reg 33)
+ (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "0")
+ (match_operand:DI 2 "const_int_operand" "K"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=d")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT
+ && s390_match_ccmode (insn, CCAmode)
+ && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')"
+ "aghi\\t%0,%h2"
+ [(set_attr "op_type" "RI")
+ (set_attr "atype" "reg")])
+
+(define_insn "*adddi3_cc"
+ [(set (reg 33)
+ (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:DI 2 "general_operand" "d,m"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=d,d")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ "@
+ algr\\t%0,%2
+ alg\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*adddi3_cconly"
+ [(set (reg 33)
+ (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:DI 2 "general_operand" "d,m"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 0 "=d,d"))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ "@
+ algr\\t%0,%2
+ alg\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*adddi3_cconly2"
+ [(set (reg 33)
+ (compare (match_operand:DI 1 "nonimmediate_operand" "%0,0")
+ (neg:SI (match_operand:DI 2 "general_operand" "d,m"))))
+ (clobber (match_scratch:DI 0 "=d,d"))]
+ "s390_match_ccmode(insn, CCLmode) && TARGET_64BIT"
+ "@
+ algr\\t%0,%2
+ alg\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*adddi3_64"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0")
+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0")
(match_operand:DI 2 "general_operand" "d,K,m") ) )
(clobber (reg:CC 33))]
"TARGET_64BIT"
@@ -3090,51 +3026,47 @@
[(set_attr "op_type" "RRE,RI,RXE")
(set_attr "atype" "reg,reg,mem")])
-(define_insn "adddi3_31"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (plus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m") ) )
+(define_insn_and_split "*adddi3_31"
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0")
+ (match_operand:DI 2 "general_operand" "do") ) )
(clobber (reg:CC 33))]
"!TARGET_64BIT"
- "*
-{
- switch (which_alternative)
- {
- case 0: /* d <- d */
- output_asm_insn (\"ar\\t%0,%2\", operands);
- output_asm_insn (\"alr\\t%N0,%N2\", operands);
- break;
-
- case 1: /* d <- m */
- output_asm_insn (\"a\\t%0,%2\", operands);
- output_asm_insn (\"al\\t%N0,%N2\", operands);
- break;
-
- default:
- abort ();
- }
-
- output_asm_insn (\"brc\\t12,.+8\", operands);
- return \"ahi\\t%0,1\";
-}"
- [(set_attr "op_type" "NN,NN")
- (set_attr "atype" "reg,mem")
- (set_attr "type" "o2,o2")
- (set_attr "length" "12,16")])
+ "#"
+ "&& reload_completed"
+ [(parallel
+ [(set (match_dup 3) (plus:SI (match_dup 4) (match_dup 5)))
+ (clobber (reg:CC 33))])
+ (parallel
+ [(set (reg:CCL1 33)
+ (compare:CCL1 (plus:SI (match_dup 7) (match_dup 8))
+ (match_dup 7)))
+ (set (match_dup 6) (plus:SI (match_dup 7) (match_dup 8)))])
+ (set (pc)
+ (if_then_else (ltu (reg:CCL1 33) (const_int 0))
+ (pc)
+ (label_ref (match_dup 9))))
+ (parallel
+ [(set (match_dup 3) (plus:SI (match_dup 3) (const_int 1)))
+ (clobber (reg:CC 33))])
+ (match_dup 9)]
+ "operands[3] = operand_subword (operands[0], 0, 0, DImode);
+ operands[4] = operand_subword (operands[1], 0, 0, DImode);
+ operands[5] = operand_subword (operands[2], 0, 0, DImode);
+ operands[6] = operand_subword (operands[0], 1, 0, DImode);
+ operands[7] = operand_subword (operands[1], 1, 0, DImode);
+ operands[8] = operand_subword (operands[2], 1, 0, DImode);
+ operands[9] = gen_label_rtx ();"
+ [(set_attr "op_type" "NN")])
(define_expand "adddi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (plus:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "general_operand" "")))]
+ [(parallel
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "")
+ (match_operand:DI 2 "general_operand" "")))
+ (clobber (reg:CC 33))])]
""
- "
-{
- if (TARGET_64BIT)
- emit_insn(gen_adddi3_64 (operands[0],operands[1],operands[2]));
- else
- emit_insn(gen_adddi3_31 (operands[0],operands[1],operands[2]));
- DONE;
-}")
+ "")
(define_insn "*la_64"
[(set (match_operand:DI 0 "register_operand" "=d")
@@ -3145,10 +3077,36 @@
(set_attr "atype" "mem")
(set_attr "type" "la")])
+(define_peephole2
+ [(parallel
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:QI 1 "address_operand" ""))
+ (clobber (reg:CC 33))])]
+ "TARGET_64BIT
+ && strict_memory_address_p (VOIDmode, operands[1])
+ && preferred_la_operand_p (operands[1])"
+ [(set (match_dup 0) (match_dup 1))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "register_operand" ""))
+ (parallel
+ [(set (match_dup 0)
+ (plus:DI (match_dup 0)
+ (match_operand:DI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 33))])]
+ "TARGET_64BIT
+ && !reg_overlap_mentioned_p (operands[0], operands[2])
+ && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (DImode, operands[1], operands[2]))
+ && preferred_la_operand_p (gen_rtx_PLUS (DImode, operands[1], operands[2]))"
+ [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
+ "")
+
(define_expand "reload_indi"
[(parallel [(match_operand:DI 0 "register_operand" "=a")
(match_operand:DI 1 "s390_plus_operand" "")
- (match_operand:TI 2 "register_operand" "=&a")])]
+ (match_operand:DI 2 "register_operand" "=&a")])]
"TARGET_64BIT"
"
{
@@ -3161,24 +3119,81 @@
; addsi3 instruction pattern(s).
;
-(define_insn "*la_ccclobber"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (match_operand:QI 1 "address_operand" "p"))
- (clobber (reg:CC 33))]
- "legitimate_la_operand_p (operands[1])"
- "la\\t%0,%a1"
- [(set_attr "op_type" "RX")
- (set_attr "atype" "mem")
- (set_attr "type" "la")])
+(define_insn "*addsi3_imm_cc"
+ [(set (reg 33)
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+ (match_operand:SI 2 "const_int_operand" "K"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCAmode)
+ && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')"
+ "ahi\\t%0,%h2"
+ [(set_attr "op_type" "RI")
+ (set_attr "atype" "reg")])
+
+(define_insn "*addsi3_carry1_cc"
+ [(set (reg 33)
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCL1mode)"
+ "@
+ alr\\t%0,%2
+ al\\t%0,%2"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*addsi3_carry1_cconly"
+ [(set (reg 33)
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
+ (match_dup 1)))
+ (clobber (match_scratch:SI 0 "=d,d"))]
+ "s390_match_ccmode (insn, CCL1mode)"
+ "@
+ alr\\t%0,%2
+ al\\t%0,%2"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*addsi3_carry2_cc"
+ [(set (reg 33)
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
+ (match_dup 2)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCL1mode)"
+ "@
+ alr\\t%0,%2
+ al\\t%0,%2"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*addsi3_carry2_cconly"
+ [(set (reg 33)
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
+ (match_dup 2)))
+ (clobber (match_scratch:SI 0 "=d,d"))]
+ "s390_match_ccmode (insn, CCL1mode)"
+ "@
+ alr\\t%0,%2
+ al\\t%0,%2"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
(define_insn "*addsi3_cc"
[(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonimmediate_operand" "d,m"))
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d,d")
(plus:SI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode(insn, CCLmode)"
+ "s390_match_ccmode (insn, CCLmode)"
"@
alr\\t%0,%2
al\\t%0,%2"
@@ -3187,11 +3202,11 @@
(define_insn "*addsi3_cconly"
[(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=d,d"))]
- "s390_match_ccmode(insn, CCLmode)"
+ "s390_match_ccmode (insn, CCLmode)"
"@
alr\\t%0,%2
al\\t%0,%2"
@@ -3200,7 +3215,7 @@
(define_insn "*addsi3_cconly2"
[(set (reg 33)
- (compare (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(neg:SI (match_operand:SI 2 "general_operand" "d,m"))))
(clobber (match_scratch:SI 0 "=d,d"))]
"s390_match_ccmode(insn, CCLmode)"
@@ -3210,9 +3225,29 @@
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
+(define_insn "*addsi3_sign"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (plus:SI (match_operand:SI 1 "register_operand" "0")
+ (sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))
+ (clobber (reg:CC 33))]
+ ""
+ "ah\\t%0,%2"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")])
+
+(define_insn "*addsi3_sub"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (plus:SI (match_operand:SI 1 "register_operand" "0")
+ (subreg:SI (match_operand:HI 2 "memory_operand" "m") 0)))
+ (clobber (reg:CC 33))]
+ ""
+ "ah\\t%0,%2"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")])
+
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
(match_operand:SI 2 "general_operand" "d,K,m")))
(clobber (reg:CC 33))]
""
@@ -3223,23 +3258,71 @@
[(set_attr "op_type" "RR,RI,RX")
(set_attr "atype" "reg,reg,mem")])
-(define_insn "*addsi3_inv"
- [(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (plus:SI (match_operand:SI 1 "general_operand" "%d,K,m")
- (match_operand:SI 2 "register_operand" "0,0,0")))
+(define_insn "*la_31"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (match_operand:QI 1 "address_operand" "p"))]
+ "!TARGET_64BIT && legitimate_la_operand_p (operands[1])"
+ "la\\t%0,%a1"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")
+ (set_attr "type" "la")])
+
+(define_peephole2
+ [(parallel
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:QI 1 "address_operand" ""))
+ (clobber (reg:CC 33))])]
+ "!TARGET_64BIT
+ && strict_memory_address_p (VOIDmode, operands[1])
+ && preferred_la_operand_p (operands[1])"
+ [(set (match_dup 0) (match_dup 1))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" ""))
+ (parallel
+ [(set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (match_operand:SI 2 "nonmemory_operand" "")))
+ (clobber (reg:CC 33))])]
+ "!TARGET_64BIT
+ && !reg_overlap_mentioned_p (operands[0], operands[2])
+ && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (SImode, operands[1], operands[2]))
+ && preferred_la_operand_p (gen_rtx_PLUS (SImode, operands[1], operands[2]))"
+ [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_insn "*la_31_and"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (and:SI (match_operand:QI 1 "address_operand" "p")
+ (const_int 2147483647)))]
+ "!TARGET_64BIT"
+ "la\\t%0,%a1"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")
+ (set_attr "type" "la")])
+
+(define_insn_and_split "*la_31_and_cc"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (and:SI (match_operand:QI 1 "address_operand" "p")
+ (const_int 2147483647)))
(clobber (reg:CC 33))]
+ "!TARGET_64BIT"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0)
+ (and:SI (match_dup 1) (const_int 2147483647)))]
""
- "@
- ar\\t%0,%1
- ahi\\t%0,%h1
- a\\t%0,%1"
- [(set_attr "op_type" "RR,RI,RX")
- (set_attr "atype" "reg,reg,mem")])
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")
+ (set_attr "type" "la")])
-(define_insn "*la_31"
+(define_insn "force_la_31"
[(set (match_operand:SI 0 "register_operand" "=d")
- (match_operand:QI 1 "address_operand" "p"))]
- "legitimate_la_operand_p (operands[1])"
+ (match_operand:QI 1 "address_operand" "p"))
+ (use (const_int 0))]
+ "!TARGET_64BIT"
"la\\t%0,%a1"
[(set_attr "op_type" "RX")
(set_attr "atype" "mem")
@@ -3248,7 +3331,7 @@
(define_expand "reload_insi"
[(parallel [(match_operand:SI 0 "register_operand" "=a")
(match_operand:SI 1 "s390_plus_operand" "")
- (match_operand:DI 2 "register_operand" "=&a")])]
+ (match_operand:SI 2 "register_operand" "=&a")])]
"!TARGET_64BIT"
"
{
@@ -3258,48 +3341,13 @@
;
-; addhi3 instruction pattern(s).
-;
-
-(define_insn "addhi3"
- [(set (match_operand:HI 0 "register_operand" "=d,d,d")
- (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0")
- (match_operand:HI 2 "general_operand" "d,K,m")))
- (clobber (reg:CC 33))]
- ""
- "@
- ar\\t%0,%2
- ahi\\t%0,%h2
- ah\\t%0,%2"
- [(set_attr "op_type" "RR,RI,RX")
- (set_attr "atype" "reg,reg,mem")])
-
-
-;
-; addqi3 instruction pattern(s).
-;
-
-(define_insn "addqi3"
- [(set (match_operand:QI 0 "register_operand" "=d,d")
- (plus:QI (match_operand:QI 1 "register_operand" "%0,0")
- (match_operand:QI 2 "general_operand" "a,n")))
- (clobber (reg:CC 33))]
- ""
- "@
- ar\\t%0,%2
- ahi\\t%0,%h2"
- [(set_attr "op_type" "RX,RX")
- (set_attr "atype" "reg,mem")])
-
-
-;
; adddf3 instruction pattern(s).
;
(define_expand "adddf3"
[(parallel
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_operand:DF 1 "register_operand" "%0,0")
+ (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
(match_operand:DF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))])]
"TARGET_HARD_FLOAT"
@@ -3307,7 +3355,7 @@
(define_insn "*adddf3"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_operand:DF 1 "register_operand" "%0,0")
+ (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
(match_operand:DF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
@@ -3319,7 +3367,7 @@
(define_insn "*adddf3_ibm"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_operand:DF 1 "register_operand" "%0,0")
+ (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
(match_operand:DF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
@@ -3336,7 +3384,7 @@
(define_expand "addsf3"
[(parallel
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_operand:SF 1 "register_operand" "%0,0")
+ (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
(match_operand:SF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))])]
"TARGET_HARD_FLOAT"
@@ -3344,7 +3392,7 @@
(define_insn "*addsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_operand:SF 1 "register_operand" "%0,0")
+ (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
(match_operand:SF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
@@ -3356,7 +3404,7 @@
(define_insn "*addsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_operand:SF 1 "register_operand" "%0,0")
+ (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
(match_operand:SF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
@@ -3375,6 +3423,84 @@
; subdi3 instruction pattern(s).
;
+(define_insn "*subdi3_sign"
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (sign_extend:DI (match_operand:SI 2 "general_operand" "d,m"))))
+ (clobber (reg:CC 33))]
+ "TARGET_64BIT"
+ "@
+ sgfr\\t%0,%2
+ sgf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*subdi3_zero_cc"
+ [(set (reg 33)
+ (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=d,d")
+ (minus:DI (match_dup 1) (zero_extend:DI (match_dup 2))))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ "@
+ slgfr\\t%0,%2
+ slgf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*subdi3_zero_cconly"
+ [(set (reg 33)
+ (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 0 "=d,d"))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ "@
+ slgfr\\t%0,%2
+ slgf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*subdi3_zero"
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))))
+ (clobber (reg:CC 33))]
+ "TARGET_64BIT"
+ "@
+ slgfr\\t%0,%2
+ slgf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*subdi3_cc"
+ [(set (reg 33)
+ (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (match_operand:DI 2 "general_operand" "d,m"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=d,d")
+ (minus:DI (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCLmode)"
+ "@
+ slgr\\t%0,%2
+ slg\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*subdi3_cconly"
+ [(set (reg 33)
+ (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (match_operand:DI 2 "general_operand" "d,m"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 0 "=d,d"))]
+ "s390_match_ccmode (insn, CCLmode)"
+ "@
+ slgr\\t%0,%2
+ slg\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")])
+
(define_insn "*subdi3_64"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(minus:DI (match_operand:DI 1 "register_operand" "0,0")
@@ -3387,41 +3513,79 @@
[(set_attr "op_type" "RRE,RRE")
(set_attr "atype" "reg,mem")])
-(define_insn "subdi3"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m")))
+(define_insn_and_split "*subdi3_31"
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (minus:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:DI 2 "general_operand" "do") ) )
(clobber (reg:CC 33))]
+ "!TARGET_64BIT"
+ "#"
+ "&& reload_completed"
+ [(parallel
+ [(set (match_dup 3) (minus:SI (match_dup 4) (match_dup 5)))
+ (clobber (reg:CC 33))])
+ (parallel
+ [(set (reg:CCL2 33)
+ (compare:CCL2 (minus:SI (match_dup 7) (match_dup 8))
+ (match_dup 7)))
+ (set (match_dup 6) (minus:SI (match_dup 7) (match_dup 8)))])
+ (set (pc)
+ (if_then_else (gtu (reg:CCL2 33) (const_int 0))
+ (pc)
+ (label_ref (match_dup 9))))
+ (parallel
+ [(set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))
+ (clobber (reg:CC 33))])
+ (match_dup 9)]
+ "operands[3] = operand_subword (operands[0], 0, 0, DImode);
+ operands[4] = operand_subword (operands[1], 0, 0, DImode);
+ operands[5] = operand_subword (operands[2], 0, 0, DImode);
+ operands[6] = operand_subword (operands[0], 1, 0, DImode);
+ operands[7] = operand_subword (operands[1], 1, 0, DImode);
+ operands[8] = operand_subword (operands[2], 1, 0, DImode);
+ operands[9] = gen_label_rtx ();"
+ [(set_attr "op_type" "NN")])
+
+(define_expand "subdi3"
+ [(parallel
+ [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "general_operand" "")))
+ (clobber (reg:CC 33))])]
""
- "*
-{
- switch (which_alternative)
- {
- case 0: /* d <- d */
- output_asm_insn (\"sr\\t%0,%2\", operands);
- output_asm_insn (\"slr\\t%N0,%N2\", operands);
- break;
- case 1: /* d <- m */
- output_asm_insn (\"s\\t%0,%2\", operands);
- output_asm_insn (\"sl\\t%N0,%N2\", operands);
- break;
-
- default:
- abort ();
- }
-
- output_asm_insn (\"brc\\t11,.+8\", operands);
- return \"ahi\\t%0,-1\";
-}"
- [(set_attr "op_type" "NN,NN")
- (set_attr "atype" "reg,mem")
- (set_attr "type" "other,other")
- (set_attr "length" "12,16")])
+ "")
;
; subsi3 instruction pattern(s).
;
+(define_insn "*subsi3_borrow_cc"
+ [(set (reg 33)
+ (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "register_operand" "=d,d")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode(insn, CCL2mode)"
+ "@
+ slr\\t%0,%2
+ sl\\t%0,%2"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*subsi3_borrow_cconly"
+ [(set (reg 33)
+ (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "d,m"))
+ (match_dup 1)))
+ (clobber (match_scratch:SI 0 "=d,d"))]
+ "s390_match_ccmode(insn, CCL2mode)"
+ "@
+ slr\\t%0,%2
+ sl\\t%0,%2"
+ [(set_attr "op_type" "RR,RX")
+ (set_attr "atype" "reg,mem")])
+
(define_insn "*subsi3_cc"
[(set (reg 33)
(compare (minus:SI (match_operand:SI 1 "register_operand" "0,0")
@@ -3449,6 +3613,26 @@
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
+(define_insn "*subsi3_sign"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_operand:SI 1 "register_operand" "0")
+ (sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))
+ (clobber (reg:CC 33))]
+ ""
+ "sh\\t%0,%2"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")])
+
+(define_insn "*subsi3_sub"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_operand:SI 1 "register_operand" "0")
+ (subreg:SI (match_operand:HI 2 "memory_operand" "m") 0)))
+ (clobber (reg:CC 33))]
+ ""
+ "sh\\t%0,%2"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")])
+
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(minus:SI (match_operand:SI 1 "register_operand" "0,0")
@@ -3461,34 +3645,6 @@
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
-;
-; subhi3 instruction pattern(s).
-;
-
-(define_insn "subhi3"
- [(set (match_operand:HI 0 "register_operand" "=d,d")
- (minus:HI (match_operand:HI 1 "register_operand" "0,0")
- (match_operand:HI 2 "general_operand" "d,m")))
- (clobber (reg:CC 33))]
- ""
- "@
- sr\\t%0,%2
- sh\\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "atype" "reg,mem")])
-
-;
-; subqi3 instruction pattern(s).
-;
-
-(define_insn "subqi3"
- [(set (match_operand:QI 0 "register_operand" "=d")
- (minus:QI (match_operand:QI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "sr\\t%0,%2"
- [(set_attr "op_type" "RR")])
;
; subdf3 instruction pattern(s).
@@ -3573,17 +3729,29 @@
; muldi3 instruction pattern(s).
;
+(define_insn "*muldi3_sign"
+ [(set (match_operand:DI 0 "register_operand" "=d,d")
+ (mult:DI (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "d,m"))
+ (match_operand:DI 1 "register_operand" "0,0")))]
+ "TARGET_64BIT"
+ "@
+ msgfr\\t%0,%2
+ msgf\\t%0,%2"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "atype" "reg,mem")
+ (set_attr "type" "imul")])
+
+
(define_insn "muldi3"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (mult:DI (match_operand:DI 1 "register_operand" "%0,0,0")
- (match_operand:DI 2 "general_operand" "d,K,m")))
- (clobber (reg:CC 33))]
+ (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:DI 2 "general_operand" "d,K,m")))]
"TARGET_64BIT"
"@
msgr\\t%0,%2
mghi\\t%0,%h2
msg\\t%0,%2"
- [(set_attr "op_type" "RRE,RI,RX")
+ [(set_attr "op_type" "RRE,RI,RXE")
(set_attr "atype" "reg,reg,mem")
(set_attr "type" "imul")])
@@ -3593,9 +3761,8 @@
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,K,m")))
- (clobber (reg:CC 33))]
+ (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:SI 2 "general_operand" "d,K,m")))]
""
"@
msr\\t%0,%2
@@ -3611,7 +3778,7 @@
(define_expand "mulsidi3"
[(set (match_operand:DI 0 "register_operand" "")
- (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))))]
"!TARGET_64BIT"
"
@@ -3635,8 +3802,7 @@
(mult:DI (sign_extend:DI
(truncate:SI (match_operand:DI 1 "register_operand" "0,0")))
(sign_extend:DI
- (match_operand:SI 2 "nonimmediate_operand" "d,m"))))
- (clobber (reg:CC 33))]
+ (match_operand:SI 2 "nonimmediate_operand" "d,m"))))]
"!TARGET_64BIT"
"@
mr\\t%0,%2
@@ -3652,7 +3818,7 @@
(define_expand "muldf3"
[(parallel
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (mult:DF (match_operand:DF 1 "register_operand" "%0,0")
+ (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
(match_operand:DF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))])]
"TARGET_HARD_FLOAT"
@@ -3660,7 +3826,7 @@
(define_insn "*muldf3"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (mult:DF (match_operand:DF 1 "register_operand" "%0,0")
+ (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
(match_operand:DF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
@@ -3673,7 +3839,7 @@
(define_insn "*muldf3_ibm"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (mult:DF (match_operand:DF 1 "register_operand" "%0,0")
+ (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
(match_operand:DF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
@@ -3691,7 +3857,7 @@
(define_expand "mulsf3"
[(parallel
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (mult:SF (match_operand:SF 1 "register_operand" "%0,0")
+ (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
(match_operand:SF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))])]
"TARGET_HARD_FLOAT"
@@ -3699,7 +3865,7 @@
(define_insn "*mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (mult:SF (match_operand:SF 1 "register_operand" "%0,0")
+ (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
(match_operand:SF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
@@ -3712,7 +3878,7 @@
(define_insn "*mulsf3_ibm"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (mult:SF (match_operand:SF 1 "register_operand" "%0,0")
+ (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
(match_operand:SF 2 "general_operand" "f,m")))
(clobber (reg:CC 33))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
@@ -4211,7 +4377,7 @@
(define_insn "*anddi3_cc"
[(set (reg 33)
- (compare (and:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -4225,7 +4391,7 @@
(define_insn "*anddi3_cconly"
[(set (reg 33)
- (compare (and:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:DI 0 "=d,d"))]
@@ -4238,7 +4404,7 @@
(define_insn "*anddi3_ni"
[(set (match_operand:DI 0 "register_operand" "=d")
- (and:DI (match_operand:DI 1 "register_operand" "%0")
+ (and:DI (match_operand:DI 1 "nonimmediate_operand" "0")
(match_operand:DI 2 "immediate_operand" "n")))
(clobber (reg:CC 33))]
"TARGET_64BIT && s390_single_hi (operands[2], DImode, -1) >= 0"
@@ -4261,7 +4427,7 @@
(define_insn "anddi3"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (and:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m")))
(clobber (reg:CC 33))]
"TARGET_64BIT"
@@ -4272,9 +4438,9 @@
(set_attr "atype" "reg,mem")])
(define_insn "*anddi3_ss"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
+ [(set (match_operand:DI 0 "s_operand" "=Q")
(and:DI (match_dup 0)
- (match_operand:DI 1 "s_imm_operand" "Qo")))
+ (match_operand:DI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"nc\\t%O0(8,%R0),%1"
@@ -4282,8 +4448,8 @@
(set_attr "atype" "mem")])
(define_insn "*anddi3_ss_inv"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
- (and:DI (match_operand:DI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:DI 0 "s_operand" "=Q")
+ (and:DI (match_operand:DI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4297,7 +4463,7 @@
(define_insn "*andsi3_cc"
[(set (reg 33)
- (compare (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d,d")
@@ -4311,7 +4477,7 @@
(define_insn "*andsi3_cconly"
[(set (reg 33)
- (compare (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=d,d"))]
@@ -4324,7 +4490,7 @@
(define_insn "*andsi3_ni"
[(set (match_operand:SI 0 "register_operand" "=d")
- (and:SI (match_operand:SI 1 "register_operand" "%0")
+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:SI 2 "immediate_operand" "n")))
(clobber (reg:CC 33))]
"TARGET_64BIT && s390_single_hi (operands[2], SImode, -1) >= 0"
@@ -4345,7 +4511,7 @@
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m")))
(clobber (reg:CC 33))]
""
@@ -4356,9 +4522,9 @@
(set_attr "atype" "reg,mem")])
(define_insn "*andsi3_ss"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
+ [(set (match_operand:SI 0 "s_operand" "=Q")
(and:SI (match_dup 0)
- (match_operand:SI 1 "s_imm_operand" "Qo")))
+ (match_operand:SI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"nc\\t%O0(4,%R0),%1"
@@ -4366,8 +4532,8 @@
(set_attr "atype" "mem")])
(define_insn "*andsi3_ss_inv"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
- (and:SI (match_operand:SI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:SI 0 "s_operand" "=Q")
+ (and:SI (match_operand:SI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4402,9 +4568,9 @@
(set_attr "atype" "reg")])
(define_insn "*andhi3_ss"
- [(set (match_operand:HI 0 "s_operand" "=Qo")
+ [(set (match_operand:HI 0 "s_operand" "=Q")
(and:HI (match_dup 0)
- (match_operand:HI 1 "s_imm_operand" "Qo")))
+ (match_operand:HI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"nc\\t%O0(2,%R0),%1"
@@ -4412,8 +4578,8 @@
(set_attr "atype" "mem")])
(define_insn "*andhi3_ss_inv"
- [(set (match_operand:HI 0 "s_operand" "=Qo")
- (and:HI (match_operand:HI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:HI 0 "s_operand" "=Q")
+ (and:HI (match_operand:HI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4448,9 +4614,9 @@
(set_attr "atype" "reg")])
(define_insn "*andqi3_ss"
- [(set (match_operand:QI 0 "s_operand" "=Qo,Qo")
+ [(set (match_operand:QI 0 "s_operand" "=Q,Q")
(and:QI (match_dup 0)
- (match_operand:QI 1 "s_imm_operand" "n,Qo")))
+ (match_operand:QI 1 "s_imm_operand" "n,Q")))
(clobber (reg:CC 33))]
""
"@
@@ -4460,8 +4626,8 @@
(set_attr "atype" "mem")])
(define_insn "*andqi3_ss_inv"
- [(set (match_operand:QI 0 "s_operand" "=Qo,Qo")
- (and:QI (match_operand:QI 1 "s_imm_operand" "n,Qo")
+ [(set (match_operand:QI 0 "s_operand" "=Q,Q")
+ (and:QI (match_operand:QI 1 "s_imm_operand" "n,Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4482,7 +4648,7 @@
(define_insn "*iordi3_cc"
[(set (reg 33)
- (compare (ior:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -4496,7 +4662,7 @@
(define_insn "*iordi3_cconly"
[(set (reg 33)
- (compare (ior:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:DI 0 "=d,d"))]
@@ -4509,7 +4675,7 @@
(define_insn "*iordi3_oi"
[(set (match_operand:DI 0 "register_operand" "=d")
- (ior:DI (match_operand:DI 1 "register_operand" "%0")
+ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "0")
(match_operand:DI 2 "immediate_operand" "n")))
(clobber (reg:CC 33))]
"TARGET_64BIT && s390_single_hi (operands[2], DImode, 0) >= 0"
@@ -4532,7 +4698,7 @@
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (ior:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m")))
(clobber (reg:CC 33))]
"TARGET_64BIT"
@@ -4543,9 +4709,9 @@
(set_attr "atype" "reg,mem")])
(define_insn "*iordi3_ss"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
+ [(set (match_operand:DI 0 "s_operand" "=Q")
(ior:DI (match_dup 0)
- (match_operand:DI 1 "s_imm_operand" "Qo")))
+ (match_operand:DI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"oc\\t%O0(8,%R0),%1"
@@ -4553,8 +4719,8 @@
(set_attr "atype" "mem")])
(define_insn "*iordi3_ss_inv"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
- (ior:DI (match_operand:DI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:DI 0 "s_operand" "=Q")
+ (ior:DI (match_operand:DI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4568,7 +4734,7 @@
(define_insn "*iorsi3_cc"
[(set (reg 33)
- (compare (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d,d")
@@ -4582,7 +4748,7 @@
(define_insn "*iorsi3_cconly"
[(set (reg 33)
- (compare (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=d,d"))]
@@ -4595,7 +4761,7 @@
(define_insn "*iorsi3_oi"
[(set (match_operand:SI 0 "register_operand" "=d")
- (ior:SI (match_operand:SI 1 "register_operand" "%0")
+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:SI 2 "immediate_operand" "n")))
(clobber (reg:CC 33))]
"TARGET_64BIT && s390_single_hi (operands[2], SImode, 0) >= 0"
@@ -4616,7 +4782,7 @@
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m")))
(clobber (reg:CC 33))]
""
@@ -4627,9 +4793,9 @@
(set_attr "atype" "reg,mem")])
(define_insn "*iorsi3_ss"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
+ [(set (match_operand:SI 0 "s_operand" "=Q")
(ior:SI (match_dup 0)
- (match_operand:SI 1 "s_imm_operand" "Qo")))
+ (match_operand:SI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"oc\\t%O0(4,%R0),%1"
@@ -4637,8 +4803,8 @@
(set_attr "atype" "mem")])
(define_insn "*iorsi3_ss_inv"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
- (ior:SI (match_operand:SI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:SI 0 "s_operand" "=Q")
+ (ior:SI (match_operand:SI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4673,9 +4839,9 @@
(set_attr "atype" "reg")])
(define_insn "*iorhi3_ss"
- [(set (match_operand:HI 0 "s_operand" "=Qo")
+ [(set (match_operand:HI 0 "s_operand" "=Q")
(ior:HI (match_dup 0)
- (match_operand:HI 1 "s_imm_operand" "Qo")))
+ (match_operand:HI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"oc\\t%O0(2,%R0),%1"
@@ -4683,8 +4849,8 @@
(set_attr "atype" "mem")])
(define_insn "*iorhi3_ss_inv"
- [(set (match_operand:HI 0 "s_operand" "=Qo")
- (ior:HI (match_operand:HI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:HI 0 "s_operand" "=Q")
+ (ior:HI (match_operand:HI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4719,9 +4885,9 @@
(set_attr "atype" "reg")])
(define_insn "*iorqi3_ss"
- [(set (match_operand:QI 0 "s_operand" "=Qo,Qo")
+ [(set (match_operand:QI 0 "s_operand" "=Q,Q")
(ior:QI (match_dup 0)
- (match_operand:QI 1 "s_imm_operand" "n,Qo")))
+ (match_operand:QI 1 "s_imm_operand" "n,Q")))
(clobber (reg:CC 33))]
""
"@
@@ -4731,8 +4897,8 @@
(set_attr "atype" "reg,mem")])
(define_insn "*iorqi3_ss_inv"
- [(set (match_operand:QI 0 "s_operand" "=Qo,Qo")
- (ior:QI (match_operand:QI 1 "s_imm_operand" "n,Qo")
+ [(set (match_operand:QI 0 "s_operand" "=Q,Q")
+ (ior:QI (match_operand:QI 1 "s_imm_operand" "n,Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4753,7 +4919,7 @@
(define_insn "*xordi3_cc"
[(set (reg 33)
- (compare (xor:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -4767,7 +4933,7 @@
(define_insn "*xordi3_cconly"
[(set (reg 33)
- (compare (xor:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:DI 0 "=d,d"))]
@@ -4780,7 +4946,7 @@
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (xor:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m")))
(clobber (reg:CC 33))]
"TARGET_64BIT"
@@ -4791,9 +4957,9 @@
(set_attr "atype" "reg,mem")])
(define_insn "*xordi3_ss"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
+ [(set (match_operand:DI 0 "s_operand" "=Q")
(xor:DI (match_dup 0)
- (match_operand:DI 1 "s_imm_operand" "Qo")))
+ (match_operand:DI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"xc\\t%O0(8,%R0),%1"
@@ -4801,8 +4967,8 @@
(set_attr "atype" "mem")])
(define_insn "*xordi3_ss_inv"
- [(set (match_operand:DI 0 "s_operand" "=Qo")
- (xor:DI (match_operand:DI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:DI 0 "s_operand" "=Q")
+ (xor:DI (match_operand:DI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4816,7 +4982,7 @@
(define_insn "*xorsi3_cc"
[(set (reg 33)
- (compare (xor:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d,d")
@@ -4830,7 +4996,7 @@
(define_insn "*xorsi3_cconly"
[(set (reg 33)
- (compare (xor:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=d,d"))]
@@ -4843,7 +5009,7 @@
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d")
- (xor:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "d,m")))
(clobber (reg:CC 33))]
""
@@ -4854,9 +5020,9 @@
(set_attr "atype" "reg,mem")])
(define_insn "*xorsi3_ss"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
+ [(set (match_operand:SI 0 "s_operand" "=Q")
(xor:SI (match_dup 0)
- (match_operand:SI 1 "s_imm_operand" "Qo")))
+ (match_operand:SI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"xc\\t%O0(4,%R0),%1"
@@ -4864,8 +5030,8 @@
(set_attr "atype" "mem")])
(define_insn "*xorsi3_ss_inv"
- [(set (match_operand:SI 0 "s_operand" "=Qo")
- (xor:SI (match_operand:SI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:SI 0 "s_operand" "=Q")
+ (xor:SI (match_operand:SI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4888,9 +5054,9 @@
(set_attr "atype" "reg")])
(define_insn "*xorhi3_ss"
- [(set (match_operand:HI 0 "s_operand" "=Qo")
+ [(set (match_operand:HI 0 "s_operand" "=Q")
(xor:HI (match_dup 0)
- (match_operand:HI 1 "s_imm_operand" "Qo")))
+ (match_operand:HI 1 "s_imm_operand" "Q")))
(clobber (reg:CC 33))]
""
"xc\\t%O0(2,%R0),%1"
@@ -4898,8 +5064,8 @@
(set_attr "atype" "mem")])
(define_insn "*xorhi3_ss_inv"
- [(set (match_operand:HI 0 "s_operand" "=Qo")
- (xor:HI (match_operand:HI 1 "s_imm_operand" "Qo")
+ [(set (match_operand:HI 0 "s_operand" "=Q")
+ (xor:HI (match_operand:HI 1 "s_imm_operand" "Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -4922,9 +5088,9 @@
(set_attr "atype" "reg")])
(define_insn "*xorqi3_ss"
- [(set (match_operand:QI 0 "s_operand" "=Qo,Qo")
+ [(set (match_operand:QI 0 "s_operand" "=Q,Q")
(xor:QI (match_dup 0)
- (match_operand:QI 1 "s_imm_operand" "n,Qo")))
+ (match_operand:QI 1 "s_imm_operand" "n,Q")))
(clobber (reg:CC 33))]
""
"@
@@ -4934,8 +5100,8 @@
(set_attr "atype" "mem")])
(define_insn "*xorqi3_ss_inv"
- [(set (match_operand:QI 0 "s_operand" "=Qo,Qo")
- (xor:QI (match_operand:QI 1 "s_imm_operand" "n,Qo")
+ [(set (match_operand:QI 0 "s_operand" "=Q,Q")
+ (xor:QI (match_operand:QI 1 "s_imm_operand" "n,Q")
(match_dup 0)))
(clobber (reg:CC 33))]
""
@@ -5682,9 +5848,6 @@
(const_int 4)
(ne (symbol_ref "TARGET_64BIT") (const_int 0))
(const_int 6)
- (ne (symbol_ref "s390_pool_overflow") (const_int 0))
- (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
- (const_int 12) (const_int 14))
(eq (symbol_ref "flag_pic") (const_int 0))
(const_int 6)] (const_int 8)))])
@@ -5734,9 +5897,6 @@
(const_int 4)
(ne (symbol_ref "TARGET_64BIT") (const_int 0))
(const_int 6)
- (ne (symbol_ref "s390_pool_overflow") (const_int 0))
- (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
- (const_int 12) (const_int 14))
(eq (symbol_ref "flag_pic") (const_int 0))
(const_int 6)] (const_int 8)))])
@@ -5759,54 +5919,217 @@
(const_string "RR") (const_string "RX")))
(set_attr "atype" "mem")])
+;;
+;;- Trap instructions.
+;;
+
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 0))]
+ ""
+ "j\\t.+2"
+ [(set_attr "op_type" "RX")])
+
+(define_expand "conditional_trap"
+ [(set (match_dup 2) (match_dup 3))
+ (trap_if (match_operator 0 "comparison_operator"
+ [(match_dup 2) (const_int 0)])
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "
+{
+ enum machine_mode ccmode;
+
+ if (operands[1] != const0_rtx) FAIL;
+
+ ccmode = s390_select_ccmode (GET_CODE (operands[0]),
+ s390_compare_op0, s390_compare_op1);
+ operands[2] = gen_rtx_REG (ccmode, 33);
+ operands[3] = gen_rtx_COMPARE (ccmode, s390_compare_op0, s390_compare_op1);
+}")
+
+(define_insn "*trap"
+ [(trap_if (match_operator 0 "comparison_operator" [(reg 33) (const_int 0)])
+ (const_int 0))]
+ ""
+ "j%C0\\t.+2";
+ [(set_attr "op_type" "RX")])
;;
-;;- Subtract one and jump if not zero.
+;;- Loop instructions.
;;
+;; This is all complicated by the fact that since this is a jump insn
+;; we must handle our own output reloads.
+
+(define_expand "doloop_end"
+ [(use (match_operand 0 "" "")) ; loop pseudo
+ (use (match_operand 1 "" "")) ; iterations; zero if unknown
+ (use (match_operand 2 "" "")) ; max iterations
+ (use (match_operand 3 "" "")) ; loop level
+ (use (match_operand 4 "" ""))] ; label
+ ""
+ "
+{
+ if (GET_MODE (operands[0]) == SImode)
+ emit_jump_insn (gen_doloop_si (operands[4], operands[0], operands[0]));
+ else if (GET_MODE (operands[0]) == DImode && TARGET_64BIT)
+ emit_jump_insn (gen_doloop_di (operands[4], operands[0], operands[0]));
+ else
+ FAIL;
-;(define_expand "decrement_and_branch_on_count"
-; [(use (match_operand 0 "register_operand" ""))
-; (use (label_ref (match_operand 1 "" "")))]
-; ""
-; "
-;{
-;/* if (TARGET_64BIT)
-; emit_jump_insn (gen_brctdi (operands[0], operands[1]));
-; else */
-; emit_jump_insn (gen_brctsi (operands[0], operands[1]));
-; DONE;
-;}")
-;
-;(define_insn "brctsi"
-; [(set (pc)
-; (if_then_else
-; (ne (match_operand:SI 0 "register_operand" "+a")
-; (const_int 1))
-; (label_ref (match_operand 1 "" ""))
-; (pc)))
-; (set (match_dup 0)
-; (plus:SI (match_dup 0) (const_int -1)))]
-; ""
-; "brct\\t%0,%l1"
-; [(set_attr "op_type" "RI")
-; (set_attr "type" "branch")]
-;)
-;
-;(define_insn "ibrctsi"
-; [(set (pc)
-; (if_then_else
-; (eq (match_operand:SI 0 "register_operand" "+a")
-; (const_int 1))
-; (pc)
-; (label_ref (match_operand 1 "" ""))))
-; (set (match_dup 0)
-; (plus:SI (match_dup 0) (const_int -1)))]
-; ""
-; "brct\\t%0,%l1"
-; [(set_attr "op_type" "RI")
-; (set_attr "type" "branch")]
-;)
+ DONE;
+}")
+
+(define_insn "doloop_si"
+ [(set (pc)
+ (if_then_else
+ (ne (match_operand:SI 1 "register_operand" "d,d")
+ (const_int 1))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,?*m*d")
+ (plus:SI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:SI 3 "=X,&d"))
+ (clobber (reg:CC 33))]
+ ""
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 4)
+ return \"brct\\t%1,%l0\";
+ else
+ abort ();
+}"
+ [(set_attr "op_type" "RI")
+ (set (attr "length")
+ (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
+ (const_int 4)
+ (ne (symbol_ref "TARGET_64BIT") (const_int 0))
+ (const_int 10)
+ (eq (symbol_ref "flag_pic") (const_int 0))
+ (const_int 6)] (const_int 8)))])
+
+(define_insn "*doloop_si_long"
+ [(set (pc)
+ (if_then_else
+ (ne (match_operand:SI 1 "register_operand" "d,d")
+ (const_int 1))
+ (match_operand 0 "address_operand" "p,p")
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,?*m*d")
+ (plus:SI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:SI 3 "=X,&d"))
+ (clobber (reg:CC 33))]
+ ""
+ "*
+{
+ if (get_attr_op_type (insn) == OP_TYPE_RR)
+ return \"bctr\\t%1,%0\";
+ else
+ return \"bct\\t%1,%a0\";
+}"
+ [(set (attr "op_type")
+ (if_then_else (match_operand 0 "register_operand" "")
+ (const_string "RR") (const_string "RX")))
+ (set_attr "atype" "mem")])
+
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "")
+ (const_int 1))
+ (match_operand 0 "" "")
+ (pc)))
+ (set (match_operand:SI 2 "nonimmediate_operand" "")
+ (plus:SI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (reg:CC 33))]
+ "reload_completed
+ && (! REG_P (operands[2])
+ || ! rtx_equal_p (operands[1], operands[2]))"
+ [(set (match_dup 3) (match_dup 1))
+ (parallel [(set (reg:CCAN 33)
+ (compare:CCAN (plus:SI (match_dup 3) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))])
+ (set (match_dup 2) (match_dup 3))
+ (set (pc) (if_then_else (ne (reg:CCAN 33) (const_int 0))
+ (match_dup 0)
+ (pc)))]
+ "")
+
+(define_insn "doloop_di"
+ [(set (pc)
+ (if_then_else
+ (ne (match_operand:DI 1 "register_operand" "d,d")
+ (const_int 1))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:DI 2 "register_operand" "=1,?*m*r")
+ (plus:DI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:DI 3 "=X,&d"))
+ (clobber (reg:CC 33))]
+ "TARGET_64BIT"
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 4)
+ return \"brctg\\t%1,%l0\";
+ else
+ abort ();
+}"
+ [(set_attr "op_type" "RI")
+ (set (attr "length")
+ (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
+ (const_int 4) (const_int 12)))])
+
+(define_insn "*doloop_di_long"
+ [(set (pc)
+ (if_then_else
+ (ne (match_operand:DI 1 "register_operand" "d,d")
+ (const_int 1))
+ (match_operand 0 "address_operand" "p,p")
+ (pc)))
+ (set (match_operand:DI 2 "register_operand" "=1,?*m*d")
+ (plus:DI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:DI 3 "=X,&d"))
+ (clobber (reg:CC 33))]
+ ""
+ "*
+{
+ if (get_attr_op_type (insn) == OP_TYPE_RRE)
+ return \"bctgr\\t%1,%0\";
+ else
+ return \"bctg\\t%1,%a0\";
+}"
+ [(set (attr "op_type")
+ (if_then_else (match_operand 0 "register_operand" "")
+ (const_string "RRE") (const_string "RXE")))
+ (set_attr "atype" "mem")])
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:DI 1 "register_operand" "")
+ (const_int 1))
+ (match_operand 0 "" "")
+ (pc)))
+ (set (match_operand:DI 2 "nonimmediate_operand" "")
+ (plus:DI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:DI 3 ""))
+ (clobber (reg:CC 33))]
+ "reload_completed
+ && (! REG_P (operands[2])
+ || ! rtx_equal_p (operands[1], operands[2]))"
+ [(set (match_dup 3) (match_dup 1))
+ (parallel [(set (reg:CCAN 33)
+ (compare:CCAN (plus:DI (match_dup 3) (const_int -1))
+ (const_int 0)))
+ (set (match_dup 3) (plus:DI (match_dup 3) (const_int -1)))])
+ (set (match_dup 2) (match_dup 3))
+ (set (pc) (if_then_else (ne (reg:CCAN 33) (const_int 0))
+ (match_dup 0)
+ (pc)))]
+ "")
;;
;;- Unconditional jump instructions.
@@ -5961,7 +6284,8 @@
[(unspec_volatile [(const_int 0)] 0)]
""
""
- [(set_attr "type" "none")])
+ [(set_attr "type" "none")
+ (set_attr "length" "0")])
@@ -6014,10 +6338,7 @@
compiler doesn't know about it, because the PLT glue
code uses it. In 64-bit, this is not necessary. */
if (plt_call && !TARGET_64BIT)
- {
- current_function_uses_pic_offset_table = 1;
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
- }
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
DONE;
}")
@@ -6139,10 +6460,7 @@
compiler doesn't know about it, because the PLT glue
code uses it. In 64-bit, this is not necessary. */
if (plt_call && !TARGET_64BIT)
- {
- current_function_uses_pic_offset_table = 1;
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
- }
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
DONE;
}")
@@ -6218,6 +6536,192 @@
(set_attr "type" "jsr")
(set_attr "atype" "mem")])
+;;
+;;- 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,%0"
+ [(set_attr "op_type" "NN,RS")
+ (set_attr "atype" "reg,mem")
+ (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,%0"
+ [(set_attr "op_type" "RRE,RS")
+ (set_attr "atype" "reg,mem")])
+
+(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,%0"
+ [(set_attr "op_type" "NN,RS")
+ (set_attr "atype" "reg,mem")
+ (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,%0"
+ [(set_attr "op_type" "RRE,RS")
+ (set_attr "atype" "reg,mem")])
+
+(define_insn "*tls_load_64"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (unspec:DI [(match_operand:DI 1 "memory_operand" "m")
+ (match_operand:DI 2 "" "")]
+ UNSPEC_TLS_LOAD))]
+ "TARGET_64BIT"
+ "lg\\t%0,%1%J2"
+ [(set_attr "op_type" "RXE")
+ (set_attr "atype" "mem")])
+
+(define_insn "*tls_load_31"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "memory_operand" "m")
+ (match_operand:SI 2 "" "")]
+ UNSPEC_TLS_LOAD))]
+ "!TARGET_64BIT"
+ "l\\t%0,%1%J2"
+ [(set_attr "op_type" "RX")
+ (set_attr "atype" "mem")])
+
+(define_expand "call_value_tls"
+ [(set (match_operand 0 "" "")
+ (call (const_int 0) (const_int 0)))
+ (use (match_operand 1 "" ""))]
+ ""
+ "
+{
+ rtx insn, sym;
+
+ if (!flag_pic)
+ abort ();
+
+ sym = s390_tls_get_offset ();
+ sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113);
+ sym = gen_rtx_CONST (Pmode, sym);
+
+ /* Unless we can use the bras(l) insn, force the
+ routine address into a register. */
+ if (!TARGET_SMALL_EXEC && !TARGET_64BIT)
+ {
+ rtx target = gen_reg_rtx (Pmode);
+ emit_move_insn (target, sym);
+ sym = target;
+ }
+
+ sym = gen_rtx_MEM (QImode, sym);
+
+ /* Emit insn. */
+ insn = emit_call_insn (
+ gen_call_value_tls_exp (operands[0], sym, const0_rtx,
+ gen_rtx_REG (Pmode, RETURN_REGNUM),
+ operands[1]));
+
+ /* The calling convention of __tls_get_offset uses the
+ GOT register implicitly. */
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), operands[0]);
+ CONST_OR_PURE_CALL_P (insn) = 1;
+
+ DONE;
+}")
+
+(define_expand "call_value_tls_exp"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (clobber (match_operand 3 "" ""))
+ (use (match_operand 4 "" ""))])]
+ ""
+ "")
+
+(define_insn "brasl_tls"
+ [(set (match_operand 0 "register_operand" "=df")
+ (call (mem:QI (match_operand:DI 1 "bras_sym_operand" "X"))
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (clobber (match_operand:DI 3 "register_operand" "=r"))
+ (use (match_operand:DI 4 "" ""))]
+ "TARGET_64BIT"
+ "brasl\\t%3,%1%J4"
+ [(set_attr "op_type" "RIL")
+ (set_attr "type" "jsr")])
+
+(define_insn "bras_tls"
+ [(set (match_operand 0 "register_operand" "=df")
+ (call (mem:QI (match_operand:SI 1 "bras_sym_operand" "X"))
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (clobber (match_operand:SI 3 "register_operand" "=r"))
+ (use (match_operand:SI 4 "" ""))]
+ "TARGET_SMALL_EXEC"
+ "bras\\t%3,%1%J4"
+ [(set_attr "op_type" "RI")
+ (set_attr "type" "jsr")])
+
+(define_insn "basr_tls_64"
+ [(set (match_operand 0 "register_operand" "=df")
+ (call (mem:QI (match_operand:DI 1 "register_operand" "a"))
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (clobber (match_operand:DI 3 "register_operand" "=r"))
+ (use (match_operand:DI 4 "" ""))]
+ "TARGET_64BIT"
+ "basr\\t%3,%1%J4"
+ [(set_attr "op_type" "RR")
+ (set_attr "type" "jsr")])
+
+(define_insn "basr_tls_31"
+ [(set (match_operand 0 "register_operand" "=df")
+ (call (mem:QI (match_operand:SI 1 "register_operand" "a"))
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (clobber (match_operand:SI 3 "register_operand" "=r"))
+ (use (match_operand:SI 4 "" ""))]
+ "!TARGET_64BIT"
+ "basr\\t%3,%1%J4"
+ [(set_attr "op_type" "RR")
+ (set_attr "type" "jsr")
+ (set_attr "atype" "mem")])
+
+(define_insn "bas_tls_64"
+ [(set (match_operand 0 "register_operand" "=df")
+ (call (mem:QI (match_operand:QI 1 "address_operand" "p"))
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (clobber (match_operand:DI 3 "register_operand" "=r"))
+ (use (match_operand:DI 4 "" ""))]
+ "TARGET_64BIT"
+ "bas\\t%3,%a1%J4"
+ [(set_attr "op_type" "RX")
+ (set_attr "type" "jsr")
+ (set_attr "atype" "mem")])
+
+(define_insn "bas_tls_31"
+ [(set (match_operand 0 "register_operand" "=df")
+ (call (mem:QI (match_operand:QI 1 "address_operand" "p"))
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (clobber (match_operand:SI 3 "register_operand" "=r"))
+ (use (match_operand:SI 4 "" ""))]
+ "!TARGET_64BIT"
+ "bas\\t%3,%a1%J4"
+ [(set_attr "op_type" "RX")
+ (set_attr "type" "jsr")
+ (set_attr "atype" "mem")])
;;
;;- Miscellaneous instructions.
@@ -6505,7 +7009,7 @@
[(set_attr "op_type" "NN")
(set_attr "length" "0")])
-(define_insn "reload_base"
+(define_insn "reload_base_31"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI [(label_ref (match_operand 1 "" ""))] 210))]
"!TARGET_64BIT"
@@ -6514,15 +7018,29 @@
(set_attr "type" "la")
(set_attr "length" "6")])
-(define_insn "reload_base2"
+(define_insn "reload_base_64"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (unspec:DI [(label_ref (match_operand 1 "" ""))] 210))]
+ "TARGET_64BIT"
+ "larl\\t%0,%1"
+ [(set_attr "op_type" "RIL")
+ (set_attr "type" "la")])
+
+(define_insn "reload_anchor"
[(set (match_operand:SI 0 "register_operand" "=a")
- (unspec:SI [(label_ref (match_operand 1 "" ""))] 211))]
+ (unspec:SI [(match_operand:SI 1 "register_operand" "a")] 211))]
"!TARGET_64BIT"
- "la\\t%0,%1-.(%0)"
+ "l\\t%0,0(%1)\;la\\t%0,0(%0,%1)"
[(set_attr "op_type" "NN")
(set_attr "type" "la")
- (set_attr "length" "4")])
+ (set_attr "length" "8")])
+(define_insn "pool"
+ [(unspec_volatile [(match_operand 0 "const_int_operand" "n")] 220)]
+ ""
+ "* abort ();"
+ [(set_attr "op_type" "NN")
+ (set (attr "length") (symbol_ref "INTVAL (operands[0])"))])
;;
;; Insns related to generating the function prologue and epilogue.
@@ -6566,162 +7084,44 @@
(set_attr "type" "jsr")
(set_attr "atype" "mem")])
-
-(define_insn "lit"
- [(set (reg 13) (pc))
- (unspec_volatile [(const_int 0)] 200)]
+(define_insn "literal_pool_31"
+ [(unspec_volatile [(const_int 0)] 300)
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (label_ref (match_operand 1 "" "")))
+ (use (label_ref (match_operand 2 "" "")))]
""
- "*
{
- s390_output_constant_pool (asm_out_file);
- return \"\";
-}"
- [(set_attr "op_type" "NN")
- (set_attr "type" "integer")])
-
-
-;;
-;; Peephole optimization patterns.
-;;
-
-(define_peephole
- [(set (match_operand:SI 0 "memory_operand" "m")
- (match_operand:SI 1 "register_operand" "d"))
- (set (match_dup 1)
- (match_dup 0))]
- ""
- "st\\t%1,%0")
-
-(define_peephole
- [(set (match_operand:SI 0 "memory_operand" "m")
- (match_operand:SI 1 "register_operand" "d"))
- (set (match_dup 0)
- (match_dup 1))]
- ""
- "st\\t%1,%0")
-
-(define_peephole
- [(set (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "register_operand" ""))
- (parallel
- [(set (match_dup 0)
- (plus:SI (match_dup 0)
- (match_operand:SI 2 "immediate_operand" "")))
- (clobber (reg:CC 33))])]
- "(REGNO (operands[0]) == STACK_POINTER_REGNUM ||
- REGNO (operands[1]) == STACK_POINTER_REGNUM ||
- REGNO (operands[0]) == BASE_REGISTER ||
- REGNO (operands[1]) == BASE_REGISTER) &&
- INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 4096"
- "la\\t%0,%c2(%1)")
-
-;
-; peepholes for fast char instructions
-;
-
-;(define_peephole
-; [(set (match_operand:QI 0 "register_operand" "d")
-; (match_operand:QI 1 "s_operand" "Q"))
-; (set (match_operand:SI 2 "register_operand" "0")
-; (zero_extend:SI (match_dup 0)))]
-; "REGNO(operands[0]) == REGNO(operands[2])"
-; "icm\\t%0,8,%1\;srl\\t%0,24")
-
-;(define_peephole
-; [(set (match_operand:QI 0 "register_operand" "d")
-; (match_operand:QI 1 "s_operand" "Q"))
-; (set (match_operand:SI 2 "register_operand" "0")
-; (sign_extend:SI (match_dup 0)))]
-; "REGNO(operands[0]) == REGNO(operands[2])"
-; "icm\\t%0,8,%1\;sra\\t%0,24")
-
-(define_peephole
- [(set (match_operand:QI 0 "register_operand" "d")
- (match_operand:QI 1 "immediate_operand" "J"))
- (set (match_operand:SI 2 "register_operand" "0" )
- (sign_extend:SI (match_dup 0) ) )]
- "REGNO(operands[0]) == REGNO(operands[2])"
- "lhi\\t%0,%h1")
-
-;
-; peepholes for fast short instructions
-;
-
-;(define_peephole
-; [(set (match_operand:HI 0 "register_operand" "d")
-; (match_operand:HI 1 "s_operand" "Q"))
-; (set (match_operand:SI 2 "register_operand" "0" )
-; (zero_extend:SI (match_dup 0)))]
-; "REGNO(operands[0]) == REGNO(operands[2])"
-; "icm\\t%0,12,%1\;srl\\t%0,16")
-
-(define_peephole
- [(set (match_operand:HI 0 "register_operand" "d")
- (match_operand:HI 1 "memory_operand" "m"))
- (set (match_operand:SI 2 "register_operand" "0" )
- (sign_extend:SI (match_dup 0)))]
- "REGNO(operands[0]) == REGNO(operands[2])"
- "lh\\t%0,%1")
-
-(define_peephole
- [(set (match_operand:HI 0 "register_operand" "d")
- (match_operand:HI 1 "immediate_operand" "K"))
- (set (match_operand:SI 2 "register_operand" "0" )
- (sign_extend:SI (match_dup 0) ) )]
- "REGNO(operands[0]) == REGNO(operands[2])"
- "lhi\\t%0,%h1")
-
-;
-; peepholes for divide instructions
-;
-
-(define_peephole
- [(set (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "memory_operand" "m"))
- (set (match_dup 0)
- (lshiftrt:DI (match_dup 0)
- (match_operand:SI 2 "immediate_operand" "J")))
- (set (match_dup 0)
- (div:SI (match_dup 0)
- (match_operand:SI 3 "nonimmediate_operand" "g")))
- (set (match_dup 1)
- (match_dup 0))]
- ""
- "*
-{
- output_asm_insn (\"l\\t%0,%1\", operands);
- output_asm_insn (\"srdl\\t%0,%b2\", operands);
-
- if (REG_P (operands[3]))
- output_asm_insn (\"dr\\t%0,%3\", operands);
- else
- output_asm_insn (\"d\\t%0,%3\", operands);
+ if (s390_nr_constants)
+ {
+ output_asm_insn ("bras\\t%0,%2", operands);
+ s390_output_constant_pool (operands[1], operands[2]);
+ }
+ else if (flag_pic)
+ {
+ /* We need the anchor label in any case. */
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (operands[1]));
+ }
- return \"st\\t%N0,%N1\";
-}")
+ return "";
+}
+ [(set_attr "op_type" "NN")
+ (set_attr "type" "la")])
-(define_peephole
- [(set (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "memory_operand" "m"))
- (set (match_dup 0)
- (lshiftrt:DI (match_dup 0)
- (match_operand:SI 2 "immediate_operand" "J")))
- (set (match_dup 0)
- (mod:SI (match_dup 0)
- (match_operand:SI 3 "nonimmediate_operand" "g")))
- (set (match_dup 1)
- (match_dup 0))]
+(define_insn "literal_pool_64"
+ [(unspec_volatile [(const_int 0)] 300)
+ (set (match_operand:DI 0 "register_operand" "=a")
+ (label_ref (match_operand 1 "" "")))
+ (use (label_ref (match_operand 2 "" "")))]
""
- "*
{
- output_asm_insn (\"l\\t%0,%1\", operands);
- output_asm_insn (\"srdl\\t%0,%b2\", operands);
-
- if (REG_P (operands[3]))
- output_asm_insn (\"dr\\t%0,%3\", operands);
- else
- output_asm_insn (\"d\\t%0,%3\", operands);
-
- return \"st\\t%0,%1\";
-}")
+ if (s390_nr_constants)
+ {
+ output_asm_insn ("larl\\t%0,%1", operands);
+ s390_output_constant_pool (operands[1], operands[2]);
+ }
+ return "";
+}
+ [(set_attr "op_type" "NN")
+ (set_attr "type" "la")])
diff --git a/contrib/gcc/config/s390/t-crtstuff b/contrib/gcc/config/s390/t-crtstuff
new file mode 100644
index 0000000..5572e6b
--- /dev/null
+++ b/contrib/gcc/config/s390/t-crtstuff
@@ -0,0 +1,4 @@
+# crtend*.o cannot be compiled without -fno-asynchronous-unwind-tables,
+# because then __FRAME_END__ might not be the last thing in .eh_frame
+# section.
+CRTSTUFF_T_CFLAGS = -fno-asynchronous-unwind-tables
diff --git a/contrib/gcc/config/s390/t-linux64 b/contrib/gcc/config/s390/t-linux64
index d5a9278..db839c6 100644
--- a/contrib/gcc/config/s390/t-linux64
+++ b/contrib/gcc/config/s390/t-linux64
@@ -1,3 +1,12 @@
+MULTILIB_OPTIONS = m64/m31
+MULTILIB_DIRNAMES = 64 32
+MULTILIB_OSDIRNAMES = ../lib64 ../lib
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
+
# Override t-slibgcc-elf-ver to export some libgcc symbols with
# the symbol versions that glibc used.
SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver $(srcdir)/config/s390/libgcc-glibc.ver
OpenPOWER on IntegriCloud