summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/alpha
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
committerobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
commitc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch)
tree086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/config/alpha
parent2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff)
downloadFreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip
FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/config/alpha')
-rw-r--r--contrib/gcc/config/alpha/alpha-interix.h83
-rw-r--r--contrib/gcc/config/alpha/alpha-protos.h187
-rw-r--r--contrib/gcc/config/alpha/alpha.c5749
-rw-r--r--contrib/gcc/config/alpha/alpha.h1102
-rw-r--r--contrib/gcc/config/alpha/alpha.md5095
-rw-r--r--contrib/gcc/config/alpha/alpha32.h37
-rw-r--r--contrib/gcc/config/alpha/crtfastmath.c46
-rw-r--r--contrib/gcc/config/alpha/elf.h573
-rw-r--r--contrib/gcc/config/alpha/freebsd.h184
-rw-r--r--contrib/gcc/config/alpha/lib1funcs.asm21
-rw-r--r--contrib/gcc/config/alpha/linux-elf.h5
-rw-r--r--contrib/gcc/config/alpha/linux.h80
-rw-r--r--contrib/gcc/config/alpha/netbsd.h80
-rw-r--r--contrib/gcc/config/alpha/openbsd.h6
-rw-r--r--contrib/gcc/config/alpha/osf.h94
-rw-r--r--contrib/gcc/config/alpha/osf2or3.h4
-rw-r--r--contrib/gcc/config/alpha/osf5.h54
-rw-r--r--contrib/gcc/config/alpha/qrnnd.asm163
-rw-r--r--contrib/gcc/config/alpha/t-alpha2
-rw-r--r--contrib/gcc/config/alpha/t-crtfm4
-rw-r--r--contrib/gcc/config/alpha/t-ieee6
-rw-r--r--contrib/gcc/config/alpha/t-interix11
-rw-r--r--contrib/gcc/config/alpha/t-osf422
-rw-r--r--contrib/gcc/config/alpha/t-unicosmk2
-rw-r--r--contrib/gcc/config/alpha/t-vms24
-rw-r--r--contrib/gcc/config/alpha/t-vms648
-rw-r--r--contrib/gcc/config/alpha/unicosmk.h626
-rw-r--r--contrib/gcc/config/alpha/va_list.h5
-rw-r--r--contrib/gcc/config/alpha/vms-cc.c379
-rw-r--r--contrib/gcc/config/alpha/vms-crt0-64.c99
-rw-r--r--contrib/gcc/config/alpha/vms-crt0.c71
-rw-r--r--contrib/gcc/config/alpha/vms-dwarf2.asm82
-rw-r--r--contrib/gcc/config/alpha/vms-dwarf2eh.asm37
-rw-r--r--contrib/gcc/config/alpha/vms-ld.c777
-rw-r--r--contrib/gcc/config/alpha/vms-psxcrt0-64.c128
-rw-r--r--contrib/gcc/config/alpha/vms-psxcrt0.c99
-rw-r--r--contrib/gcc/config/alpha/vms.h358
-rw-r--r--contrib/gcc/config/alpha/vms64.h32
-rw-r--r--contrib/gcc/config/alpha/vms_tramp.asm52
-rw-r--r--contrib/gcc/config/alpha/vxworks.h4
-rw-r--r--contrib/gcc/config/alpha/x-vms22
-rw-r--r--contrib/gcc/config/alpha/xm-alpha-interix.h8
-rw-r--r--contrib/gcc/config/alpha/xm-vms.h66
-rw-r--r--contrib/gcc/config/alpha/xm-vms64.h29
44 files changed, 12386 insertions, 4130 deletions
diff --git a/contrib/gcc/config/alpha/alpha-interix.h b/contrib/gcc/config/alpha/alpha-interix.h
index 668fe93..4dc2186 100644
--- a/contrib/gcc/config/alpha/alpha-interix.h
+++ b/contrib/gcc/config/alpha/alpha-interix.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha
running Windows/NT.
- Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1999, 2000 Free Software Foundation, Inc.
Donn Terry, Softway Systems, Inc.
From code
@@ -33,13 +33,13 @@ Boston, MA 02111-1307, USA. */
-D__alpha -D__alpha__\
-D__stdcall= \
-D__cdecl= \
- -Asystem(unix) -Asystem(interix) -Asystem(interix) -Acpu(alpha) -Amachine(alpha)"
+ -Asystem=unix -Asystem=interix -Acpu=alpha -Amachine=alpha"
#undef CPP_SUBTARGET_SPEC
#define CPP_SUBTARGET_SPEC "\
-remap \
%{posix:-D_POSIX_SOURCE} \
--idirafter %$INTERIX_ROOT/usr/include"
+-isystem %$INTERIX_ROOT/usr/include"
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (alpha Interix)");
@@ -62,12 +62,6 @@ Boston, MA 02111-1307, USA. */
#undef PUT_SDB_BLOCK_START
#undef PUT_SDB_BLOCK_END
-/* the following are OSF linker (not gld) specific... we don't want them */
-#undef HAS_INIT_SECTION
-#undef LD_INIT_SWITCH
-#undef LD_FINI_SWITCH
-
-
/* The following are needed for C++, but also needed for profiling */
/* Support const sections and the ctors and dtors sections for g++.
@@ -80,7 +74,7 @@ Boston, MA 02111-1307, USA. */
#define USE_CONST_SECTION 1
-#define CONST_SECTION_ASM_OP ".rdata"
+#define CONST_SECTION_ASM_OP "\t.rdata"
/* Define the pseudo-ops used to switch to the .ctors and .dtors sections.
@@ -97,8 +91,8 @@ Boston, MA 02111-1307, USA. */
errors unless the .ctors and .dtors sections are marked as writable
via the SHF_WRITE attribute.) */
-#define CTORS_SECTION_ASM_OP ".ctors"
-#define DTORS_SECTION_ASM_OP ".dtors"
+#define CTORS_SECTION_ASM_OP "\t.ctors"
+#define DTORS_SECTION_ASM_OP "\t.dtors"
/* A default list of other sections which we might be "in" at any given
time. For targets that use additional sections (e.g. .tdesc) you
@@ -106,7 +100,7 @@ Boston, MA 02111-1307, USA. */
includes this file. */
#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_const, in_ctors, in_dtors
+#define EXTRA_SECTIONS in_const
/* A default list of extra section function definitions. For targets
that use additional sections (e.g. .tdesc) you should override this
@@ -114,15 +108,11 @@ Boston, MA 02111-1307, USA. */
#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
- CONST_SECTION_FUNCTION \
- CTORS_SECTION_FUNCTION \
- DTORS_SECTION_FUNCTION
+ CONST_SECTION_FUNCTION
#undef READONLY_DATA_SECTION
#define READONLY_DATA_SECTION() const_section ()
-extern void text_section ();
-
#define CONST_SECTION_FUNCTION \
void \
const_section () \
@@ -136,55 +126,11 @@ const_section () \
} \
}
-#define CTORS_SECTION_FUNCTION \
-void \
-ctors_section () \
-{ \
- if (in_section != in_ctors) \
- { \
- fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
- in_section = in_ctors; \
- } \
-}
-
-#define DTORS_SECTION_FUNCTION \
-void \
-dtors_section () \
-{ \
- if (in_section != in_dtors) \
- { \
- fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
- in_section = in_dtors; \
- } \
-}
-
-#define INT_ASM_OP ".long"
-
-/* A C statement (sans semicolon) to output an element in the table of
- global constructors. */
-#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
- do { \
- ctors_section (); \
- fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, "\n"); \
- } while (0)
-
-/* A C statement (sans semicolon) to output an element in the table of
- global destructors. */
-#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
- do { \
- dtors_section (); \
- fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, "\n"); \
- } while (0)
-
/* The linker will take care of this, and having them causes problems with
- ld -r (specifically -rU). */
+ ld -r (specifically -rU). */
#define CTOR_LISTS_DEFINED_EXTERNALLY 1
-#define SET_ASM_OP ".set"
+#define SET_ASM_OP "\t.set\t"
/* Output a definition (implements alias) */
#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \
do \
@@ -209,10 +155,11 @@ while (0)
#define PCC_BITFIELD_TYPE_TEST TYPE_NATIVE(rec)
#define GROUP_BITFIELDS_BY_ALIGN TYPE_NATIVE(rec)
-/* DWARF2 Unwinding doesn't work with exception handling yet. */
+/* DWARF2 Unwinding doesn't work with exception handling yet. */
#undef DWARF2_UNWIND_INFO
+#define DWARF2_UNWIND_INFO 0
-/* Don't assume anything about the header files. */
+/* Don't assume anything about the header files. */
#define NO_IMPLICIT_EXTERN_C
/* The definition of this macro implies that there are cases where
@@ -220,7 +167,7 @@ while (0)
On NT (according to the spec) anything except strings/array that fits
in 64 bits is returned in the registers (this appears to differ from
- the rest of the Alpha family). */
+ the rest of the Alpha family). */
#undef RETURN_IN_MEMORY
#define RETURN_IN_MEMORY(TYPE) \
@@ -240,7 +187,7 @@ while (0)
}
/* The current Interix assembler (consistent with the DEC documentation)
- uses a=b NOT .set a,b; .set is for assembler options. */
+ uses a=b NOT .set a,b; .set is for assembler options. */
#undef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \
do { \
diff --git a/contrib/gcc/config/alpha/alpha-protos.h b/contrib/gcc/config/alpha/alpha-protos.h
new file mode 100644
index 0000000..2ff0350
--- /dev/null
+++ b/contrib/gcc/config/alpha/alpha-protos.h
@@ -0,0 +1,187 @@
+/* Prototypes for alpha.c functions used in the md file & elsewhere.
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+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. */
+
+extern int alpha_next_sequence_number;
+
+extern void literal_section PARAMS ((void));
+extern void override_options PARAMS ((void));
+extern int zap_mask PARAMS ((HOST_WIDE_INT));
+extern int direct_return PARAMS ((void));
+
+extern int alpha_sa_size PARAMS ((void));
+extern int alpha_pv_save_size PARAMS ((void));
+extern int alpha_using_fp PARAMS ((void));
+extern void alpha_write_verstamp PARAMS ((FILE *));
+extern void alpha_expand_prologue PARAMS ((void));
+extern void alpha_expand_epilogue PARAMS ((void));
+extern void alpha_output_filename PARAMS ((FILE *, const char *));
+extern void alpha_output_lineno PARAMS ((FILE *, int));
+
+#ifdef RTX_CODE
+extern int reg_or_0_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_or_6bit_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_or_8bit_operand PARAMS ((rtx, enum machine_mode));
+extern int cint8_operand PARAMS ((rtx, enum machine_mode));
+extern int add_operand PARAMS ((rtx, enum machine_mode));
+extern int sext_add_operand PARAMS ((rtx, enum machine_mode));
+extern int const48_operand PARAMS ((rtx, enum machine_mode));
+extern int and_operand PARAMS ((rtx, enum machine_mode));
+extern int or_operand PARAMS ((rtx, enum machine_mode));
+extern int mode_width_operand PARAMS ((rtx, enum machine_mode));
+extern int mode_mask_operand PARAMS ((rtx, enum machine_mode));
+extern int mul8_operand PARAMS ((rtx, enum machine_mode));
+extern int fp0_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_or_fp0_operand PARAMS ((rtx, enum machine_mode));
+extern int hard_fp_register_operand PARAMS ((rtx, enum machine_mode));
+extern int hard_int_register_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_or_cint_operand PARAMS ((rtx, enum machine_mode));
+extern int some_operand PARAMS ((rtx, enum machine_mode));
+extern int some_ni_operand PARAMS ((rtx, enum machine_mode));
+extern int input_operand PARAMS ((rtx, enum machine_mode));
+extern int current_file_function_operand PARAMS ((rtx, enum machine_mode));
+extern int direct_call_operand PARAMS ((rtx, enum machine_mode));
+extern int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
+extern int small_symbolic_operand PARAMS ((rtx, enum machine_mode));
+extern int some_small_symbolic_mem_operand PARAMS ((rtx, enum machine_mode));
+extern int global_symbolic_operand PARAMS ((rtx, enum machine_mode));
+extern int call_operand PARAMS ((rtx, enum machine_mode));
+extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
+extern int alpha_comparison_operator PARAMS ((rtx, enum machine_mode));
+extern int alpha_zero_comparison_operator PARAMS ((rtx, enum machine_mode));
+extern int alpha_swapped_comparison_operator PARAMS ((rtx, enum machine_mode));
+extern int signed_comparison_operator PARAMS ((rtx, enum machine_mode));
+extern int alpha_fp_comparison_operator PARAMS ((rtx, enum machine_mode));
+extern int divmod_operator PARAMS ((rtx, enum machine_mode));
+extern int aligned_memory_operand PARAMS ((rtx, enum machine_mode));
+extern int unaligned_memory_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_or_unaligned_mem_operand PARAMS ((rtx, enum machine_mode));
+extern int any_memory_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_not_elim_operand PARAMS ((rtx, enum machine_mode));
+extern int normal_memory_operand PARAMS ((rtx, enum machine_mode));
+extern int reg_no_subreg_operand PARAMS ((rtx, enum machine_mode));
+extern int addition_operation PARAMS ((rtx, enum machine_mode));
+
+extern bool alpha_const_ok_for_letter_p PARAMS ((HOST_WIDE_INT, int));
+extern bool alpha_const_double_ok_for_letter_p PARAMS ((rtx, int));
+extern bool alpha_extra_constraint PARAMS ((rtx, int));
+
+extern rtx alpha_tablejump_addr_vec PARAMS ((rtx));
+extern rtx alpha_tablejump_best_label PARAMS ((rtx));
+
+extern bool alpha_legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
+extern rtx alpha_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
+extern rtx alpha_legitimize_reload_address PARAMS ((rtx, enum machine_mode,
+ int, int, int));
+
+extern rtx split_small_symbolic_mem_operand PARAMS ((rtx));
+
+extern void get_aligned_mem PARAMS ((rtx, rtx *, rtx *));
+extern rtx get_unaligned_address PARAMS ((rtx, int));
+extern enum reg_class alpha_preferred_reload_class PARAMS ((rtx,
+ enum reg_class));
+extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
+ enum machine_mode,
+ rtx, int));
+
+extern void alpha_set_memflags PARAMS ((rtx, rtx));
+extern rtx alpha_emit_set_const PARAMS ((rtx, enum machine_mode,
+ HOST_WIDE_INT, int));
+extern rtx alpha_emit_set_long_const PARAMS ((rtx, HOST_WIDE_INT,
+ HOST_WIDE_INT));
+extern bool alpha_expand_mov PARAMS ((enum machine_mode, rtx *));
+extern bool alpha_expand_mov_nobwx PARAMS ((enum machine_mode, rtx *));
+extern void alpha_emit_floatuns PARAMS ((rtx[]));
+extern rtx alpha_emit_conditional_branch PARAMS ((enum rtx_code));
+extern rtx alpha_emit_setcc PARAMS ((enum rtx_code));
+extern rtx alpha_emit_conditional_move PARAMS ((rtx, enum machine_mode));
+extern int alpha_split_conditional_move PARAMS ((enum rtx_code, rtx, rtx,
+ rtx, rtx));
+extern void alpha_emit_xfloating_arith PARAMS ((enum rtx_code, rtx[]));
+extern void alpha_emit_xfloating_cvt PARAMS ((enum rtx_code, rtx[]));
+extern void alpha_split_tfmode_pair PARAMS ((rtx[]));
+extern void alpha_split_tfmode_frobsign PARAMS ((rtx[],
+ rtx (*)(rtx, rtx, rtx)));
+extern void alpha_expand_unaligned_load PARAMS ((rtx, rtx, HOST_WIDE_INT,
+ HOST_WIDE_INT, int));
+extern void alpha_expand_unaligned_store PARAMS ((rtx, rtx, HOST_WIDE_INT,
+ HOST_WIDE_INT));
+extern int alpha_expand_block_move PARAMS ((rtx []));
+extern int alpha_expand_block_clear PARAMS ((rtx []));
+extern rtx alpha_return_addr PARAMS ((int, rtx));
+extern rtx alpha_gp_save_rtx PARAMS ((void));
+extern void print_operand PARAMS ((FILE *, rtx, int));
+extern void print_operand_address PARAMS ((FILE *, rtx));
+extern void alpha_initialize_trampoline PARAMS ((rtx, rtx, rtx, int, int, int));
+extern void alpha_reorg PARAMS ((rtx));
+#endif /* RTX_CODE */
+
+#ifdef REAL_VALUE_TYPE
+extern int check_float_value PARAMS ((enum machine_mode,
+ REAL_VALUE_TYPE *, int));
+#endif
+
+#if TARGET_ABI_OPEN_VMS
+#ifdef HAVE_MACHINE_MODES
+extern enum avms_arg_type alpha_arg_type PARAMS ((enum machine_mode));
+#endif
+#ifdef RTX_CODE
+extern rtx alpha_arg_info_reg_val PARAMS ((CUMULATIVE_ARGS));
+#endif
+#ifdef BUFSIZ
+extern void alpha_write_linkage PARAMS ((FILE *));
+#endif
+#endif /* TARGET_ABI_OPEN_VMS */
+
+#ifdef RTX_CODE
+extern rtx alpha_need_linkage PARAMS ((const char *, int));
+#endif
+
+#ifdef TREE_CODE
+extern tree alpha_build_va_list PARAMS ((void));
+#ifdef RTX_CODE
+extern void alpha_va_start PARAMS ((int, tree, rtx));
+extern rtx alpha_va_arg PARAMS ((tree, tree));
+extern rtx function_arg PARAMS ((CUMULATIVE_ARGS, enum machine_mode,
+ tree, int));
+#endif
+extern void alpha_start_function PARAMS ((FILE *, const char *, tree));
+extern void alpha_end_function PARAMS ((FILE *, const char *, tree));
+extern void alpha_encode_section_info PARAMS ((tree));
+#endif /* TREE CODE */
+
+#ifdef RTX_CODE
+extern rtx unicosmk_add_call_info_word PARAMS ((rtx));
+#endif
+
+#if TARGET_ABI_UNICOSMK
+#ifdef RTX_CODE
+extern void unicosmk_defer_case_vector PARAMS ((rtx, rtx));
+#endif
+#ifdef TREE_CODE
+extern void unicosmk_unique_section PARAMS ((tree, int));
+#endif
+extern void unicosmk_add_extern PARAMS ((const char *));
+extern void unicosmk_output_align PARAMS ((FILE *, int));
+extern char * unicosmk_text_section PARAMS ((void));
+extern char * unicosmk_data_section PARAMS ((void));
+extern void unicosmk_asm_file_start PARAMS ((FILE *));
+extern void unicosmk_asm_file_end PARAMS ((FILE *));
+extern void unicosmk_output_common PARAMS ((FILE *, const char *, int, int));
+#endif /* TARGET_ABI_UNICOSMK */
diff --git a/contrib/gcc/config/alpha/alpha.c b/contrib/gcc/config/alpha/alpha.c
index 2d62693..0a1be01 100644
--- a/contrib/gcc/config/alpha/alpha.c
+++ b/contrib/gcc/config/alpha/alpha.c
@@ -1,5 +1,6 @@
/* Subroutines used for code generation on the DEC Alpha.
- Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -23,29 +24,33 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "rtl.h"
+#include "tree.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
-#include "reload.h"
-#include "tree.h"
#include "expr.h"
+#include "optabs.h"
+#include "reload.h"
#include "obstack.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
+#include "ggc.h"
+#include "integrate.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
/* External data. */
-extern char *version_string;
extern int rtx_equal_function_value_matters;
-/* Specify which cpu to schedule for. */
+/* Specify which cpu to schedule for. */
enum processor_type alpha_cpu;
static const char * const alpha_cpu_name[] =
@@ -68,6 +73,7 @@ enum alpha_fp_trap_mode alpha_fptm;
/* Strings decoded into the above options. */
const char *alpha_cpu_string; /* -mcpu= */
+const char *alpha_tune_string; /* -mtune= */
const char *alpha_tp_string; /* -mtrap-precision=[p|s|i] */
const char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */
const char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] */
@@ -76,22 +82,13 @@ const char *alpha_mlat_string; /* -mmemory-latency= */
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
-rtx alpha_compare_op0, alpha_compare_op1;
-int alpha_compare_fp_p;
-
-/* Define the information needed to modify the epilogue for EH. */
-
-rtx alpha_eh_epilogue_sp_ofs;
+struct alpha_compare alpha_compare;
/* Non-zero if inside of a function, because the Alpha asm can't
handle .files inside of functions. */
static int inside_function = FALSE;
-/* If non-null, this rtx holds the return address for the function. */
-
-static rtx alpha_return_addr_rtx;
-
/* The number of cycles of latency we should assume on memory reads. */
int alpha_memory_latency = 3;
@@ -104,23 +101,82 @@ static int alpha_function_needs_gp;
static int alpha_sr_alias_set;
+/* The assembler name of the current function. */
+
+static const char *alpha_fnname;
+
+/* The next explicit relocation sequence number. */
+int alpha_next_sequence_number = 1;
+
+/* The literal and gpdisp sequence numbers for this insn, as printed
+ by %# and %* respectively. */
+int alpha_this_literal_sequence_number;
+int alpha_this_gpdisp_sequence_number;
+
/* Declarations of static functions. */
+static bool decl_in_text_section
+ PARAMS ((tree));
+static int some_small_symbolic_mem_operand_1
+ PARAMS ((rtx *, void *));
+static int split_small_symbolic_mem_operand_1
+ PARAMS ((rtx *, void *));
+static bool local_symbol_p
+ PARAMS ((rtx));
static void alpha_set_memflags_1
- PROTO((rtx, int, int, int));
+ PARAMS ((rtx, int, int, int));
static rtx alpha_emit_set_const_1
- PROTO((rtx, enum machine_mode, HOST_WIDE_INT, int));
+ PARAMS ((rtx, enum machine_mode, HOST_WIDE_INT, int));
static void alpha_expand_unaligned_load_words
- PROTO((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
+ PARAMS ((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
static void alpha_expand_unaligned_store_words
- PROTO((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
+ PARAMS ((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
static void alpha_sa_mask
- PROTO((unsigned long *imaskP, unsigned long *fmaskP));
+ PARAMS ((unsigned long *imaskP, unsigned long *fmaskP));
+static int find_lo_sum
+ PARAMS ((rtx *, void *));
static int alpha_does_function_need_gp
- PROTO((void));
+ PARAMS ((void));
+static int alpha_ra_ever_killed
+ PARAMS ((void));
+static const char *get_trap_mode_suffix
+ PARAMS ((void));
+static const char *get_round_mode_suffix
+ PARAMS ((void));
+static rtx set_frame_related_p
+ PARAMS ((void));
+static const char *alpha_lookup_xfloating_lib_func
+ PARAMS ((enum rtx_code));
+static int alpha_compute_xfloating_mode_arg
+ PARAMS ((enum rtx_code, enum alpha_fp_rounding_mode));
+static void alpha_emit_xfloating_libcall
+ PARAMS ((const char *, rtx, rtx[], int, rtx));
+static rtx alpha_emit_xfloating_compare
+ PARAMS ((enum rtx_code, rtx, rtx));
+static void alpha_output_function_end_prologue
+ PARAMS ((FILE *));
+static int alpha_adjust_cost
+ PARAMS ((rtx, rtx, rtx, int));
+static int alpha_issue_rate
+ PARAMS ((void));
+static int alpha_variable_issue
+ PARAMS ((FILE *, int, rtx, int));
+
+#if TARGET_ABI_UNICOSMK
+static void alpha_init_machine_status
+ PARAMS ((struct function *p));
+static void alpha_mark_machine_status
+ PARAMS ((struct function *p));
+static void alpha_free_machine_status
+ PARAMS ((struct function *p));
+#endif
+static void unicosmk_output_deferred_case_vectors PARAMS ((FILE *));
+static void unicosmk_gen_dsib PARAMS ((unsigned long *imaskP));
+static void unicosmk_output_ssib PARAMS ((FILE *, const char *));
+static int unicosmk_need_dex PARAMS ((rtx));
/* Get the number of args of a function in one of two ways. */
-#ifdef OPEN_VMS
+#if TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK
#define NUM_ARGS current_function_args_info.num_args
#else
#define NUM_ARGS current_function_args_info
@@ -129,25 +185,132 @@ static int alpha_does_function_need_gp
#define REG_PV 27
#define REG_RA 26
-/* Parse target option strings. */
+/* Initialize the GCC target structure. */
+#if TARGET_ABI_OPEN_VMS
+const struct attribute_spec vms_attribute_table[];
+static unsigned int vms_section_type_flags PARAMS ((tree, const char *, int));
+static void vms_asm_named_section PARAMS ((const char *, unsigned int));
+static void vms_asm_out_constructor PARAMS ((rtx, int));
+static void vms_asm_out_destructor PARAMS ((rtx, int));
+# undef TARGET_ATTRIBUTE_TABLE
+# define TARGET_ATTRIBUTE_TABLE vms_attribute_table
+# undef TARGET_SECTION_TYPE_FLAGS
+# define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags
+#endif
+
+#if TARGET_ABI_UNICOSMK
+static void unicosmk_asm_named_section PARAMS ((const char *, unsigned int));
+static void unicosmk_insert_attributes PARAMS ((tree, tree *));
+static unsigned int unicosmk_section_type_flags PARAMS ((tree, const char *,
+ int));
+# undef TARGET_INSERT_ATTRIBUTES
+# define TARGET_INSERT_ATTRIBUTES unicosmk_insert_attributes
+# undef TARGET_SECTION_TYPE_FLAGS
+# define TARGET_SECTION_TYPE_FLAGS unicosmk_section_type_flags
+#endif
+
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
+
+/* Default unaligned ops are provided for ELF systems. To get unaligned
+ data for non-ELF systems, we have to turn off auto alignment. */
+#ifndef OBJECT_FORMAT_ELF
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.long\t"
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP "\t.align 0\n\t.quad\t"
+#endif
+
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST alpha_adjust_cost
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE alpha_issue_rate
+#undef TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE alpha_variable_issue
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+/* Parse target option strings. */
void
override_options ()
{
+ int i;
+ static const struct cpu_table {
+ const char *const name;
+ const enum processor_type processor;
+ const int flags;
+ } cpu_table[] = {
+#define EV5_MASK (MASK_CPU_EV5)
+#define EV6_MASK (MASK_CPU_EV6|MASK_BWX|MASK_MAX|MASK_FIX)
+ { "ev4", PROCESSOR_EV4, 0 },
+ { "ev45", PROCESSOR_EV4, 0 },
+ { "21064", PROCESSOR_EV4, 0 },
+ { "ev5", PROCESSOR_EV5, EV5_MASK },
+ { "21164", PROCESSOR_EV5, EV5_MASK },
+ { "ev56", PROCESSOR_EV5, EV5_MASK|MASK_BWX },
+ { "21164a", PROCESSOR_EV5, EV5_MASK|MASK_BWX },
+ { "pca56", PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX },
+ { "21164PC",PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX },
+ { "21164pc",PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX },
+ { "ev6", PROCESSOR_EV6, EV6_MASK },
+ { "21264", PROCESSOR_EV6, EV6_MASK },
+ { "ev67", PROCESSOR_EV6, EV6_MASK|MASK_CIX },
+ { "21264a", PROCESSOR_EV6, EV6_MASK|MASK_CIX },
+ { 0, 0, 0 }
+ };
+
+ /* Unicos/Mk doesn't have shared libraries. */
+ if (TARGET_ABI_UNICOSMK && flag_pic)
+ {
+ warning ("-f%s ignored for Unicos/Mk (not supported)",
+ (flag_pic > 1) ? "PIC" : "pic");
+ flag_pic = 0;
+ }
+
+ /* On Unicos/Mk, the native compiler consistenly generates /d suffices for
+ floating-point instructions. Make that the default for this target. */
+ if (TARGET_ABI_UNICOSMK)
+ alpha_fprm = ALPHA_FPRM_DYN;
+ else
+ alpha_fprm = ALPHA_FPRM_NORM;
+
alpha_tp = ALPHA_TP_PROG;
- alpha_fprm = ALPHA_FPRM_NORM;
alpha_fptm = ALPHA_FPTM_N;
+ /* We cannot use su and sui qualifiers for conversion instructions on
+ Unicos/Mk. I'm not sure if this is due to assembler or hardware
+ limitations. Right now, we issue a warning if -mieee is specified
+ and then ignore it; eventually, we should either get it right or
+ disable the option altogether. */
+
if (TARGET_IEEE)
{
- alpha_tp = ALPHA_TP_INSN;
- alpha_fptm = ALPHA_FPTM_SU;
+ if (TARGET_ABI_UNICOSMK)
+ warning ("-mieee not supported on Unicos/Mk");
+ else
+ {
+ alpha_tp = ALPHA_TP_INSN;
+ alpha_fptm = ALPHA_FPTM_SU;
+ }
}
if (TARGET_IEEE_WITH_INEXACT)
{
- alpha_tp = ALPHA_TP_INSN;
- alpha_fptm = ALPHA_FPTM_SUI;
+ if (TARGET_ABI_UNICOSMK)
+ warning ("-mieee-with-inexact not supported on Unicos/Mk");
+ else
+ {
+ alpha_tp = ALPHA_TP_INSN;
+ alpha_fptm = ALPHA_FPTM_SUI;
+ }
}
if (alpha_tp_string)
@@ -197,53 +360,54 @@ override_options ()
if (alpha_cpu_string)
{
- if (! strcmp (alpha_cpu_string, "ev4")
- || ! strcmp (alpha_cpu_string, "21064"))
- {
- alpha_cpu = PROCESSOR_EV4;
- target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX);
- }
- else if (! strcmp (alpha_cpu_string, "ev5")
- || ! strcmp (alpha_cpu_string, "21164"))
- {
- alpha_cpu = PROCESSOR_EV5;
- target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX);
- }
- else if (! strcmp (alpha_cpu_string, "ev56")
- || ! strcmp (alpha_cpu_string, "21164a"))
- {
- alpha_cpu = PROCESSOR_EV5;
- target_flags |= MASK_BWX;
- target_flags &= ~ (MASK_MAX | MASK_FIX | MASK_CIX);
- }
- else if (! strcmp (alpha_cpu_string, "pca56")
- || ! strcmp (alpha_cpu_string, "21164PC")
- || ! strcmp (alpha_cpu_string, "21164pc"))
- {
- alpha_cpu = PROCESSOR_EV5;
- target_flags |= MASK_BWX | MASK_MAX;
- target_flags &= ~ (MASK_FIX | MASK_CIX);
- }
- else if (! strcmp (alpha_cpu_string, "ev6")
- || ! strcmp (alpha_cpu_string, "21264"))
- {
- alpha_cpu = PROCESSOR_EV6;
- target_flags |= MASK_BWX | MASK_MAX | MASK_FIX;
- target_flags &= ~ (MASK_CIX);
- }
- else
+ for (i = 0; cpu_table [i].name; i++)
+ if (! strcmp (alpha_cpu_string, cpu_table [i].name))
+ {
+ alpha_cpu = cpu_table [i].processor;
+ target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX
+ | MASK_CPU_EV5 | MASK_CPU_EV6);
+ target_flags |= cpu_table [i].flags;
+ break;
+ }
+ if (! cpu_table [i].name)
error ("bad value `%s' for -mcpu switch", alpha_cpu_string);
}
- /* Do some sanity checks on the above options. */
+ if (alpha_tune_string)
+ {
+ for (i = 0; cpu_table [i].name; i++)
+ if (! strcmp (alpha_tune_string, cpu_table [i].name))
+ {
+ alpha_cpu = cpu_table [i].processor;
+ break;
+ }
+ if (! cpu_table [i].name)
+ error ("bad value `%s' for -mcpu switch", alpha_tune_string);
+ }
+
+ /* Do some sanity checks on the above options. */
+
+ if (TARGET_ABI_UNICOSMK && alpha_fptm != ALPHA_FPTM_N)
+ {
+ warning ("trap mode not supported on Unicos/Mk");
+ alpha_fptm = ALPHA_FPTM_N;
+ }
if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI)
- && alpha_tp != ALPHA_TP_INSN && alpha_cpu != PROCESSOR_EV6)
+ && alpha_tp != ALPHA_TP_INSN && ! TARGET_CPU_EV6)
{
warning ("fp software completion requires -mtrap-precision=i");
alpha_tp = ALPHA_TP_INSN;
}
+ if (TARGET_CPU_EV6)
+ {
+ /* Except for EV6 pass 1 (not released), we always have precise
+ arithmetic traps. Which means we can do software completion
+ without minding trap shadows. */
+ alpha_tp = ALPHA_TP_PROG;
+ }
+
if (TARGET_FLOAT_VAX)
{
if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN)
@@ -276,11 +440,11 @@ override_options ()
{
{ 3, 30, -1 }, /* ev4 -- Bcache is a guess */
{ 2, 12, 38 }, /* ev5 -- Bcache from PC164 LMbench numbers */
- { 3, 13, -1 }, /* ev6 -- Ho hum, doesn't exist yet */
+ { 3, 12, 30 }, /* ev6 -- Bcache from DS20 LMbench. */
};
lat = alpha_mlat_string[1] - '0';
- if (lat < 0 || lat > 3 || cache_latency[alpha_cpu][lat-1] == -1)
+ if (lat <= 0 || lat > 3 || cache_latency[alpha_cpu][lat-1] == -1)
{
warning ("L%d cache latency unknown for %s",
lat, alpha_cpu_name[alpha_cpu]);
@@ -308,8 +472,36 @@ override_options ()
if (!g_switch_set)
g_switch_value = 8;
+ /* Infer TARGET_SMALL_DATA from -fpic/-fPIC. */
+ if (flag_pic == 1)
+ target_flags |= MASK_SMALL_DATA;
+ else if (flag_pic == 2)
+ target_flags &= ~MASK_SMALL_DATA;
+
+ /* Align labels and loops for optimal branching. */
+ /* ??? Kludge these by not doing anything if we don't optimize and also if
+ we are writing ECOFF symbols to work around a bug in DEC's assembler. */
+ if (optimize > 0 && write_symbols != SDB_DEBUG)
+ {
+ if (align_loops <= 0)
+ align_loops = 16;
+ if (align_jumps <= 0)
+ align_jumps = 16;
+ }
+ if (align_functions <= 0)
+ align_functions = 16;
+
/* Acquire a unique set number for our register saves and restores. */
alpha_sr_alias_set = new_alias_set ();
+
+ /* Register variables and functions with the garbage collector. */
+
+#if TARGET_ABI_UNICOSMK
+ /* Set up function hooks. */
+ init_machine_status = alpha_init_machine_status;
+ mark_machine_status = alpha_mark_machine_status;
+ free_machine_status = alpha_free_machine_status;
+#endif
}
/* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */
@@ -403,7 +595,7 @@ sext_add_operand (op, mode)
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
- return register_operand (op, mode);
+ return reg_not_elim_operand (op, mode);
}
/* Return 1 if OP is the constant 4 or 8. */
@@ -531,9 +723,27 @@ hard_fp_register_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
- return ((GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS)
- || (GET_CODE (op) == SUBREG
- && hard_fp_register_operand (SUBREG_REG (op), mode)));
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return 0;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS;
+}
+
+/* Return 1 if OP is a hard general register. */
+
+int
+hard_int_register_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return 0;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS;
}
/* Return 1 if OP is a register or a constant integer. */
@@ -562,7 +772,7 @@ some_operand (op, mode)
switch (GET_CODE (op))
{
case REG: case MEM: case CONST_DOUBLE: case CONST_INT: case LABEL_REF:
- case SYMBOL_REF: case CONST:
+ case SYMBOL_REF: case CONST: case HIGH:
return 1;
case SUBREG:
@@ -575,6 +785,22 @@ some_operand (op, mode)
return 0;
}
+/* Likewise, but don't accept constants. */
+
+int
+some_ni_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return 0;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (GET_CODE (op) == REG || GET_CODE (op) == MEM);
+}
+
/* Return 1 if OP is a valid operand for the source of a move insn. */
int
@@ -593,16 +819,31 @@ input_operand (op, mode)
case LABEL_REF:
case SYMBOL_REF:
case CONST:
+ if (TARGET_EXPLICIT_RELOCS)
+ {
+ /* We don't split symbolic operands into something unintelligable
+ until after reload, but we do not wish non-small, non-global
+ symbolic operands to be reconstructed from their high/lo_sum
+ form. */
+ return (small_symbolic_operand (op, mode)
+ || global_symbolic_operand (op, mode));
+ }
+
/* This handles both the Windows/NT and OSF cases. */
return mode == ptr_mode || mode == DImode;
+ case HIGH:
+ return (TARGET_EXPLICIT_RELOCS
+ && local_symbolic_operand (XEXP (op, 0), mode));
+
case REG:
+ case ADDRESSOF:
return 1;
case SUBREG:
if (register_operand (op, mode))
return 1;
- /* ... fall through ... */
+ /* ... fall through ... */
case MEM:
return ((TARGET_BWX || (mode != HImode && mode != QImode))
&& general_operand (op, mode));
@@ -624,17 +865,149 @@ input_operand (op, mode)
}
/* Return 1 if OP is a SYMBOL_REF for a function known to be in this
- file. */
+ file, and in the same section as the current function. */
int
current_file_function_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
- return (GET_CODE (op) == SYMBOL_REF
- && ! profile_flag && ! profile_block_flag
- && (SYMBOL_REF_FLAG (op)
- || op == XEXP (DECL_RTL (current_function_decl), 0)));
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+
+ /* Easy test for recursion. */
+ if (op == XEXP (DECL_RTL (current_function_decl), 0))
+ return 1;
+
+ /* Otherwise, we need the DECL for the SYMBOL_REF, which we can't get.
+ So SYMBOL_REF_FLAG has been declared to imply that the function is
+ in the default text section. So we must also check that the current
+ function is also in the text section. */
+ if (SYMBOL_REF_FLAG (op) && decl_in_text_section (current_function_decl))
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr. */
+
+int
+direct_call_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ /* Must be defined in this file. */
+ if (! current_file_function_operand (op, mode))
+ return 0;
+
+ /* If profiling is implemented via linker tricks, we can't jump
+ to the nogp alternate entry point. */
+ /* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test,
+ but is approximately correct for the OSF ABIs. Don't know
+ what to do for VMS, NT, or UMK. */
+ if (! TARGET_PROFILING_NEEDS_GP
+ && ! current_function_profile)
+ return 0;
+
+ return 1;
+}
+
+/* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
+ a variable known to be defined in this file. */
+
+static bool
+local_symbol_p (op)
+ rtx op;
+{
+ const char *str = XSTR (op, 0);
+
+ /* ??? SYMBOL_REF_FLAG is set for local function symbols, but we
+ run into problems with the rtl inliner in that the symbol was
+ once external, but is local after inlining, which results in
+ unrecognizable insns. */
+
+ return (CONSTANT_POOL_ADDRESS_P (op)
+ /* If @, then ENCODE_SECTION_INFO sez it's local. */
+ || str[0] == '@'
+ /* If *$, then ASM_GENERATE_INTERNAL_LABEL sez it's local. */
+ || (str[0] == '*' && str[1] == '$'));
+}
+
+int
+local_symbolic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return 0;
+
+ if (GET_CODE (op) == LABEL_REF)
+ return 1;
+
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+ op = XEXP (XEXP (op, 0), 0);
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+
+ return local_symbol_p (op);
+}
+
+/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
+ known to be defined in this file in the small data area. */
+
+int
+small_symbolic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ const char *str;
+
+ if (! TARGET_SMALL_DATA)
+ return 0;
+
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return 0;
+
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+ op = XEXP (XEXP (op, 0), 0);
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+
+ if (CONSTANT_POOL_ADDRESS_P (op))
+ return GET_MODE_SIZE (get_pool_mode (op)) <= (unsigned) g_switch_value;
+ else
+ {
+ str = XSTR (op, 0);
+ return str[0] == '@' && str[1] == 's';
+ }
+}
+
+/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
+ not known (or known not) to be defined in this file. */
+
+int
+global_symbolic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return 0;
+
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+ op = XEXP (XEXP (op, 0), 0);
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+
+ return ! local_symbol_p (op);
}
/* Return 1 if OP is a valid operand for the MEM of a CALL insn. */
@@ -647,9 +1020,44 @@ call_operand (op, mode)
if (mode != Pmode)
return 0;
- return (GET_CODE (op) == SYMBOL_REF
- || (GET_CODE (op) == REG
- && (TARGET_OPEN_VMS || TARGET_WINDOWS_NT || REGNO (op) == 27)));
+ if (GET_CODE (op) == REG)
+ {
+ if (TARGET_ABI_OSF)
+ {
+ /* Disallow virtual registers to cope with pathalogical test cases
+ such as compile/930117-1.c in which the virtual reg decomposes
+ to the frame pointer. Which is a hard reg that is not $27. */
+ return (REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER);
+ }
+ else
+ return 1;
+ }
+ if (TARGET_ABI_UNICOSMK)
+ return 0;
+ if (GET_CODE (op) == SYMBOL_REF)
+ return 1;
+
+ return 0;
+}
+
+/* Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
+ possibly with an offset. */
+
+int
+symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return 0;
+ if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
+ return 1;
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op,0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT)
+ return 1;
+ return 0;
}
/* Return 1 if OP is a valid Alpha comparison operator. Here we know which
@@ -662,11 +1070,28 @@ alpha_comparison_operator (op, mode)
{
enum rtx_code code = GET_CODE (op);
- if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
+ if (mode != GET_MODE (op) && mode != VOIDmode)
return 0;
return (code == EQ || code == LE || code == LT
- || (mode == DImode && (code == LEU || code == LTU)));
+ || code == LEU || code == LTU);
+}
+
+/* Return 1 if OP is a valid Alpha comparison operator against zero.
+ Here we know which comparisons are valid in which insn. */
+
+int
+alpha_zero_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
+
+ return (code == EQ || code == NE || code == LE || code == LT
+ || code == LEU || code == LTU);
}
/* Return 1 if OP is a valid Alpha swapped comparison operator. */
@@ -678,12 +1103,13 @@ alpha_swapped_comparison_operator (op, mode)
{
enum rtx_code code = GET_CODE (op);
- if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
+ if ((mode != GET_MODE (op) && mode != VOIDmode)
+ || GET_RTX_CLASS (code) != '<')
return 0;
code = swap_condition (code);
return (code == EQ || code == LE || code == LT
- || (mode == DImode && (code == LEU || code == LTU)));
+ || code == LEU || code == LTU);
}
/* Return 1 if OP is a signed comparison operation. */
@@ -693,16 +1119,30 @@ signed_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
- switch (GET_CODE (op))
- {
- case EQ: case NE: case LE: case LT: case GE: case GT:
- return 1;
+ enum rtx_code code = GET_CODE (op);
- default:
- break;
- }
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
- return 0;
+ return (code == EQ || code == NE
+ || code == LE || code == LT
+ || code == GE || code == GT);
+}
+
+/* Return 1 if OP is a valid Alpha floating point comparison operator.
+ Here we know which comparisons are valid in which insn. */
+
+int
+alpha_fp_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
+
+ return (code == EQ || code == LE || code == LT || code == UNORDERED);
}
/* Return 1 if this is a divide or modulus operator. */
@@ -769,8 +1209,7 @@ aligned_memory_operand (op, mode)
base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
}
- return (GET_CODE (base) == REG
- && REGNO_POINTER_ALIGN (REGNO (base)) >= 4);
+ return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) >= 32);
}
/* Similar, but return 1 if OP is a MEM which is not alignable. */
@@ -814,8 +1253,7 @@ unaligned_memory_operand (op, mode)
base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
}
- return (GET_CODE (base) == REG
- && REGNO_POINTER_ALIGN (REGNO (base)) < 4);
+ return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) < 32);
}
/* Return 1 if OP is either a register or an unaligned memory location. */
@@ -907,22 +1345,650 @@ reg_no_subreg_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
- if (GET_CODE (op) == SUBREG)
+ if (GET_CODE (op) != REG)
return 0;
return register_operand (op, mode);
}
-
+
+/* Recognize an addition operation that includes a constant. Used to
+ convince reload to canonize (plus (plus reg c1) c2) during register
+ elimination. */
+
+int
+addition_operation (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return 0;
+ if (GET_CODE (op) == PLUS
+ && register_operand (XEXP (op, 0), mode)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K'))
+ return 1;
+ return 0;
+}
+
+/* Implements CONST_OK_FOR_LETTER_P. Return true if the value matches
+ the range defined for C in [I-P]. */
+
+bool
+alpha_const_ok_for_letter_p (value, c)
+ HOST_WIDE_INT value;
+ int c;
+{
+ switch (c)
+ {
+ case 'I':
+ /* An unsigned 8 bit constant. */
+ return (unsigned HOST_WIDE_INT) value < 0x100;
+ case 'J':
+ /* The constant zero. */
+ return value == 0;
+ case 'K':
+ /* A signed 16 bit constant. */
+ return (unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000;
+ case 'L':
+ /* A shifted signed 16 bit constant appropriate for LDAH. */
+ return ((value & 0xffff) == 0
+ && ((value) >> 31 == -1 || value >> 31 == 0));
+ case 'M':
+ /* A constant that can be AND'ed with using a ZAP insn. */
+ return zap_mask (value);
+ case 'N':
+ /* A complemented unsigned 8 bit constant. */
+ return (unsigned HOST_WIDE_INT) (~ value) < 0x100;
+ case 'O':
+ /* A negated unsigned 8 bit constant. */
+ return (unsigned HOST_WIDE_INT) (- value) < 0x100;
+ case 'P':
+ /* The constant 1, 2 or 3. */
+ return value == 1 || value == 2 || value == 3;
+
+ default:
+ return false;
+ }
+}
+
+/* Implements CONST_DOUBLE_OK_FOR_LETTER_P. Return true if VALUE
+ matches for C in [GH]. */
+
+bool
+alpha_const_double_ok_for_letter_p (value, c)
+ rtx value;
+ int c;
+{
+ switch (c)
+ {
+ case 'G':
+ /* The floating point zero constant. */
+ return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT
+ && value == CONST0_RTX (GET_MODE (value)));
+
+ case 'H':
+ /* A valid operand of a ZAP insn. */
+ return (GET_MODE (value) == VOIDmode
+ && zap_mask (CONST_DOUBLE_LOW (value))
+ && zap_mask (CONST_DOUBLE_HIGH (value)));
+
+ default:
+ return false;
+ }
+}
+
+/* Implements CONST_DOUBLE_OK_FOR_LETTER_P. Return true if VALUE
+ matches for C. */
+
+bool
+alpha_extra_constraint (value, c)
+ rtx value;
+ int c;
+{
+ switch (c)
+ {
+ case 'Q':
+ return normal_memory_operand (value, VOIDmode);
+ case 'R':
+ return direct_call_operand (value, Pmode);
+ case 'S':
+ return (GET_CODE (value) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (value) < 64);
+ case 'T':
+ return GET_CODE (value) == HIGH;
+ case 'U':
+ return TARGET_ABI_UNICOSMK && symbolic_operand (value, VOIDmode);
+
+ default:
+ return false;
+ }
+}
+
/* Return 1 if this function can directly return via $26. */
int
direct_return ()
{
- return (! TARGET_OPEN_VMS && reload_completed && alpha_sa_size () == 0
+ return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK
+ && reload_completed
+ && alpha_sa_size () == 0
&& get_frame_size () == 0
&& current_function_outgoing_args_size == 0
&& current_function_pretend_args_size == 0);
}
+/* Return the ADDR_VEC associated with a tablejump insn. */
+
+rtx
+alpha_tablejump_addr_vec (insn)
+ rtx insn;
+{
+ rtx tmp;
+
+ tmp = JUMP_LABEL (insn);
+ if (!tmp)
+ return NULL_RTX;
+ tmp = NEXT_INSN (tmp);
+ if (!tmp)
+ return NULL_RTX;
+ if (GET_CODE (tmp) == JUMP_INSN
+ && GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)
+ return PATTERN (tmp);
+ return NULL_RTX;
+}
+
+/* Return the label of the predicted edge, or CONST0_RTX if we don't know. */
+
+rtx
+alpha_tablejump_best_label (insn)
+ rtx insn;
+{
+ rtx jump_table = alpha_tablejump_addr_vec (insn);
+ rtx best_label = NULL_RTX;
+
+ /* ??? Once the CFG doesn't keep getting completely rebuilt, look
+ there for edge frequency counts from profile data. */
+
+ if (jump_table)
+ {
+ int n_labels = XVECLEN (jump_table, 1);
+ int best_count = -1;
+ int i, j;
+
+ for (i = 0; i < n_labels; i++)
+ {
+ int count = 1;
+
+ for (j = i + 1; j < n_labels; j++)
+ if (XEXP (XVECEXP (jump_table, 1, i), 0)
+ == XEXP (XVECEXP (jump_table, 1, j), 0))
+ count++;
+
+ if (count > best_count)
+ best_count = count, best_label = XVECEXP (jump_table, 1, i);
+ }
+ }
+
+ return best_label ? best_label : const0_rtx;
+}
+
+/* Return true if the function DECL will be placed in the default text
+ section. */
+/* ??? Ideally we'd be able to always move from a SYMBOL_REF back to the
+ decl, as that would allow us to determine if two functions are in the
+ same section, which is what we really want to know. */
+
+static bool
+decl_in_text_section (decl)
+ tree decl;
+{
+ return (DECL_SECTION_NAME (decl) == NULL_TREE
+ && ! (flag_function_sections
+ || (targetm.have_named_sections
+ && DECL_ONE_ONLY (decl))));
+}
+
+/* If we are referencing a function that is static, make the SYMBOL_REF
+ special. We use this to see indicate we can branch to this function
+ without setting PV or restoring GP.
+
+ If this is a variable that is known to be defined locally, add "@v"
+ to the name. If in addition the variable is to go in .sdata/.sbss,
+ then add "@s" instead. */
+
+void
+alpha_encode_section_info (decl)
+ tree decl;
+{
+ const char *symbol_str;
+ bool is_local, is_small;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* We mark public functions once they are emitted; otherwise we
+ don't know that they exist in this unit of translation. */
+ if (TREE_PUBLIC (decl))
+ return;
+ /* Do not mark functions that are not in .text; otherwise we
+ don't know that they are near enough for a direct branch. */
+ if (! decl_in_text_section (decl))
+ return;
+
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+ return;
+ }
+
+ /* Early out if we're not going to do anything with this data. */
+ if (! TARGET_EXPLICIT_RELOCS)
+ return;
+
+ /* Careful not to prod global register variables. */
+ if (TREE_CODE (decl) != VAR_DECL
+ || GET_CODE (DECL_RTL (decl)) != MEM
+ || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
+ return;
+
+ symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+
+ /* A variable is considered "local" if it is defined in this module. */
+
+ if (DECL_EXTERNAL (decl))
+ is_local = false;
+ /* Linkonce and weak data is never local. */
+ else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+ is_local = false;
+ else if (! TREE_PUBLIC (decl))
+ is_local = true;
+ /* If PIC, then assume that any global name can be overridden by
+ symbols resolved from other modules. */
+ else if (flag_pic)
+ is_local = false;
+ /* Uninitialized COMMON variable may be unified with symbols
+ resolved from other modules. */
+ else if (DECL_COMMON (decl)
+ && (DECL_INITIAL (decl) == NULL
+ || DECL_INITIAL (decl) == error_mark_node))
+ is_local = false;
+ /* Otherwise we're left with initialized (or non-common) global data
+ which is of necessity defined locally. */
+ else
+ is_local = true;
+
+ /* Determine if DECL will wind up in .sdata/.sbss. */
+
+ is_small = false;
+ if (DECL_SECTION_NAME (decl))
+ {
+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (strcmp (section, ".sdata") == 0
+ || strcmp (section, ".sbss") == 0)
+ is_small = true;
+ }
+ else
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+ /* If the variable has already been defined in the output file, then it
+ is too late to put it in sdata if it wasn't put there in the first
+ place. The test is here rather than above, because if it is already
+ in sdata, then it can stay there. */
+
+ if (TREE_ASM_WRITTEN (decl))
+ ;
+
+ /* If this is an incomplete type with size 0, then we can't put it in
+ sdata because it might be too big when completed. */
+ else if (size > 0 && size <= g_switch_value)
+ is_small = true;
+ }
+
+ /* Finally, encode this into the symbol string. */
+ if (is_local)
+ {
+ const char *string;
+ char *newstr;
+ size_t len;
+
+ if (symbol_str[0] == '@')
+ {
+ if (symbol_str[1] == (is_small ? 's' : 'v'))
+ return;
+ symbol_str += 2;
+ }
+
+ len = strlen (symbol_str) + 1;
+ newstr = alloca (len + 2);
+
+ newstr[0] = '@';
+ newstr[1] = (is_small ? 's' : 'v');
+ memcpy (newstr + 2, symbol_str, len);
+
+ string = ggc_alloc_string (newstr, len + 2 - 1);
+ XSTR (XEXP (DECL_RTL (decl), 0), 0) = string;
+ }
+ else if (symbol_str[0] == '@')
+ abort ();
+}
+
+/* legitimate_address_p 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.
+
+ For Alpha, we have either a constant address or the sum of a
+ register and a constant address, or just a register. For DImode,
+ any of those forms can be surrounded with an AND that clear the
+ low-order three bits; this is an "unaligned" access. */
+
+bool
+alpha_legitimate_address_p (mode, x, strict)
+ enum machine_mode mode;
+ rtx x;
+ int strict;
+{
+ /* If this is an ldq_u type address, discard the outer AND. */
+ if (mode == DImode
+ && GET_CODE (x) == AND
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) == -8)
+ x = XEXP (x, 0);
+
+ /* Discard non-paradoxical subregs. */
+ if (GET_CODE (x) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ x = SUBREG_REG (x);
+
+ /* Unadorned general registers are valid. */
+ if (REG_P (x)
+ && (strict
+ ? STRICT_REG_OK_FOR_BASE_P (x)
+ : NONSTRICT_REG_OK_FOR_BASE_P (x)))
+ return true;
+
+ /* Constant addresses (i.e. +/- 32k) are valid. */
+ if (CONSTANT_ADDRESS_P (x))
+ return true;
+
+ /* Register plus a small constant offset is valid. */
+ if (GET_CODE (x) == PLUS)
+ {
+ rtx ofs = XEXP (x, 1);
+ x = XEXP (x, 0);
+
+ /* Discard non-paradoxical subregs. */
+ if (GET_CODE (x) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ x = SUBREG_REG (x);
+
+ if (REG_P (x))
+ {
+ if (! strict
+ && NONSTRICT_REG_OK_FP_BASE_P (x)
+ && GET_CODE (ofs) == CONST_INT)
+ return true;
+ if ((strict
+ ? STRICT_REG_OK_FOR_BASE_P (x)
+ : NONSTRICT_REG_OK_FOR_BASE_P (x))
+ && CONSTANT_ADDRESS_P (ofs))
+ return true;
+ }
+ else if (GET_CODE (x) == ADDRESSOF
+ && GET_CODE (ofs) == CONST_INT)
+ return true;
+ }
+
+ /* If we're managing explicit relocations, LO_SUM is valid, as
+ are small data symbols. */
+ else if (TARGET_EXPLICIT_RELOCS)
+ {
+ if (small_symbolic_operand (x, Pmode))
+ return true;
+
+ if (GET_CODE (x) == LO_SUM)
+ {
+ rtx ofs = XEXP (x, 1);
+ x = XEXP (x, 0);
+
+ /* Discard non-paradoxical subregs. */
+ if (GET_CODE (x) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ x = SUBREG_REG (x);
+
+ /* Must have a valid base register. */
+ if (! (REG_P (x)
+ && (strict
+ ? STRICT_REG_OK_FOR_BASE_P (x)
+ : NONSTRICT_REG_OK_FOR_BASE_P (x))))
+ return false;
+
+ /* The symbol must be local. */
+ if (local_symbolic_operand (ofs, Pmode))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address. */
+
+rtx
+alpha_legitimize_address (x, scratch, mode)
+ rtx x;
+ rtx scratch;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ HOST_WIDE_INT addend;
+
+ /* If the address is (plus reg const_int) and the CONST_INT is not a
+ valid offset, compute the high part of the constant and add it to
+ the register. Then our address is (plus temp low-part-const). */
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && ! CONSTANT_ADDRESS_P (XEXP (x, 1)))
+ {
+ addend = INTVAL (XEXP (x, 1));
+ x = XEXP (x, 0);
+ goto split_addend;
+ }
+
+ /* If the address is (const (plus FOO const_int)), find the low-order
+ part of the CONST_INT. Then load FOO plus any high-order part of the
+ CONST_INT into a register. Our address is (plus reg low-part-const).
+ This is done to reduce the number of GOT entries. */
+ if (!no_new_pseudos
+ && GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+ {
+ addend = INTVAL (XEXP (XEXP (x, 0), 1));
+ x = force_reg (Pmode, XEXP (XEXP (x, 0), 0));
+ goto split_addend;
+ }
+
+ /* If we have a (plus reg const), emit the load as in (2), then add
+ the two registers, and finally generate (plus reg low-part-const) as
+ our address. */
+ if (!no_new_pseudos
+ && GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == CONST
+ && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == CONST_INT)
+ {
+ addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1));
+ x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0),
+ XEXP (XEXP (XEXP (x, 1), 0), 0),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ goto split_addend;
+ }
+
+ /* If this is a local symbol, split the address into HIGH/LO_SUM parts. */
+ if (TARGET_EXPLICIT_RELOCS && symbolic_operand (x, Pmode))
+ {
+ if (local_symbolic_operand (x, Pmode))
+ {
+ if (small_symbolic_operand (x, Pmode))
+ return x;
+ else
+ {
+ if (!no_new_pseudos)
+ scratch = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (VOIDmode, scratch,
+ gen_rtx_HIGH (Pmode, x)));
+ return gen_rtx_LO_SUM (Pmode, scratch, x);
+ }
+ }
+ }
+
+ return NULL;
+
+ split_addend:
+ {
+ HOST_WIDE_INT low, high;
+
+ low = ((addend & 0xffff) ^ 0x8000) - 0x8000;
+ addend -= low;
+ high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000;
+ addend -= high;
+
+ if (addend)
+ x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend),
+ (no_new_pseudos ? scratch : NULL_RTX),
+ 1, OPTAB_LIB_WIDEN);
+ if (high)
+ x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high),
+ (no_new_pseudos ? scratch : NULL_RTX),
+ 1, OPTAB_LIB_WIDEN);
+
+ return plus_constant (x, low);
+ }
+}
+
+/* For TARGET_EXPLICIT_RELOCS, we don't obfuscate a SYMBOL_REF to a
+ small symbolic operand until after reload. At which point we need
+ to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref))
+ so that sched2 has the proper dependency information. */
+
+int
+some_small_symbolic_mem_operand (x, mode)
+ rtx x;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return for_each_rtx (&x, some_small_symbolic_mem_operand_1, NULL);
+}
+
+static int
+some_small_symbolic_mem_operand_1 (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *px;
+
+ if (GET_CODE (x) != MEM)
+ return 0;
+ x = XEXP (x, 0);
+
+ /* If this is an ldq_u type address, discard the outer AND. */
+ if (GET_CODE (x) == AND)
+ x = XEXP (x, 0);
+
+ return small_symbolic_operand (x, Pmode) ? 1 : -1;
+}
+
+rtx
+split_small_symbolic_mem_operand (x)
+ rtx x;
+{
+ x = copy_insn (x);
+ for_each_rtx (&x, split_small_symbolic_mem_operand_1, NULL);
+ return x;
+}
+
+static int
+split_small_symbolic_mem_operand_1 (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *px;
+
+ if (GET_CODE (x) != MEM)
+ return 0;
+
+ px = &XEXP (x, 0), x = *px;
+ if (GET_CODE (x) == AND)
+ px = &XEXP (x, 0), x = *px;
+
+ if (small_symbolic_operand (x, Pmode))
+ {
+ x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x);
+ *px = x;
+ }
+
+ return -1;
+}
+
+/* Try a machine-dependent way of reloading an illegitimate address
+ operand. If we find one, push the reload and return the new rtx. */
+
+rtx
+alpha_legitimize_reload_address (x, mode, opnum, type, ind_levels)
+ rtx x;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ int opnum;
+ int type;
+ int ind_levels ATTRIBUTE_UNUSED;
+{
+ /* We must recognize output that we have already generated ourselves. */
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+ BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+ opnum, type);
+ return x;
+ }
+
+ /* We wish to handle large displacements off a base register by
+ splitting the addend across an ldah and the mem insn. This
+ cuts number of extra insns needed from 3 to 1. */
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 0)) == REG
+ && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
+ && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0)))
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+ HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
+ HOST_WIDE_INT high
+ = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+ /* Check for 32-bit overflow. */
+ if (high + low != val)
+ return NULL_RTX;
+
+ /* Reload the high part into a base reg; leave the low part
+ in the mem directly. */
+ x = gen_rtx_PLUS (GET_MODE (x),
+ gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
+ GEN_INT (high)),
+ GEN_INT (low));
+
+ push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+ BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+ opnum, type);
+ return x;
+ }
+
+ return NULL_RTX;
+}
+
/* REF is an alignable memory location. Place an aligned SImode
reference into *PALIGNED_MEM and the number of bits to shift into
*PBITNUM. SCRATCH is a free register for use in reloading out
@@ -955,15 +2021,14 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
if (GET_CODE (base) == PLUS)
offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
- *paligned_mem = gen_rtx_MEM (SImode, plus_constant (base, offset & ~3));
- MEM_COPY_ATTRIBUTES (*paligned_mem, ref);
- RTX_UNCHANGING_P (*paligned_mem) = RTX_UNCHANGING_P (ref);
+ *paligned_mem
+ = widen_memory_access (ref, SImode, (offset & ~3) - offset);
- /* Sadly, we cannot use alias sets here because we may overlap other
- data in a different alias set. */
- /* MEM_ALIAS_SET (*paligned_mem) = MEM_ALIAS_SET (ref); */
-
- *pbitnum = GEN_INT ((offset & 3) * 8);
+ if (WORDS_BIG_ENDIAN)
+ *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
+ + (offset & 3) * 8));
+ else
+ *pbitnum = GEN_INT ((offset & 3) * 8);
}
/* Similar, but just get the address. Handle the two reload cases.
@@ -998,6 +2063,89 @@ get_unaligned_address (ref, extra_offset)
return plus_constant (base, offset + extra_offset);
}
+
+/* On the Alpha, all (non-symbolic) constants except zero go into
+ a floating-point register via memory. Note that we cannot
+ return anything that is not a subset of CLASS, and that some
+ symbolic constants cannot be dropped to memory. */
+
+enum reg_class
+alpha_preferred_reload_class(x, class)
+ rtx x;
+ enum reg_class class;
+{
+ /* Zero is present in any register class. */
+ if (x == CONST0_RTX (GET_MODE (x)))
+ return class;
+
+ /* These sorts of constants we can easily drop to memory. */
+ if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+ {
+ if (class == FLOAT_REGS)
+ return NO_REGS;
+ if (class == ALL_REGS)
+ return GENERAL_REGS;
+ return class;
+ }
+
+ /* All other kinds of constants should not (and in the case of HIGH
+ cannot) be dropped to memory -- instead we use a GENERAL_REGS
+ secondary reload. */
+ if (CONSTANT_P (x))
+ return (class == ALL_REGS ? GENERAL_REGS : class);
+
+ return class;
+}
+
+/* Loading and storing HImode or QImode values to and from memory
+ usually requires a scratch register. The exceptions are loading
+ QImode and HImode from an aligned address to a general register
+ unless byte instructions are permitted.
+
+ We also cannot load an unaligned address or a paradoxical SUBREG
+ into an FP register.
+
+ We also cannot do integral arithmetic into FP regs, as might result
+ from register elimination into a DImode fp register. */
+
+enum reg_class
+secondary_reload_class (class, mode, x, in)
+ enum reg_class class;
+ enum machine_mode mode;
+ rtx x;
+ int in;
+{
+ if ((mode == QImode || mode == HImode) && ! TARGET_BWX)
+ {
+ if (GET_CODE (x) == MEM
+ || (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+ || (GET_CODE (x) == SUBREG
+ && (GET_CODE (SUBREG_REG (x)) == MEM
+ || (GET_CODE (SUBREG_REG (x)) == REG
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER))))
+ {
+ if (!in || !aligned_memory_operand(x, mode))
+ return GENERAL_REGS;
+ }
+ }
+
+ if (class == FLOAT_REGS)
+ {
+ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND)
+ return GENERAL_REGS;
+
+ if (GET_CODE (x) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (x))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ return GENERAL_REGS;
+
+ if (in && INTEGRAL_MODE_P (mode)
+ && ! (memory_operand (x, mode) || x == const0_rtx))
+ return GENERAL_REGS;
+ }
+
+ return NO_REGS;
+}
/* Subfunction of the following function. Update the flags of any MEM
found in part of X. */
@@ -1039,7 +2187,6 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
are the only thing we would be able to differentiate anyway,
there does not seem to be any point in convoluting the early
out of the alias check. */
- /* MEM_ALIAS_SET (x) = alias_set; */
break;
default:
@@ -1092,7 +2239,7 @@ alpha_emit_set_const (target, mode, c, n)
rtx pat;
int i;
- /* Try 1 insn, then 2, then up to N. */
+ /* Try 1 insn, then 2, then up to N. */
for (i = 1; i <= n; i++)
if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0)
return pat;
@@ -1109,7 +2256,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
HOST_WIDE_INT c;
int n;
{
- HOST_WIDE_INT new = c;
+ HOST_WIDE_INT new;
int i, bits;
/* Use a pseudo if highly optimizing and still generating RTL. */
rtx subtarget
@@ -1123,20 +2270,19 @@ alpha_emit_set_const_1 (target, mode, c, n)
cross-compiling on a narrow machine. */
if (mode == SImode)
- c = (c & 0xffffffff) - 2 * (c & 0x80000000);
+ c = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
#endif
/* If this is a sign-extended 32-bit constant, we can do this in at most
three insns, so do it if we have enough insns left. We always have
- a sign-extended 32-bit constant when compiling on a narrow machine. */
+ a sign-extended 32-bit constant when compiling on a narrow machine. */
if (HOST_BITS_PER_WIDE_INT != 64
|| c >> 31 == -1 || c >> 31 == 0)
{
- HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000);
+ HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000;
HOST_WIDE_INT tmp1 = c - low;
- HOST_WIDE_INT high
- = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000);
+ HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000;
HOST_WIDE_INT extra = 0;
/* If HIGH will be interpreted as negative but the constant is
@@ -1164,13 +2310,13 @@ alpha_emit_set_const_1 (target, mode, c, n)
}
else if (n >= 2 + (extra != 0))
{
- temp = copy_to_suggested_reg (GEN_INT (low), subtarget, mode);
+ temp = copy_to_suggested_reg (GEN_INT (high << 16), subtarget, mode);
if (extra != 0)
temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16),
subtarget, 0, OPTAB_WIDEN);
- return expand_binop (mode, add_optab, temp, GEN_INT (high << 16),
+ return expand_binop (mode, add_optab, temp, GEN_INT (low),
target, 0, OPTAB_WIDEN);
}
}
@@ -1184,34 +2330,22 @@ alpha_emit_set_const_1 (target, mode, c, n)
|| (mode == SImode && ! rtx_equal_function_value_matters))
return 0;
-#if HOST_BITS_PER_WIDE_INT == 64
- /* First, see if can load a value into the target that is the same as the
- constant except that all bytes that are 0 are changed to be 0xff. If we
- can, then we can do a ZAPNOT to obtain the desired constant. */
-
- for (i = 0; i < 64; i += 8)
- if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0)
- new |= (HOST_WIDE_INT) 0xff << i;
-
- /* We are only called for SImode and DImode. If this is SImode, ensure that
- we are sign extended to a full word. */
-
- if (mode == SImode)
- new = (new & 0xffffffff) - 2 * (new & 0x80000000);
-
- if (new != c
- && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0)
- return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
- target, 0, OPTAB_WIDEN);
-#endif
-
/* Next, see if we can load a related constant and then shift and possibly
negate it to get the constant we want. Try this once each increasing
numbers of insns. */
for (i = 1; i < n; i++)
{
- /* First try complementing. */
+ /* First, see if minus some low bits, we've an easy load of
+ high bits. */
+
+ new = ((c & 0xffff) ^ 0x8000) - 0x8000;
+ if (new != 0
+ && (temp = alpha_emit_set_const (subtarget, mode, c - new, i)) != 0)
+ return expand_binop (mode, add_optab, temp, GEN_INT (new),
+ target, 0, OPTAB_WIDEN);
+
+ /* Next try complementing. */
if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0)
return expand_unop (mode, one_cmpl_optab, temp, target, 0);
@@ -1227,8 +2361,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
if ((bits = exact_log2 (c & - c)) > 0)
for (; bits > 0; bits--)
if ((temp = (alpha_emit_set_const
- (subtarget, mode,
- (unsigned HOST_WIDE_INT) (c >> bits), i))) != 0
+ (subtarget, mode, c >> bits, i))) != 0
|| ((temp = (alpha_emit_set_const
(subtarget, mode,
((unsigned HOST_WIDE_INT) c) >> bits, i)))
@@ -1257,8 +2390,8 @@ alpha_emit_set_const_1 (target, mode, c, n)
/* Now try high-order 1 bits. We get that with a sign-extension.
But one bit isn't enough here. Be careful to avoid shifting outside
- the mode and to avoid shifting outside the host wide int size. */
-
+ the mode and to avoid shifting outside the host wide int size. */
+
if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
- floor_log2 (~ c) - 2)) > 0)
for (; bits > 0; bits--)
@@ -1273,6 +2406,28 @@ alpha_emit_set_const_1 (target, mode, c, n)
target, 0, OPTAB_WIDEN);
}
+#if HOST_BITS_PER_WIDE_INT == 64
+ /* Finally, see if can load a value into the target that is the same as the
+ constant except that all bytes that are 0 are changed to be 0xff. If we
+ can, then we can do a ZAPNOT to obtain the desired constant. */
+
+ new = c;
+ for (i = 0; i < 64; i += 8)
+ if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0)
+ new |= (HOST_WIDE_INT) 0xff << i;
+
+ /* We are only called for SImode and DImode. If this is SImode, ensure that
+ we are sign extended to a full word. */
+
+ if (mode == SImode)
+ new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+ if (new != c && new != -1
+ && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0)
+ return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
+ target, 0, OPTAB_WIDEN);
+#endif
+
return 0;
}
@@ -1337,6 +2492,276 @@ alpha_emit_set_long_const (target, c1, c2)
return target;
}
+/* Expand a move instruction; return true if all work is done.
+ We don't handle non-bwx subword loads here. */
+
+bool
+alpha_expand_mov (mode, operands)
+ enum machine_mode mode;
+ rtx *operands;
+{
+ /* If the output is not a register, the input must be. */
+ if (GET_CODE (operands[0]) == MEM
+ && ! reg_or_0_operand (operands[1], mode))
+ operands[1] = force_reg (mode, operands[1]);
+
+ /* Allow legitimize_address to perform some simplifications. */
+ if (mode == Pmode && symbolic_operand (operands[1], mode))
+ {
+ rtx tmp = alpha_legitimize_address (operands[1], operands[0], mode);
+ if (tmp)
+ {
+ operands[1] = tmp;
+ return false;
+ }
+ }
+
+ /* Early out for non-constants and valid constants. */
+ if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode))
+ return false;
+
+ /* Split large integers. */
+ if (GET_CODE (operands[1]) == CONST_INT
+ || GET_CODE (operands[1]) == CONST_DOUBLE)
+ {
+ HOST_WIDE_INT i0, i1;
+ rtx temp = NULL_RTX;
+
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ i0 = INTVAL (operands[1]);
+ i1 = -(i0 < 0);
+ }
+ else if (HOST_BITS_PER_WIDE_INT >= 64)
+ {
+ i0 = CONST_DOUBLE_LOW (operands[1]);
+ i1 = -(i0 < 0);
+ }
+ else
+ {
+ i0 = CONST_DOUBLE_LOW (operands[1]);
+ i1 = CONST_DOUBLE_HIGH (operands[1]);
+ }
+
+ if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
+ temp = alpha_emit_set_const (operands[0], mode, i0, 3);
+
+ if (!temp && TARGET_BUILD_CONSTANTS)
+ temp = alpha_emit_set_long_const (operands[0], i0, i1);
+
+ if (temp)
+ {
+ if (rtx_equal_p (operands[0], temp))
+ return true;
+ operands[1] = temp;
+ return false;
+ }
+ }
+
+ /* Otherwise we've nothing left but to drop the thing to memory. */
+ operands[1] = force_const_mem (DImode, operands[1]);
+ if (reload_in_progress)
+ {
+ emit_move_insn (operands[0], XEXP (operands[1], 0));
+ operands[1] = copy_rtx (operands[1]);
+ XEXP (operands[1], 0) = operands[0];
+ }
+ else
+ operands[1] = validize_mem (operands[1]);
+ return false;
+}
+
+/* Expand a non-bwx QImode or HImode move instruction;
+ return true if all work is done. */
+
+bool
+alpha_expand_mov_nobwx (mode, operands)
+ enum machine_mode mode;
+ rtx *operands;
+{
+ /* If the output is not a register, the input must be. */
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (mode, operands[1]);
+
+ /* Handle four memory cases, unaligned and aligned for either the input
+ or the output. The only case where we can be called during reload is
+ for aligned loads; all other cases require temporaries. */
+
+ if (GET_CODE (operands[1]) == MEM
+ || (GET_CODE (operands[1]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[1])) == MEM)
+ || (reload_in_progress && GET_CODE (operands[1]) == REG
+ && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
+ || (reload_in_progress && GET_CODE (operands[1]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[1])) == REG
+ && REGNO (SUBREG_REG (operands[1])) >= FIRST_PSEUDO_REGISTER))
+ {
+ if (aligned_memory_operand (operands[1], mode))
+ {
+ if (reload_in_progress)
+ {
+ emit_insn ((mode == QImode
+ ? gen_reload_inqi_help
+ : gen_reload_inhi_help)
+ (operands[0], operands[1],
+ gen_rtx_REG (SImode, REGNO (operands[0]))));
+ }
+ else
+ {
+ rtx aligned_mem, bitnum;
+ rtx scratch = gen_reg_rtx (SImode);
+
+ get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+
+ emit_insn ((mode == QImode
+ ? gen_aligned_loadqi
+ : gen_aligned_loadhi)
+ (operands[0], aligned_mem, bitnum, scratch));
+ }
+ }
+ else
+ {
+ /* Don't pass these as parameters since that makes the generated
+ code depend on parameter evaluation order which will cause
+ bootstrap failures. */
+
+ rtx temp1 = gen_reg_rtx (DImode);
+ rtx temp2 = gen_reg_rtx (DImode);
+ rtx seq = ((mode == QImode
+ ? gen_unaligned_loadqi
+ : gen_unaligned_loadhi)
+ (operands[0], get_unaligned_address (operands[1], 0),
+ temp1, temp2));
+
+ alpha_set_memflags (seq, operands[1]);
+ emit_insn (seq);
+ }
+ return true;
+ }
+
+ if (GET_CODE (operands[0]) == MEM
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == MEM)
+ || (reload_in_progress && GET_CODE (operands[0]) == REG
+ && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
+ || (reload_in_progress && GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
+ {
+ if (aligned_memory_operand (operands[0], mode))
+ {
+ rtx aligned_mem, bitnum;
+ rtx temp1 = gen_reg_rtx (SImode);
+ rtx temp2 = gen_reg_rtx (SImode);
+
+ get_aligned_mem (operands[0], &aligned_mem, &bitnum);
+
+ emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
+ temp1, temp2));
+ }
+ else
+ {
+ rtx temp1 = gen_reg_rtx (DImode);
+ rtx temp2 = gen_reg_rtx (DImode);
+ rtx temp3 = gen_reg_rtx (DImode);
+ rtx seq = ((mode == QImode
+ ? gen_unaligned_storeqi
+ : gen_unaligned_storehi)
+ (get_unaligned_address (operands[0], 0),
+ operands[1], temp1, temp2, temp3));
+
+ alpha_set_memflags (seq, operands[0]);
+ emit_insn (seq);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/* Generate an unsigned DImode to FP conversion. This is the same code
+ optabs would emit if we didn't have TFmode patterns.
+
+ For SFmode, this is the only construction I've found that can pass
+ gcc.c-torture/execute/ieee/rbug.c. No scenario that uses DFmode
+ intermediates will work, because you'll get intermediate rounding
+ that ruins the end result. Some of this could be fixed by turning
+ on round-to-positive-infinity, but that requires diddling the fpsr,
+ which kills performance. I tried turning this around and converting
+ to a negative number, so that I could turn on /m, but either I did
+ it wrong or there's something else cause I wound up with the exact
+ same single-bit error. There is a branch-less form of this same code:
+
+ srl $16,1,$1
+ and $16,1,$2
+ cmplt $16,0,$3
+ or $1,$2,$2
+ cmovge $16,$16,$2
+ itoft $3,$f10
+ itoft $2,$f11
+ cvtqs $f11,$f11
+ adds $f11,$f11,$f0
+ fcmoveq $f10,$f11,$f0
+
+ I'm not using it because it's the same number of instructions as
+ this branch-full form, and it has more serialized long latency
+ instructions on the critical path.
+
+ For DFmode, we can avoid rounding errors by breaking up the word
+ into two pieces, converting them separately, and adding them back:
+
+ LC0: .long 0,0x5f800000
+
+ itoft $16,$f11
+ lda $2,LC0
+ cmplt $16,0,$1
+ cpyse $f11,$f31,$f10
+ cpyse $f31,$f11,$f11
+ s4addq $1,$2,$1
+ lds $f12,0($1)
+ cvtqt $f10,$f10
+ cvtqt $f11,$f11
+ addt $f12,$f10,$f0
+ addt $f0,$f11,$f0
+
+ This doesn't seem to be a clear-cut win over the optabs form.
+ It probably all depends on the distribution of numbers being
+ converted -- in the optabs form, all but high-bit-set has a
+ much lower minimum execution time. */
+
+void
+alpha_emit_floatuns (operands)
+ rtx operands[2];
+{
+ rtx neglab, donelab, i0, i1, f0, in, out;
+ enum machine_mode mode;
+
+ out = operands[0];
+ in = force_reg (DImode, operands[1]);
+ mode = GET_MODE (out);
+ neglab = gen_label_rtx ();
+ donelab = gen_label_rtx ();
+ i0 = gen_reg_rtx (DImode);
+ i1 = gen_reg_rtx (DImode);
+ f0 = gen_reg_rtx (mode);
+
+ emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
+
+ emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
+ emit_jump_insn (gen_jump (donelab));
+ emit_barrier ();
+
+ emit_label (neglab);
+
+ emit_insn (gen_lshrdi3 (i0, in, const1_rtx));
+ emit_insn (gen_anddi3 (i1, in, const1_rtx));
+ emit_insn (gen_iordi3 (i0, i0, i1));
+ emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
+ emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
+
+ emit_label (donelab);
+}
+
/* Generate the comparison for a conditional branch. */
rtx
@@ -1345,26 +2770,56 @@ alpha_emit_conditional_branch (code)
{
enum rtx_code cmp_code, branch_code;
enum machine_mode cmp_mode, branch_mode = VOIDmode;
- rtx op0 = alpha_compare_op0, op1 = alpha_compare_op1;
+ rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
rtx tem;
+ if (alpha_compare.fp_p && GET_MODE (op0) == TFmode)
+ {
+ if (! TARGET_HAS_XFLOATING_LIBS)
+ abort ();
+
+ /* X_floating library comparison functions return
+ -1 unordered
+ 0 false
+ 1 true
+ Convert the compare against the raw return value. */
+
+ if (code == UNORDERED || code == ORDERED)
+ cmp_code = EQ;
+ else
+ cmp_code = code;
+
+ op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
+ op1 = const0_rtx;
+ alpha_compare.fp_p = 0;
+
+ if (code == UNORDERED)
+ code = LT;
+ else if (code == ORDERED)
+ code = GE;
+ else
+ code = GT;
+ }
+
/* The general case: fold the comparison code to the types of compares
that we have, choosing the branch as necessary. */
switch (code)
{
case EQ: case LE: case LT: case LEU: case LTU:
+ case UNORDERED:
/* We have these compares: */
cmp_code = code, branch_code = NE;
break;
case NE:
- /* This must be reversed. */
- cmp_code = EQ, branch_code = EQ;
+ case ORDERED:
+ /* These must be reversed. */
+ cmp_code = reverse_condition (code), branch_code = EQ;
break;
case GE: case GT: case GEU: case GTU:
/* For FP, we swap them, for INT, we reverse them. */
- if (alpha_compare_fp_p)
+ if (alpha_compare.fp_p)
{
cmp_code = swap_condition (code);
branch_code = NE;
@@ -1381,10 +2836,10 @@ alpha_emit_conditional_branch (code)
abort ();
}
- if (alpha_compare_fp_p)
+ if (alpha_compare.fp_p)
{
cmp_mode = DFmode;
- if (flag_fast_math)
+ if (flag_unsafe_math_optimizations)
{
/* When we are not as concerned about non-finite values, and we
are comparing against zero, we can branch directly. */
@@ -1433,11 +2888,12 @@ alpha_emit_conditional_branch (code)
}
}
}
- }
- /* Force op0 into a register. */
- if (GET_CODE (op0) != REG)
- op0 = force_reg (cmp_mode, op0);
+ if (!reg_or_0_operand (op0, DImode))
+ op0 = force_reg (DImode, op0);
+ if (cmp_code != PLUS && !reg_or_8bit_operand (op1, DImode))
+ op1 = force_reg (DImode, op1);
+ }
/* Emit an initial compare instruction, if necessary. */
tem = op0;
@@ -1447,17 +2903,129 @@ alpha_emit_conditional_branch (code)
emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1));
}
+ /* Zero the operands. */
+ memset (&alpha_compare, 0, sizeof (alpha_compare));
+
/* Return the branch comparison. */
return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode));
}
+/* Certain simplifications can be done to make invalid setcc operations
+ valid. Return the final comparison, or NULL if we can't work. */
+
+rtx
+alpha_emit_setcc (code)
+ enum rtx_code code;
+{
+ enum rtx_code cmp_code;
+ rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
+ int fp_p = alpha_compare.fp_p;
+ rtx tmp;
+
+ /* Zero the operands. */
+ memset (&alpha_compare, 0, sizeof (alpha_compare));
+
+ if (fp_p && GET_MODE (op0) == TFmode)
+ {
+ if (! TARGET_HAS_XFLOATING_LIBS)
+ abort ();
+
+ /* X_floating library comparison functions return
+ -1 unordered
+ 0 false
+ 1 true
+ Convert the compare against the raw return value. */
+
+ if (code == UNORDERED || code == ORDERED)
+ cmp_code = EQ;
+ else
+ cmp_code = code;
+
+ op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
+ op1 = const0_rtx;
+ fp_p = 0;
+
+ if (code == UNORDERED)
+ code = LT;
+ else if (code == ORDERED)
+ code = GE;
+ else
+ code = GT;
+ }
+
+ if (fp_p && !TARGET_FIX)
+ return NULL_RTX;
+
+ /* The general case: fold the comparison code to the types of compares
+ that we have, choosing the branch as necessary. */
+
+ cmp_code = NIL;
+ switch (code)
+ {
+ case EQ: case LE: case LT: case LEU: case LTU:
+ case UNORDERED:
+ /* We have these compares. */
+ if (fp_p)
+ cmp_code = code, code = NE;
+ break;
+
+ case NE:
+ if (!fp_p && op1 == const0_rtx)
+ break;
+ /* FALLTHRU */
+
+ case ORDERED:
+ cmp_code = reverse_condition (code);
+ code = EQ;
+ break;
+
+ case GE: case GT: case GEU: case GTU:
+ /* These normally need swapping, but for integer zero we have
+ special patterns that recognize swapped operands. */
+ if (!fp_p && op1 == const0_rtx)
+ break;
+ code = swap_condition (code);
+ if (fp_p)
+ cmp_code = code, code = NE;
+ tmp = op0, op0 = op1, op1 = tmp;
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (!fp_p)
+ {
+ if (!register_operand (op0, DImode))
+ op0 = force_reg (DImode, op0);
+ if (!reg_or_8bit_operand (op1, DImode))
+ op1 = force_reg (DImode, op1);
+ }
+
+ /* Emit an initial compare instruction, if necessary. */
+ if (cmp_code != NIL)
+ {
+ enum machine_mode mode = fp_p ? DFmode : DImode;
+
+ tmp = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, tmp,
+ gen_rtx_fmt_ee (cmp_code, mode, op0, op1)));
+
+ op0 = fp_p ? gen_lowpart (DImode, tmp) : tmp;
+ op1 = const0_rtx;
+ }
+
+ /* Return the setcc comparison. */
+ return gen_rtx_fmt_ee (code, DImode, op0, op1);
+}
+
/* Rewrite a comparison against zero CMP of the form
(CODE (cc0) (const_int 0)) so it can be written validly in
a conditional move (if_then_else CMP ...).
If both of the operands that set cc0 are non-zero we must emit
an insn to perform the compare (it can't be done within
- the conditional move). */
+ the conditional move). */
rtx
alpha_emit_conditional_move (cmp, mode)
rtx cmp;
@@ -1465,29 +3033,87 @@ alpha_emit_conditional_move (cmp, mode)
{
enum rtx_code code = GET_CODE (cmp);
enum rtx_code cmov_code = NE;
- rtx op0 = alpha_compare_op0;
- rtx op1 = alpha_compare_op1;
+ rtx op0 = alpha_compare.op0;
+ rtx op1 = alpha_compare.op1;
+ int fp_p = alpha_compare.fp_p;
enum machine_mode cmp_mode
= (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0));
- enum machine_mode cmp_op_mode = alpha_compare_fp_p ? DFmode : DImode;
+ enum machine_mode cmp_op_mode = fp_p ? DFmode : DImode;
enum machine_mode cmov_mode = VOIDmode;
+ int local_fast_math = flag_unsafe_math_optimizations;
rtx tem;
- if (alpha_compare_fp_p != FLOAT_MODE_P (mode))
- return 0;
+ /* Zero the operands. */
+ memset (&alpha_compare, 0, sizeof (alpha_compare));
+
+ if (fp_p != FLOAT_MODE_P (mode))
+ {
+ enum rtx_code cmp_code;
+
+ if (! TARGET_FIX)
+ return 0;
+
+ /* If we have fp<->int register move instructions, do a cmov by
+ performing the comparison in fp registers, and move the
+ zero/non-zero value to integer registers, where we can then
+ use a normal cmov, or vice-versa. */
+
+ switch (code)
+ {
+ case EQ: case LE: case LT: case LEU: case LTU:
+ /* We have these compares. */
+ cmp_code = code, code = NE;
+ break;
+
+ case NE:
+ /* This must be reversed. */
+ cmp_code = EQ, code = EQ;
+ break;
+
+ case GE: case GT: case GEU: case GTU:
+ /* These normally need swapping, but for integer zero we have
+ special patterns that recognize swapped operands. */
+ if (!fp_p && op1 == const0_rtx)
+ cmp_code = code, code = NE;
+ else
+ {
+ cmp_code = swap_condition (code);
+ code = NE;
+ tem = op0, op0 = op1, op1 = tem;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ tem = gen_reg_rtx (cmp_op_mode);
+ emit_insn (gen_rtx_SET (VOIDmode, tem,
+ gen_rtx_fmt_ee (cmp_code, cmp_op_mode,
+ op0, op1)));
+
+ cmp_mode = cmp_op_mode = fp_p ? DImode : DFmode;
+ op0 = gen_lowpart (cmp_op_mode, tem);
+ op1 = CONST0_RTX (cmp_op_mode);
+ fp_p = !fp_p;
+ local_fast_math = 1;
+ }
/* We may be able to use a conditional move directly.
- This avoids emitting spurious compares. */
- if (signed_comparison_operator (cmp, cmp_op_mode)
- && (!alpha_compare_fp_p || flag_fast_math)
+ This avoids emitting spurious compares. */
+ if (signed_comparison_operator (cmp, VOIDmode)
+ && (!fp_p || local_fast_math)
&& (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode)))
return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
- /* We can't put the comparison insides a conditional move;
+ /* We can't put the comparison inside the conditional move;
emit a compare instruction and put that inside the
conditional move. Make sure we emit only comparisons we have;
swap or reverse as necessary. */
+ if (no_new_pseudos)
+ return NULL_RTX;
+
switch (code)
{
case EQ: case LE: case LT: case LEU: case LTU:
@@ -1495,33 +3121,502 @@ alpha_emit_conditional_move (cmp, mode)
break;
case NE:
- /* This must be reversed. */
+ /* This must be reversed. */
code = reverse_condition (code);
cmov_code = EQ;
break;
case GE: case GT: case GEU: case GTU:
- /* These must be swapped. Make sure the new first operand is in
- a register. */
- code = swap_condition (code);
- tem = op0, op0 = op1, op1 = tem;
- op0 = force_reg (cmp_mode, op0);
+ /* These must be swapped. */
+ if (op1 != CONST0_RTX (cmp_mode))
+ {
+ code = swap_condition (code);
+ tem = op0, op0 = op1, op1 = tem;
+ }
break;
default:
abort ();
}
+ if (!fp_p)
+ {
+ if (!reg_or_0_operand (op0, DImode))
+ op0 = force_reg (DImode, op0);
+ if (!reg_or_8bit_operand (op1, DImode))
+ op1 = force_reg (DImode, op1);
+ }
+
/* ??? We mark the branch mode to be CCmode to prevent the compare
and cmov from being combined, since the compare insn follows IEEE
rules that the cmov does not. */
- if (alpha_compare_fp_p && !flag_fast_math)
+ if (fp_p && !local_fast_math)
cmov_mode = CCmode;
tem = gen_reg_rtx (cmp_op_mode);
emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_op_mode, op0, op1));
return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_op_mode));
}
+
+/* Simplify a conditional move of two constants into a setcc with
+ arithmetic. This is done with a splitter since combine would
+ just undo the work if done during code generation. It also catches
+ cases we wouldn't have before cse. */
+
+int
+alpha_split_conditional_move (code, dest, cond, t_rtx, f_rtx)
+ enum rtx_code code;
+ rtx dest, cond, t_rtx, f_rtx;
+{
+ HOST_WIDE_INT t, f, diff;
+ enum machine_mode mode;
+ rtx target, subtarget, tmp;
+
+ mode = GET_MODE (dest);
+ t = INTVAL (t_rtx);
+ f = INTVAL (f_rtx);
+ diff = t - f;
+
+ if (((code == NE || code == EQ) && diff < 0)
+ || (code == GE || code == GT))
+ {
+ code = reverse_condition (code);
+ diff = t, t = f, f = diff;
+ diff = t - f;
+ }
+
+ subtarget = target = dest;
+ if (mode != DImode)
+ {
+ target = gen_lowpart (DImode, dest);
+ if (! no_new_pseudos)
+ subtarget = gen_reg_rtx (DImode);
+ else
+ subtarget = target;
+ }
+ /* Below, we must be careful to use copy_rtx on target and subtarget
+ in intermediate insns, as they may be a subreg rtx, which may not
+ be shared. */
+
+ if (f == 0 && exact_log2 (diff) > 0
+ /* On EV6, we've got enough shifters to make non-arithmatic shifts
+ viable over a longer latency cmove. On EV5, the E0 slot is a
+ scarce resource, and on EV4 shift has the same latency as a cmove. */
+ && (diff <= 8 || alpha_cpu == PROCESSOR_EV6))
+ {
+ tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
+
+ tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget),
+ GEN_INT (exact_log2 (t)));
+ emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
+ }
+ else if (f == 0 && t == -1)
+ {
+ tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
+
+ emit_insn (gen_negdi2 (target, copy_rtx (subtarget)));
+ }
+ else if (diff == 1 || diff == 4 || diff == 8)
+ {
+ rtx add_op;
+
+ tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
+
+ if (diff == 1)
+ emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f)));
+ else
+ {
+ add_op = GEN_INT (f);
+ if (sext_add_operand (add_op, mode))
+ {
+ tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget),
+ GEN_INT (diff));
+ tmp = gen_rtx_PLUS (DImode, tmp, add_op);
+ emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
+ }
+ else
+ return 0;
+ }
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
+/* Look up the function X_floating library function name for the
+ given operation. */
+
+static const char *
+alpha_lookup_xfloating_lib_func (code)
+ enum rtx_code code;
+{
+ struct xfloating_op
+ {
+ const enum rtx_code code;
+ const char *const func;
+ };
+
+ static const struct xfloating_op vms_xfloating_ops[] =
+ {
+ { PLUS, "OTS$ADD_X" },
+ { MINUS, "OTS$SUB_X" },
+ { MULT, "OTS$MUL_X" },
+ { DIV, "OTS$DIV_X" },
+ { EQ, "OTS$EQL_X" },
+ { NE, "OTS$NEQ_X" },
+ { LT, "OTS$LSS_X" },
+ { LE, "OTS$LEQ_X" },
+ { GT, "OTS$GTR_X" },
+ { GE, "OTS$GEQ_X" },
+ { FIX, "OTS$CVTXQ" },
+ { FLOAT, "OTS$CVTQX" },
+ { UNSIGNED_FLOAT, "OTS$CVTQUX" },
+ { FLOAT_EXTEND, "OTS$CVT_FLOAT_T_X" },
+ { FLOAT_TRUNCATE, "OTS$CVT_FLOAT_X_T" },
+ };
+
+ static const struct xfloating_op osf_xfloating_ops[] =
+ {
+ { PLUS, "_OtsAddX" },
+ { MINUS, "_OtsSubX" },
+ { MULT, "_OtsMulX" },
+ { DIV, "_OtsDivX" },
+ { EQ, "_OtsEqlX" },
+ { NE, "_OtsNeqX" },
+ { LT, "_OtsLssX" },
+ { LE, "_OtsLeqX" },
+ { GT, "_OtsGtrX" },
+ { GE, "_OtsGeqX" },
+ { FIX, "_OtsCvtXQ" },
+ { FLOAT, "_OtsCvtQX" },
+ { UNSIGNED_FLOAT, "_OtsCvtQUX" },
+ { FLOAT_EXTEND, "_OtsConvertFloatTX" },
+ { FLOAT_TRUNCATE, "_OtsConvertFloatXT" },
+ };
+
+ const struct xfloating_op *ops;
+ const long n = ARRAY_SIZE (osf_xfloating_ops);
+ long i;
+
+ /* How irritating. Nothing to key off for the table. Hardcode
+ knowledge of the G_floating routines. */
+ if (TARGET_FLOAT_VAX)
+ {
+ if (TARGET_ABI_OPEN_VMS)
+ {
+ if (code == FLOAT_EXTEND)
+ return "OTS$CVT_FLOAT_G_X";
+ if (code == FLOAT_TRUNCATE)
+ return "OTS$CVT_FLOAT_X_G";
+ }
+ else
+ {
+ if (code == FLOAT_EXTEND)
+ return "_OtsConvertFloatGX";
+ if (code == FLOAT_TRUNCATE)
+ return "_OtsConvertFloatXG";
+ }
+ }
+
+ if (TARGET_ABI_OPEN_VMS)
+ ops = vms_xfloating_ops;
+ else
+ ops = osf_xfloating_ops;
+
+ for (i = 0; i < n; ++i)
+ if (ops[i].code == code)
+ return ops[i].func;
+
+ abort();
+}
+
+/* Most X_floating operations take the rounding mode as an argument.
+ Compute that here. */
+
+static int
+alpha_compute_xfloating_mode_arg (code, round)
+ enum rtx_code code;
+ enum alpha_fp_rounding_mode round;
+{
+ int mode;
+
+ switch (round)
+ {
+ case ALPHA_FPRM_NORM:
+ mode = 2;
+ break;
+ case ALPHA_FPRM_MINF:
+ mode = 1;
+ break;
+ case ALPHA_FPRM_CHOP:
+ mode = 0;
+ break;
+ case ALPHA_FPRM_DYN:
+ mode = 4;
+ break;
+ default:
+ abort ();
+
+ /* XXX For reference, round to +inf is mode = 3. */
+ }
+
+ if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N)
+ mode |= 0x10000;
+
+ return mode;
+}
+
+/* Emit an X_floating library function call.
+
+ Note that these functions do not follow normal calling conventions:
+ TFmode arguments are passed in two integer registers (as opposed to
+ indirect); TFmode return values appear in R16+R17.
+
+ FUNC is the function name to call.
+ TARGET is where the output belongs.
+ OPERANDS are the inputs.
+ NOPERANDS is the count of inputs.
+ EQUIV is the expression equivalent for the function.
+*/
+
+static void
+alpha_emit_xfloating_libcall (func, target, operands, noperands, equiv)
+ const char *func;
+ rtx target;
+ rtx operands[];
+ int noperands;
+ rtx equiv;
+{
+ rtx usage = NULL_RTX, tmp, reg;
+ int regno = 16, i;
+
+ start_sequence ();
+
+ for (i = 0; i < noperands; ++i)
+ {
+ switch (GET_MODE (operands[i]))
+ {
+ case TFmode:
+ reg = gen_rtx_REG (TFmode, regno);
+ regno += 2;
+ break;
+
+ case DFmode:
+ reg = gen_rtx_REG (DFmode, regno + 32);
+ regno += 1;
+ break;
+
+ case VOIDmode:
+ if (GET_CODE (operands[i]) != CONST_INT)
+ abort ();
+ /* FALLTHRU */
+ case DImode:
+ reg = gen_rtx_REG (DImode, regno);
+ regno += 1;
+ break;
+
+ default:
+ abort ();
+ }
+
+ emit_move_insn (reg, operands[i]);
+ usage = alloc_EXPR_LIST (0, gen_rtx_USE (VOIDmode, reg), usage);
+ }
+
+ switch (GET_MODE (target))
+ {
+ case TFmode:
+ reg = gen_rtx_REG (TFmode, 16);
+ break;
+ case DFmode:
+ reg = gen_rtx_REG (DFmode, 32);
+ break;
+ case DImode:
+ reg = gen_rtx_REG (DImode, 0);
+ break;
+ default:
+ abort ();
+ }
+
+ tmp = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, (char *) func));
+ tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx,
+ const0_rtx, const0_rtx));
+ CALL_INSN_FUNCTION_USAGE (tmp) = usage;
+
+ tmp = get_insns ();
+ end_sequence ();
+
+ emit_libcall_block (tmp, target, reg, equiv);
+}
+
+/* Emit an X_floating library function call for arithmetic (+,-,*,/). */
+
+void
+alpha_emit_xfloating_arith (code, operands)
+ enum rtx_code code;
+ rtx operands[];
+{
+ const char *func;
+ int mode;
+ rtx out_operands[3];
+
+ func = alpha_lookup_xfloating_lib_func (code);
+ mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
+
+ out_operands[0] = operands[1];
+ out_operands[1] = operands[2];
+ out_operands[2] = GEN_INT (mode);
+ alpha_emit_xfloating_libcall (func, operands[0], out_operands, 3,
+ gen_rtx_fmt_ee (code, TFmode, operands[1],
+ operands[2]));
+}
+
+/* Emit an X_floating library function call for a comparison. */
+
+static rtx
+alpha_emit_xfloating_compare (code, op0, op1)
+ enum rtx_code code;
+ rtx op0, op1;
+{
+ const char *func;
+ rtx out, operands[2];
+
+ func = alpha_lookup_xfloating_lib_func (code);
+
+ operands[0] = op0;
+ operands[1] = op1;
+ out = gen_reg_rtx (DImode);
+
+ /* ??? Strange mode for equiv because what's actually returned
+ is -1,0,1, not a proper boolean value. */
+ alpha_emit_xfloating_libcall (func, out, operands, 2,
+ gen_rtx_fmt_ee (code, CCmode, op0, op1));
+
+ return out;
+}
+
+/* Emit an X_floating library function call for a conversion. */
+
+void
+alpha_emit_xfloating_cvt (code, operands)
+ enum rtx_code code;
+ rtx operands[];
+{
+ int noperands = 1, mode;
+ rtx out_operands[2];
+ const char *func;
+
+ func = alpha_lookup_xfloating_lib_func (code);
+
+ out_operands[0] = operands[1];
+
+ switch (code)
+ {
+ case FIX:
+ mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP);
+ out_operands[1] = GEN_INT (mode);
+ noperands = 2;
+ break;
+ case FLOAT_TRUNCATE:
+ mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
+ out_operands[1] = GEN_INT (mode);
+ noperands = 2;
+ break;
+ default:
+ break;
+ }
+
+ alpha_emit_xfloating_libcall (func, operands[0], out_operands, noperands,
+ gen_rtx_fmt_e (code, GET_MODE (operands[0]),
+ operands[1]));
+}
+
+/* Split a TFmode OP[1] into DImode OP[2,3] and likewise for
+ OP[0] into OP[0,1]. Naturally, output operand ordering is
+ little-endian. */
+
+void
+alpha_split_tfmode_pair (operands)
+ rtx operands[4];
+{
+ if (GET_CODE (operands[1]) == REG)
+ {
+ operands[3] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1);
+ operands[2] = gen_rtx_REG (DImode, REGNO (operands[1]));
+ }
+ else if (GET_CODE (operands[1]) == MEM)
+ {
+ operands[3] = adjust_address (operands[1], DImode, 8);
+ operands[2] = adjust_address (operands[1], DImode, 0);
+ }
+ else if (operands[1] == CONST0_RTX (TFmode))
+ operands[2] = operands[3] = const0_rtx;
+ else
+ abort ();
+
+ if (GET_CODE (operands[0]) == REG)
+ {
+ operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1);
+ operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
+ }
+ else if (GET_CODE (operands[0]) == MEM)
+ {
+ operands[1] = adjust_address (operands[0], DImode, 8);
+ operands[0] = adjust_address (operands[0], DImode, 0);
+ }
+ else
+ abort ();
+}
+
+/* Implement negtf2 or abstf2. Op0 is destination, op1 is source,
+ op2 is a register containing the sign bit, operation is the
+ logical operation to be performed. */
+
+void
+alpha_split_tfmode_frobsign (operands, operation)
+ rtx operands[3];
+ rtx (*operation) PARAMS ((rtx, rtx, rtx));
+{
+ rtx high_bit = operands[2];
+ rtx scratch;
+ int move;
+
+ alpha_split_tfmode_pair (operands);
+
+ /* Detect three flavours of operand overlap. */
+ move = 1;
+ if (rtx_equal_p (operands[0], operands[2]))
+ move = 0;
+ else if (rtx_equal_p (operands[1], operands[2]))
+ {
+ if (rtx_equal_p (operands[0], high_bit))
+ move = 2;
+ else
+ move = -1;
+ }
+
+ if (move < 0)
+ emit_move_insn (operands[0], operands[2]);
+
+ /* ??? If the destination overlaps both source tf and high_bit, then
+ assume source tf is dead in its entirety and use the other half
+ for a scratch register. Otherwise "scratch" is just the proper
+ destination register. */
+ scratch = operands[move < 2 ? 1 : 3];
+
+ emit_insn ((*operation) (scratch, high_bit, operands[3]));
+
+ if (move > 0)
+ {
+ emit_move_insn (operands[0], operands[2]);
+ if (move > 1)
+ emit_move_insn (operands[1], scratch);
+ }
+}
/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
unaligned data:
@@ -1556,7 +3651,7 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
HOST_WIDE_INT size, ofs;
int sign;
{
- rtx meml, memh, addr, extl, exth;
+ rtx meml, memh, addr, extl, exth, tmp, mema;
enum machine_mode mode;
meml = gen_reg_rtx (DImode);
@@ -1565,26 +3660,45 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
extl = gen_reg_rtx (DImode);
exth = gen_reg_rtx (DImode);
- emit_move_insn (meml,
- change_address (mem, DImode,
- gen_rtx_AND (DImode,
- plus_constant (XEXP (mem, 0),
- ofs),
- GEN_INT (-8))));
+ mema = XEXP (mem, 0);
+ if (GET_CODE (mema) == LO_SUM)
+ mema = force_reg (Pmode, mema);
+
+ /* AND addresses cannot be in any alias set, since they may implicitly
+ alias surrounding code. Ideally we'd have some alias set that
+ covered all types except those with alignment 8 or higher. */
+
+ tmp = change_address (mem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (mema, ofs),
+ GEN_INT (-8)));
+ set_mem_alias_set (tmp, 0);
+ emit_move_insn (meml, tmp);
+
+ tmp = change_address (mem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (mema, ofs + size - 1),
+ GEN_INT (-8)));
+ set_mem_alias_set (tmp, 0);
+ emit_move_insn (memh, tmp);
+
+ if (WORDS_BIG_ENDIAN && sign && (size == 2 || size == 4))
+ {
+ emit_move_insn (addr, plus_constant (mema, -1));
- emit_move_insn (memh,
- change_address (mem, DImode,
- gen_rtx_AND (DImode,
- plus_constant (XEXP (mem, 0),
- ofs + size - 1),
- GEN_INT (-8))));
+ emit_insn (gen_extqh_be (extl, meml, addr));
+ emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr));
- if (sign && size == 2)
+ addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
+ addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8),
+ addr, 1, OPTAB_WIDEN);
+ }
+ else if (sign && size == 2)
{
- emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs+2));
+ emit_move_insn (addr, plus_constant (mema, ofs+2));
- emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
- emit_insn (gen_extqh (exth, memh, addr));
+ emit_insn (gen_extxl_le (extl, meml, GEN_INT (64), addr));
+ emit_insn (gen_extqh_le (exth, memh, addr));
/* We must use tgt here for the target. Alpha-vms port fails if we use
addr for the target, because addr is marked as a pointer and combine
@@ -1595,26 +3709,55 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
}
else
{
- emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs));
- emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr));
- switch (size)
+ if (WORDS_BIG_ENDIAN)
{
- case 2:
- emit_insn (gen_extwh (exth, memh, addr));
- mode = HImode;
- break;
+ emit_move_insn (addr, plus_constant (mema, ofs+size-1));
+ switch ((int) size)
+ {
+ case 2:
+ emit_insn (gen_extwh_be (extl, meml, addr));
+ mode = HImode;
+ break;
- case 4:
- emit_insn (gen_extlh (exth, memh, addr));
- mode = SImode;
- break;
+ case 4:
+ emit_insn (gen_extlh_be (extl, meml, addr));
+ mode = SImode;
+ break;
- case 8:
- emit_insn (gen_extqh (exth, memh, addr));
- mode = DImode;
- break;
- default:
- abort();
+ case 8:
+ emit_insn (gen_extqh_be (extl, meml, addr));
+ mode = DImode;
+ break;
+
+ default:
+ abort ();
+ }
+ emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr));
+ }
+ else
+ {
+ emit_move_insn (addr, plus_constant (mema, ofs));
+ emit_insn (gen_extxl_le (extl, meml, GEN_INT (size*8), addr));
+ switch ((int) size)
+ {
+ case 2:
+ emit_insn (gen_extwh_le (exth, memh, addr));
+ mode = HImode;
+ break;
+
+ case 4:
+ emit_insn (gen_extlh_le (exth, memh, addr));
+ mode = SImode;
+ break;
+
+ case 8:
+ emit_insn (gen_extqh_le (exth, memh, addr));
+ mode = DImode;
+ break;
+
+ default:
+ abort();
+ }
}
addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl),
@@ -1633,66 +3776,123 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
rtx dst, src;
HOST_WIDE_INT size, ofs;
{
- rtx dstl, dsth, addr, insl, insh, meml, memh;
+ rtx dstl, dsth, addr, insl, insh, meml, memh, dsta;
dstl = gen_reg_rtx (DImode);
dsth = gen_reg_rtx (DImode);
insl = gen_reg_rtx (DImode);
insh = gen_reg_rtx (DImode);
+ dsta = XEXP (dst, 0);
+ if (GET_CODE (dsta) == LO_SUM)
+ dsta = force_reg (Pmode, dsta);
+
+ /* AND addresses cannot be in any alias set, since they may implicitly
+ alias surrounding code. Ideally we'd have some alias set that
+ covered all types except those with alignment 8 or higher. */
+
meml = change_address (dst, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (dst, 0), ofs),
+ plus_constant (dsta, ofs),
GEN_INT (-8)));
+ set_mem_alias_set (meml, 0);
+
memh = change_address (dst, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP (dst, 0),
- ofs+size-1),
+ plus_constant (dsta, ofs + size - 1),
GEN_INT (-8)));
+ set_mem_alias_set (memh, 0);
emit_move_insn (dsth, memh);
emit_move_insn (dstl, meml);
- addr = copy_addr_to_reg (plus_constant (XEXP (dst, 0), ofs));
-
- if (src != const0_rtx)
+ if (WORDS_BIG_ENDIAN)
{
- emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
- GEN_INT (size*8), addr));
+ addr = copy_addr_to_reg (plus_constant (dsta, ofs+size-1));
+
+ if (src != const0_rtx)
+ {
+ switch ((int) size)
+ {
+ case 2:
+ emit_insn (gen_inswl_be (insh, gen_lowpart (HImode,src), addr));
+ break;
+ case 4:
+ emit_insn (gen_insll_be (insh, gen_lowpart (SImode,src), addr));
+ break;
+ case 8:
+ emit_insn (gen_insql_be (insh, gen_lowpart (DImode,src), addr));
+ break;
+ }
+ emit_insn (gen_insxh (insl, gen_lowpart (DImode, src),
+ GEN_INT (size*8), addr));
+ }
- switch (size)
+ switch ((int) size)
{
case 2:
- emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr));
+ emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr));
break;
case 4:
- emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr));
+ emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffffffff), addr));
break;
case 8:
- emit_insn (gen_insql (insl, src, addr));
+ {
+#if HOST_BITS_PER_WIDE_INT == 32
+ rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
+#else
+ rtx msk = constm1_rtx;
+#endif
+ emit_insn (gen_mskxl_be (dsth, dsth, msk, addr));
+ }
break;
}
+
+ emit_insn (gen_mskxh (dstl, dstl, GEN_INT (size*8), addr));
}
+ else
+ {
+ addr = copy_addr_to_reg (plus_constant (dsta, ofs));
- emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
+ if (src != const0_rtx)
+ {
+ emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
+ GEN_INT (size*8), addr));
- switch (size)
- {
- case 2:
- emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffff), addr));
- break;
- case 4:
- emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffffffff), addr));
- break;
- case 8:
- {
+ switch ((int) size)
+ {
+ case 2:
+ emit_insn (gen_inswl_le (insl, gen_lowpart (HImode, src), addr));
+ break;
+ case 4:
+ emit_insn (gen_insll_le (insl, gen_lowpart (SImode, src), addr));
+ break;
+ case 8:
+ emit_insn (gen_insql_le (insl, src, addr));
+ break;
+ }
+ }
+
+ emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
+
+ switch ((int) size)
+ {
+ case 2:
+ emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffff), addr));
+ break;
+ case 4:
+ emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffffffff), addr));
+ break;
+ case 8:
+ {
#if HOST_BITS_PER_WIDE_INT == 32
- rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
+ rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
#else
- rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode);
+ rtx msk = constm1_rtx;
#endif
- emit_insn (gen_mskxl (dstl, dstl, msk, addr));
- }
- break;
+ emit_insn (gen_mskxl_le (dstl, dstl, msk, addr));
+ }
+ break;
+ }
}
if (src != const0_rtx)
@@ -1700,10 +3900,18 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
}
-
- /* Must store high before low for degenerate case of aligned. */
- emit_move_insn (memh, dsth);
- emit_move_insn (meml, dstl);
+
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_move_insn (meml, dstl);
+ emit_move_insn (memh, dsth);
+ }
+ else
+ {
+ /* Must store high before low for degenerate case of aligned. */
+ emit_move_insn (memh, dsth);
+ emit_move_insn (meml, dstl);
+ }
}
/* The block move code tries to maximize speed by separating loads and
@@ -1725,9 +3933,13 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
rtx const im8 = GEN_INT (-8);
rtx const i64 = GEN_INT (64);
rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1];
- rtx sreg, areg;
+ rtx sreg, areg, tmp, smema;
HOST_WIDE_INT i;
+ smema = XEXP (smem, 0);
+ if (GET_CODE (smema) == LO_SUM)
+ smema = force_reg (Pmode, smema);
+
/* Generate all the tmp registers we need. */
for (i = 0; i < words; ++i)
{
@@ -1737,38 +3949,47 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
data_regs[words] = gen_reg_rtx (DImode);
if (ofs != 0)
- smem = change_address (smem, GET_MODE (smem),
- plus_constant (XEXP (smem, 0), ofs));
+ smem = adjust_address (smem, GET_MODE (smem), ofs);
/* Load up all of the source data. */
for (i = 0; i < words; ++i)
{
- emit_move_insn (data_regs[i],
- change_address (smem, DImode,
- gen_rtx_AND (DImode,
- plus_constant (XEXP(smem,0),
- 8*i),
- im8)));
+ tmp = change_address (smem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (smema, 8*i),
+ im8));
+ set_mem_alias_set (tmp, 0);
+ emit_move_insn (data_regs[i], tmp);
}
- emit_move_insn (data_regs[words],
- change_address (smem, DImode,
- gen_rtx_AND (DImode,
- plus_constant (XEXP(smem,0),
- 8*words - 1),
- im8)));
+
+ tmp = change_address (smem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (smema, 8*words - 1),
+ im8));
+ set_mem_alias_set (tmp, 0);
+ emit_move_insn (data_regs[words], tmp);
/* Extract the half-word fragments. Unfortunately DEC decided to make
extxh with offset zero a noop instead of zeroing the register, so
we must take care of that edge condition ourselves with cmov. */
- sreg = copy_addr_to_reg (XEXP (smem, 0));
+ sreg = copy_addr_to_reg (smema);
areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL,
1, OPTAB_WIDEN);
+ if (WORDS_BIG_ENDIAN)
+ emit_move_insn (sreg, plus_constant (sreg, 7));
for (i = 0; i < words; ++i)
{
- emit_insn (gen_extxl (data_regs[i], data_regs[i], i64, sreg));
-
- emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], sreg));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_extqh_be (data_regs[i], data_regs[i], sreg));
+ emit_insn (gen_extxl_be (ext_tmps[i], data_regs[i+1], i64, sreg));
+ }
+ else
+ {
+ emit_insn (gen_extxl_le (data_regs[i], data_regs[i], i64, sreg));
+ emit_insn (gen_extqh_le (ext_tmps[i], data_regs[i+1], sreg));
+ }
emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i],
gen_rtx_IF_THEN_ELSE (DImode,
gen_rtx_EQ (DImode, areg,
@@ -1798,13 +4019,17 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
#if HOST_BITS_PER_WIDE_INT == 32
rtx const im1 = immed_double_const (0xffffffff, 0xffffffff, DImode);
#else
- rtx const im1 = immed_double_const (0xffffffffffffffff, 0, DImode);
+ rtx const im1 = constm1_rtx;
#endif
rtx ins_tmps[MAX_MOVE_WORDS];
rtx st_tmp_1, st_tmp_2, dreg;
- rtx st_addr_1, st_addr_2;
+ rtx st_addr_1, st_addr_2, dmema;
HOST_WIDE_INT i;
+ dmema = XEXP (dmem, 0);
+ if (GET_CODE (dmema) == LO_SUM)
+ dmema = force_reg (Pmode, dmema);
+
/* Generate all the tmp registers we need. */
if (data_regs != NULL)
for (i = 0; i < words; ++i)
@@ -1813,32 +4038,40 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
st_tmp_2 = gen_reg_rtx(DImode);
if (ofs != 0)
- dmem = change_address (dmem, GET_MODE (dmem),
- plus_constant (XEXP (dmem, 0), ofs));
-
+ dmem = adjust_address (dmem, GET_MODE (dmem), ofs);
st_addr_2 = change_address (dmem, DImode,
gen_rtx_AND (DImode,
- plus_constant (XEXP(dmem,0),
- words*8 - 1),
+ plus_constant (dmema, words*8 - 1),
im8));
+ set_mem_alias_set (st_addr_2, 0);
+
st_addr_1 = change_address (dmem, DImode,
- gen_rtx_AND (DImode,
- XEXP (dmem, 0),
- im8));
+ gen_rtx_AND (DImode, dmema, im8));
+ set_mem_alias_set (st_addr_1, 0);
/* Load up the destination end bits. */
emit_move_insn (st_tmp_2, st_addr_2);
emit_move_insn (st_tmp_1, st_addr_1);
/* Shift the input data into place. */
- dreg = copy_addr_to_reg (XEXP (dmem, 0));
+ dreg = copy_addr_to_reg (dmema);
+ if (WORDS_BIG_ENDIAN)
+ emit_move_insn (dreg, plus_constant (dreg, 7));
if (data_regs != NULL)
{
for (i = words-1; i >= 0; --i)
{
- emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg));
- emit_insn (gen_insql (data_regs[i], data_regs[i], dreg));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_insql_be (ins_tmps[i], data_regs[i], dreg));
+ emit_insn (gen_insxh (data_regs[i], data_regs[i], i64, dreg));
+ }
+ else
+ {
+ emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg));
+ emit_insn (gen_insql_le (data_regs[i], data_regs[i], dreg));
+ }
}
for (i = words-1; i > 0; --i)
{
@@ -1849,8 +4082,16 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
}
/* Split and merge the ends with the destination data. */
- emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg));
- emit_insn (gen_mskxl (st_tmp_1, st_tmp_1, im1, dreg));
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_mskxl_be (st_tmp_2, st_tmp_2, im1, dreg));
+ emit_insn (gen_mskxh (st_tmp_1, st_tmp_1, i64, dreg));
+ }
+ else
+ {
+ emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg));
+ emit_insn (gen_mskxl_le (st_tmp_1, st_tmp_1, im1, dreg));
+ }
if (data_regs != NULL)
{
@@ -1861,17 +4102,24 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
}
/* Store it all. */
- emit_move_insn (st_addr_2, st_tmp_2);
+ if (WORDS_BIG_ENDIAN)
+ emit_move_insn (st_addr_1, st_tmp_1);
+ else
+ emit_move_insn (st_addr_2, st_tmp_2);
for (i = words-1; i > 0; --i)
{
- emit_move_insn (change_address (dmem, DImode,
- gen_rtx_AND (DImode,
- plus_constant(XEXP (dmem,0),
- i*8),
- im8)),
- data_regs ? ins_tmps[i-1] : const0_rtx);
+ rtx tmp = change_address (dmem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant(dmema,
+ WORDS_BIG_ENDIAN ? i*8-1 : i*8),
+ im8));
+ set_mem_alias_set (tmp, 0);
+ emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx);
}
- emit_move_insn (st_addr_1, st_tmp_1);
+ if (WORDS_BIG_ENDIAN)
+ emit_move_insn (st_addr_2, st_tmp_2);
+ else
+ emit_move_insn (st_addr_1, st_tmp_1);
}
@@ -1890,76 +4138,68 @@ alpha_expand_block_move (operands)
rtx align_rtx = operands[3];
HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx);
HOST_WIDE_INT bytes = orig_bytes;
- HOST_WIDE_INT src_align = INTVAL (align_rtx);
+ HOST_WIDE_INT src_align = INTVAL (align_rtx) * BITS_PER_UNIT;
HOST_WIDE_INT dst_align = src_align;
- rtx orig_src = operands[1];
- rtx orig_dst = operands[0];
- rtx data_regs[2*MAX_MOVE_WORDS+16];
+ rtx orig_src = operands[1];
+ rtx orig_dst = operands[0];
+ rtx data_regs[2 * MAX_MOVE_WORDS + 16];
rtx tmp;
- int i, words, ofs, nregs = 0;
+ unsigned int i, words, ofs, nregs = 0;
- if (bytes <= 0)
+ if (orig_bytes <= 0)
return 1;
- if (bytes > MAX_MOVE_WORDS*8)
+ else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD)
return 0;
/* Look for additional alignment information from recorded register info. */
tmp = XEXP (orig_src, 0);
if (GET_CODE (tmp) == REG)
- {
- if (REGNO_POINTER_ALIGN (REGNO (tmp)) > src_align)
- src_align = REGNO_POINTER_ALIGN (REGNO (tmp));
- }
+ src_align = MAX (src_align, REGNO_POINTER_ALIGN (REGNO (tmp)));
else if (GET_CODE (tmp) == PLUS
&& GET_CODE (XEXP (tmp, 0)) == REG
&& GET_CODE (XEXP (tmp, 1)) == CONST_INT)
{
- HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
- int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
+ unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
+ unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
if (a > src_align)
{
- if (a >= 8 && c % 8 == 0)
- src_align = 8;
- else if (a >= 4 && c % 4 == 0)
- src_align = 4;
- else if (a >= 2 && c % 2 == 0)
- src_align = 2;
+ if (a >= 64 && c % 8 == 0)
+ src_align = 64;
+ else if (a >= 32 && c % 4 == 0)
+ src_align = 32;
+ else if (a >= 16 && c % 2 == 0)
+ src_align = 16;
}
}
tmp = XEXP (orig_dst, 0);
if (GET_CODE (tmp) == REG)
- {
- if (REGNO_POINTER_ALIGN (REGNO (tmp)) > dst_align)
- dst_align = REGNO_POINTER_ALIGN (REGNO (tmp));
- }
+ dst_align = MAX (dst_align, REGNO_POINTER_ALIGN (REGNO (tmp)));
else if (GET_CODE (tmp) == PLUS
&& GET_CODE (XEXP (tmp, 0)) == REG
&& GET_CODE (XEXP (tmp, 1)) == CONST_INT)
{
- HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
- int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
+ unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
+ unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
if (a > dst_align)
{
- if (a >= 8 && c % 8 == 0)
- dst_align = 8;
- else if (a >= 4 && c % 4 == 0)
- dst_align = 4;
- else if (a >= 2 && c % 2 == 0)
- dst_align = 2;
+ if (a >= 64 && c % 8 == 0)
+ dst_align = 64;
+ else if (a >= 32 && c % 4 == 0)
+ dst_align = 32;
+ else if (a >= 16 && c % 2 == 0)
+ dst_align = 16;
}
}
- /*
- * Load the entire block into registers.
- */
-
+ /* Load the entire block into registers. */
if (GET_CODE (XEXP (orig_src, 0)) == ADDRESSOF)
{
enum machine_mode mode;
+
tmp = XEXP (XEXP (orig_src, 0), 0);
/* Don't use the existing register if we're reading more than
@@ -1972,64 +4212,60 @@ alpha_expand_block_move (operands)
if (mode == TImode)
{
data_regs[nregs] = gen_lowpart (DImode, tmp);
- data_regs[nregs+1] = gen_highpart (DImode, tmp);
+ data_regs[nregs + 1] = gen_highpart (DImode, tmp);
nregs += 2;
}
else
data_regs[nregs++] = gen_lowpart (mode, tmp);
+
goto src_done;
}
/* No appropriate mode; fall back on memory. */
- orig_src = change_address (orig_src, GET_MODE (orig_src),
- copy_addr_to_reg (XEXP (orig_src, 0)));
+ orig_src = replace_equiv_address (orig_src,
+ copy_addr_to_reg (XEXP (orig_src, 0)));
+ src_align = GET_MODE_BITSIZE (GET_MODE (tmp));
}
ofs = 0;
- if (src_align >= 8 && bytes >= 8)
+ if (src_align >= 64 && bytes >= 8)
{
words = bytes / 8;
for (i = 0; i < words; ++i)
- data_regs[nregs+i] = gen_reg_rtx(DImode);
+ data_regs[nregs + i] = gen_reg_rtx (DImode);
for (i = 0; i < words; ++i)
- {
- emit_move_insn (data_regs[nregs+i],
- change_address (orig_src, DImode,
- plus_constant (XEXP (orig_src, 0),
- ofs + i*8)));
- }
+ emit_move_insn (data_regs[nregs + i],
+ adjust_address (orig_src, DImode, ofs + i * 8));
nregs += words;
bytes -= words * 8;
ofs += words * 8;
}
- if (src_align >= 4 && bytes >= 4)
+
+ if (src_align >= 32 && bytes >= 4)
{
words = bytes / 4;
for (i = 0; i < words; ++i)
- data_regs[nregs+i] = gen_reg_rtx(SImode);
+ data_regs[nregs + i] = gen_reg_rtx (SImode);
for (i = 0; i < words; ++i)
- {
- emit_move_insn (data_regs[nregs+i],
- change_address (orig_src, SImode,
- plus_constant (XEXP (orig_src, 0),
- ofs + i*4)));
- }
+ emit_move_insn (data_regs[nregs + i],
+ adjust_address (orig_src, SImode, ofs + i * 4));
nregs += words;
bytes -= words * 4;
ofs += words * 4;
}
- if (bytes >= 16)
+
+ if (bytes >= 8)
{
words = bytes / 8;
for (i = 0; i < words+1; ++i)
- data_regs[nregs+i] = gen_reg_rtx(DImode);
+ data_regs[nregs + i] = gen_reg_rtx (DImode);
alpha_expand_unaligned_load_words (data_regs + nregs, orig_src,
words, ofs);
@@ -2038,35 +4274,27 @@ alpha_expand_block_move (operands)
bytes -= words * 8;
ofs += words * 8;
}
- if (!TARGET_BWX && bytes >= 8)
- {
- data_regs[nregs++] = tmp = gen_reg_rtx (DImode);
- alpha_expand_unaligned_load (tmp, orig_src, 8, ofs, 0);
- bytes -= 8;
- ofs += 8;
- }
- if (!TARGET_BWX && bytes >= 4)
+
+ if (! TARGET_BWX && bytes >= 4)
{
data_regs[nregs++] = tmp = gen_reg_rtx (SImode);
alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0);
bytes -= 4;
ofs += 4;
}
+
if (bytes >= 2)
{
- if (src_align >= 2)
+ if (src_align >= 16)
{
do {
data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
- emit_move_insn (tmp,
- change_address (orig_src, HImode,
- plus_constant (XEXP (orig_src, 0),
- ofs)));
+ emit_move_insn (tmp, adjust_address (orig_src, HImode, ofs));
bytes -= 2;
ofs += 2;
} while (bytes >= 2);
}
- else if (!TARGET_BWX)
+ else if (! TARGET_BWX)
{
data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0);
@@ -2074,24 +4302,21 @@ alpha_expand_block_move (operands)
ofs += 2;
}
}
+
while (bytes > 0)
{
data_regs[nregs++] = tmp = gen_reg_rtx (QImode);
- emit_move_insn (tmp,
- change_address (orig_src, QImode,
- plus_constant (XEXP (orig_src, 0),
- ofs)));
+ emit_move_insn (tmp, adjust_address (orig_src, QImode, ofs));
bytes -= 1;
ofs += 1;
}
+
src_done:
- if (nregs > (int)(sizeof(data_regs)/sizeof(*data_regs)))
- abort();
+ if (nregs > ARRAY_SIZE (data_regs))
+ abort ();
- /*
- * Now save it back out again.
- */
+ /* Now save it back out again. */
i = 0, ofs = 0;
@@ -2109,15 +4334,14 @@ alpha_expand_block_move (operands)
i = 1;
goto dst_done;
}
+
else if (nregs == 2 && mode == TImode)
{
/* Undo the subregging done above when copying between
two TImode registers. */
if (GET_CODE (data_regs[0]) == SUBREG
&& GET_MODE (SUBREG_REG (data_regs[0])) == TImode)
- {
- emit_move_insn (tmp, SUBREG_REG (data_regs[0]));
- }
+ emit_move_insn (tmp, SUBREG_REG (data_regs[0]));
else
{
rtx seq;
@@ -2142,25 +4366,24 @@ alpha_expand_block_move (operands)
/* No appropriate mode; fall back on memory. We can speed things
up by recognizing extra alignment information. */
- orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
- copy_addr_to_reg (XEXP (orig_dst, 0)));
- dst_align = GET_MODE_SIZE (GET_MODE (tmp));
+ orig_dst = replace_equiv_address (orig_dst,
+ copy_addr_to_reg (XEXP (orig_dst, 0)));
+ dst_align = GET_MODE_BITSIZE (GET_MODE (tmp));
}
/* Write out the data in whatever chunks reading the source allowed. */
- if (dst_align >= 8)
+ if (dst_align >= 64)
{
while (i < nregs && GET_MODE (data_regs[i]) == DImode)
{
- emit_move_insn (change_address (orig_dst, DImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
+ emit_move_insn (adjust_address (orig_dst, DImode, ofs),
data_regs[i]);
ofs += 8;
i++;
}
}
- if (dst_align >= 4)
+
+ if (dst_align >= 32)
{
/* If the source has remaining DImode regs, write them out in
two pieces. */
@@ -2169,13 +4392,9 @@ alpha_expand_block_move (operands)
tmp = expand_binop (DImode, lshr_optab, data_regs[i], GEN_INT (32),
NULL_RTX, 1, OPTAB_WIDEN);
- emit_move_insn (change_address (orig_dst, SImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
+ emit_move_insn (adjust_address (orig_dst, SImode, ofs),
gen_lowpart (SImode, data_regs[i]));
- emit_move_insn (change_address (orig_dst, SImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs+4)),
+ emit_move_insn (adjust_address (orig_dst, SImode, ofs + 4),
gen_lowpart (SImode, tmp));
ofs += 8;
i++;
@@ -2183,26 +4402,26 @@ alpha_expand_block_move (operands)
while (i < nregs && GET_MODE (data_regs[i]) == SImode)
{
- emit_move_insn (change_address(orig_dst, SImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
+ emit_move_insn (adjust_address (orig_dst, SImode, ofs),
data_regs[i]);
ofs += 4;
i++;
}
}
+
if (i < nregs && GET_MODE (data_regs[i]) == DImode)
{
/* Write out a remaining block of words using unaligned methods. */
- for (words = 1; i+words < nregs ; ++words)
- if (GET_MODE (data_regs[i+words]) != DImode)
+ for (words = 1; i + words < nregs; words++)
+ if (GET_MODE (data_regs[i + words]) != DImode)
break;
if (words == 1)
alpha_expand_unaligned_store (orig_dst, data_regs[i], 8, ofs);
else
- alpha_expand_unaligned_store_words (data_regs+i, orig_dst, words, ofs);
+ alpha_expand_unaligned_store_words (data_regs + i, orig_dst,
+ words, ofs);
i += words;
ofs += words * 8;
@@ -2218,13 +4437,10 @@ alpha_expand_block_move (operands)
i++;
}
- if (dst_align >= 2)
+ if (dst_align >= 16)
while (i < nregs && GET_MODE (data_regs[i]) == HImode)
{
- emit_move_insn (change_address (orig_dst, HImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
- data_regs[i]);
+ emit_move_insn (adjust_address (orig_dst, HImode, ofs), data_regs[i]);
i++;
ofs += 2;
}
@@ -2235,19 +4451,18 @@ alpha_expand_block_move (operands)
i++;
ofs += 2;
}
+
while (i < nregs && GET_MODE (data_regs[i]) == QImode)
{
- emit_move_insn (change_address (orig_dst, QImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
- data_regs[i]);
+ emit_move_insn (adjust_address (orig_dst, QImode, ofs), data_regs[i]);
i++;
ofs += 1;
}
+
dst_done:
if (i != nregs)
- abort();
+ abort ();
return 1;
}
@@ -2258,25 +4473,23 @@ alpha_expand_block_clear (operands)
{
rtx bytes_rtx = operands[1];
rtx align_rtx = operands[2];
- HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
- HOST_WIDE_INT align = INTVAL (align_rtx);
- rtx orig_dst = operands[0];
+ HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx);
+ HOST_WIDE_INT bytes = orig_bytes;
+ HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT;
+ HOST_WIDE_INT alignofs = 0;
+ rtx orig_dst = operands[0];
rtx tmp;
- HOST_WIDE_INT i, words, ofs = 0;
+ int i, words, ofs = 0;
- if (bytes <= 0)
+ if (orig_bytes <= 0)
return 1;
- if (bytes > MAX_MOVE_WORDS*8)
+ if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD)
return 0;
/* Look for stricter alignment. */
-
tmp = XEXP (orig_dst, 0);
if (GET_CODE (tmp) == REG)
- {
- if (REGNO_POINTER_ALIGN (REGNO (tmp)) > align)
- align = REGNO_POINTER_ALIGN (REGNO (tmp));
- }
+ align = MAX (align, REGNO_POINTER_ALIGN (REGNO (tmp)));
else if (GET_CODE (tmp) == PLUS
&& GET_CODE (XEXP (tmp, 0)) == REG
&& GET_CODE (XEXP (tmp, 1)) == CONST_INT)
@@ -2286,12 +4499,12 @@ alpha_expand_block_clear (operands)
if (a > align)
{
- if (a >= 8 && c % 8 == 0)
- align = 8;
- else if (a >= 4 && c % 4 == 0)
- align = 4;
- else if (a >= 2 && c % 2 == 0)
- align = 2;
+ if (a >= 64)
+ align = a, alignofs = 8 - c % 8;
+ else if (a >= 32)
+ align = a, alignofs = 4 - c % 4;
+ else if (a >= 16)
+ align = a, alignofs = 2 - c % 2;
}
}
else if (GET_CODE (tmp) == ADDRESSOF)
@@ -2306,44 +4519,149 @@ alpha_expand_block_clear (operands)
}
/* No appropriate mode; fall back on memory. */
- orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
- copy_addr_to_reg (tmp));
- align = GET_MODE_SIZE (GET_MODE (XEXP (tmp, 0)));
+ orig_dst = replace_equiv_address (orig_dst, copy_addr_to_reg (tmp));
+ align = GET_MODE_BITSIZE (GET_MODE (XEXP (tmp, 0)));
}
- /* Handle a block of contiguous words first. */
+ /* Handle an unaligned prefix first. */
- if (align >= 8 && bytes >= 8)
+ if (alignofs > 0)
{
- words = bytes / 8;
+#if HOST_BITS_PER_WIDE_INT >= 64
+ /* Given that alignofs is bounded by align, the only time BWX could
+ generate three stores is for a 7 byte fill. Prefer two individual
+ stores over a load/mask/store sequence. */
+ if ((!TARGET_BWX || alignofs == 7)
+ && align >= 32
+ && !(alignofs == 4 && bytes >= 4))
+ {
+ enum machine_mode mode = (align >= 64 ? DImode : SImode);
+ int inv_alignofs = (align >= 64 ? 8 : 4) - alignofs;
+ rtx mem, tmp;
+ HOST_WIDE_INT mask;
- for (i = 0; i < words; ++i)
+ mem = adjust_address (orig_dst, mode, ofs - inv_alignofs);
+ set_mem_alias_set (mem, 0);
+
+ mask = ~(~(HOST_WIDE_INT)0 << (inv_alignofs * 8));
+ if (bytes < alignofs)
+ {
+ mask |= ~(HOST_WIDE_INT)0 << ((inv_alignofs + bytes) * 8);
+ ofs += bytes;
+ bytes = 0;
+ }
+ else
+ {
+ bytes -= alignofs;
+ ofs += alignofs;
+ }
+ alignofs = 0;
+
+ tmp = expand_binop (mode, and_optab, mem, GEN_INT (mask),
+ NULL_RTX, 1, OPTAB_WIDEN);
+
+ emit_move_insn (mem, tmp);
+ }
+#endif
+
+ if (TARGET_BWX && (alignofs & 1) && bytes >= 1)
+ {
+ emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx);
+ bytes -= 1;
+ ofs += 1;
+ alignofs -= 1;
+ }
+ if (TARGET_BWX && align >= 16 && (alignofs & 3) == 2 && bytes >= 2)
+ {
+ emit_move_insn (adjust_address (orig_dst, HImode, ofs), const0_rtx);
+ bytes -= 2;
+ ofs += 2;
+ alignofs -= 2;
+ }
+ if (alignofs == 4 && bytes >= 4)
{
- emit_move_insn (change_address(orig_dst, DImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs + i*8)),
- const0_rtx);
+ emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx);
+ bytes -= 4;
+ ofs += 4;
+ alignofs = 0;
}
+ /* If we've not used the extra lead alignment information by now,
+ we won't be able to. Downgrade align to match what's left over. */
+ if (alignofs > 0)
+ {
+ alignofs = alignofs & -alignofs;
+ align = MIN (align, alignofs * BITS_PER_UNIT);
+ }
+ }
+
+ /* Handle a block of contiguous long-words. */
+
+ if (align >= 64 && bytes >= 8)
+ {
+ words = bytes / 8;
+
+ for (i = 0; i < words; ++i)
+ emit_move_insn (adjust_address (orig_dst, DImode, ofs + i * 8),
+ const0_rtx);
+
bytes -= words * 8;
ofs += words * 8;
}
- if (align >= 4 && bytes >= 4)
+
+ /* If the block is large and appropriately aligned, emit a single
+ store followed by a sequence of stq_u insns. */
+
+ if (align >= 32 && bytes > 16)
{
- words = bytes / 4;
+ rtx orig_dsta;
+
+ emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx);
+ bytes -= 4;
+ ofs += 4;
+ orig_dsta = XEXP (orig_dst, 0);
+ if (GET_CODE (orig_dsta) == LO_SUM)
+ orig_dsta = force_reg (Pmode, orig_dsta);
+
+ words = bytes / 8;
for (i = 0; i < words; ++i)
{
- emit_move_insn (change_address (orig_dst, SImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs + i*4)),
- const0_rtx);
+ rtx mem
+ = change_address (orig_dst, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (orig_dsta, ofs + i*8),
+ GEN_INT (-8)));
+ set_mem_alias_set (mem, 0);
+ emit_move_insn (mem, const0_rtx);
}
+ /* Depending on the alignment, the first stq_u may have overlapped
+ with the initial stl, which means that the last stq_u didn't
+ write as much as it would appear. Leave those questionable bytes
+ unaccounted for. */
+ bytes -= words * 8 - 4;
+ ofs += words * 8 - 4;
+ }
+
+ /* Handle a smaller block of aligned words. */
+
+ if ((align >= 64 && bytes == 4)
+ || (align == 32 && bytes >= 4))
+ {
+ words = bytes / 4;
+
+ for (i = 0; i < words; ++i)
+ emit_move_insn (adjust_address (orig_dst, SImode, ofs + i * 4),
+ const0_rtx);
+
bytes -= words * 4;
ofs += words * 4;
}
- if (bytes >= 16)
+
+ /* An unaligned block uses stq_u stores for as many as possible. */
+
+ if (bytes >= 8)
{
words = bytes / 8;
@@ -2353,59 +4671,95 @@ alpha_expand_block_clear (operands)
ofs += words * 8;
}
- /* Next clean up any trailing pieces. We know from the contiguous
- block move that there are no aligned SImode or DImode hunks left. */
+ /* Next clean up any trailing pieces. */
- if (!TARGET_BWX && bytes >= 8)
+#if HOST_BITS_PER_WIDE_INT >= 64
+ /* Count the number of bits in BYTES for which aligned stores could
+ be emitted. */
+ words = 0;
+ for (i = (TARGET_BWX ? 1 : 4); i * BITS_PER_UNIT <= align ; i <<= 1)
+ if (bytes & i)
+ words += 1;
+
+ /* If we have appropriate alignment (and it wouldn't take too many
+ instructions otherwise), mask out the bytes we need. */
+ if (TARGET_BWX ? words > 2 : bytes > 0)
{
- alpha_expand_unaligned_store (orig_dst, const0_rtx, 8, ofs);
- bytes -= 8;
- ofs += 8;
+ if (align >= 64)
+ {
+ rtx mem, tmp;
+ HOST_WIDE_INT mask;
+
+ mem = adjust_address (orig_dst, DImode, ofs);
+ set_mem_alias_set (mem, 0);
+
+ mask = ~(HOST_WIDE_INT)0 << (bytes * 8);
+
+ tmp = expand_binop (DImode, and_optab, mem, GEN_INT (mask),
+ NULL_RTX, 1, OPTAB_WIDEN);
+
+ emit_move_insn (mem, tmp);
+ return 1;
+ }
+ else if (align >= 32 && bytes < 4)
+ {
+ rtx mem, tmp;
+ HOST_WIDE_INT mask;
+
+ mem = adjust_address (orig_dst, SImode, ofs);
+ set_mem_alias_set (mem, 0);
+
+ mask = ~(HOST_WIDE_INT)0 << (bytes * 8);
+
+ tmp = expand_binop (SImode, and_optab, mem, GEN_INT (mask),
+ NULL_RTX, 1, OPTAB_WIDEN);
+
+ emit_move_insn (mem, tmp);
+ return 1;
+ }
}
+#endif
+
if (!TARGET_BWX && bytes >= 4)
{
alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs);
bytes -= 4;
ofs += 4;
}
+
if (bytes >= 2)
{
- if (align >= 2)
+ if (align >= 16)
{
do {
- emit_move_insn (change_address (orig_dst, HImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
+ emit_move_insn (adjust_address (orig_dst, HImode, ofs),
const0_rtx);
bytes -= 2;
ofs += 2;
} while (bytes >= 2);
}
- else if (!TARGET_BWX)
+ else if (! TARGET_BWX)
{
alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs);
bytes -= 2;
ofs += 2;
}
}
+
while (bytes > 0)
{
- emit_move_insn (change_address (orig_dst, QImode,
- plus_constant (XEXP (orig_dst, 0),
- ofs)),
- const0_rtx);
+ emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx);
bytes -= 1;
ofs += 1;
}
return 1;
}
-
/* Adjust the cost of a scheduling dependency. Return the new cost of
a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
-int
+static int
alpha_adjust_cost (insn, link, dep_insn, cost)
rtx insn;
rtx link;
@@ -2546,52 +4900,71 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
break;
}
- /* Otherwise, return the default cost. */
+ /* Otherwise, return the default cost. */
return cost;
}
-
-/* Functions to save and restore alpha_return_addr_rtx. */
-struct machine_function
+/* Function to initialize the issue rate used by the scheduler. */
+static int
+alpha_issue_rate ()
{
- rtx ra_rtx;
-};
+ return (alpha_cpu == PROCESSOR_EV4 ? 2 : 4);
+}
+
+static int
+alpha_variable_issue (dump, verbose, insn, cim)
+ FILE *dump ATTRIBUTE_UNUSED;
+ int verbose ATTRIBUTE_UNUSED;
+ rtx insn;
+ int cim;
+{
+ if (recog_memoized (insn) < 0 || get_attr_type (insn) == TYPE_MULTI)
+ return 0;
+
+ return cim - 1;
+}
+
+
+/* Register global variables and machine-specific functions with the
+ garbage collector. */
+#if TARGET_ABI_UNICOSMK
static void
-alpha_save_machine_status (p)
+alpha_init_machine_status (p)
struct function *p;
{
- struct machine_function *machine =
- (struct machine_function *) xmalloc (sizeof (struct machine_function));
+ p->machine =
+ (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
- p->machine = machine;
- machine->ra_rtx = alpha_return_addr_rtx;
+ p->machine->first_ciw = NULL_RTX;
+ p->machine->last_ciw = NULL_RTX;
+ p->machine->ciw_count = 0;
+ p->machine->addr_list = NULL_RTX;
}
static void
-alpha_restore_machine_status (p)
+alpha_mark_machine_status (p)
struct function *p;
{
struct machine_function *machine = p->machine;
- alpha_return_addr_rtx = machine->ra_rtx;
-
- free (machine);
- p->machine = (struct machine_function *)0;
+ if (machine)
+ {
+ ggc_mark_rtx (machine->first_ciw);
+ ggc_mark_rtx (machine->addr_list);
+ }
}
-/* Do anything needed before RTL is emitted for each function. */
-
-void
-alpha_init_expanders ()
+static void
+alpha_free_machine_status (p)
+ struct function *p;
{
- alpha_return_addr_rtx = NULL_RTX;
- alpha_eh_epilogue_sp_ofs = NULL_RTX;
-
- /* Arrange to save and restore machine status around nested functions. */
- save_machine_status = alpha_save_machine_status;
- restore_machine_status = alpha_restore_machine_status;
+ free (p->machine);
+ p->machine = NULL;
}
+#endif /* TARGET_ABI_UNICOSMK */
+
+/* Functions to save and restore alpha_return_addr_rtx. */
/* Start the ball rolling with RETURN_ADDR_RTX. */
@@ -2600,25 +4973,19 @@ alpha_return_addr (count, frame)
int count;
rtx frame ATTRIBUTE_UNUSED;
{
- rtx init;
-
if (count != 0)
return const0_rtx;
- if (alpha_return_addr_rtx)
- return alpha_return_addr_rtx;
+ return get_hard_reg_initial_val (Pmode, REG_RA);
+}
- /* No rtx yet. Invent one, and initialize it from $26 in the prologue. */
- alpha_return_addr_rtx = gen_reg_rtx (Pmode);
- init = gen_rtx_SET (VOIDmode, alpha_return_addr_rtx,
- gen_rtx_REG (Pmode, REG_RA));
+/* Return or create a pseudo containing the gp value for the current
+ function. Needed only if TARGET_LD_BUGGY_LDGP. */
- /* Emit the insn to the prologue with the other argument copies. */
- push_topmost_sequence ();
- emit_insn_after (init, get_insns ());
- pop_topmost_sequence ();
-
- return alpha_return_addr_rtx;
+rtx
+alpha_gp_save_rtx ()
+{
+ return get_hard_reg_initial_val (DImode, 29);
}
static int
@@ -2630,7 +4997,7 @@ alpha_ra_ever_killed ()
if (current_function_is_thunk)
return 0;
#endif
- if (!alpha_return_addr_rtx)
+ if (!has_hard_reg_initial_val (Pmode, REG_RA))
return regs_ever_live[REG_RA];
push_topmost_sequence ();
@@ -2641,125 +5008,170 @@ alpha_ra_ever_killed ()
}
-/* Print an operand. Recognize special options, documented below. */
+/* Return the trap mode suffix applicable to the current
+ instruction, or NULL. */
-void
-print_operand (file, x, code)
- FILE *file;
- rtx x;
- char code;
+static const char *
+get_trap_mode_suffix ()
{
- int i;
+ enum attr_trap_suffix s = get_attr_trap_suffix (current_output_insn);
- switch (code)
+ switch (s)
{
- case '&':
- /* Generates fp-rounding mode suffix: nothing for normal, 'c' for
- chopped, 'm' for minus-infinity, and 'd' for dynamic rounding
- mode. alpha_fprm controls which suffix is generated. */
- switch (alpha_fprm)
- {
- case ALPHA_FPRM_NORM:
- break;
- case ALPHA_FPRM_MINF:
- fputc ('m', file);
- break;
- case ALPHA_FPRM_CHOP:
- fputc ('c', file);
- break;
- case ALPHA_FPRM_DYN:
- fputc ('d', file);
- break;
- }
- break;
+ case TRAP_SUFFIX_NONE:
+ return NULL;
- case '\'':
- /* Generates trap-mode suffix for instructions that accept the su
- suffix only (cmpt et al). */
- if (alpha_tp == ALPHA_TP_INSN)
- fputs ("su", file);
- break;
+ case TRAP_SUFFIX_SU:
+ if (alpha_fptm >= ALPHA_FPTM_SU)
+ return "su";
+ return NULL;
+
+ case TRAP_SUFFIX_SUI:
+ if (alpha_fptm >= ALPHA_FPTM_SUI)
+ return "sui";
+ return NULL;
- case '`':
- /* Generates trap-mode suffix for instructions that accept the
- v and sv suffix. The only instruction that needs this is cvtql. */
+ case TRAP_SUFFIX_V_SV:
switch (alpha_fptm)
{
case ALPHA_FPTM_N:
- break;
+ return NULL;
case ALPHA_FPTM_U:
- fputs ("v", file);
- break;
+ return "v";
case ALPHA_FPTM_SU:
case ALPHA_FPTM_SUI:
- fputs ("sv", file);
- break;
+ return "sv";
}
break;
- case '(':
- /* Generates trap-mode suffix for instructions that accept the
- v, sv, and svi suffix. The only instruction that needs this
- is cvttq. */
+ case TRAP_SUFFIX_V_SV_SVI:
switch (alpha_fptm)
{
case ALPHA_FPTM_N:
- break;
+ return NULL;
case ALPHA_FPTM_U:
- fputs ("v", file);
- break;
+ return "v";
case ALPHA_FPTM_SU:
- fputs ("sv", file);
- break;
+ return "sv";
case ALPHA_FPTM_SUI:
- fputs ("svi", file);
- break;
+ return "svi";
}
break;
- case ')':
- /* Generates trap-mode suffix for instructions that accept the u, su,
- and sui suffix. This is the bulk of the IEEE floating point
- instructions (addt et al). */
+ case TRAP_SUFFIX_U_SU_SUI:
switch (alpha_fptm)
{
case ALPHA_FPTM_N:
- break;
+ return NULL;
case ALPHA_FPTM_U:
- fputc ('u', file);
- break;
+ return "u";
case ALPHA_FPTM_SU:
- fputs ("su", file);
- break;
+ return "su";
case ALPHA_FPTM_SUI:
- fputs ("sui", file);
- break;
+ return "sui";
}
break;
+ }
+ abort ();
+}
- case '+':
- /* Generates trap-mode suffix for instructions that accept the sui
- suffix (cvtqt and cvtqs). */
- switch (alpha_fptm)
+/* Return the rounding mode suffix applicable to the current
+ instruction, or NULL. */
+
+static const char *
+get_round_mode_suffix ()
+{
+ enum attr_round_suffix s = get_attr_round_suffix (current_output_insn);
+
+ switch (s)
+ {
+ case ROUND_SUFFIX_NONE:
+ return NULL;
+ case ROUND_SUFFIX_NORMAL:
+ switch (alpha_fprm)
{
- case ALPHA_FPTM_N:
- case ALPHA_FPTM_U:
- case ALPHA_FPTM_SU: /* cvtqt/cvtqs can't cause underflow */
- break;
- case ALPHA_FPTM_SUI:
- fputs ("sui", file);
- break;
+ case ALPHA_FPRM_NORM:
+ return NULL;
+ case ALPHA_FPRM_MINF:
+ return "m";
+ case ALPHA_FPRM_CHOP:
+ return "c";
+ case ALPHA_FPRM_DYN:
+ return "d";
}
break;
+ case ROUND_SUFFIX_C:
+ return "c";
+ }
+ abort ();
+}
+
+/* Print an operand. Recognize special options, documented below. */
+
+void
+print_operand (file, x, code)
+ FILE *file;
+ rtx x;
+ int code;
+{
+ int i;
+
+ switch (code)
+ {
+ case '~':
+ /* Print the assembler name of the current function. */
+ assemble_name (file, alpha_fnname);
+ break;
+
+ case '/':
+ {
+ const char *trap = get_trap_mode_suffix ();
+ const char *round = get_round_mode_suffix ();
+
+ if (trap || round)
+ fprintf (file, (TARGET_AS_SLASH_BEFORE_SUFFIX ? "/%s%s" : "%s%s"),
+ (trap ? trap : ""), (round ? round : ""));
+ break;
+ }
+
case ',':
/* Generates single precision instruction suffix. */
- fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'f' : 's'));
+ fputc ((TARGET_FLOAT_VAX ? 'f' : 's'), file);
break;
case '-':
/* Generates double precision instruction suffix. */
- fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'g' : 't'));
+ fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file);
+ break;
+
+ case '#':
+ if (alpha_this_literal_sequence_number == 0)
+ alpha_this_literal_sequence_number = alpha_next_sequence_number++;
+ fprintf (file, "%d", alpha_this_literal_sequence_number);
+ break;
+
+ case '*':
+ if (alpha_this_gpdisp_sequence_number == 0)
+ alpha_this_gpdisp_sequence_number = alpha_next_sequence_number++;
+ fprintf (file, "%d", alpha_this_gpdisp_sequence_number);
+ break;
+
+ case 'H':
+ if (GET_CODE (x) == HIGH)
+ output_addr_const (file, XEXP (x, 0));
+ else
+ output_operand_lossage ("invalid %%H value");
+ break;
+
+ case 'J':
+ if (GET_CODE (x) == CONST_INT)
+ {
+ if (INTVAL (x) != 0)
+ fprintf (file, "\t\t!lituse_jsr!%d", (int) INTVAL (x));
+ }
+ else
+ output_operand_lossage ("invalid %%J value");
break;
case 'r':
@@ -2770,7 +5182,6 @@ print_operand (file, x, code)
fprintf (file, "$31");
else
output_operand_lossage ("invalid %%r value");
-
break;
case 'R':
@@ -2781,7 +5192,6 @@ print_operand (file, x, code)
fprintf (file, "$f31");
else
output_operand_lossage ("invalid %%R value");
-
break;
case 'N':
@@ -2897,13 +5307,20 @@ print_operand (file, x, code)
break;
case 's':
- /* Write the constant value divided by 8. */
+ /* Write the constant value divided by 8 for little-endian mode or
+ (56 - value) / 8 for big-endian mode. */
+
if (GET_CODE (x) != CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64
- && (INTVAL (x) & 7) != 8)
+ || (unsigned HOST_WIDE_INT) INTVAL (x) >= (WORDS_BIG_ENDIAN
+ ? 56
+ : 64)
+ || (INTVAL (x) & 7) != 0)
output_operand_lossage ("invalid %%s value");
- fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ WORDS_BIG_ENDIAN
+ ? (56 - INTVAL (x)) / 8
+ : INTVAL (x) / 8);
break;
case 'S':
@@ -2917,6 +5334,18 @@ print_operand (file, x, code)
fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8);
break;
+ case 't':
+ {
+ /* On Unicos/Mk systems: use a DEX expression if the symbol
+ clashes with a register name. */
+ int dex = unicosmk_need_dex (x);
+ if (dex)
+ fprintf (file, "DEX(%d)", dex);
+ else
+ output_addr_const (file, x);
+ }
+ break;
+
case 'C': case 'D': case 'c': case 'd':
/* Write out comparison name. */
{
@@ -2925,7 +5354,7 @@ print_operand (file, x, code)
if (GET_RTX_CLASS (c) != '<')
output_operand_lossage ("invalid %%C value");
- if (code == 'D')
+ else if (code == 'D')
c = reverse_condition (c);
else if (code == 'c')
c = swap_condition (c);
@@ -2936,6 +5365,8 @@ print_operand (file, x, code)
fprintf (file, "ule");
else if (c == LTU)
fprintf (file, "ult");
+ else if (c == UNORDERED)
+ fprintf (file, "un");
else
fprintf (file, "%s", GET_RTX_NAME (c));
}
@@ -3000,11 +5431,35 @@ print_operand_address (file, addr)
offset = INTVAL (XEXP (addr, 1));
addr = XEXP (addr, 0);
}
+
+ if (GET_CODE (addr) == LO_SUM)
+ {
+ output_addr_const (file, XEXP (addr, 1));
+ if (offset)
+ {
+ fputc ('+', file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
+ }
+
+ addr = XEXP (addr, 0);
+ if (GET_CODE (addr) == REG)
+ basereg = REGNO (addr);
+ else if (GET_CODE (addr) == SUBREG
+ && GET_CODE (SUBREG_REG (addr)) == REG)
+ basereg = subreg_regno (addr);
+ else
+ abort ();
+
+ fprintf (file, "($%d)\t\t!%s", basereg,
+ (basereg == 29 ? "gprel" : "gprellow"));
+ return;
+ }
+
if (GET_CODE (addr) == REG)
basereg = REGNO (addr);
else if (GET_CODE (addr) == SUBREG
&& GET_CODE (SUBREG_REG (addr)) == REG)
- basereg = REGNO (SUBREG_REG (addr)) + SUBREG_WORD (addr);
+ basereg = subreg_regno (addr);
else if (GET_CODE (addr) == CONST_INT)
offset = INTVAL (addr);
else
@@ -3034,7 +5489,7 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
{
rtx temp, temp1, addr;
/* VMS really uses DImode pointers in memory at this point. */
- enum machine_mode mode = TARGET_OPEN_VMS ? Pmode : ptr_mode;
+ enum machine_mode mode = TARGET_ABI_OPEN_VMS ? Pmode : ptr_mode;
#ifdef POINTERS_EXTEND_UNSIGNED
fnaddr = convert_memory_address (mode, fnaddr);
@@ -3043,12 +5498,12 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
/* Store function address and CXT. */
addr = memory_address (mode, plus_constant (tramp, fnofs));
- emit_move_insn (gen_rtx (MEM, mode, addr), fnaddr);
+ emit_move_insn (gen_rtx_MEM (mode, addr), fnaddr);
addr = memory_address (mode, plus_constant (tramp, cxtofs));
- emit_move_insn (gen_rtx (MEM, mode, addr), cxt);
+ emit_move_insn (gen_rtx_MEM (mode, addr), cxt);
/* This has been disabled since the hint only has a 32k range, and in
- no existing OS is the stack within 32k of the text segment. */
+ no existing OS is the stack within 32k of the text segment. */
if (0 && jmpofs >= 0)
{
/* Compute hint value. */
@@ -3061,15 +5516,15 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
/* Merge in the hint. */
addr = memory_address (SImode, plus_constant (tramp, jmpofs));
- temp1 = force_reg (SImode, gen_rtx (MEM, SImode, addr));
+ temp1 = force_reg (SImode, gen_rtx_MEM (SImode, addr));
temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX);
temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1,
OPTAB_WIDEN);
- emit_move_insn (gen_rtx (MEM, SImode, addr), temp1);
+ emit_move_insn (gen_rtx_MEM (SImode, addr), temp1);
}
#ifdef TRANSFER_FROM_TRAMPOLINE
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
0, VOIDmode, 1, addr, Pmode);
#endif
@@ -3077,101 +5532,296 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
emit_insn (gen_imb ());
}
-/* Do what is necessary for `va_start'. The argument is ignored;
- We look at the current function to determine if stdarg or varargs
- is used and fill in an initial va_list. A pointer to this constructor
- is returned. */
-
-struct rtx_def *
-alpha_builtin_saveregs (arglist)
- tree arglist ATTRIBUTE_UNUSED;
-{
- rtx block, addr, dest, argsize;
- tree fntype = TREE_TYPE (current_function_decl);
- int stdarg = (TYPE_ARG_TYPES (fntype) != 0
- && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
- != void_type_node));
-
- /* Compute the current position into the args, taking into account
- both registers and memory. Both of these are already included in
- NUM_ARGS. */
-
- argsize = GEN_INT (NUM_ARGS * UNITS_PER_WORD);
-
- /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base up by 48,
- storing fp arg registers in the first 48 bytes, and the integer arg
- registers in the next 48 bytes. This is only done, however, if any
- integer registers need to be stored.
-
- If no integer registers need be stored, then we must subtract 48 in
- order to account for the integer arg registers which are counted in
- argsize above, but which are not actually stored on the stack. */
-
- if (TARGET_OPEN_VMS)
- addr = plus_constant (virtual_incoming_args_rtx,
- NUM_ARGS <= 5 + stdarg
- ? UNITS_PER_WORD : - 6 * UNITS_PER_WORD);
+/* Determine where to put an argument to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis).
+
+ On Alpha the first 6 words of args are normally in registers
+ and the rest are pushed. */
+
+rtx
+function_arg (cum, mode, type, named)
+ CUMULATIVE_ARGS cum;
+ enum machine_mode mode;
+ tree type;
+ int named ATTRIBUTE_UNUSED;
+{
+ int basereg;
+ int num_args;
+
+ /* Set up defaults for FP operands passed in FP registers, and
+ integral operands passed in integer registers. */
+ if (TARGET_FPREGS
+ && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ || GET_MODE_CLASS (mode) == MODE_FLOAT))
+ basereg = 32 + 16;
else
- addr = (NUM_ARGS <= 5 + stdarg
- ? plus_constant (virtual_incoming_args_rtx,
- 6 * UNITS_PER_WORD)
- : plus_constant (virtual_incoming_args_rtx,
- - (6 * UNITS_PER_WORD)));
+ basereg = 16;
+
+ /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for
+ the three platforms, so we can't avoid conditional compilation. */
+#if TARGET_ABI_OPEN_VMS
+ {
+ if (mode == VOIDmode)
+ return alpha_arg_info_reg_val (cum);
+
+ num_args = cum.num_args;
+ if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type))
+ return NULL_RTX;
+ }
+#else
+#if TARGET_ABI_UNICOSMK
+ {
+ int size;
- /* For VMS, we include the argsize, while on Unix, it's handled as
- a separate field. */
- if (TARGET_OPEN_VMS)
- addr = plus_constant (addr, INTVAL (argsize));
+ /* If this is the last argument, generate the call info word (CIW). */
+ /* ??? We don't include the caller's line number in the CIW because
+ I don't know how to determine it if debug infos are turned off. */
+ if (mode == VOIDmode)
+ {
+ int i;
+ HOST_WIDE_INT lo;
+ HOST_WIDE_INT hi;
+ rtx ciw;
- addr = force_operand (addr, NULL_RTX);
+ lo = 0;
-#ifdef POINTERS_EXTEND_UNSIGNED
- addr = convert_memory_address (ptr_mode, addr);
+ for (i = 0; i < cum.num_reg_words && i < 5; i++)
+ if (cum.reg_args_type[i])
+ lo |= (1 << (7 - i));
+
+ if (cum.num_reg_words == 6 && cum.reg_args_type[5])
+ lo |= 7;
+ else
+ lo |= cum.num_reg_words;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ hi = (cum.num_args << 20) | cum.num_arg_words;
+#else
+ lo = lo | ((HOST_WIDE_INT) cum.num_args << 52)
+ | ((HOST_WIDE_INT) cum.num_arg_words << 32);
+ hi = 0;
#endif
+ ciw = immed_double_const (lo, hi, DImode);
+
+ return gen_rtx_UNSPEC (DImode, gen_rtvec (1, ciw),
+ UNSPEC_UMK_LOAD_CIW);
+ }
+
+ size = ALPHA_ARG_SIZE (mode, type, named);
+ num_args = cum.num_reg_words;
+ if (MUST_PASS_IN_STACK (mode, type)
+ || cum.num_reg_words + size > 6 || cum.force_stack)
+ return NULL_RTX;
+ else if (type && TYPE_MODE (type) == BLKmode)
+ {
+ rtx reg1, reg2;
+
+ reg1 = gen_rtx_REG (DImode, num_args + 16);
+ reg1 = gen_rtx_EXPR_LIST (DImode, reg1, const0_rtx);
+
+ /* The argument fits in two registers. Note that we still need to
+ reserve a register for empty structures. */
+ if (size == 0)
+ return NULL_RTX;
+ else if (size == 1)
+ return gen_rtx_PARALLEL (mode, gen_rtvec (1, reg1));
+ else
+ {
+ reg2 = gen_rtx_REG (DImode, num_args + 17);
+ reg2 = gen_rtx_EXPR_LIST (DImode, reg2, GEN_INT (8));
+ return gen_rtx_PARALLEL (mode, gen_rtvec (2, reg1, reg2));
+ }
+ }
+ }
+#else
+ {
+ if (cum >= 6)
+ return NULL_RTX;
+ num_args = cum;
+
+ /* VOID is passed as a special flag for "last argument". */
+ if (type == void_type_node)
+ basereg = 16;
+ else if (MUST_PASS_IN_STACK (mode, type))
+ return NULL_RTX;
+ else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named))
+ basereg = 16;
+ }
+#endif /* TARGET_ABI_UNICOSMK */
+#endif /* TARGET_ABI_OPEN_VMS */
+
+ return gen_rtx_REG (mode, num_args + basereg);
+}
+
+tree
+alpha_build_va_list ()
+{
+ tree base, ofs, record, type_decl;
+
+ if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
+ return ptr_type_node;
+
+ record = make_lang_type (RECORD_TYPE);
+ type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
+ TREE_CHAIN (record) = type_decl;
+ TYPE_NAME (record) = type_decl;
- if (TARGET_OPEN_VMS)
- return addr;
+ /* C++? SET_IS_AGGR_TYPE (record, 1); */
+
+ ofs = build_decl (FIELD_DECL, get_identifier ("__offset"),
+ integer_type_node);
+ DECL_FIELD_CONTEXT (ofs) = record;
+
+ base = build_decl (FIELD_DECL, get_identifier ("__base"),
+ ptr_type_node);
+ DECL_FIELD_CONTEXT (base) = record;
+ TREE_CHAIN (base) = ofs;
+
+ TYPE_FIELDS (record) = base;
+ layout_type (record);
+
+ return record;
+}
+
+void
+alpha_va_start (stdarg_p, valist, nextarg)
+ int stdarg_p;
+ tree valist;
+ rtx nextarg ATTRIBUTE_UNUSED;
+{
+ HOST_WIDE_INT offset;
+ tree t, offset_field, base_field;
+
+ if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK)
+ return;
+
+ if (TARGET_ABI_UNICOSMK)
+ std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+
+ /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base
+ up by 48, storing fp arg registers in the first 48 bytes, and the
+ integer arg registers in the next 48 bytes. This is only done,
+ however, if any integer registers need to be stored.
+
+ If no integer registers need be stored, then we must subtract 48
+ in order to account for the integer arg registers which are counted
+ in argsize above, but which are not actually stored on the stack. */
+
+ if (NUM_ARGS <= 5 + stdarg_p)
+ offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD;
else
+ offset = -6 * UNITS_PER_WORD;
+
+ if (TARGET_ABI_OPEN_VMS)
{
- /* Allocate the va_list constructor */
- block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD);
- RTX_UNCHANGING_P (block) = 1;
- RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
+ nextarg = plus_constant (nextarg, offset);
+ nextarg = plus_constant (nextarg, NUM_ARGS * UNITS_PER_WORD);
+ t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+ make_tree (ptr_type_node, nextarg));
+ TREE_SIDE_EFFECTS (t) = 1;
- /* Store the address of the first integer register in the __base
- member. */
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+ else
+ {
+ base_field = TYPE_FIELDS (TREE_TYPE (valist));
+ offset_field = TREE_CHAIN (base_field);
+
+ base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
+ valist, base_field);
+ offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
+ valist, offset_field);
+
+ t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
+ t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ t = build_int_2 (NUM_ARGS * UNITS_PER_WORD, 0);
+ t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+}
+
+rtx
+alpha_va_arg (valist, type)
+ tree valist, type;
+{
+ HOST_WIDE_INT tsize;
+ rtx addr;
+ tree t;
+ tree offset_field, base_field, addr_tree, addend;
+ tree wide_type, wide_ofs;
+ int indirect = 0;
- dest = change_address (block, ptr_mode, XEXP (block, 0));
- emit_move_insn (dest, addr);
+ if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
+ return std_expand_builtin_va_arg (valist, type);
- if (current_function_check_memory_usage)
- emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
- dest, ptr_mode,
- GEN_INT (GET_MODE_SIZE (ptr_mode)),
- TYPE_MODE (sizetype),
- GEN_INT (MEMORY_USE_RW),
- TYPE_MODE (integer_type_node));
-
- /* Store the argsize as the __va_offset member. */
- dest = change_address (block, TYPE_MODE (integer_type_node),
- plus_constant (XEXP (block, 0),
- POINTER_SIZE/BITS_PER_UNIT));
- emit_move_insn (dest, argsize);
-
- if (current_function_check_memory_usage)
- emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
- dest, ptr_mode,
- GEN_INT (GET_MODE_SIZE
- (TYPE_MODE (integer_type_node))),
- TYPE_MODE (sizetype),
- GEN_INT (MEMORY_USE_RW),
- TYPE_MODE (integer_type_node));
-
- /* Return the address of the va_list constructor, but don't put it in a
- register. Doing so would fail when not optimizing and produce worse
- code when optimizing. */
- return XEXP (block, 0);
+ tsize = ((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT + 7) / 8) * 8;
+
+ base_field = TYPE_FIELDS (TREE_TYPE (valist));
+ offset_field = TREE_CHAIN (base_field);
+
+ base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
+ valist, base_field);
+ offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
+ valist, offset_field);
+
+ wide_type = make_signed_type (64);
+ wide_ofs = save_expr (build1 (CONVERT_EXPR, wide_type, offset_field));
+
+ addend = wide_ofs;
+
+ if (TYPE_MODE (type) == TFmode || TYPE_MODE (type) == TCmode)
+ {
+ indirect = 1;
+ tsize = UNITS_PER_WORD;
+ }
+ else if (FLOAT_TYPE_P (type))
+ {
+ tree fpaddend, cond;
+
+ fpaddend = fold (build (PLUS_EXPR, TREE_TYPE (addend),
+ addend, build_int_2 (-6*8, 0)));
+
+ cond = fold (build (LT_EXPR, integer_type_node,
+ wide_ofs, build_int_2 (6*8, 0)));
+
+ addend = fold (build (COND_EXPR, TREE_TYPE (addend), cond,
+ fpaddend, addend));
}
+
+ addr_tree = build (PLUS_EXPR, TREE_TYPE (base_field),
+ base_field, addend);
+
+ addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr = copy_to_reg (addr);
+
+ t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field,
+ build (PLUS_EXPR, TREE_TYPE (offset_field),
+ offset_field, build_int_2 (tsize, 0)));
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ if (indirect)
+ {
+ addr = force_reg (Pmode, addr);
+ addr = gen_rtx_MEM (Pmode, addr);
+ }
+
+ return addr;
}
/* This page contains routines that are used to determine what the function
@@ -3182,10 +5832,10 @@ alpha_builtin_saveregs (arglist)
/* These variables are used for communication between the following functions.
They indicate various things about the current function being compiled
that are used to tell what kind of prologue, epilogue and procedure
- descriptior to generate. */
+ descriptior to generate. */
/* Nonzero if we need a stack procedure. */
-static int vms_is_stack_procedure;
+static int alpha_is_stack_procedure;
/* Register number (either FP or SP) that is used to unwind the frame. */
static int vms_unwind_regno;
@@ -3207,19 +5857,20 @@ alpha_sa_mask (imaskP, fmaskP)
{
unsigned long imask = 0;
unsigned long fmask = 0;
- int i;
+ unsigned int i;
#ifdef ASM_OUTPUT_MI_THUNK
if (!current_function_is_thunk)
#endif
{
- if (TARGET_OPEN_VMS && vms_is_stack_procedure)
+ if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
imask |= (1L << HARD_FRAME_POINTER_REGNUM);
/* One for every register we have to save. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (! fixed_regs[i] && ! call_used_regs[i]
- && regs_ever_live[i] && i != REG_RA)
+ && regs_ever_live[i] && i != REG_RA
+ && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
{
if (i < 32)
imask |= (1L << i);
@@ -3227,6 +5878,21 @@ alpha_sa_mask (imaskP, fmaskP)
fmask |= (1L << (i - 32));
}
+ /* We need to restore these for the handler. */
+ if (current_function_calls_eh_return)
+ {
+ for (i = 0; ; ++i)
+ {
+ unsigned regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+ imask |= 1L << regno;
+ }
+ }
+
+ /* If any register spilled, then spill the return address also. */
+ /* ??? This is required by the Digital stack unwind specification
+ and isn't needed if we're doing Dwarf2 unwinding. */
if (imask || fmask || alpha_ra_ever_killed ())
imask |= (1L << REG_RA);
}
@@ -3238,28 +5904,57 @@ alpha_sa_mask (imaskP, fmaskP)
int
alpha_sa_size ()
{
+ unsigned long mask[2];
int sa_size = 0;
- int i;
+ int i, j;
-#ifdef ASM_OUTPUT_MI_THUNK
- if (current_function_is_thunk)
- sa_size = 0;
+ alpha_sa_mask (&mask[0], &mask[1]);
+
+ if (TARGET_ABI_UNICOSMK)
+ {
+ if (mask[0] || mask[1])
+ sa_size = 14;
+ }
else
-#endif
{
- /* One for every register we have to save. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (! fixed_regs[i] && ! call_used_regs[i]
- && regs_ever_live[i] && i != REG_RA)
- sa_size++;
+ for (j = 0; j < 2; ++j)
+ for (i = 0; i < 32; ++i)
+ if ((mask[j] >> i) & 1)
+ sa_size++;
}
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_UNICOSMK)
+ {
+ /* We might not need to generate a frame if we don't make any calls
+ (including calls to __T3E_MISMATCH if this is a vararg function),
+ don't have any local variables which require stack slots, don't
+ use alloca and have not determined that we need a frame for other
+ reasons. */
+
+ alpha_is_stack_procedure = (sa_size
+ || get_frame_size() != 0
+ || current_function_outgoing_args_size
+ || current_function_varargs
+ || current_function_stdarg
+ || current_function_calls_alloca
+ || frame_pointer_needed);
+
+ /* Always reserve space for saving callee-saved registers if we
+ need a frame as required by the calling convention. */
+ if (alpha_is_stack_procedure)
+ sa_size = 14;
+ }
+ else if (TARGET_ABI_OPEN_VMS)
{
/* Start by assuming we can use a register procedure if we don't
make any calls (REG_RA not used) or need to save any
registers and a stack procedure if we do. */
- vms_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed ();
+ alpha_is_stack_procedure = ((mask[0] >> REG_RA) & 1);
+
+ /* Don't reserve space for saving RA yet. Do that later after we've
+ made the final decision on stack procedure vs register procedure. */
+ if (alpha_is_stack_procedure)
+ sa_size--;
/* Decide whether to refer to objects off our PV via FP or PV.
If we need FP for something else or if we receive a nonlocal
@@ -3267,7 +5962,7 @@ alpha_sa_size ()
Otherwise, start by assuming we can use FP. */
vms_base_regno = (frame_pointer_needed
|| current_function_has_nonlocal_label
- || vms_is_stack_procedure
+ || alpha_is_stack_procedure
|| current_function_outgoing_args_size
? REG_PV : HARD_FRAME_POINTER_REGNUM);
@@ -3281,23 +5976,18 @@ alpha_sa_size ()
vms_save_fp_regno = i;
if (vms_save_fp_regno == -1)
- vms_base_regno = REG_PV, vms_is_stack_procedure = 1;
+ vms_base_regno = REG_PV, alpha_is_stack_procedure = 1;
/* Stack unwinding should be done via FP unless we use it for PV. */
vms_unwind_regno = (vms_base_regno == REG_PV
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
/* If this is a stack procedure, allow space for saving FP and RA. */
- if (vms_is_stack_procedure)
+ if (alpha_is_stack_procedure)
sa_size += 2;
}
else
{
- /* If some registers were saved but not RA, RA must also be saved,
- so leave space for it. */
- if (sa_size != 0 || alpha_ra_ever_killed ())
- sa_size++;
-
/* Our size must be even (multiple of 16 bytes). */
if (sa_size & 1)
sa_size++;
@@ -3310,7 +6000,7 @@ int
alpha_pv_save_size ()
{
alpha_sa_size ();
- return vms_is_stack_procedure ? 8 : 0;
+ return alpha_is_stack_procedure ? 8 : 0;
}
int
@@ -3320,16 +6010,25 @@ alpha_using_fp ()
return vms_unwind_regno == HARD_FRAME_POINTER_REGNUM;
}
-int
-vms_valid_decl_attribute_p (decl, attributes, identifier, args)
- tree decl ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+#if TARGET_ABI_OPEN_VMS
+
+const struct attribute_spec vms_attribute_table[] =
{
- if (is_attribute_p ("overlaid", identifier))
- return (args == NULL_TREE);
- return 0;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "overlaid", 0, 0, true, false, false, NULL },
+ { "global", 0, 0, true, false, false, NULL },
+ { "initialize", 0, 0, true, false, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+#endif
+
+static int
+find_lo_sum (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return GET_CODE (*px) == LO_SUM;
}
static int
@@ -3337,14 +6036,12 @@ alpha_does_function_need_gp ()
{
rtx insn;
- /* We never need a GP for Windows/NT or VMS. */
- if (TARGET_WINDOWS_NT || TARGET_OPEN_VMS)
+ /* The GP being variable is an OSF abi thing. */
+ if (! TARGET_ABI_OSF)
return 0;
-#ifdef TARGET_PROFILING_NEEDS_GP
- if (profile_flag)
+ if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
return 1;
-#endif
#ifdef ASM_OUTPUT_MI_THUNK
if (current_function_is_thunk)
@@ -3360,13 +6057,16 @@ alpha_does_function_need_gp ()
pop_topmost_sequence ();
for (; insn; insn = NEXT_INSN (insn))
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ if (INSN_P (insn)
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER)
{
enum attr_type type = get_attr_type (insn);
if (type == TYPE_LDSYM || type == TYPE_JSR)
return 1;
+ if (TARGET_EXPLICIT_RELOCS
+ && for_each_rtx (&PATTERN (insn), find_lo_sum, NULL) > 0)
+ return 1;
}
return 0;
@@ -3449,24 +6149,48 @@ alpha_expand_prologue ()
sa_size = alpha_sa_size ();
frame_size = get_frame_size ();
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
frame_size = ALPHA_ROUND (sa_size
- + (vms_is_stack_procedure ? 8 : 0)
+ + (alpha_is_stack_procedure ? 8 : 0)
+ frame_size
+ current_function_pretend_args_size);
+ else if (TARGET_ABI_UNICOSMK)
+ /* We have to allocate space for the DSIB if we generate a frame. */
+ frame_size = ALPHA_ROUND (sa_size
+ + (alpha_is_stack_procedure ? 48 : 0))
+ + ALPHA_ROUND (frame_size
+ + current_function_outgoing_args_size);
else
frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
+ sa_size
+ ALPHA_ROUND (frame_size
+ current_function_pretend_args_size));
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
reg_offset = 8;
else
reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
alpha_sa_mask (&imask, &fmask);
+ /* Emit an insn to reload GP, if needed. */
+ if (TARGET_ABI_OSF)
+ {
+ alpha_function_needs_gp = alpha_does_function_need_gp ();
+ if (alpha_function_needs_gp)
+ emit_insn (gen_prologue_ldgp ());
+ }
+
+ /* TARGET_PROFILING_NEEDS_GP actually implies that we need to insert
+ the call to mcount ourselves, rather than having the linker do it
+ magically in response to -pg. Since _mcount has special linkage,
+ don't represent the call as a call. */
+ if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
+ emit_insn (gen_prologue_mcount ());
+
+ if (TARGET_ABI_UNICOSMK)
+ unicosmk_gen_dsib (&imask);
+
/* Adjust the stack by the frame size. If the frame size is > 4096
bytes, we need to be sure we probe somewhere in the first and last
4096 bytes (we can probably get away without the latter test) and
@@ -3483,7 +6207,9 @@ alpha_expand_prologue ()
int probed = 4096;
do
- emit_insn (gen_probe_stack (GEN_INT (-probed)));
+ emit_insn (gen_probe_stack (GEN_INT (TARGET_ABI_UNICOSMK
+ ? -probed + 64
+ : -probed)));
while ((probed += 8192) < frame_size);
/* We only have to do this probe if we aren't saving registers. */
@@ -3492,10 +6218,10 @@ alpha_expand_prologue ()
}
if (frame_size != 0)
- {
- FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-frame_size))));
- }
+ FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (TARGET_ABI_UNICOSMK
+ ? -frame_size + 64
+ : -frame_size))));
}
else
{
@@ -3512,7 +6238,8 @@ alpha_expand_prologue ()
rtx seq;
emit_move_insn (count, GEN_INT (blocks));
- emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, GEN_INT (4096)));
+ emit_insn (gen_adddi3 (ptr, stack_pointer_rtx,
+ GEN_INT (TARGET_ABI_UNICOSMK ? 4096 - 64 : 4096)));
/* Because of the difficulty in emitting a new basic block this
late in the compilation, generate the loop as a single insn. */
@@ -3525,7 +6252,7 @@ alpha_expand_prologue ()
emit_move_insn (last, const0_rtx);
}
- if (TARGET_WINDOWS_NT)
+ if (TARGET_ABI_WINDOWS_NT)
{
/* For NT stack unwind (done by 'reverse execution'), it's
not OK to take the result of a loop, even though the value
@@ -3559,90 +6286,119 @@ alpha_expand_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_size))),
+ GEN_INT (TARGET_ABI_UNICOSMK
+ ? -frame_size + 64
+ : -frame_size))),
REG_NOTES (seq));
}
- /* Cope with very large offsets to the register save area. */
- sa_reg = stack_pointer_rtx;
- if (reg_offset + sa_size > 0x8000)
+ if (!TARGET_ABI_UNICOSMK)
{
- int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
- HOST_WIDE_INT bias;
+ /* Cope with very large offsets to the register save area. */
+ sa_reg = stack_pointer_rtx;
+ if (reg_offset + sa_size > 0x8000)
+ {
+ int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
+ HOST_WIDE_INT bias;
- if (low + sa_size <= 0x8000)
- bias = reg_offset - low, reg_offset = low;
- else
- bias = reg_offset, reg_offset = 0;
+ if (low + sa_size <= 0x8000)
+ bias = reg_offset - low, reg_offset = low;
+ else
+ bias = reg_offset, reg_offset = 0;
- sa_reg = gen_rtx_REG (DImode, 24);
- FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, GEN_INT (bias))));
- }
+ sa_reg = gen_rtx_REG (DImode, 24);
+ FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx,
+ GEN_INT (bias))));
+ }
- /* Save regs in stack order. Beginning with VMS PV. */
- if (TARGET_OPEN_VMS && vms_is_stack_procedure)
- {
- mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
- FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV)));
- }
+ /* Save regs in stack order. Beginning with VMS PV. */
+ if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
+ {
+ mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV)));
+ }
- /* Save register RA next. */
- if (imask & (1L << REG_RA))
- {
- mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
- FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
- imask &= ~(1L << REG_RA);
- reg_offset += 8;
- }
+ /* Save register RA next. */
+ if (imask & (1L << REG_RA))
+ {
+ mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
+ imask &= ~(1L << REG_RA);
+ reg_offset += 8;
+ }
- /* Now save any other registers required to be saved. */
- for (i = 0; i < 32; i++)
- if (imask & (1L << i))
- {
- mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
- FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
- reg_offset += 8;
- }
+ /* Now save any other registers required to be saved. */
+ for (i = 0; i < 32; i++)
+ if (imask & (1L << i))
+ {
+ mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
+ reg_offset += 8;
+ }
- for (i = 0; i < 32; i++)
- if (fmask & (1L << i))
- {
- mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
- FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
- reg_offset += 8;
- }
+ for (i = 0; i < 32; i++)
+ if (fmask & (1L << i))
+ {
+ mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
+ reg_offset += 8;
+ }
+ }
+ else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+ {
+ /* The standard frame on the T3E includes space for saving registers.
+ We just have to use it. We don't have to save the return address and
+ the old frame pointer here - they are saved in the DSIB. */
+
+ reg_offset = -56;
+ for (i = 9; i < 15; i++)
+ if (imask & (1L << i))
+ {
+ mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
+ reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
+ reg_offset -= 8;
+ }
+ for (i = 2; i < 10; i++)
+ if (fmask & (1L << i))
+ {
+ mem = gen_rtx_MEM (DFmode, plus_constant (hard_frame_pointer_rtx,
+ reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
+ reg_offset -= 8;
+ }
+ }
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
{
- if (!vms_is_stack_procedure)
- {
- /* Register frame procedures fave the fp. */
- FRP (emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
- hard_frame_pointer_rtx));
- }
+ if (!alpha_is_stack_procedure)
+ /* Register frame procedures save the fp. */
+ /* ??? Ought to have a dwarf2 save for this. */
+ emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
+ hard_frame_pointer_rtx);
if (vms_base_regno != REG_PV)
- FRP (emit_move_insn (gen_rtx_REG (DImode, vms_base_regno),
- gen_rtx_REG (DImode, REG_PV)));
+ emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno),
+ gen_rtx_REG (DImode, REG_PV)));
if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
- {
- FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
- }
+ FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
/* If we have to allocate space for outgoing args, do it now. */
if (current_function_outgoing_args_size != 0)
- {
- FRP (emit_move_insn (stack_pointer_rtx,
- plus_constant (hard_frame_pointer_rtx,
- - ALPHA_ROUND (current_function_outgoing_args_size))));
- }
+ FRP (emit_move_insn
+ (stack_pointer_rtx,
+ plus_constant (hard_frame_pointer_rtx,
+ - (ALPHA_ROUND
+ (current_function_outgoing_args_size)))));
}
- else
+ else if (!TARGET_ABI_UNICOSMK)
{
/* If we need a frame pointer, set it from the stack pointer. */
if (frame_pointer_needed)
@@ -3650,12 +6406,10 @@ alpha_expand_prologue ()
if (TARGET_CAN_FAULT_IN_PROLOGUE)
FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
else
- {
- /* This must always be the last instruction in the
- prologue, thus we emit a special move + clobber. */
+ /* This must always be the last instruction in the
+ prologue, thus we emit a special move + clobber. */
FRP (emit_insn (gen_init_fp (hard_frame_pointer_rtx,
stack_pointer_rtx, sa_reg)));
- }
}
}
@@ -3678,7 +6432,7 @@ alpha_expand_prologue ()
void
alpha_start_function (file, fnname, decl)
FILE *file;
- char *fnname;
+ const char *fnname;
tree decl ATTRIBUTE_UNUSED;
{
unsigned long imask = 0;
@@ -3692,21 +6446,35 @@ alpha_start_function (file, fnname, decl)
char *entry_label = (char *) alloca (strlen (fnname) + 6);
int i;
+ /* Don't emit an extern directive for functions defined in the same file. */
+ if (TARGET_ABI_UNICOSMK)
+ {
+ tree name_tree;
+ name_tree = get_identifier (fnname);
+ TREE_ASM_WRITTEN (name_tree) = 1;
+ }
+
+ alpha_fnname = fnname;
sa_size = alpha_sa_size ();
frame_size = get_frame_size ();
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
frame_size = ALPHA_ROUND (sa_size
- + (vms_is_stack_procedure ? 8 : 0)
+ + (alpha_is_stack_procedure ? 8 : 0)
+ frame_size
+ current_function_pretend_args_size);
+ else if (TARGET_ABI_UNICOSMK)
+ frame_size = ALPHA_ROUND (sa_size
+ + (alpha_is_stack_procedure ? 48 : 0))
+ + ALPHA_ROUND (frame_size
+ + current_function_outgoing_args_size);
else
frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
+ sa_size
+ ALPHA_ROUND (frame_size
+ current_function_pretend_args_size));
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
reg_offset = 8;
else
reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
@@ -3723,36 +6491,56 @@ alpha_start_function (file, fnname, decl)
if (write_symbols == SDB_DEBUG)
{
+#ifdef ASM_OUTPUT_SOURCE_FILENAME
ASM_OUTPUT_SOURCE_FILENAME (file,
DECL_SOURCE_FILE (current_function_decl));
+#endif
+#ifdef ASM_OUTPUT_SOURCE_LINE
if (debug_info_level != DINFO_LEVEL_TERSE)
ASM_OUTPUT_SOURCE_LINE (file,
DECL_SOURCE_LINE (current_function_decl));
+#endif
}
/* Issue function start and label. */
- if (TARGET_OPEN_VMS || !flag_inhibit_size_directive)
+ if (TARGET_ABI_OPEN_VMS
+ || (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive))
{
fputs ("\t.ent ", file);
assemble_name (file, fnname);
putc ('\n', file);
+
+ /* If the function needs GP, we'll write the "..ng" label there.
+ Otherwise, do it here. */
+ if (TARGET_ABI_OSF && ! alpha_function_needs_gp)
+ {
+ putc ('$', file);
+ assemble_name (file, fnname);
+ fputs ("..ng:\n", file);
+ }
}
strcpy (entry_label, fnname);
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
strcat (entry_label, "..en");
+
+ /* For public functions, the label must be globalized by appending an
+ additional colon. */
+ if (TARGET_ABI_UNICOSMK && TREE_PUBLIC (decl))
+ strcat (entry_label, ":");
+
ASM_OUTPUT_LABEL (file, entry_label);
inside_function = TRUE;
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
fprintf (file, "\t.base $%d\n", vms_base_regno);
- if (!TARGET_OPEN_VMS && TARGET_IEEE_CONFORMANT
+ if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK && TARGET_IEEE_CONFORMANT
&& !flag_inhibit_size_directive)
{
/* Set flags in procedure descriptor to request IEEE-conformant
math-library routines. The value we set it to is PDSC_EXC_IEEE
- (/usr/include/pdsc.h). */
+ (/usr/include/pdsc.h). */
fputs ("\t.eflag 48\n", file);
}
@@ -3763,11 +6551,13 @@ alpha_start_function (file, fnname, decl)
/* Describe our frame. If the frame size is larger than an integer,
print it as zero to avoid an assembler error. We won't be
properly describing such a frame, but that's the best we can do. */
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_UNICOSMK)
+ ;
+ else if (TARGET_ABI_OPEN_VMS)
{
fprintf (file, "\t.frame $%d,", vms_unwind_regno);
fprintf (file, HOST_WIDE_INT_PRINT_DEC,
- frame_size >= (1l << 31) ? 0 : frame_size);
+ frame_size >= ((HOST_WIDE_INT) 1 << 31) ? 0 : frame_size);
fputs (",$26,", file);
fprintf (file, HOST_WIDE_INT_PRINT_DEC, reg_offset);
fputs ("\n", file);
@@ -3783,15 +6573,17 @@ alpha_start_function (file, fnname, decl)
}
/* Describe which registers were spilled. */
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_UNICOSMK)
+ ;
+ else if (TARGET_ABI_OPEN_VMS)
{
if (imask)
- /* ??? Does VMS care if mask contains ra? The old code did'nt
+ /* ??? Does VMS care if mask contains ra? The old code didn't
set it, so I don't here. */
fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1L << REG_RA));
if (fmask)
fprintf (file, "\t.fmask 0x%lx,0\n", fmask);
- if (!vms_is_stack_procedure)
+ if (!alpha_is_stack_procedure)
fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno);
}
else if (!flag_inhibit_size_directive)
@@ -3817,21 +6609,7 @@ alpha_start_function (file, fnname, decl)
}
}
- /* Emit GP related things. It is rather unfortunate about the alignment
- issues surrounding a CODE_LABEL that forces us to do the label in
- plain text. */
- if (!TARGET_OPEN_VMS && !TARGET_WINDOWS_NT)
- {
- alpha_function_needs_gp = alpha_does_function_need_gp ();
- if (alpha_function_needs_gp)
- fputs ("\tldgp $29,0($27)\n", file);
-
- putc ('$', file);
- assemble_name (file, fnname);
- fputs ("..ng:\n", file);
- }
-
-#ifdef OPEN_VMS
+#if TARGET_ABI_OPEN_VMS
/* Ifdef'ed cause readonly_section and link_section are only
available then. */
readonly_section ();
@@ -3849,7 +6627,7 @@ alpha_start_function (file, fnname, decl)
ASM_OUTPUT_LABEL (file, fnname);
fprintf (file, "\t.pdesc ");
assemble_name (file, fnname);
- fprintf (file, "..en,%s\n", vms_is_stack_procedure ? "stack" : "reg");
+ fprintf (file, "..en,%s\n", alpha_is_stack_procedure ? "stack" : "reg");
alpha_need_linkage (fnname, 1);
text_section ();
#endif
@@ -3857,13 +6635,15 @@ alpha_start_function (file, fnname, decl)
/* Emit the .prologue note at the scheduled end of the prologue. */
-void
-output_end_prologue (file)
+static void
+alpha_output_function_end_prologue (file)
FILE *file;
{
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_UNICOSMK)
+ ;
+ else if (TARGET_ABI_OPEN_VMS)
fputs ("\t.prologue\n", file);
- else if (TARGET_WINDOWS_NT)
+ else if (TARGET_ABI_WINDOWS_NT)
fputs ("\t.prologue 0\n", file);
else if (!flag_inhibit_size_directive)
fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
@@ -3892,44 +6672,54 @@ alpha_expand_epilogue ()
int fp_is_frame_pointer, fp_offset;
rtx sa_reg, sa_reg_exp = NULL;
rtx sp_adj1, sp_adj2, mem;
+ rtx eh_ofs;
int i;
sa_size = alpha_sa_size ();
frame_size = get_frame_size ();
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
frame_size = ALPHA_ROUND (sa_size
- + (vms_is_stack_procedure ? 8 : 0)
+ + (alpha_is_stack_procedure ? 8 : 0)
+ frame_size
+ current_function_pretend_args_size);
+ else if (TARGET_ABI_UNICOSMK)
+ frame_size = ALPHA_ROUND (sa_size
+ + (alpha_is_stack_procedure ? 48 : 0))
+ + ALPHA_ROUND (frame_size
+ + current_function_outgoing_args_size);
else
frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
+ sa_size
+ ALPHA_ROUND (frame_size
+ current_function_pretend_args_size));
- if (TARGET_OPEN_VMS)
+ if (TARGET_ABI_OPEN_VMS)
reg_offset = 8;
else
reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
alpha_sa_mask (&imask, &fmask);
- fp_is_frame_pointer = ((TARGET_OPEN_VMS && vms_is_stack_procedure)
- || (!TARGET_OPEN_VMS && frame_pointer_needed));
+ fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
+ || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
+ fp_offset = 0;
+ sa_reg = stack_pointer_rtx;
- if (sa_size)
+ if (current_function_calls_eh_return)
+ eh_ofs = EH_RETURN_STACKADJ_RTX;
+ else
+ eh_ofs = NULL_RTX;
+
+ if (!TARGET_ABI_UNICOSMK && sa_size)
{
/* If we have a frame pointer, restore SP from it. */
- if ((TARGET_OPEN_VMS
+ if ((TARGET_ABI_OPEN_VMS
&& vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
- || (!TARGET_OPEN_VMS && frame_pointer_needed))
- {
- FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx));
- }
+ || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed))
+ FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx));
/* Cope with very large offsets to the register save area. */
- sa_reg = stack_pointer_rtx;
if (reg_offset + sa_size > 0x8000)
{
int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
@@ -3946,14 +6736,13 @@ alpha_expand_epilogue ()
FRP (emit_move_insn (sa_reg, sa_reg_exp));
}
- /* Restore registers in order, excepting a true frame pointer. */
+ /* Restore registers in order, excepting a true frame pointer. */
+
+ mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+ if (! eh_ofs)
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
- if (! alpha_eh_epilogue_sp_ofs)
- {
- mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
- FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
- }
reg_offset += 8;
imask &= ~(1L << REG_RA);
@@ -3965,7 +6754,7 @@ alpha_expand_epilogue ()
else
{
mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+ set_mem_alias_set (mem, alpha_sr_alias_set);
FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem));
}
reg_offset += 8;
@@ -3975,29 +6764,67 @@ alpha_expand_epilogue ()
if (fmask & (1L << i))
{
mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+ set_mem_alias_set (mem, alpha_sr_alias_set);
FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem));
reg_offset += 8;
}
}
+ else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+ {
+ /* Restore callee-saved general-purpose registers. */
+
+ reg_offset = -56;
+
+ for (i = 9; i < 15; i++)
+ if (imask & (1L << i))
+ {
+ mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
+ reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem));
+ reg_offset -= 8;
+ }
+
+ for (i = 2; i < 10; i++)
+ if (fmask & (1L << i))
+ {
+ mem = gen_rtx_MEM (DFmode, plus_constant(hard_frame_pointer_rtx,
+ reg_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem));
+ reg_offset -= 8;
+ }
+
+ /* Restore the return address from the DSIB. */
+
+ mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, -8));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
+ }
- if (frame_size || alpha_eh_epilogue_sp_ofs)
+ if (frame_size || eh_ofs)
{
sp_adj1 = stack_pointer_rtx;
- if (alpha_eh_epilogue_sp_ofs)
+ if (eh_ofs)
{
sp_adj1 = gen_rtx_REG (DImode, 23);
emit_move_insn (sp_adj1,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- alpha_eh_epilogue_sp_ofs));
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, eh_ofs));
}
/* If the stack size is large, begin computation into a temporary
register so as not to interfere with a potential fp restore,
which must be consecutive with an SP restore. */
- if (frame_size < 32768)
+ if (frame_size < 32768
+ && ! (TARGET_ABI_UNICOSMK && current_function_calls_alloca))
sp_adj2 = GEN_INT (frame_size);
+ else if (TARGET_ABI_UNICOSMK)
+ {
+ sp_adj1 = gen_rtx_REG (DImode, 23);
+ FRP (emit_move_insn (sp_adj1, hard_frame_pointer_rtx));
+ sp_adj2 = const0_rtx;
+ }
else if (frame_size < 0x40007fffL)
{
int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000;
@@ -4030,14 +6857,22 @@ alpha_expand_epilogue ()
/* From now on, things must be in order. So emit blockages. */
/* Restore the frame pointer. */
- if (fp_is_frame_pointer)
+ if (TARGET_ABI_UNICOSMK)
{
emit_insn (gen_blockage ());
- mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, fp_offset));
- MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+ mem = gen_rtx_MEM (DImode,
+ plus_constant (hard_frame_pointer_rtx, -16));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
}
- else if (TARGET_OPEN_VMS)
+ else if (fp_is_frame_pointer)
+ {
+ emit_insn (gen_blockage ());
+ mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, fp_offset));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
+ }
+ else if (TARGET_ABI_OPEN_VMS)
{
emit_insn (gen_blockage ());
FRP (emit_move_insn (hard_frame_pointer_rtx,
@@ -4046,21 +6881,30 @@ alpha_expand_epilogue ()
/* Restore the stack pointer. */
emit_insn (gen_blockage ());
- FRP (emit_move_insn (stack_pointer_rtx,
- gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)));
+ if (sp_adj2 == const0_rtx)
+ FRP (emit_move_insn (stack_pointer_rtx, sp_adj1));
+ else
+ FRP (emit_move_insn (stack_pointer_rtx,
+ gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)));
}
else
{
- if (TARGET_OPEN_VMS && !vms_is_stack_procedure)
+ if (TARGET_ABI_OPEN_VMS && !alpha_is_stack_procedure)
{
emit_insn (gen_blockage ());
FRP (emit_move_insn (hard_frame_pointer_rtx,
gen_rtx_REG (DImode, vms_save_fp_regno)));
}
- }
+ else if (TARGET_ABI_UNICOSMK && !alpha_is_stack_procedure)
+ {
+ /* Decrement the frame pointer if the function does not have a
+ frame. */
- /* Return. */
- emit_jump_insn (gen_return_internal ());
+ emit_insn (gen_blockage ());
+ FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+ hard_frame_pointer_rtx, GEN_INT (-1))));
+ }
+ }
}
/* Output the rest of the textual info surrounding the epilogue. */
@@ -4068,11 +6912,11 @@ alpha_expand_epilogue ()
void
alpha_end_function (file, fnname, decl)
FILE *file;
- char *fnname;
+ const char *fnname;
tree decl ATTRIBUTE_UNUSED;
{
/* End the function. */
- if (!flag_inhibit_size_directive)
+ if (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive)
{
fputs ("\t.end ", file);
assemble_name (file, fnname);
@@ -4084,11 +6928,23 @@ alpha_end_function (file, fnname, decl)
Don't do this for global functions in object files destined for a
shared library because the function may be overridden by the application
- or other libraries. Similarly, don't do this for weak functions. */
+ or other libraries. Similarly, don't do this for weak functions.
+
+ Don't do this for functions not defined in the .text section, as
+ otherwise it's not unlikely that the destination is out of range
+ for a direct branch. */
if (!DECL_WEAK (current_function_decl)
- && (!flag_pic || !TREE_PUBLIC (current_function_decl)))
+ && (!flag_pic || !TREE_PUBLIC (current_function_decl))
+ && decl_in_text_section (current_function_decl))
SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+
+ /* Output jump tables and the static subroutine information block. */
+ if (TARGET_ABI_UNICOSMK)
+ {
+ unicosmk_output_ssib (file, fnname);
+ unicosmk_output_deferred_case_vectors (file);
+ }
}
/* Debugging support. */
@@ -4122,7 +6978,7 @@ long alpha_auto_offset;
void
alpha_output_filename (stream, name)
FILE *stream;
- char *name;
+ const char *name;
{
static int first_time = TRUE;
char ltext_label_name[100];
@@ -4142,7 +6998,7 @@ alpha_output_filename (stream, name)
else if (write_symbols == DBX_DEBUG)
{
ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
- fprintf (stream, "%s ", ASM_STABS_OP);
+ fprintf (stream, "%s", ASM_STABS_OP);
output_quoted_string (stream, name);
fprintf (stream, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
}
@@ -4175,7 +7031,7 @@ alpha_output_lineno (stream, line)
{
/* mips-tfile doesn't understand .stabd directives. */
++sym_lineno;
- fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n",
+ fprintf (stream, "$LM%d:\n%s%d,0,%d,$LM%d\n",
sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
}
else
@@ -4187,14 +7043,14 @@ alpha_output_lineno (stream, line)
struct shadow_summary
{
struct {
- unsigned long i : 31; /* Mask of int regs */
- unsigned long fp : 31; /* Mask of fp regs */
- unsigned long mem : 1; /* mem == imem | fpmem */
+ unsigned int i : 31; /* Mask of int regs */
+ unsigned int fp : 31; /* Mask of fp regs */
+ unsigned int mem : 1; /* mem == imem | fpmem */
} used, defd;
};
-static void summarize_insn PROTO((rtx, struct shadow_summary *, int));
-static void alpha_handle_trap_shadows PROTO((rtx));
+static void summarize_insn PARAMS ((rtx, struct shadow_summary *, int));
+static void alpha_handle_trap_shadows PARAMS ((rtx));
/* Summary the effects of expression X on the machine. Update SUM, a pointer
to the summary structure. SET is nonzero if the insn is setting the
@@ -4206,7 +7062,7 @@ summarize_insn (x, sum, set)
struct shadow_summary *sum;
int set;
{
- char *format_ptr;
+ const char *format_ptr;
int i, j;
if (x == 0)
@@ -4246,7 +7102,7 @@ summarize_insn (x, sum, set)
case REG:
{
int regno = REGNO (x);
- unsigned long mask = 1UL << (regno % 32);
+ unsigned long mask = ((unsigned long) 1) << (regno % 32);
if (regno == 31 || regno == 63)
break;
@@ -4280,6 +7136,7 @@ summarize_insn (x, sum, set)
case CONST_INT: case CONST_DOUBLE:
case SYMBOL_REF: case LABEL_REF: case CONST:
+ case SCRATCH: case ASM_INPUT:
break;
/* Handle common unary and binary ops for efficiency. */
@@ -4490,7 +7347,6 @@ alpha_handle_trap_shadows (insns)
}
}
-#ifdef HAIFA
/* Alpha can only issue instruction groups simultaneously if they are
suitibly aligned. This is very processor-specific. */
@@ -4512,15 +7368,15 @@ enum alphaev5_pipe {
EV5_FM = 64
};
-static enum alphaev4_pipe alphaev4_insn_pipe PROTO((rtx));
-static enum alphaev5_pipe alphaev5_insn_pipe PROTO((rtx));
-static rtx alphaev4_next_group PROTO((rtx, int*, int*));
-static rtx alphaev5_next_group PROTO((rtx, int*, int*));
-static rtx alphaev4_next_nop PROTO((int*));
-static rtx alphaev5_next_nop PROTO((int*));
+static enum alphaev4_pipe alphaev4_insn_pipe PARAMS ((rtx));
+static enum alphaev5_pipe alphaev5_insn_pipe PARAMS ((rtx));
+static rtx alphaev4_next_group PARAMS ((rtx, int *, int *));
+static rtx alphaev5_next_group PARAMS ((rtx, int *, int *));
+static rtx alphaev4_next_nop PARAMS ((int *));
+static rtx alphaev5_next_nop PARAMS ((int *));
static void alpha_align_insns
- PROTO((rtx, int, rtx (*)(rtx, int*, int*), rtx (*)(int*), int));
+ PARAMS ((rtx, unsigned int, rtx (*)(rtx, int *, int *), rtx (*)(int *)));
static enum alphaev4_pipe
alphaev4_insn_pipe (insn)
@@ -4560,7 +7416,7 @@ alphaev4_insn_pipe (insn)
return EV4_IB1;
default:
- abort();
+ abort ();
}
}
@@ -4628,7 +7484,7 @@ alphaev4_next_group (insn, pin_use, plen)
len = in_use = 0;
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+ if (! INSN_P (insn)
|| GET_CODE (PATTERN (insn)) == CLOBBER
|| GET_CODE (PATTERN (insn)) == USE)
goto next_and_done;
@@ -4693,7 +7549,7 @@ alphaev4_next_group (insn, pin_use, plen)
next:
insn = next_nonnote_insn (insn);
- if (!insn || GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ if (!insn || ! INSN_P (insn))
goto done;
/* Let Haifa tell us where it thinks insn group boundaries are. */
@@ -4728,7 +7584,7 @@ alphaev5_next_group (insn, pin_use, plen)
len = in_use = 0;
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+ if (! INSN_P (insn)
|| GET_CODE (PATTERN (insn)) == CLOBBER
|| GET_CODE (PATTERN (insn)) == USE)
goto next_and_done;
@@ -4826,7 +7682,7 @@ alphaev5_next_group (insn, pin_use, plen)
next:
insn = next_nonnote_insn (insn);
- if (!insn || GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ if (!insn || ! INSN_P (insn))
goto done;
/* Let Haifa tell us where it thinks insn group boundaries are. */
@@ -4907,15 +7763,14 @@ alphaev5_next_nop (pin_use)
/* The instruction group alignment main loop. */
static void
-alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
+alpha_align_insns (insns, max_align, next_group, next_nop)
rtx insns;
- int max_align;
- rtx (*next_group) PROTO((rtx, int*, int*));
- rtx (*next_nop) PROTO((int*));
- int gp_in_use;
+ unsigned int max_align;
+ rtx (*next_group) PARAMS ((rtx, int *, int *));
+ rtx (*next_nop) PARAMS ((int *));
{
/* ALIGN is the known alignment for the insn group. */
- int align;
+ unsigned int align;
/* OFS is the offset of the current insn in the insn group. */
int ofs;
int prev_in_use, in_use, len;
@@ -4924,35 +7779,33 @@ alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
/* Let shorten branches care for assigning alignments to code labels. */
shorten_branches (insns);
- align = (FUNCTION_BOUNDARY/BITS_PER_UNIT < max_align
- ? FUNCTION_BOUNDARY/BITS_PER_UNIT : max_align);
+ if (align_functions < 4)
+ align = 4;
+ else if ((unsigned int) align_functions < max_align)
+ align = align_functions;
+ else
+ align = max_align;
- /* Account for the initial GP load, which happens before the scheduled
- prologue we emitted as RTL. */
ofs = prev_in_use = 0;
- if (alpha_does_function_need_gp())
- {
- ofs = 8 & (align - 1);
- prev_in_use = gp_in_use;
- }
-
i = insns;
if (GET_CODE (i) == NOTE)
i = next_nonnote_insn (i);
while (i)
{
- next = (*next_group)(i, &in_use, &len);
+ next = (*next_group) (i, &in_use, &len);
/* When we see a label, resync alignment etc. */
if (GET_CODE (i) == CODE_LABEL)
{
- int new_align = 1 << label_to_alignment (i);
+ unsigned int new_align = 1 << label_to_alignment (i);
+
if (new_align >= align)
{
align = new_align < max_align ? new_align : max_align;
ofs = 0;
}
+
else if (ofs & (new_align-1))
ofs = (ofs | (new_align-1)) + 1;
if (len != 0)
@@ -4975,18 +7828,23 @@ alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
/* If the known alignment is smaller than the recognized insn group,
realign the output. */
- else if (align < len)
+ else if ((int) align < len)
{
- int new_log_align = len > 8 ? 4 : 3;
- rtx where;
+ unsigned int new_log_align = len > 8 ? 4 : 3;
+ rtx prev, where;
- where = prev_nonnote_insn (i);
+ where = prev = prev_nonnote_insn (i);
if (!where || GET_CODE (where) != CODE_LABEL)
where = i;
- emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
- align = 1 << new_log_align;
- ofs = 0;
+ /* Can't realign between a call and its gp reload. */
+ if (! (TARGET_EXPLICIT_RELOCS
+ && prev && GET_CODE (prev) == CALL_INSN))
+ {
+ emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
+ align = 1 << new_log_align;
+ ofs = 0;
+ }
}
/* If the group won't fit in the same INT16 as the previous,
@@ -4995,13 +7853,13 @@ alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
can make use of the knowledge of what sorts of instructions
were issued in the previous group to make sure that all of
the added nops are really free. */
- else if (ofs + len > align)
+ else if (ofs + len > (int) align)
{
int nop_count = (align - ofs) / 4;
rtx where;
- /* Insert nops before labels and branches to truely merge the
- execution of the nops with the previous instruction group. */
+ /* Insert nops before labels, branches, and calls to truely merge
+ the execution of the nops with the previous instruction group. */
where = prev_nonnote_insn (i);
if (where)
{
@@ -5011,7 +7869,7 @@ alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
if (where2 && GET_CODE (where2) == JUMP_INSN)
where = where2;
}
- else if (GET_CODE (where) != JUMP_INSN)
+ else if (GET_CODE (where) == INSN)
where = i;
}
else
@@ -5028,9 +7886,8 @@ alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
i = next;
}
}
-#endif /* HAIFA */
-/* Machine dependant reorg pass. */
+/* Machine dependent reorg pass. */
void
alpha_reorg (insns)
@@ -5039,28 +7896,23 @@ alpha_reorg (insns)
if (alpha_tp != ALPHA_TP_PROG || flag_exceptions)
alpha_handle_trap_shadows (insns);
-#ifdef HAIFA
/* Due to the number of extra trapb insns, don't bother fixing up
alignment when trap precision is instruction. Moreover, we can
- only do our job when sched2 is run and Haifa is our scheduler. */
+ only do our job when sched2 is run. */
if (optimize && !optimize_size
&& alpha_tp != ALPHA_TP_INSN
&& flag_schedule_insns_after_reload)
{
if (alpha_cpu == PROCESSOR_EV4)
- alpha_align_insns (insns, 8, alphaev4_next_group,
- alphaev4_next_nop, EV4_IB0);
+ alpha_align_insns (insns, 8, alphaev4_next_group, alphaev4_next_nop);
else if (alpha_cpu == PROCESSOR_EV5)
- alpha_align_insns (insns, 16, alphaev5_next_group,
- alphaev5_next_nop, EV5_E01 | EV5_E0);
+ alpha_align_insns (insns, 16, alphaev5_next_group, alphaev5_next_nop);
}
-#endif
}
-
/* Check a floating-point value for validity for a particular machine mode. */
-static char * const float_strings[] =
+static const char * const float_strings[] =
{
/* These are for FLOAT_VAX. */
"1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */
@@ -5107,37 +7959,35 @@ check_float_value (mode, d, overflow)
else
fvptr = &float_values[4];
- bcopy ((char *) d, (char *) &r, sizeof (REAL_VALUE_TYPE));
+ memcpy (&r, d, sizeof (REAL_VALUE_TYPE));
if (REAL_VALUES_LESS (fvptr[0], r))
{
- bcopy ((char *) &fvptr[0], (char *) d,
- sizeof (REAL_VALUE_TYPE));
+ memcpy (d, &fvptr[0], sizeof (REAL_VALUE_TYPE));
return 1;
}
else if (REAL_VALUES_LESS (r, fvptr[1]))
{
- bcopy ((char *) &fvptr[1], (char *) d,
- sizeof (REAL_VALUE_TYPE));
+ memcpy (d, &fvptr[1], sizeof (REAL_VALUE_TYPE));
return 1;
}
else if (REAL_VALUES_LESS (dconst0, r)
&& REAL_VALUES_LESS (r, fvptr[2]))
{
- bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+ memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
return 1;
}
else if (REAL_VALUES_LESS (r, dconst0)
&& REAL_VALUES_LESS (fvptr[3], r))
{
- bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+ memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
return 1;
}
}
return 0;
}
-
-#if OPEN_VMS
+
+#if TARGET_ABI_OPEN_VMS
/* Return the VMS argument type corresponding to MODE. */
@@ -5159,7 +8009,7 @@ alpha_arg_type (mode)
/* Return an rtx for an integer representing the VMS Argument Information
register value. */
-struct rtx_def *
+rtx
alpha_arg_info_reg_val (cum)
CUMULATIVE_ARGS cum;
{
@@ -5172,109 +8022,1044 @@ alpha_arg_info_reg_val (cum)
return GEN_INT (regval);
}
+#include <splay-tree.h>
+
/* Structure to collect function names for final output
in link section. */
enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
-
-struct alpha_links {
- struct alpha_links *next;
- char *name;
+struct alpha_links
+{
+ rtx linkage;
enum links_kind kind;
};
-static struct alpha_links *alpha_links_base = 0;
+static splay_tree alpha_links;
+
+static int mark_alpha_links_node PARAMS ((splay_tree_node, void *));
+static void mark_alpha_links PARAMS ((void *));
+static int alpha_write_one_linkage PARAMS ((splay_tree_node, void *));
+
+/* Protect alpha_links from garbage collection. */
+
+static int
+mark_alpha_links_node (node, data)
+ splay_tree_node node;
+ void *data ATTRIBUTE_UNUSED;
+{
+ struct alpha_links *links = (struct alpha_links *) node->value;
+ ggc_mark_rtx (links->linkage);
+ return 0;
+}
+
+static void
+mark_alpha_links (ptr)
+ void *ptr;
+{
+ splay_tree tree = *(splay_tree *) ptr;
+ splay_tree_foreach (tree, mark_alpha_links_node, NULL);
+}
/* Make (or fake) .linkage entry for function call.
- IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */
+ IS_LOCAL is 0 if name is used in call, 1 if name is used in definition.
-void
+ Return an SYMBOL_REF rtx for the linkage. */
+
+rtx
alpha_need_linkage (name, is_local)
- char *name;
+ const char *name;
int is_local;
{
- rtx x;
- struct alpha_links *lptr, *nptr;
+ splay_tree_node node;
+ struct alpha_links *al;
if (name[0] == '*')
name++;
- /* Is this name already defined ? */
+ if (alpha_links)
+ {
+ /* Is this name already defined? */
- for (lptr = alpha_links_base; lptr; lptr = lptr->next)
- if (strcmp (lptr->name, name) == 0)
- {
- if (is_local)
- {
- /* Defined here but external assumed. */
- if (lptr->kind == KIND_EXTERN)
- lptr->kind = KIND_LOCAL;
- }
- else
- {
- /* Used here but unused assumed. */
- if (lptr->kind == KIND_UNUSED)
- lptr->kind = KIND_LOCAL;
- }
- return;
- }
+ node = splay_tree_lookup (alpha_links, (splay_tree_key) name);
+ if (node)
+ {
+ al = (struct alpha_links *) node->value;
+ if (is_local)
+ {
+ /* Defined here but external assumed. */
+ if (al->kind == KIND_EXTERN)
+ al->kind = KIND_LOCAL;
+ }
+ else
+ {
+ /* Used here but unused assumed. */
+ if (al->kind == KIND_UNUSED)
+ al->kind = KIND_LOCAL;
+ }
+ return al->linkage;
+ }
+ }
+ else
+ {
+ alpha_links = splay_tree_new ((splay_tree_compare_fn) strcmp,
+ (splay_tree_delete_key_fn) free,
+ (splay_tree_delete_key_fn) free);
+ ggc_add_root (&alpha_links, 1, 1, mark_alpha_links);
+ }
- nptr = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
- nptr->next = alpha_links_base;
- nptr->name = xstrdup (name);
+ al = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
+ name = xstrdup (name);
/* Assume external if no definition. */
- nptr->kind = (is_local ? KIND_UNUSED : KIND_EXTERN);
+ al->kind = (is_local ? KIND_UNUSED : KIND_EXTERN);
- /* Ensure we have an IDENTIFIER so assemble_name can mark is used. */
+ /* Ensure we have an IDENTIFIER so assemble_name can mark it used. */
get_identifier (name);
- alpha_links_base = nptr;
+ /* Construct a SYMBOL_REF for us to call. */
+ {
+ size_t name_len = strlen (name);
+ char *linksym = alloca (name_len + 6);
+ linksym[0] = '$';
+ memcpy (linksym + 1, name, name_len);
+ memcpy (linksym + 1 + name_len, "..lk", 5);
+ al->linkage = gen_rtx_SYMBOL_REF (Pmode,
+ ggc_alloc_string (linksym, name_len + 5));
+ }
+
+ splay_tree_insert (alpha_links, (splay_tree_key) name,
+ (splay_tree_value) al);
- return;
+ return al->linkage;
}
+static int
+alpha_write_one_linkage (node, data)
+ splay_tree_node node;
+ void *data;
+{
+ const char *const name = (const char *) node->key;
+ struct alpha_links *links = (struct alpha_links *) node->value;
+ FILE *stream = (FILE *) data;
+
+ if (links->kind == KIND_UNUSED
+ || ! TREE_SYMBOL_REFERENCED (get_identifier (name)))
+ return 0;
+
+ fprintf (stream, "$%s..lk:\n", name);
+ if (links->kind == KIND_LOCAL)
+ {
+ /* Local and used, build linkage pair. */
+ fprintf (stream, "\t.quad %s..en\n", name);
+ fprintf (stream, "\t.quad %s\n", name);
+ }
+ else
+ {
+ /* External and used, request linkage pair. */
+ fprintf (stream, "\t.linkage %s\n", name);
+ }
+
+ return 0;
+}
void
alpha_write_linkage (stream)
FILE *stream;
{
- struct alpha_links *lptr, *nptr;
+ if (alpha_links)
+ {
+ readonly_section ();
+ fprintf (stream, "\t.align 3\n");
+ splay_tree_foreach (alpha_links, alpha_write_one_linkage, stream);
+ }
+}
- readonly_section ();
+/* Given a decl, a section name, and whether the decl initializer
+ has relocs, choose attributes for the section. */
+
+#define SECTION_VMS_OVERLAY SECTION_FORGET
+#define SECTION_VMS_GLOBAL SECTION_MACH_DEP
+#define SECTION_VMS_INITIALIZE (SECTION_VMS_GLOBAL << 1)
+
+static unsigned int
+vms_section_type_flags (decl, name, reloc)
+ tree decl;
+ const char *name;
+ int reloc;
+{
+ unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+ if (decl && DECL_ATTRIBUTES (decl)
+ && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl)))
+ flags |= SECTION_VMS_OVERLAY;
+ if (decl && DECL_ATTRIBUTES (decl)
+ && lookup_attribute ("global", DECL_ATTRIBUTES (decl)))
+ flags |= SECTION_VMS_GLOBAL;
+ if (decl && DECL_ATTRIBUTES (decl)
+ && lookup_attribute ("initialize", DECL_ATTRIBUTES (decl)))
+ flags |= SECTION_VMS_INITIALIZE;
+
+ return flags;
+}
+
+/* Switch to an arbitrary section NAME with attributes as specified
+ by FLAGS. ALIGN specifies any known alignment requirements for
+ the section; 0 if the default should be used. */
+
+static void
+vms_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ fputc ('\n', asm_out_file);
+ fprintf (asm_out_file, ".section\t%s", name);
+
+ if (flags & SECTION_VMS_OVERLAY)
+ fprintf (asm_out_file, ",OVR");
+ if (flags & SECTION_VMS_GLOBAL)
+ fprintf (asm_out_file, ",GBL");
+ if (flags & SECTION_VMS_INITIALIZE)
+ fprintf (asm_out_file, ",NOMOD");
+ if (flags & SECTION_DEBUG)
+ fprintf (asm_out_file, ",NOWRT");
+
+ fputc ('\n', asm_out_file);
+}
+
+/* Record an element in the table of global constructors. SYMBOL is
+ a SYMBOL_REF of the function to be called; PRIORITY is a number
+ between 0 and MAX_INIT_PRIORITY.
+
+ Differs from default_ctors_section_asm_out_constructor in that the
+ width of the .ctors entry is always 64 bits, rather than the 32 bits
+ used by a normal pointer. */
+
+static void
+vms_asm_out_constructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ ctors_section ();
+ assemble_align (BITS_PER_WORD);
+ assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
+}
+
+static void
+vms_asm_out_destructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ dtors_section ();
+ assemble_align (BITS_PER_WORD);
+ assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
+}
+#else
+
+rtx
+alpha_need_linkage (name, is_local)
+ const char *name ATTRIBUTE_UNUSED;
+ int is_local ATTRIBUTE_UNUSED;
+{
+ return NULL_RTX;
+}
+
+#endif /* TARGET_ABI_OPEN_VMS */
+
+#if TARGET_ABI_UNICOSMK
+
+static void unicosmk_output_module_name PARAMS ((FILE *));
+static void unicosmk_output_default_externs PARAMS ((FILE *));
+static void unicosmk_output_dex PARAMS ((FILE *));
+static void unicosmk_output_externs PARAMS ((FILE *));
+static void unicosmk_output_addr_vec PARAMS ((FILE *, rtx));
+static const char *unicosmk_ssib_name PARAMS ((void));
+static int unicosmk_special_name PARAMS ((const char *));
+
+/* Define the offset between two registers, one to be eliminated, and the
+ other its replacement, at the start of a routine. */
+
+int
+unicosmk_initial_elimination_offset (from, to)
+ int from;
+ int to;
+{
+ int fixed_size;
+
+ fixed_size = alpha_sa_size();
+ if (fixed_size != 0)
+ fixed_size += 48;
+
+ if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+ return -fixed_size;
+ else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+ return 0;
+ else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+ return (ALPHA_ROUND (current_function_outgoing_args_size)
+ + ALPHA_ROUND (get_frame_size()));
+ else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+ return (ALPHA_ROUND (fixed_size)
+ + ALPHA_ROUND (get_frame_size()
+ + current_function_outgoing_args_size));
+ else
+ abort ();
+}
+
+/* Output the module name for .ident and .end directives. We have to strip
+ directories and add make sure that the module name starts with a letter
+ or '$'. */
+
+static void
+unicosmk_output_module_name (file)
+ FILE *file;
+{
+ const char *name;
+
+ /* Strip directories. */
+
+ name = strrchr (main_input_filename, '/');
+ if (name)
+ ++name;
+ else
+ name = main_input_filename;
+
+ /* CAM only accepts module names that start with a letter or '$'. We
+ prefix the module name with a '$' if necessary. */
+
+ if (!ISALPHA (*name))
+ fprintf (file, "$%s", name);
+ else
+ fputs (name, file);
+}
+
+/* Output text that to appear at the beginning of an assembler file. */
+
+void
+unicosmk_asm_file_start (file)
+ FILE *file;
+{
+ int i;
+
+ fputs ("\t.ident\t", file);
+ unicosmk_output_module_name (file);
+ fputs ("\n\n", file);
+
+ /* The Unicos/Mk assembler uses different register names. Instead of trying
+ to support them, we simply use micro definitions. */
+
+ /* CAM has different register names: rN for the integer register N and fN
+ for the floating-point register N. Instead of trying to use these in
+ alpha.md, we define the symbols $N and $fN to refer to the appropriate
+ register. */
+
+ for (i = 0; i < 32; ++i)
+ fprintf (file, "$%d <- r%d\n", i, i);
+
+ for (i = 0; i < 32; ++i)
+ fprintf (file, "$f%d <- f%d\n", i, i);
+
+ putc ('\n', file);
+
+ /* The .align directive fill unused space with zeroes which does not work
+ in code sections. We define the macro 'gcc@code@align' which uses nops
+ instead. Note that it assumes that code sections always have the
+ biggest possible alignment since . refers to the current offset from
+ the beginning of the section. */
+
+ fputs ("\t.macro gcc@code@align n\n", file);
+ fputs ("gcc@n@bytes = 1 << n\n", file);
+ fputs ("gcc@here = . % gcc@n@bytes\n", file);
+ fputs ("\t.if ne, gcc@here, 0\n", file);
+ fputs ("\t.repeat (gcc@n@bytes - gcc@here) / 4\n", file);
+ fputs ("\tbis r31,r31,r31\n", file);
+ fputs ("\t.endr\n", file);
+ fputs ("\t.endif\n", file);
+ fputs ("\t.endm gcc@code@align\n\n", file);
+
+ /* Output extern declarations which should always be visible. */
+ unicosmk_output_default_externs (file);
+
+ /* Open a dummy section. We always need to be inside a section for the
+ section-switching code to work correctly.
+ ??? This should be a module id or something like that. I still have to
+ figure out what the rules for those are. */
+ fputs ("\n\t.psect\t$SG00000,data\n", file);
+}
+
+/* Output text to appear at the end of an assembler file. This includes all
+ pending extern declarations and DEX expressions. */
+
+void
+unicosmk_asm_file_end (file)
+ FILE *file;
+{
+ fputs ("\t.endp\n\n", file);
+
+ /* Output all pending externs. */
+
+ unicosmk_output_externs (file);
+
+ /* Output dex definitions used for functions whose names conflict with
+ register names. */
+
+ unicosmk_output_dex (file);
+
+ fputs ("\t.end\t", file);
+ unicosmk_output_module_name (file);
+ putc ('\n', file);
+}
+
+/* Output the definition of a common variable. */
+
+void
+unicosmk_output_common (file, name, size, align)
+ FILE *file;
+ const char *name;
+ int size;
+ int align;
+{
+ tree name_tree;
+ printf ("T3E__: common %s\n", name);
+
+ common_section ();
+ fputs("\t.endp\n\n\t.psect ", file);
+ assemble_name(file, name);
+ fprintf(file, ",%d,common\n", floor_log2 (align / BITS_PER_UNIT));
+ fprintf(file, "\t.byte\t0:%d\n", size);
+
+ /* Mark the symbol as defined in this module. */
+ name_tree = get_identifier (name);
+ TREE_ASM_WRITTEN (name_tree) = 1;
+}
+
+#define SECTION_PUBLIC SECTION_MACH_DEP
+#define SECTION_MAIN (SECTION_PUBLIC << 1)
+static int current_section_align;
+
+static unsigned int
+unicosmk_section_type_flags (decl, name, reloc)
+ tree decl;
+ const char *name;
+ int reloc ATTRIBUTE_UNUSED;
+{
+ unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+ if (!decl)
+ return flags;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ current_section_align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ if (align_functions_log > current_section_align)
+ current_section_align = align_functions_log;
+
+ if (! strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "main"))
+ flags |= SECTION_MAIN;
+ }
+ else
+ current_section_align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
+
+ if (TREE_PUBLIC (decl))
+ flags |= SECTION_PUBLIC;
+
+ return flags;
+}
+
+/* Generate a section name for decl and associate it with the
+ declaration. */
+
+void
+unicosmk_unique_section (decl, reloc)
+ tree decl;
+ int reloc ATTRIBUTE_UNUSED;
+{
+ const char *name;
+ int len;
+
+ if (!decl)
+ abort ();
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ STRIP_NAME_ENCODING (name, name);
+ len = strlen (name);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ char *string;
+
+ /* It is essential that we prefix the section name here because
+ otherwise the section names generated for constructors and
+ destructors confuse collect2. */
+
+ string = alloca (len + 6);
+ sprintf (string, "code@%s", name);
+ DECL_SECTION_NAME (decl) = build_string (len + 5, string);
+ }
+ else if (TREE_PUBLIC (decl))
+ DECL_SECTION_NAME (decl) = build_string (len, name);
+ else
+ {
+ char *string;
+
+ string = alloca (len + 6);
+ sprintf (string, "data@%s", name);
+ DECL_SECTION_NAME (decl) = build_string (len + 5, string);
+ }
+}
+
+/* Switch to an arbitrary section NAME with attributes as specified
+ by FLAGS. ALIGN specifies any known alignment requirements for
+ the section; 0 if the default should be used. */
+
+static void
+unicosmk_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ const char *kind;
+
+ /* Close the previous section. */
+
+ fputs ("\t.endp\n\n", asm_out_file);
+
+ /* Find out what kind of section we are opening. */
+
+ if (flags & SECTION_MAIN)
+ fputs ("\t.start\tmain\n", asm_out_file);
+
+ if (flags & SECTION_CODE)
+ kind = "code";
+ else if (flags & SECTION_PUBLIC)
+ kind = "common";
+ else
+ kind = "data";
+
+ if (current_section_align != 0)
+ fprintf (asm_out_file, "\t.psect\t%s,%d,%s\n", name,
+ current_section_align, kind);
+ else
+ fprintf (asm_out_file, "\t.psect\t%s,%s\n", name, kind);
+}
+
+static void
+unicosmk_insert_attributes (decl, attr_ptr)
+ tree decl;
+ tree *attr_ptr ATTRIBUTE_UNUSED;
+{
+ if (DECL_P (decl)
+ && (TREE_PUBLIC (decl) || TREE_CODE (decl) == FUNCTION_DECL))
+ UNIQUE_SECTION (decl, 0);
+}
+
+/* Output an alignment directive. We have to use the macro 'gcc@code@align'
+ in code sections because .align fill unused space with zeroes. */
+
+void
+unicosmk_output_align (file, align)
+ FILE *file;
+ int align;
+{
+ if (inside_function)
+ fprintf (file, "\tgcc@code@align\t%d\n", align);
+ else
+ fprintf (file, "\t.align\t%d\n", align);
+}
+
+/* Add a case vector to the current function's list of deferred case
+ vectors. Case vectors have to be put into a separate section because CAM
+ does not allow data definitions in code sections. */
+
+void
+unicosmk_defer_case_vector (lab, vec)
+ rtx lab;
+ rtx vec;
+{
+ struct machine_function *machine = cfun->machine;
+
+ vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
+ machine->addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec,
+ machine->addr_list);
+}
+
+/* Output a case vector. */
+
+static void
+unicosmk_output_addr_vec (file, vec)
+ FILE *file;
+ rtx vec;
+{
+ rtx lab = XEXP (vec, 0);
+ rtx body = XEXP (vec, 1);
+ int vlen = XVECLEN (body, 0);
+ int idx;
+
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (lab));
+
+ for (idx = 0; idx < vlen; idx++)
+ {
+ ASM_OUTPUT_ADDR_VEC_ELT
+ (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
+ }
+}
+
+/* Output current function's deferred case vectors. */
+
+static void
+unicosmk_output_deferred_case_vectors (file)
+ FILE *file;
+{
+ struct machine_function *machine = cfun->machine;
+ rtx t;
+
+ if (machine->addr_list == NULL_RTX)
+ return;
+
+ data_section ();
+ for (t = machine->addr_list; t; t = XEXP (t, 1))
+ unicosmk_output_addr_vec (file, XEXP (t, 0));
+}
+
+/* Set up the dynamic subprogram information block (DSIB) and update the
+ frame pointer register ($15) for subroutines which have a frame. If the
+ subroutine doesn't have a frame, simply increment $15. */
+
+static void
+unicosmk_gen_dsib (imaskP)
+ unsigned long * imaskP;
+{
+ if (alpha_is_stack_procedure)
+ {
+ const char *ssib_name;
+ rtx mem;
+
+ /* Allocate 64 bytes for the DSIB. */
+
+ FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-64))));
+ emit_insn (gen_blockage ());
- fprintf (stream, "\t.align 3\n");
+ /* Save the return address. */
- for (lptr = alpha_links_base; lptr; lptr = nptr)
+ mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 56));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
+ (*imaskP) &= ~(1L << REG_RA);
+
+ /* Save the old frame pointer. */
+
+ mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 48));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, hard_frame_pointer_rtx));
+ (*imaskP) &= ~(1L << HARD_FRAME_POINTER_REGNUM);
+
+ emit_insn (gen_blockage ());
+
+ /* Store the SSIB pointer. */
+
+ ssib_name = ggc_strdup (unicosmk_ssib_name ());
+ mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 32));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+
+ FRP (emit_move_insn (gen_rtx_REG (DImode, 5),
+ gen_rtx_SYMBOL_REF (Pmode, ssib_name)));
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 5)));
+
+ /* Save the CIW index. */
+
+ mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 24));
+ set_mem_alias_set (mem, alpha_sr_alias_set);
+ FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 25)));
+
+ emit_insn (gen_blockage ());
+
+ /* Set the new frame pointer. */
+
+ FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+ stack_pointer_rtx, GEN_INT (64))));
+
+ }
+ else
{
- nptr = lptr->next;
+ /* Increment the frame pointer register to indicate that we do not
+ have a frame. */
+
+ FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+ hard_frame_pointer_rtx, GEN_INT (1))));
+ }
+}
+
+#define SSIB_PREFIX "__SSIB_"
+#define SSIB_PREFIX_LEN 7
+
+/* Generate the name of the SSIB section for the current function. */
+
+static const char *
+unicosmk_ssib_name ()
+{
+ /* This is ok since CAM won't be able to deal with names longer than that
+ anyway. */
+
+ static char name[256];
+
+ rtx x;
+ const char *fnname;
+ int len;
+
+ x = DECL_RTL (cfun->decl);
+ if (GET_CODE (x) != MEM)
+ abort ();
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
+ fnname = XSTR (x, 0);
+ STRIP_NAME_ENCODING (fnname, fnname);
+
+ len = strlen (fnname);
+ if (len + SSIB_PREFIX_LEN > 255)
+ len = 255 - SSIB_PREFIX_LEN;
+
+ strcpy (name, SSIB_PREFIX);
+ strncpy (name + SSIB_PREFIX_LEN, fnname, len);
+ name[len + SSIB_PREFIX_LEN] = 0;
+
+ return name;
+}
+
+/* Output the static subroutine information block for the current
+ function. */
+
+static void
+unicosmk_output_ssib (file, fnname)
+ FILE *file;
+ const char *fnname;
+{
+ int len;
+ int i;
+ rtx x;
+ rtx ciw;
+ struct machine_function *machine = cfun->machine;
+
+ ssib_section ();
+ fprintf (file, "\t.endp\n\n\t.psect\t%s%s,data\n", user_label_prefix,
+ unicosmk_ssib_name ());
+
+ /* Some required stuff and the function name length. */
+
+ len = strlen (fnname);
+ fprintf (file, "\t.quad\t^X20008%2.2X28\n", len);
+
+ /* Saved registers
+ ??? We don't do that yet. */
- if (lptr->kind == KIND_UNUSED
- || ! TREE_SYMBOL_REFERENCED (get_identifier (lptr->name)))
- continue;
+ fputs ("\t.quad\t0\n", file);
- fprintf (stream, "$%s..lk:\n", lptr->name);
- if (lptr->kind == KIND_LOCAL)
+ /* Function address. */
+
+ fputs ("\t.quad\t", file);
+ assemble_name (file, fnname);
+ putc ('\n', file);
+
+ fputs ("\t.quad\t0\n", file);
+ fputs ("\t.quad\t0\n", file);
+
+ /* Function name.
+ ??? We do it the same way Cray CC does it but this could be
+ simplified. */
+
+ for( i = 0; i < len; i++ )
+ fprintf (file, "\t.byte\t%d\n", (int)(fnname[i]));
+ if( (len % 8) == 0 )
+ fputs ("\t.quad\t0\n", file);
+ else
+ fprintf (file, "\t.bits\t%d : 0\n", (8 - (len % 8))*8);
+
+ /* All call information words used in the function. */
+
+ for (x = machine->first_ciw; x; x = XEXP (x, 1))
+ {
+ ciw = XEXP (x, 0);
+ fprintf (file, "\t.quad\t");
+#if HOST_BITS_PER_WIDE_INT == 32
+ fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+ CONST_DOUBLE_HIGH (ciw), CONST_DOUBLE_LOW (ciw));
+#else
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (ciw));
+#endif
+ fprintf (file, "\n");
+ }
+}
+
+/* Add a call information word (CIW) to the list of the current function's
+ CIWs and return its index.
+
+ X is a CONST_INT or CONST_DOUBLE representing the CIW. */
+
+rtx
+unicosmk_add_call_info_word (x)
+ rtx x;
+{
+ rtx node;
+ struct machine_function *machine = cfun->machine;
+
+ node = gen_rtx_EXPR_LIST (VOIDmode, x, NULL_RTX);
+ if (machine->first_ciw == NULL_RTX)
+ machine->first_ciw = node;
+ else
+ XEXP (machine->last_ciw, 1) = node;
+
+ machine->last_ciw = node;
+ ++machine->ciw_count;
+
+ return GEN_INT (machine->ciw_count
+ + strlen (current_function_name)/8 + 5);
+}
+
+static char unicosmk_section_buf[100];
+
+char *
+unicosmk_text_section ()
+{
+ static int count = 0;
+ sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@text___%d,code",
+ count++);
+ return unicosmk_section_buf;
+}
+
+char *
+unicosmk_data_section ()
+{
+ static int count = 1;
+ sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@data___%d,data",
+ count++);
+ return unicosmk_section_buf;
+}
+
+/* The Cray assembler doesn't accept extern declarations for symbols which
+ are defined in the same file. We have to keep track of all global
+ symbols which are referenced and/or defined in a source file and output
+ extern declarations for those which are referenced but not defined at
+ the end of file. */
+
+/* List of identifiers for which an extern declaration might have to be
+ emitted. */
+
+struct unicosmk_extern_list
+{
+ struct unicosmk_extern_list *next;
+ const char *name;
+};
+
+static struct unicosmk_extern_list *unicosmk_extern_head = 0;
+
+/* Output extern declarations which are required for every asm file. */
+
+static void
+unicosmk_output_default_externs (file)
+ FILE *file;
+{
+ static const char *const externs[] =
+ { "__T3E_MISMATCH" };
+
+ int i;
+ int n;
+
+ n = ARRAY_SIZE (externs);
+
+ for (i = 0; i < n; i++)
+ fprintf (file, "\t.extern\t%s\n", externs[i]);
+}
+
+/* Output extern declarations for global symbols which are have been
+ referenced but not defined. */
+
+static void
+unicosmk_output_externs (file)
+ FILE *file;
+{
+ struct unicosmk_extern_list *p;
+ const char *real_name;
+ int len;
+ tree name_tree;
+
+ len = strlen (user_label_prefix);
+ for (p = unicosmk_extern_head; p != 0; p = p->next)
+ {
+ /* We have to strip the encoding and possibly remove user_label_prefix
+ from the identifier in order to handle -fleading-underscore and
+ explicit asm names correctly (cf. gcc.dg/asm-names-1.c). */
+ STRIP_NAME_ENCODING (real_name, p->name);
+ if (len && p->name[0] == '*'
+ && !memcmp (real_name, user_label_prefix, len))
+ real_name += len;
+
+ name_tree = get_identifier (real_name);
+ if (! TREE_ASM_WRITTEN (name_tree))
{
- /* Local and used, build linkage pair. */
- fprintf (stream, "\t.quad %s..en\n", lptr->name);
- fprintf (stream, "\t.quad %s\n", lptr->name);
+ TREE_ASM_WRITTEN (name_tree) = 1;
+ fputs ("\t.extern\t", file);
+ assemble_name (file, p->name);
+ putc ('\n', file);
}
- else
- /* External and used, request linkage pair. */
- fprintf (stream, "\t.linkage %s\n", lptr->name);
}
}
+
+/* Record an extern. */
+
+void
+unicosmk_add_extern (name)
+ const char *name;
+{
+ struct unicosmk_extern_list *p;
+
+ p = (struct unicosmk_extern_list *)
+ permalloc (sizeof (struct unicosmk_extern_list));
+ p->next = unicosmk_extern_head;
+ p->name = name;
+ unicosmk_extern_head = p;
+}
+
+/* The Cray assembler generates incorrect code if identifiers which
+ conflict with register names are used as instruction operands. We have
+ to replace such identifiers with DEX expressions. */
+
+/* Structure to collect identifiers which have been replaced by DEX
+ expressions. */
+
+struct unicosmk_dex {
+ struct unicosmk_dex *next;
+ const char *name;
+};
+
+/* List of identifiers which have been replaced by DEX expressions. The DEX
+ number is determined by the position in the list. */
+
+static struct unicosmk_dex *unicosmk_dex_list = NULL;
+
+/* The number of elements in the DEX list. */
+
+static int unicosmk_dex_count = 0;
+
+/* Check if NAME must be replaced by a DEX expression. */
+
+static int
+unicosmk_special_name (name)
+ const char *name;
+{
+ if (name[0] == '*')
+ ++name;
+
+ if (name[0] == '$')
+ ++name;
+
+ if (name[0] != 'r' && name[0] != 'f' && name[0] != 'R' && name[0] != 'F')
+ return 0;
+
+ switch (name[1])
+ {
+ case '1': case '2':
+ return (name[2] == '\0' || (ISDIGIT (name[2]) && name[3] == '\0'));
+
+ case '3':
+ return (name[2] == '\0'
+ || ((name[2] == '0' || name[2] == '1') && name[3] == '\0'));
+
+ default:
+ return (ISDIGIT (name[1]) && name[2] == '\0');
+ }
+}
+
+/* Return the DEX number if X must be replaced by a DEX expression and 0
+ otherwise. */
+
+static int
+unicosmk_need_dex (x)
+ rtx x;
+{
+ struct unicosmk_dex *dex;
+ const char *name;
+ int i;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ return 0;
+
+ name = XSTR (x,0);
+ if (! unicosmk_special_name (name))
+ return 0;
+
+ i = unicosmk_dex_count;
+ for (dex = unicosmk_dex_list; dex; dex = dex->next)
+ {
+ if (! strcmp (name, dex->name))
+ return i;
+ --i;
+ }
+
+ dex = (struct unicosmk_dex *) permalloc (sizeof (struct unicosmk_dex));
+ dex->name = name;
+ dex->next = unicosmk_dex_list;
+ unicosmk_dex_list = dex;
+
+ ++unicosmk_dex_count;
+ return unicosmk_dex_count;
+}
+
+/* Output the DEX definitions for this file. */
+
+static void
+unicosmk_output_dex (file)
+ FILE *file;
+{
+ struct unicosmk_dex *dex;
+ int i;
+
+ if (unicosmk_dex_list == NULL)
+ return;
+
+ fprintf (file, "\t.dexstart\n");
+
+ i = unicosmk_dex_count;
+ for (dex = unicosmk_dex_list; dex; dex = dex->next)
+ {
+ fprintf (file, "\tDEX (%d) = ", i);
+ assemble_name (file, dex->name);
+ putc ('\n', file);
+ --i;
+ }
+
+ fprintf (file, "\t.dexend\n");
+}
#else
-void
-alpha_need_linkage (name, is_local)
- char *name ATTRIBUTE_UNUSED;
- int is_local ATTRIBUTE_UNUSED;
+static void
+unicosmk_output_deferred_case_vectors (file)
+ FILE *file ATTRIBUTE_UNUSED;
+{}
+
+static void
+unicosmk_gen_dsib (imaskP)
+ unsigned long * imaskP ATTRIBUTE_UNUSED;
+{}
+
+static void
+unicosmk_output_ssib (file, fnname)
+ FILE * file ATTRIBUTE_UNUSED;
+ const char * fnname ATTRIBUTE_UNUSED;
+{}
+
+rtx
+unicosmk_add_call_info_word (x)
+ rtx x ATTRIBUTE_UNUSED;
{
+ return NULL_RTX;
+}
+
+static int
+unicosmk_need_dex (x)
+ rtx x ATTRIBUTE_UNUSED;
+{
+ return 0;
}
-#endif /* OPEN_VMS */
+#endif /* TARGET_ABI_UNICOSMK */
diff --git a/contrib/gcc/config/alpha/alpha.h b/contrib/gcc/config/alpha/alpha.h
index e9c3f6d..dd8d820 100644
--- a/contrib/gcc/config/alpha/alpha.h
+++ b/contrib/gcc/config/alpha/alpha.h
@@ -1,5 +1,6 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha.
- Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -20,14 +21,20 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/* For C++ we need to ensure that __LANGUAGE_C_PLUS_PLUS is defined independent
+ of the source file extension. */
+#define CPLUSPLUS_CPP_SPEC "\
+-D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus \
+%(cpp) \
+"
+
/* Write out the correct language type definition for the header files.
Unless we have assembler language, write out the symbols for C. */
#define CPP_SPEC "\
%{!undef:\
%{.S:-D__LANGUAGE_ASSEMBLY__ -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY }}\
-%{.cc|.cxx|.C:-D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus }\
%{.m:-D__LANGUAGE_OBJECTIVE_C__ -D__LANGUAGE_OBJECTIVE_C }\
-%{!.S:%{!.cc:%{!.cxx:%{!.C:%{!.m:-D__LANGUAGE_C__ -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C }}}}}}\
+%{!.S:%{!.cc:%{!.cxx:%{!.cpp:%{!.cp:%{!.c++:%{!.C:%{!.m:-D__LANGUAGE_C__ -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C }}}}}}}}}\
%{mieee:-D_IEEE_FP }\
%{mieee-with-inexact:-D_IEEE_FP -D_IEEE_FP_INEXACT }}\
%(cpp_cpu) %(cpp_subtarget)"
@@ -43,11 +50,7 @@ Boston, MA 02111-1307, USA. */
#define SIGNED_CHAR_SPEC "%{funsigned-char:-D__CHAR_UNSIGNED__}"
#define WORD_SWITCH_TAKES_ARG(STR) \
- (!strcmp (STR, "rpath") || !strcmp (STR, "include") \
- || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
- || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
- || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
- || !strcmp (STR, "isystem"))
+ (!strcmp (STR, "rpath") || DEFAULT_WORD_SWITCH_TAKES_ARG(STR))
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION
@@ -68,20 +71,20 @@ enum alpha_trap_precision
{
ALPHA_TP_PROG, /* No precision (default). */
ALPHA_TP_FUNC, /* Trap contained within originating function. */
- ALPHA_TP_INSN /* Instruction accuracy and code is resumption safe. */
+ ALPHA_TP_INSN /* Instruction accuracy and code is resumption safe. */
};
enum alpha_fp_rounding_mode
{
ALPHA_FPRM_NORM, /* Normal rounding mode. */
ALPHA_FPRM_MINF, /* Round towards minus-infinity. */
- ALPHA_FPRM_CHOP, /* Chopped rounding mode (towards 0). */
+ ALPHA_FPRM_CHOP, /* Chopped rounding mode (towards 0). */
ALPHA_FPRM_DYN /* Dynamic rounding mode. */
};
enum alpha_fp_trap_mode
{
- ALPHA_FPTM_N, /* Normal trap mode. */
+ ALPHA_FPTM_N, /* Normal trap mode. */
ALPHA_FPTM_U, /* Underflow traps enabled. */
ALPHA_FPTM_SU, /* Software completion, w/underflow traps */
ALPHA_FPTM_SUI /* Software completion, w/underflow & inexact traps */
@@ -110,7 +113,7 @@ extern enum alpha_fp_trap_mode alpha_fptm;
#define MASK_GAS (1 << 2)
#define TARGET_GAS (target_flags & MASK_GAS)
-/* This means that we should mark procedures as IEEE conformant. */
+/* This means that we should mark procedures as IEEE conformant. */
#define MASK_IEEE_CONFORMANT (1 << 3)
#define TARGET_IEEE_CONFORMANT (target_flags & MASK_IEEE_CONFORMANT)
@@ -155,12 +158,22 @@ extern enum alpha_fp_trap_mode alpha_fptm;
#define MASK_CIX (1 << 11)
#define TARGET_CIX (target_flags & MASK_CIX)
-/* This means that the processor is an EV5, EV56, or PCA56. This is defined
- only in TARGET_CPU_DEFAULT. */
+/* This means use !literal style explicit relocations. */
+#define MASK_EXPLICIT_RELOCS (1 << 12)
+#define TARGET_EXPLICIT_RELOCS (target_flags & MASK_EXPLICIT_RELOCS)
+
+/* This means use 16-bit relocations to .sdata/.sbss. */
+#define MASK_SMALL_DATA (1 << 13)
+#define TARGET_SMALL_DATA (target_flags & MASK_SMALL_DATA)
+
+/* This means that the processor is an EV5, EV56, or PCA56.
+ Unlike alpha_cpu this is not affected by -mtune= setting. */
#define MASK_CPU_EV5 (1 << 28)
+#define TARGET_CPU_EV5 (target_flags & MASK_CPU_EV5)
/* Likewise for EV6. */
#define MASK_CPU_EV6 (1 << 29)
+#define TARGET_CPU_EV6 (target_flags & MASK_CPU_EV6)
/* This means we support the .arch directive in the assembler. Only
defined in TARGET_CPU_DEFAULT. */
@@ -168,19 +181,34 @@ extern enum alpha_fp_trap_mode alpha_fptm;
#define TARGET_SUPPORT_ARCH (target_flags & MASK_SUPPORT_ARCH)
/* These are for target os support and cannot be changed at runtime. */
-#ifndef TARGET_WINDOWS_NT
-#define TARGET_WINDOWS_NT 0
-#endif
-#ifndef TARGET_OPEN_VMS
-#define TARGET_OPEN_VMS 0
-#endif
+#define TARGET_ABI_WINDOWS_NT 0
+#define TARGET_ABI_OPEN_VMS 0
+#define TARGET_ABI_UNICOSMK 0
+#define TARGET_ABI_OSF (!TARGET_ABI_WINDOWS_NT \
+ && !TARGET_ABI_OPEN_VMS \
+ && !TARGET_ABI_UNICOSMK)
#ifndef TARGET_AS_CAN_SUBTRACT_LABELS
#define TARGET_AS_CAN_SUBTRACT_LABELS TARGET_GAS
#endif
+#ifndef TARGET_AS_SLASH_BEFORE_SUFFIX
+#define TARGET_AS_SLASH_BEFORE_SUFFIX TARGET_GAS
+#endif
#ifndef TARGET_CAN_FAULT_IN_PROLOGUE
#define TARGET_CAN_FAULT_IN_PROLOGUE 0
#endif
+#ifndef TARGET_HAS_XFLOATING_LIBS
+#define TARGET_HAS_XFLOATING_LIBS 0
+#endif
+#ifndef TARGET_PROFILING_NEEDS_GP
+#define TARGET_PROFILING_NEEDS_GP 0
+#endif
+#ifndef TARGET_LD_BUGGY_LDGP
+#define TARGET_LD_BUGGY_LDGP 0
+#endif
+#ifndef TARGET_FIXUP_EV5_PREFETCH
+#define TARGET_FIXUP_EV5_PREFETCH 0
+#endif
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
@@ -189,31 +217,42 @@ extern enum alpha_fp_trap_mode alpha_fptm;
An empty string NAME is used to identify the default VALUE. */
#define TARGET_SWITCHES \
- { {"no-soft-float", MASK_FP, "Use hardware fp"}, \
- {"soft-float", - MASK_FP, "Do not use hardware fp"}, \
- {"fp-regs", MASK_FPREGS, "Use fp registers"}, \
- {"no-fp-regs", - (MASK_FP|MASK_FPREGS), "Do not use fp registers"}, \
- {"alpha-as", -MASK_GAS, "Do not assume GAS"}, \
- {"gas", MASK_GAS, "Assume GAS"}, \
+ { {"no-soft-float", MASK_FP, N_("Use hardware fp")}, \
+ {"soft-float", - MASK_FP, N_("Do not use hardware fp")}, \
+ {"fp-regs", MASK_FPREGS, N_("Use fp registers")}, \
+ {"no-fp-regs", - (MASK_FP|MASK_FPREGS), \
+ N_("Do not use fp registers")}, \
+ {"alpha-as", -MASK_GAS, N_("Do not assume GAS")}, \
+ {"gas", MASK_GAS, N_("Assume GAS")}, \
{"ieee-conformant", MASK_IEEE_CONFORMANT, \
- "Request IEEE-conformant math library routines (OSF/1)"}, \
+ N_("Request IEEE-conformant math library routines (OSF/1)")}, \
{"ieee", MASK_IEEE|MASK_IEEE_CONFORMANT, \
- "Emit IEEE-conformant code, without inexact exceptions"}, \
+ N_("Emit IEEE-conformant code, without inexact exceptions")}, \
{"ieee-with-inexact", MASK_IEEE_WITH_INEXACT|MASK_IEEE_CONFORMANT, \
- "Emit IEEE-conformant code, with inexact exceptions"}, \
+ N_("Emit IEEE-conformant code, with inexact exceptions")}, \
{"build-constants", MASK_BUILD_CONSTANTS, \
- "Do not emit complex integer constants to read-only memory"}, \
- {"float-vax", MASK_FLOAT_VAX, "Use VAX fp"}, \
- {"float-ieee", -MASK_FLOAT_VAX, "Do not use VAX fp"}, \
- {"bwx", MASK_BWX, "Emit code for the byte/word ISA extension"}, \
+ N_("Do not emit complex integer constants to read-only memory")}, \
+ {"float-vax", MASK_FLOAT_VAX, N_("Use VAX fp")}, \
+ {"float-ieee", -MASK_FLOAT_VAX, N_("Do not use VAX fp")}, \
+ {"bwx", MASK_BWX, N_("Emit code for the byte/word ISA extension")}, \
{"no-bwx", -MASK_BWX, ""}, \
- {"max", MASK_MAX, "Emit code for the motion video ISA extension"}, \
+ {"max", MASK_MAX, \
+ N_("Emit code for the motion video ISA extension")}, \
{"no-max", -MASK_MAX, ""}, \
- {"fix", MASK_FIX, "Emit code for the fp move and sqrt ISA extension"}, \
+ {"fix", MASK_FIX, \
+ N_("Emit code for the fp move and sqrt ISA extension")}, \
{"no-fix", -MASK_FIX, ""}, \
- {"cix", MASK_CIX, "Emit code for the counting ISA extension"}, \
+ {"cix", MASK_CIX, N_("Emit code for the counting ISA extension")}, \
{"no-cix", -MASK_CIX, ""}, \
- {"", TARGET_DEFAULT | TARGET_CPU_DEFAULT, ""} }
+ {"explicit-relocs", MASK_EXPLICIT_RELOCS, \
+ N_("Emit code using explicit relocation directives")}, \
+ {"no-explicit-relocs", -MASK_EXPLICIT_RELOCS, ""}, \
+ {"small-data", MASK_SMALL_DATA, \
+ N_("Emit 16-bit relocations to the small data areas")}, \
+ {"large-data", -MASK_SMALL_DATA, \
+ N_("Emit 32-bit relocations to the small data areas")}, \
+ {"", TARGET_DEFAULT | TARGET_CPU_DEFAULT \
+ | TARGET_DEFAULT_EXPLICIT_RELOCS, ""} }
#define TARGET_DEFAULT MASK_FP|MASK_FPREGS
@@ -221,24 +260,16 @@ extern enum alpha_fp_trap_mode alpha_fptm;
#define TARGET_CPU_DEFAULT 0
#endif
-/* This macro is similar to `TARGET_SWITCHES' but defines names of
- command options that have values. Its definition is an initializer
- with a subgrouping for each command option.
-
- Each subgrouping contains a string constant, that defines the fixed
- part of the option name, and the address of a variable. The
- variable, type `char *', is set to the variable part of the given
- option if the fixed part matches. The actual option name is made
- by appending `-m' to the specified name.
-
- Here is an example which defines `-mshort-data-NUMBER'. If the
- given option is `-mshort-data-512', the variable `m88k_short_data'
- will be set to the string `"512"'.
-
- extern char *m88k_short_data;
- #define TARGET_OPTIONS { { "short-data-", &m88k_short_data } } */
+#ifndef TARGET_DEFAULT_EXPLICIT_RELOCS
+#ifdef HAVE_AS_EXPLICIT_RELOCS
+#define TARGET_DEFAULT_EXPLICIT_RELOCS MASK_EXPLICIT_RELOCS
+#else
+#define TARGET_DEFAULT_EXPLICIT_RELOCS 0
+#endif
+#endif
extern const char *alpha_cpu_string; /* For -mcpu= */
+extern const char *alpha_tune_string; /* For -mtune= */
extern const char *alpha_fprm_string; /* For -mfp-rounding-mode=[n|m|c|d] */
extern const char *alpha_fptm_string; /* For -mfp-trap-mode=[n|u|su|sui] */
extern const char *alpha_tp_string; /* For -mtrap-precision=[p|f|i] */
@@ -247,40 +278,49 @@ extern const char *alpha_mlat_string; /* For -mmemory-latency= */
#define TARGET_OPTIONS \
{ \
{"cpu=", &alpha_cpu_string, \
- "Generate code for a given CPU"}, \
+ N_("Use features of and schedule given CPU")}, \
+ {"tune=", &alpha_tune_string, \
+ N_("Schedule given CPU")}, \
{"fp-rounding-mode=", &alpha_fprm_string, \
- "Control the generated fp rounding mode"}, \
+ N_("Control the generated fp rounding mode")}, \
{"fp-trap-mode=", &alpha_fptm_string, \
- "Control the IEEE trap mode"}, \
+ N_("Control the IEEE trap mode")}, \
{"trap-precision=", &alpha_tp_string, \
- "Control the precision given to fp exceptions"}, \
+ N_("Control the precision given to fp exceptions")}, \
{"memory-latency=", &alpha_mlat_string, \
- "Tune expected memory latency"}, \
+ N_("Tune expected memory latency")}, \
}
/* Attempt to describe CPU characteristics to the preprocessor. */
-/* Corresponding to amask... */
-#define CPP_AM_BWX_SPEC "-D__alpha_bwx__ -Acpu(bwx)"
-#define CPP_AM_MAX_SPEC "-D__alpha_max__ -Acpu(max)"
-#define CPP_AM_FIX_SPEC "-D__alpha_fix__ -Acpu(fix)"
-#define CPP_AM_CIX_SPEC "-D__alpha_cix__ -Acpu(cix)"
+/* Corresponding to amask... */
+#define CPP_AM_BWX_SPEC "-D__alpha_bwx__ -Acpu=bwx"
+#define CPP_AM_MAX_SPEC "-D__alpha_max__ -Acpu=max"
+#define CPP_AM_FIX_SPEC "-D__alpha_fix__ -Acpu=fix"
+#define CPP_AM_CIX_SPEC "-D__alpha_cix__ -Acpu=cix"
-/* Corresponding to implver... */
-#define CPP_IM_EV4_SPEC "-D__alpha_ev4__ -Acpu(ev4)"
-#define CPP_IM_EV5_SPEC "-D__alpha_ev5__ -Acpu(ev5)"
-#define CPP_IM_EV6_SPEC "-D__alpha_ev6__ -Acpu(ev6)"
+/* Corresponding to implver... */
+#define CPP_IM_EV4_SPEC "-D__alpha_ev4__ -Acpu=ev4"
+#define CPP_IM_EV5_SPEC "-D__alpha_ev5__ -Acpu=ev5"
+#define CPP_IM_EV6_SPEC "-D__alpha_ev6__ -Acpu=ev6"
/* Common combinations. */
#define CPP_CPU_EV4_SPEC "%(cpp_im_ev4)"
#define CPP_CPU_EV5_SPEC "%(cpp_im_ev5)"
#define CPP_CPU_EV56_SPEC "%(cpp_im_ev5) %(cpp_am_bwx)"
#define CPP_CPU_PCA56_SPEC "%(cpp_im_ev5) %(cpp_am_bwx) %(cpp_am_max)"
-#define CPP_CPU_EV6_SPEC "%(cpp_im_ev6) %(cpp_am_bwx) %(cpp_am_max) %(cpp_am_fix)"
+#define CPP_CPU_EV6_SPEC \
+ "%(cpp_im_ev6) %(cpp_am_bwx) %(cpp_am_max) %(cpp_am_fix)"
+#define CPP_CPU_EV67_SPEC \
+ "%(cpp_im_ev6) %(cpp_am_bwx) %(cpp_am_max) %(cpp_am_fix) %(cpp_am_cix)"
#ifndef CPP_CPU_DEFAULT_SPEC
# if TARGET_CPU_DEFAULT & MASK_CPU_EV6
-# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV6_SPEC
+# if TARGET_CPU_DEFAULT & MASK_CIX
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV67_SPEC
+# else
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV6_SPEC
+# endif
# else
# if TARGET_CPU_DEFAULT & MASK_CPU_EV5
# if TARGET_CPU_DEFAULT & MASK_MAX
@@ -300,12 +340,13 @@ extern const char *alpha_mlat_string; /* For -mmemory-latency= */
#ifndef CPP_CPU_SPEC
#define CPP_CPU_SPEC "\
-%{!undef:-Acpu(alpha) -Amachine(alpha) -D__alpha -D__alpha__ \
+%{!undef:-Acpu=alpha -Amachine=alpha -D__alpha -D__alpha__ \
%{mcpu=ev4|mcpu=21064:%(cpp_cpu_ev4) }\
%{mcpu=ev5|mcpu=21164:%(cpp_cpu_ev5) }\
%{mcpu=ev56|mcpu=21164a:%(cpp_cpu_ev56) }\
%{mcpu=pca56|mcpu=21164pc|mcpu=21164PC:%(cpp_cpu_pca56) }\
%{mcpu=ev6|mcpu=21264:%(cpp_cpu_ev6) }\
+%{mcpu=ev67|mcpu=21264a:%(cpp_cpu_ev67) }\
%{!mcpu*:%(cpp_cpu_default) }}"
#endif
@@ -336,6 +377,7 @@ extern const char *alpha_mlat_string; /* For -mmemory-latency= */
{ "cpp_cpu_ev56", CPP_CPU_EV56_SPEC }, \
{ "cpp_cpu_pca56", CPP_CPU_PCA56_SPEC }, \
{ "cpp_cpu_ev6", CPP_CPU_EV6_SPEC }, \
+ { "cpp_cpu_ev67", CPP_CPU_EV67_SPEC }, \
{ "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
{ "cpp_cpu", CPP_CPU_SPEC }, \
{ "cpp_subtarget", CPP_SUBTARGET_SPEC }, \
@@ -351,7 +393,6 @@ extern const char *alpha_mlat_string; /* For -mmemory-latency= */
On the Alpha, it is used to translate target-option strings into
numeric values. */
-extern void override_options ();
#define OVERRIDE_OPTIONS override_options ()
@@ -360,36 +401,23 @@ extern void override_options ();
On the Alpha, we use this to disable the floating-point registers when
they don't exist. */
-#define CONDITIONAL_REGISTER_USAGE \
- if (! TARGET_FPREGS) \
- for (i = 32; i < 63; i++) \
- fixed_regs[i] = call_used_regs[i] = 1;
+#define CONDITIONAL_REGISTER_USAGE \
+{ \
+ int i; \
+ if (! TARGET_FPREGS) \
+ for (i = 32; i < 63; i++) \
+ fixed_regs[i] = call_used_regs[i] = 1; \
+}
+
/* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP
/* target machine storage layout */
-/* Define to enable software floating point emulation. */
+/* Define to enable software floating point emulation. */
#define REAL_ARITHMETIC
-/* The following #defines are used when compiling the routines in
- libgcc1.c. Since the Alpha calling conventions require single
- precision floats to be passed in the floating-point registers
- (rather than in the general registers) we have to build the
- libgcc1.c routines in such a way that they know the actual types
- of their formal arguments and the actual types of their return
- values. Otherwise, gcc will generate calls to the libgcc1.c
- routines, passing arguments in the floating-point registers,
- but the libgcc1.c routines will expect their arguments on the
- stack (where the Alpha calling conventions require structs &
- unions to be passed). */
-
-#define FLOAT_VALUE_TYPE double
-#define INTIFY(FLOATVAL) (FLOATVAL)
-#define FLOATIFY(INTVAL) (INTVAL)
-#define FLOAT_ARG_TYPE double
-
/* Define the size of `int'. The default is the same as the word size. */
#define INT_TYPE_SIZE 32
@@ -449,7 +477,7 @@ extern void override_options ();
numbered.
For Alpha we can decide arbitrarily since there are no machine instructions
- for them. Might as well be consistent with bytes. */
+ for them. Might as well be consistent with bytes. */
#define WORDS_BIG_ENDIAN 0
/* number of bits in an addressable storage unit */
@@ -475,7 +503,7 @@ extern void override_options ();
#define STACK_BOUNDARY 64
/* Allocation boundary (in *bits*) for the code of a function. */
-#define FUNCTION_BOUNDARY 256
+#define FUNCTION_BOUNDARY 32
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 64
@@ -486,28 +514,12 @@ extern void override_options ();
/* A bitfield declared as `int' forces `int' alignment for the struct. */
#define PCC_BITFIELD_TYPE_MATTERS 1
-/* Align loop starts for optimal branching.
-
- ??? Kludge this and the next macro for the moment by not doing anything if
- we don't optimize and also if we are writing ECOFF symbols to work around
- a bug in DEC's assembler. */
-
-#define LOOP_ALIGN(LABEL) \
- (optimize > 0 && write_symbols != SDB_DEBUG ? 4 : 0)
-
-/* This is how to align an instruction for optimal branching. On
- Alpha we'll get better performance by aligning on an octaword
- boundary. */
-
-#define LABEL_ALIGN_AFTER_BARRIER(FILE) \
- (optimize > 0 && write_symbols != SDB_DEBUG ? 4 : 0)
-
/* No data type wants to be aligned rounder than this. */
-#define BIGGEST_ALIGNMENT 64
+#define BIGGEST_ALIGNMENT 128
/* For atomic access to objects, must have at least 32-bit alignment
unless the machine has byte operations. */
-#define MINIMUM_ATOMIC_ALIGNMENT (TARGET_BWX ? 8 : 32)
+#define MINIMUM_ATOMIC_ALIGNMENT ((unsigned int) (TARGET_BWX ? 8 : 32))
/* Align all constants and variables to at least a word boundary so
we can pick up pieces of them faster. */
@@ -529,7 +541,7 @@ extern void override_options ();
On the Alpha, they trap. */
-#define SLOW_UNALIGNED_ACCESS 1
+#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 1
/* Standard register usage. */
@@ -675,6 +687,18 @@ extern void override_options ();
doesn't seem to specify this. */
#define STATIC_CHAIN_REGNUM 1
+/* The register number of the register used to address a table of
+ static data addresses in memory. */
+#define PIC_OFFSET_TABLE_REGNUM 29
+
+/* Define this macro if the register defined by `PIC_OFFSET_TABLE_REGNUM'
+ is clobbered by calls. */
+/* ??? It is and it isn't. It's required to be valid for a given
+ function when the function returns. It isn't clobbered by
+ current_file functions. Moreover, we do not expose the ldgp
+ until after reload, so we're probably safe. */
+/* #define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED */
+
/* Register in which address to store a structure value
arrives in the function. On the Alpha, the address is passed
as a hidden argument. */
@@ -700,30 +724,44 @@ extern void override_options ();
For any two classes, it is very desirable that there be another
class that represents their union. */
-enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
- LIM_REG_CLASSES };
+enum reg_class {
+ NO_REGS, R24_REG, R25_REG, R27_REG,
+ GENERAL_REGS, FLOAT_REGS, ALL_REGS,
+ LIM_REG_CLASSES
+};
#define N_REG_CLASSES (int) LIM_REG_CLASSES
-/* Give names of register classes as strings for dump file. */
+/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
- {"NO_REGS", "GENERAL_REGS", "FLOAT_REGS", "ALL_REGS" }
+ {"NO_REGS", "R24_REG", "R25_REG", "R27_REG", \
+ "GENERAL_REGS", "FLOAT_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. */
-#define REG_CLASS_CONTENTS \
- { {0, 0}, {~0, 0x80000000}, {0, 0x7fffffff}, {~0, ~0} }
+#define REG_CLASS_CONTENTS \
+{ {0x00000000, 0x00000000}, /* NO_REGS */ \
+ {0x01000000, 0x00000000}, /* R24_REG */ \
+ {0x02000000, 0x00000000}, /* R25_REG */ \
+ {0x08000000, 0x00000000}, /* R27_REG */ \
+ {0xffffffff, 0x80000000}, /* GENERAL_REGS */ \
+ {0x00000000, 0x7fffffff}, /* FLOAT_REGS */ \
+ {0xffffffff, 0xffffffff} }
/* 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. */
-#define REGNO_REG_CLASS(REGNO) \
- ((REGNO) >= 32 && (REGNO) <= 62 ? FLOAT_REGS : GENERAL_REGS)
+#define REGNO_REG_CLASS(REGNO) \
+ ((REGNO) == 24 ? R24_REG \
+ : (REGNO) == 25 ? R25_REG \
+ : (REGNO) == 27 ? R27_REG \
+ : (REGNO) >= 32 && (REGNO) <= 62 ? FLOAT_REGS \
+ : GENERAL_REGS)
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS NO_REGS
@@ -732,7 +770,11 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
/* Get reg_class from a letter such as appears in the machine description. */
#define REG_CLASS_FROM_LETTER(C) \
- ((C) == 'f' ? FLOAT_REGS : NO_REGS)
+ ((C) == 'a' ? R24_REG \
+ : (C) == 'b' ? R25_REG \
+ : (C) == 'c' ? R27_REG \
+ : (C) == 'f' ? FLOAT_REGS \
+ : NO_REGS)
/* Define this macro to change register usage conditional on target flags. */
/* #define CONDITIONAL_REGISTER_USAGE */
@@ -753,17 +795,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
`O' is used for negated 8-bit constants.
`P' is used for the constants 1, 2 and 3. */
-#define CONST_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VALUE) < 0x100 \
- : (C) == 'J' ? (VALUE) == 0 \
- : (C) == 'K' ? (unsigned HOST_WIDE_INT) ((VALUE) + 0x8000) < 0x10000 \
- : (C) == 'L' ? (((VALUE) & 0xffff) == 0 \
- && (((VALUE)) >> 31 == -1 || (VALUE) >> 31 == 0)) \
- : (C) == 'M' ? zap_mask (VALUE) \
- : (C) == 'N' ? (unsigned HOST_WIDE_INT) (~ (VALUE)) < 0x100 \
- : (C) == 'O' ? (unsigned HOST_WIDE_INT) (- (VALUE)) < 0x100 \
- : (C) == 'P' ? (VALUE) == 1 || (VALUE) == 2 || (VALUE) == 3 \
- : 0)
+#define CONST_OK_FOR_LETTER_P alpha_const_ok_for_letter_p
/* Similar, but for floating or large integer constants, and defining letters
G and H. Here VALUE is the CONST_DOUBLE rtx itself.
@@ -771,13 +803,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
For Alpha, `G' is the floating-point constant zero. `H' is a CONST_DOUBLE
that is the operand of a ZAP insn. */
-#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'G' ? (GET_MODE_CLASS (GET_MODE (VALUE)) == MODE_FLOAT \
- && (VALUE) == CONST0_RTX (GET_MODE (VALUE))) \
- : (C) == 'H' ? (GET_MODE (VALUE) == VOIDmode \
- && zap_mask (CONST_DOUBLE_LOW (VALUE)) \
- && zap_mask (CONST_DOUBLE_HIGH (VALUE))) \
- : 0)
+#define CONST_DOUBLE_OK_FOR_LETTER_P alpha_const_double_ok_for_letter_p
/* Optional extra constraints for this machine.
@@ -787,78 +813,40 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
`R' is a SYMBOL_REF that has SYMBOL_REF_FLAG set or is the current
function.
- 'S' is a 6-bit constant (valid for a shift insn). */
+ 'S' is a 6-bit constant (valid for a shift insn).
+
+ 'T' is a HIGH.
-#define EXTRA_CONSTRAINT(OP, C) \
- ((C) == 'Q' ? normal_memory_operand (OP, VOIDmode) \
- : (C) == 'R' ? current_file_function_operand (OP, Pmode) \
- : (C) == 'S' ? (GET_CODE (OP) == CONST_INT \
- && (unsigned HOST_WIDE_INT) INTVAL (OP) < 64) \
- : 0)
-extern int normal_memory_operand ();
+ 'U' is a symbolic operand. */
+
+#define EXTRA_CONSTRAINT alpha_extra_constraint
/* 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.
-
- On the Alpha, all constants except zero go into a floating-point
- register via memory. */
+ in some cases it is preferable to use a more restrictive class. */
-#define PREFERRED_RELOAD_CLASS(X, CLASS) \
- (CONSTANT_P (X) && (X) != const0_rtx && (X) != CONST0_RTX (GET_MODE (X)) \
- ? ((CLASS) == FLOAT_REGS || (CLASS) == NO_REGS ? NO_REGS : GENERAL_REGS)\
- : (CLASS))
+#define PREFERRED_RELOAD_CLASS alpha_preferred_reload_class
/* Loading and storing HImode or QImode values to and from memory
usually requires a scratch register. The exceptions are loading
QImode and HImode from an aligned address to a general register
unless byte instructions are permitted.
We also cannot load an unaligned address or a paradoxical SUBREG into an
- FP register. */
-
-#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,IN) \
-(((GET_CODE (IN) == MEM \
- || (GET_CODE (IN) == REG && REGNO (IN) >= FIRST_PSEUDO_REGISTER) \
- || (GET_CODE (IN) == SUBREG \
- && (GET_CODE (SUBREG_REG (IN)) == MEM \
- || (GET_CODE (SUBREG_REG (IN)) == REG \
- && REGNO (SUBREG_REG (IN)) >= FIRST_PSEUDO_REGISTER)))) \
- && (((CLASS) == FLOAT_REGS \
- && ((MODE) == SImode || (MODE) == HImode || (MODE) == QImode)) \
- || (((MODE) == QImode || (MODE) == HImode) \
- && ! TARGET_BWX && ! aligned_memory_operand (IN, MODE)))) \
- ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (IN) == MEM \
- && GET_CODE (XEXP (IN, 0)) == AND) ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (IN) == SUBREG \
- && (GET_MODE_SIZE (GET_MODE (IN)) \
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (IN))))) ? GENERAL_REGS \
- : NO_REGS)
-
-#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,OUT) \
-(((GET_CODE (OUT) == MEM \
- || (GET_CODE (OUT) == REG && REGNO (OUT) >= FIRST_PSEUDO_REGISTER) \
- || (GET_CODE (OUT) == SUBREG \
- && (GET_CODE (SUBREG_REG (OUT)) == MEM \
- || (GET_CODE (SUBREG_REG (OUT)) == REG \
- && REGNO (SUBREG_REG (OUT)) >= FIRST_PSEUDO_REGISTER)))) \
- && ((((MODE) == HImode || (MODE) == QImode) \
- && (! TARGET_BWX || (CLASS) == FLOAT_REGS)) \
- || ((MODE) == SImode && (CLASS) == FLOAT_REGS))) \
- ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (OUT) == MEM \
- && GET_CODE (XEXP (OUT, 0)) == AND) ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (OUT) == SUBREG \
- && (GET_MODE_SIZE (GET_MODE (OUT)) \
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (OUT))))) ? GENERAL_REGS \
- : NO_REGS)
+ FP register. */
+
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,IN) \
+ secondary_reload_class((CLASS), (MODE), (IN), 1)
+
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,OUT) \
+ secondary_reload_class((CLASS), (MODE), (OUT), 0)
/* If we are copying between general and FP registers, we need a memory
location unless the FIX extension is available. */
#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
- (! TARGET_FIX && (CLASS1) != (CLASS2))
+ (! TARGET_FIX && (((CLASS1) == FLOAT_REGS && (CLASS2) != FLOAT_REGS) \
+ || ((CLASS2) == FLOAT_REGS && (CLASS1) != FLOAT_REGS)))
/* Specify the mode to be used for memory when a secondary memory
location is needed. If MODE is floating-point, use it. Otherwise,
@@ -877,9 +865,14 @@ extern int normal_memory_operand ();
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* If defined, gives a class of registers that cannot be used as the
- operand of a SUBREG that changes the size of the object. */
+ operand of a SUBREG that changes the mode of the object illegally. */
+
+#define CLASS_CANNOT_CHANGE_MODE FLOAT_REGS
-#define CLASS_CANNOT_CHANGE_SIZE FLOAT_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 the cost of moving between registers of various classes. Moving
between FLOAT_REGS and anything else except float regs is expensive.
@@ -888,7 +881,7 @@ extern int normal_memory_operand ();
reduce the impact of not being able to allocate a pseudo to a
hard register. */
-#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
+#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
(((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS) \
? 2 \
: TARGET_FIX ? 3 : 4+2*alpha_memory_latency)
@@ -903,11 +896,6 @@ extern int alpha_memory_latency;
/* Provide the cost of a branch. Exact meaning under development. */
#define BRANCH_COST 5
-
-/* Adjust the cost of dependencies. */
-
-#define ADJUST_COST(INSN,LINK,DEP,COST) \
- (COST) = alpha_adjust_cost (INSN, LINK, DEP, COST)
/* Stack layout; function entry, exit and calling. */
@@ -939,7 +927,7 @@ extern int alpha_memory_latency;
/* Define this if the maximum size of all the outgoing args is to be
accumulated and pushed during the prologue. The amount can be
found in the variable current_function_outgoing_args_size. */
-#define ACCUMULATE_OUTGOING_ARGS
+#define ACCUMULATE_OUTGOING_ARGS 1
/* Offset of first parameter from the argument pointer register value. */
@@ -950,7 +938,7 @@ extern int alpha_memory_latency;
We have two registers that can be eliminated on the Alpha. First, the
frame pointer register can often be eliminated in favor of the stack
pointer register. Secondly, the argument pointer register can always be
- eliminated; it is replaced with either the stack or frame pointer. */
+ eliminated; it is replaced with either the stack or frame pointer. */
/* This is an array of structures. Each structure initializes one pair
of eliminable registers. The "from" register number is given first,
@@ -986,6 +974,8 @@ extern int alpha_memory_latency;
+ (ALPHA_ROUND (get_frame_size () \
+ current_function_pretend_args_size) \
- current_function_pretend_args_size)); \
+ else \
+ abort (); \
}
/* Define this if stack space is still allocated for a parameter passed
@@ -1009,25 +999,25 @@ extern int alpha_memory_latency;
On Alpha the value is found in $0 for integer functions and
$f0 for floating-point functions. */
-#define FUNCTION_VALUE(VALTYPE, FUNC) \
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \
- && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
- || POINTER_TYPE_P (VALTYPE)) \
+ && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
+ || POINTER_TYPE_P (VALTYPE)) \
? word_mode : TYPE_MODE (VALTYPE), \
((TARGET_FPREGS \
- && (TREE_CODE (VALTYPE) == REAL_TYPE \
+ && (TREE_CODE (VALTYPE) == REAL_TYPE \
|| TREE_CODE (VALTYPE) == COMPLEX_TYPE)) \
- ? 32 : 0))
+ ? 32 : 0))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
-#define LIBCALL_VALUE(MODE) \
+#define LIBCALL_VALUE(MODE) \
gen_rtx_REG (MODE, \
- (TARGET_FPREGS \
- && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ (TARGET_FPREGS \
+ && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
- ? 32 : 0))
+ ? 32 : 0))
/* The definition of this macro implies that there are cases where
a scalar value cannot be returned in registers.
@@ -1037,6 +1027,8 @@ extern int alpha_memory_latency;
#define RETURN_IN_MEMORY(TYPE) \
(TYPE_MODE (TYPE) == BLKmode \
+ || TYPE_MODE (TYPE) == TFmode \
+ || TYPE_MODE (TYPE) == TCmode \
|| (TREE_CODE (TYPE) == INTEGER_TYPE && TYPE_PRECISION (TYPE) > 64))
/* 1 if N is a possible register number for a function value
@@ -1073,9 +1065,9 @@ extern int alpha_memory_latency;
for the Alpha. */
#define ALPHA_ARG_SIZE(MODE, TYPE, NAMED) \
-((MODE) != BLKmode \
- ? (GET_MODE_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD \
- : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+ ((MODE) == TFmode || (MODE) == TCmode ? 1 \
+ : (((MODE) == BLKmode ? int_size_in_bytes (TYPE) : GET_MODE_SIZE (MODE)) \
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
@@ -1104,13 +1096,16 @@ extern int alpha_memory_latency;
and the rest are pushed. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
-((CUM) < 6 && ! MUST_PASS_IN_STACK (MODE, TYPE) \
- ? gen_rtx(REG, (MODE), \
- (CUM) + 16 + ((TARGET_FPREGS \
- && (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \
- || GET_MODE_CLASS (MODE) == MODE_FLOAT)) \
- * 32)) \
- : 0)
+ function_arg((CUM), (MODE), (TYPE), (NAMED))
+
+/* A C expression that indicates when an argument must be passed by
+ reference. If nonzero for an argument, a copy of that argument is
+ made in memory and a pointer to the argument is passed instead of
+ the argument itself. The pointer is passed in whatever way is
+ appropriate for passing a pointer to that type. */
+
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
+ ((MODE) == TFmode || (MODE) == TCmode)
/* Specify the padding direction of arguments.
@@ -1155,59 +1150,61 @@ extern int alpha_memory_latency;
class, but it isn't worth doing anything more efficient in this rare
case. */
-
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
{ if ((CUM) < 6) \
{ \
if (! (NO_RTL)) \
{ \
+ rtx tmp; int set = get_varargs_alias_set (); \
+ tmp = gen_rtx_MEM (BLKmode, \
+ plus_constant (virtual_incoming_args_rtx, \
+ ((CUM) + 6)* UNITS_PER_WORD)); \
+ set_mem_alias_set (tmp, set); \
move_block_from_reg \
- (16 + CUM, \
- gen_rtx (MEM, BLKmode, \
- plus_constant (virtual_incoming_args_rtx, \
- ((CUM) + 6)* UNITS_PER_WORD)), \
+ (16 + CUM, tmp, \
6 - (CUM), (6 - (CUM)) * UNITS_PER_WORD); \
+ \
+ tmp = gen_rtx_MEM (BLKmode, \
+ plus_constant (virtual_incoming_args_rtx, \
+ (CUM) * UNITS_PER_WORD)); \
+ set_mem_alias_set (tmp, set); \
move_block_from_reg \
- (16 + (TARGET_FPREGS ? 32 : 0) + CUM, \
- gen_rtx (MEM, BLKmode, \
- plus_constant (virtual_incoming_args_rtx, \
- (CUM) * UNITS_PER_WORD)), \
+ (16 + (TARGET_FPREGS ? 32 : 0) + CUM, tmp, \
6 - (CUM), (6 - (CUM)) * UNITS_PER_WORD); \
- emit_insn (gen_blockage ()); \
} \
PRETEND_SIZE = 12 * UNITS_PER_WORD; \
} \
}
+/* We do not allow indirect calls to be optimized into sibling calls, nor
+ can we allow a call to a function in a different compilation unit to
+ be optimized into a sibcall. Except if the function is known not to
+ return, in which case our caller doesn't care what the gp is. */
+#define FUNCTION_OK_FOR_SIBCALL(DECL) \
+ (DECL \
+ && ((TREE_ASM_WRITTEN (DECL) && !flag_pic) \
+ || ! TREE_PUBLIC (DECL)))
+
/* Try to output insns to set TARGET equal to the constant C if it can be
done in less than N insns. Do all computations in MODE. Returns the place
where the output has been placed if it can be done and the insns have been
emitted. If it would take more than N insns, zero is returned and no
insns and emitted. */
-extern struct rtx_def *alpha_emit_set_const ();
-extern struct rtx_def *alpha_emit_set_long_const ();
-extern struct rtx_def *alpha_emit_conditional_branch ();
-extern struct rtx_def *alpha_emit_conditional_move ();
-
-/* Generate necessary RTL for __builtin_saveregs().
- ARGLIST is the argument list; see expr.c. */
-extern struct rtx_def *alpha_builtin_saveregs ();
-#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) alpha_builtin_saveregs (ARGLIST)
/* 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 *alpha_compare_op0, *alpha_compare_op1;
-extern int alpha_compare_fp_p;
-
-/* Define the information needed to modify the epilogue for EH. */
+struct alpha_compare
+{
+ struct rtx_def *op0, *op1;
+ int fp_p;
+};
-extern struct rtx_def *alpha_eh_epilogue_sp_ofs;
+extern struct alpha_compare alpha_compare;
/* Make (or fake) .linkage entry for function call.
IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */
-extern void alpha_need_linkage ();
/* This macro defines the start of an assembly comment. */
@@ -1217,19 +1214,12 @@ extern void alpha_need_linkage ();
#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \
alpha_start_function(FILE,NAME,DECL);
-extern void alpha_start_function ();
/* This macro closes up a function definition for the assembler. */
#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \
alpha_end_function(FILE,NAME,DECL)
-extern void alpha_end_function ();
-/* This macro notes the end of the prologue. */
-
-#define FUNCTION_END_PROLOGUE(FILE) output_end_prologue (FILE)
-extern void output_end_prologue ();
-
/* Output any profiling code before the prologue. */
#define PROFILE_BEFORE_PROLOGUE 1
@@ -1242,7 +1232,7 @@ extern void output_end_prologue ();
/* Output assembler code to FILE to initialize this source file's
basic block profiling info, if that has not already been done.
- This assumes that __bb_init_func doesn't garble a1-a5. */
+ This assumes that __bb_init_func doesn't garble a1-a5. */
#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \
do { \
@@ -1282,6 +1272,10 @@ extern void output_end_prologue ();
No definition is equivalent to always zero. */
#define EXIT_IGNORE_STACK 1
+
+/* Define registers used by the epilogue and return instruction. */
+
+#define EPILOGUE_USES(REGNO) ((REGNO) == 26)
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts.
@@ -1289,8 +1283,7 @@ extern void output_end_prologue ();
The trampoline should set the static chain pointer to value placed
into the trampoline and should branch to the specified routine.
Note that $27 has been set to the address of the trampoline, so we can
- use it for addressability of the two data items. Trampolines are always
- aligned to FUNCTION_BOUNDARY, which is 64 bits. */
+ use it for addressability of the two data items. */
#define TRAMPOLINE_TEMPLATE(FILE) \
do { \
@@ -1310,13 +1303,16 @@ do { \
#define TRAMPOLINE_SIZE 32
+/* The alignment of a trampoline, in bits. */
+
+#define TRAMPOLINE_ALIGNMENT 64
+
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
CXT is an RTX for the static chain value for the function. */
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
alpha_initialize_trampoline (TRAMP, FNADDR, CXT, 16, 24, 8)
-extern void alpha_initialize_trampoline ();
/* A C expression whose value is RTL representing the value of the return
address for the frame COUNT steps up from the current frame.
@@ -1324,16 +1320,17 @@ extern void alpha_initialize_trampoline ();
the COUNT-1 frame if RETURN_ADDR_IN_PREVIOUS_FRAME is defined. */
#define RETURN_ADDR_RTX alpha_return_addr
-extern struct rtx_def *alpha_return_addr ();
-/* Before the prologue, RA lives in $26. */
+/* Before the prologue, RA lives in $26. */
#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 26)
-
-/* Initialize data used by insn expanders. This is called from insn_emit,
- once for every function before code is generated. */
-
-#define INIT_EXPANDERS alpha_init_expanders ()
-extern void alpha_init_expanders ();
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (26)
+
+/* Describe how we implement __builtin_eh_return. */
+#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 16 : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 28)
+#define EH_RETURN_HANDLER_RTX \
+ gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, \
+ current_function_outgoing_args_size))
/* Addressing modes, and classification of registers for them. */
@@ -1387,220 +1384,77 @@ extern void alpha_init_expanders ();
After reload, it makes no difference, since pseudo regs have
been eliminated by then. */
-#ifndef REG_OK_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_P(X) 0
/* 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_P(X) \
+#define NONSTRICT_REG_OK_FOR_BASE_P(X) \
(REGNO (X) < 32 || REGNO (X) == 63 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
/* ??? Nonzero if X is the frame pointer, or some virtual register
that may eliminate to the frame pointer. These will be allowed to
have offsets greater than 32K. This is done because register
elimination offsets will change the hi/lo split, and if we split
- before reload, we will require additional instructions. */
-#define REG_OK_FP_BASE_P(X) \
+ before reload, we will require additional instructions. */
+#define NONSTRICT_REG_OK_FP_BASE_P(X) \
(REGNO (X) == 31 || REGNO (X) == 63 \
|| (REGNO (X) >= FIRST_PSEUDO_REGISTER \
&& REGNO (X) < LAST_VIRTUAL_REGISTER))
-#else
-
-/* Nonzero if X is a hard reg that can be used as an index. */
-#define REG_OK_FOR_INDEX_P(X) 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_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
-
-#define REG_OK_FP_BASE_P(X) 0
+#define STRICT_REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#ifdef REG_OK_STRICT
+#define REG_OK_FOR_BASE_P(X) STRICT_REG_OK_FOR_BASE_P (X)
+#else
+#define REG_OK_FOR_BASE_P(X) NONSTRICT_REG_OK_FOR_BASE_P (X)
#endif
-/* 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.
-
- For Alpha, we have either a constant address or the sum of a register
- and a constant address, or just a register. For DImode, any of those
- forms can be surrounded with an AND that clear the low-order three bits;
- this is an "unaligned" access.
-
- First define the basic valid address. */
-
-#define GO_IF_LEGITIMATE_SIMPLE_ADDRESS(MODE, X, ADDR) \
-{ \
- rtx tmp = (X); \
- if (GET_CODE (tmp) == SUBREG \
- && (GET_MODE_SIZE (GET_MODE (tmp)) \
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (tmp))))) \
- tmp = SUBREG_REG (tmp); \
- if (REG_P (tmp) && REG_OK_FOR_BASE_P (tmp)) \
- goto ADDR; \
- if (CONSTANT_ADDRESS_P (X)) \
- goto ADDR; \
- if (GET_CODE (X) == PLUS) \
- { \
- tmp = XEXP (X, 0); \
- if (GET_CODE (tmp) == SUBREG \
- && (GET_MODE_SIZE (GET_MODE (tmp)) \
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (tmp))))) \
- tmp = SUBREG_REG (tmp); \
- if (REG_P (tmp)) \
- { \
- if (REG_OK_FP_BASE_P (tmp) \
- && GET_CODE (XEXP (X, 1)) == CONST_INT) \
- goto ADDR; \
- if (REG_OK_FOR_BASE_P (tmp) \
- && CONSTANT_ADDRESS_P (XEXP (X, 1))) \
- goto ADDR; \
- } \
- } \
-}
-
-/* Now accept the simple address, or, for DImode only, an AND of a simple
- address that turns off the low three bits. */
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a
+ valid memory address for an instruction. */
-#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
-{ GO_IF_LEGITIMATE_SIMPLE_ADDRESS (MODE, X, ADDR); \
- if ((MODE) == DImode \
- && GET_CODE (X) == AND \
- && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && INTVAL (XEXP (X, 1)) == -8) \
- GO_IF_LEGITIMATE_SIMPLE_ADDRESS (MODE, XEXP (X, 0), ADDR); \
-}
+#ifdef REG_OK_STRICT
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \
+do { \
+ if (alpha_legitimate_address_p (MODE, X, 1)) \
+ goto WIN; \
+} while (0)
+#else
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \
+do { \
+ if (alpha_legitimate_address_p (MODE, X, 0)) \
+ goto WIN; \
+} while (0)
+#endif
/* 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.
-
- OLDX is the address as it was before break_out_memory_refs was called.
- In some cases it is useful to look at this to decide what needs to be done.
-
- MODE and WIN are passed so that this macro can use
- GO_IF_LEGITIMATE_ADDRESS.
-
- It is always safe for this macro to do nothing. It exists to recognize
- opportunities to optimize the output.
-
- For the Alpha, there are three cases we handle:
-
- (1) If the address is (plus reg const_int) and the CONST_INT is not a
- valid offset, compute the high part of the constant and add it to the
- register. Then our address is (plus temp low-part-const).
- (2) If the address is (const (plus FOO const_int)), find the low-order
- part of the CONST_INT. Then load FOO plus any high-order part of the
- CONST_INT into a register. Our address is (plus reg low-part-const).
- This is done to reduce the number of GOT entries.
- (3) If we have a (plus reg const), emit the load as in (2), then add
- the two registers, and finally generate (plus reg low-part-const) as
- our address. */
+ This macro is used in only one place: `memory_address' in explow.c. */
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
-{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
- && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && ! CONSTANT_ADDRESS_P (XEXP (X, 1))) \
- { \
- HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \
- HOST_WIDE_INT lowpart = (val & 0xffff) - 2 * (val & 0x8000); \
- HOST_WIDE_INT highpart = val - lowpart; \
- rtx high = GEN_INT (highpart); \
- rtx temp = expand_binop (Pmode, add_optab, XEXP (x, 0), \
- high, NULL_RTX, 1, OPTAB_LIB_WIDEN); \
- \
- (X) = plus_constant (temp, lowpart); \
- goto WIN; \
- } \
- else if (GET_CODE (X) == CONST \
- && GET_CODE (XEXP (X, 0)) == PLUS \
- && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT) \
- { \
- HOST_WIDE_INT val = INTVAL (XEXP (XEXP (X, 0), 1)); \
- HOST_WIDE_INT lowpart = (val & 0xffff) - 2 * (val & 0x8000); \
- HOST_WIDE_INT highpart = val - lowpart; \
- rtx high = XEXP (XEXP (X, 0), 0); \
- \
- if (highpart) \
- high = plus_constant (high, highpart); \
- \
- (X) = plus_constant (force_reg (Pmode, high), lowpart); \
- goto WIN; \
- } \
- else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
- && GET_CODE (XEXP (X, 1)) == CONST \
- && GET_CODE (XEXP (XEXP (X, 1), 0)) == PLUS \
- && GET_CODE (XEXP (XEXP (XEXP (X, 1), 0), 1)) == CONST_INT) \
+do { \
+ rtx new_x = alpha_legitimize_address (X, NULL_RTX, MODE); \
+ if (new_x) \
{ \
- HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (X, 1), 0), 1)); \
- HOST_WIDE_INT lowpart = (val & 0xffff) - 2 * (val & 0x8000); \
- HOST_WIDE_INT highpart = val - lowpart; \
- rtx high = XEXP (XEXP (XEXP (X, 1), 0), 0); \
- \
- if (highpart) \
- high = plus_constant (high, highpart); \
- \
- high = expand_binop (Pmode, add_optab, XEXP (X, 0), \
- force_reg (Pmode, high), \
- high, 1, OPTAB_LIB_WIDEN); \
- (X) = plus_constant (high, lowpart); \
+ X = new_x; \
goto WIN; \
} \
-}
+} while (0)
/* Try a machine-dependent way of reloading an illegitimate address
operand. If we find one, push the reload and jump to WIN. This
- macro is used in only one place: `find_reloads_address' in reload.c.
-
- For the Alpha, we wish to handle large displacements off a base
- register by splitting the addend across an ldah and the mem insn.
- This cuts number of extra insns needed from 3 to 1. */
+ macro is used in only one place: `find_reloads_address' in reload.c. */
-#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
-do { \
- /* We must recognize output that we have already generated ourselves. */ \
- if (GET_CODE (X) == PLUS \
- && GET_CODE (XEXP (X, 0)) == PLUS \
- && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \
- && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
- && GET_CODE (XEXP (X, 1)) == CONST_INT) \
- { \
- push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
- BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
- OPNUM, TYPE); \
- goto WIN; \
- } \
- if (GET_CODE (X) == PLUS \
- && GET_CODE (XEXP (X, 0)) == REG \
- && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \
- && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \
- && GET_CODE (XEXP (X, 1)) == CONST_INT) \
- { \
- HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \
- HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; \
- HOST_WIDE_INT high \
- = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; \
- \
- /* Check for 32-bit overflow. */ \
- if (high + low != val) \
- break; \
- \
- /* Reload the high part into a base reg; leave the low part \
- in the mem directly. */ \
- \
- X = gen_rtx_PLUS (GET_MODE (X), \
- gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \
- GEN_INT (high)), \
- GEN_INT (low)); \
- \
- push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
- BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
- OPNUM, TYPE); \
- goto WIN; \
- } \
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_L,WIN) \
+do { \
+ rtx new_x = alpha_legitimize_reload_address (X, MODE, OPNUM, TYPE, IND_L); \
+ if (new_x) \
+ { \
+ X = new_x; \
+ goto WIN; \
+ } \
} while (0)
/* Go to LABEL if ADDR (a legitimate address expression)
@@ -1616,7 +1470,7 @@ do { \
#define ADDRESS_COST(X) 0
-/* Machine-dependent reorg pass. */
+/* Machine-dependent reorg pass. */
#define MACHINE_DEPENDENT_REORG(X) alpha_reorg(X)
/* Specify the machine mode that this machine uses
@@ -1633,12 +1487,6 @@ do { \
but we should try to find some better way sometime. */
#define CASE_VECTOR_PC_RELATIVE 1
-/* Specify the tree operation to be used to convert reals to integers. */
-#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
-
-/* This is the kind of divide that is easiest to do in the general case. */
-#define EASY_DIV_EXPR TRUNC_DIV_EXPR
-
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 1
@@ -1659,7 +1507,7 @@ do { \
move-instruction pairs, we will do a movstr or libcall instead.
Without byte/word accesses, we want no more than four instructions;
- with, several single byte accesses are better. */
+ with, several single byte accesses are better. */
#define MOVE_RATIO (TARGET_BWX ? 7 : 2)
@@ -1700,7 +1548,8 @@ do { \
/* Define the value returned by a floating-point comparison instruction. */
-#define FLOAT_STORE_FLAG_VALUE (TARGET_FLOAT_VAX ? 0.5 : 2.0)
+#define FLOAT_STORE_FLAG_VALUE(MODE) \
+ REAL_VALUE_ATOF ((TARGET_FLOAT_VAX ? "0.5" : "2.0"), (MODE))
/* Canonicalize a comparison from one we don't have to one we do have. */
@@ -1727,7 +1576,7 @@ do { \
between pointers and any other objects of this machine mode. */
#define Pmode DImode
-/* Mode of a function address in a call instruction (for indexing purposes). */
+/* Mode of a function address in a call instruction (for indexing purposes). */
#define FUNCTION_MODE Pmode
@@ -1744,22 +1593,9 @@ do { \
#define NO_FUNCTION_CSE
/* Define this to be nonzero if shift instructions ignore all but the low-order
- few bits. */
+ few bits. */
#define SHIFT_COUNT_TRUNCATED 1
-/* Use atexit for static constructors/destructors, instead of defining
- our own exit function. */
-#define HAVE_ATEXIT
-
-/* The EV4 is dual issue; EV5/EV6 are quad issue. */
-#define ISSUE_RATE (alpha_cpu == PROCESSOR_EV4 ? 2 : 4)
-
-/* Describe the fact that MULTI instructions are multiple instructions
- and so to assume they don't pair with anything. */
-#define MD_SCHED_VARIABLE_ISSUE(DUMP, SCHED_VERBOSE, INSN, CAN_ISSUE_MORE) \
- if (recog_memoized (INSN) < 0 || get_attr_type (INSN) == TYPE_MULTI) \
- (CAN_ISSUE_MORE) = 0
-
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
@@ -1843,7 +1679,7 @@ do { \
if (GET_CODE (XEXP (X, 1)) == CONST_INT \
&& INTVAL (XEXP (X, 1)) <= 3) \
break; \
- /* ... fall through ... */ \
+ /* ... fall through ... */ \
case ASHIFTRT: case LSHIFTRT: \
switch (alpha_cpu) \
{ \
@@ -1903,7 +1739,7 @@ do { \
case NEG: case ABS: \
if (! FLOAT_MODE_P (GET_MODE (X))) \
break; \
- /* ... fall through ... */ \
+ /* ... fall through ... */ \
case FLOAT: case UNSIGNED_FLOAT: case FIX: case UNSIGNED_FIX: \
case FLOAT_EXTEND: case FLOAT_TRUNCATE: \
switch (alpha_cpu) \
@@ -1918,34 +1754,23 @@ do { \
/* Control the assembler format that we output. */
-/* We don't emit these labels, so as to avoid getting linker errors about
- missing exception handling info. If we emit a gcc_compiled. label into
- text, and the file has no code, then the DEC assembler gives us a zero
- sized text section with no associated exception handling info. The
- DEC linker sees this text section, and gives a warning saying that
- the exception handling info is missing. */
-#define ASM_IDENTIFY_GCC(x)
-#define ASM_IDENTIFY_LANGUAGE(x)
-
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
-
-#define ASM_APP_ON ""
+#define ASM_APP_ON (TARGET_EXPLICIT_RELOCS ? "\t.set\tmacro\n" : "")
/* Output to assembler file text saying following lines
no longer contain unusual constructs. */
+#define ASM_APP_OFF (TARGET_EXPLICIT_RELOCS ? "\t.set\tnomacro\n" : "")
-#define ASM_APP_OFF ""
-
-#define TEXT_SECTION_ASM_OP ".text"
+#define TEXT_SECTION_ASM_OP "\t.text"
/* Output before read-only data. */
-#define READONLY_DATA_SECTION_ASM_OP ".rdata"
+#define READONLY_DATA_SECTION_ASM_OP "\t.rdata"
/* Output before writable data. */
-#define DATA_SECTION_ASM_OP ".data"
+#define DATA_SECTION_ASM_OP "\t.data"
/* Define an extra section for read-only data, a routine to enter it, and
indicate that it is for read-only data.
@@ -1968,7 +1793,7 @@ literal_section () \
if (firsttime) \
{ \
firsttime = 0; \
- ASM_OUTPUT_DOUBLE_INT (asm_out_file, const0_rtx); \
+ assemble_aligned_integer (8, const0_rtx); \
} \
\
in_section = readonly_data; \
@@ -1977,13 +1802,29 @@ literal_section () \
#define READONLY_DATA_SECTION literal_section
-/* If we are referencing a function that is static, make the SYMBOL_REF
- special. We use this to see indicate we can branch to this function
- without setting PV or restoring GP. */
+/* 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). */
-#define ENCODE_SECTION_INFO(DECL) \
- if (TREE_CODE (DECL) == FUNCTION_DECL && ! TREE_PUBLIC (DECL)) \
- SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1;
+#define ENCODE_SECTION_INFO(DECL) alpha_encode_section_info (DECL)
+
+/* If a variable is weakened, made one only or moved into a different
+ section, it may be necessary to redo the section info to move the
+ variable out of sdata. */
+
+#define REDO_SECTION_INFO_P(DECL) \
+ ((TREE_CODE (DECL) == VAR_DECL) \
+ && (DECL_ONE_ONLY (DECL) || DECL_WEAK (DECL) || DECL_COMMON (DECL) \
+ || DECL_SECTION_NAME (DECL) != 0))
+
+#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
+do { \
+ (VAR) = (SYMBOL_NAME); \
+ if ((VAR)[0] == '@') \
+ (VAR) += 2; \
+ if ((VAR)[0] == '*') \
+ (VAR)++; \
+} while (0)
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
@@ -1998,9 +1839,19 @@ literal_section () \
"$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",\
"$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "FP"}
-/* How to renumber registers for dbx and gdb. */
+/* Strip name encoding when emitting labels. */
-#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+do { \
+ const char *name_ = NAME; \
+ if (*name_ == '@') \
+ name_ += 2; \
+ if (*name_ == '*') \
+ name_++; \
+ else \
+ fputs (user_label_prefix, STREAM); \
+ fputs (name_, STREAM); \
+} while (0)
/* 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. */
@@ -2014,7 +1865,7 @@ literal_section () \
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
do { fputs ("\t.globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
-/* The prefix to add to user-visible assembler symbols. */
+/* The prefix to add to user-visible assembler symbols. */
#define USER_LABEL_PREFIX ""
@@ -2026,7 +1877,7 @@ literal_section () \
/* This is how to output a label for a jump table. Arguments are the same as
for ASM_OUTPUT_INTERNAL_LABEL, except the insn for the jump table is
- passed. */
+ passed. */
#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN) \
{ ASM_OUTPUT_ALIGN (FILE, 2); ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); }
@@ -2044,74 +1895,18 @@ literal_section () \
#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
((OVERFLOW) = check_float_value (MODE, &D, OVERFLOW))
-/* This is how to output an assembler line defining a `double' constant. */
-
-#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
- { \
- if (REAL_VALUE_ISINF (VALUE) \
- || REAL_VALUE_ISNAN (VALUE) \
- || REAL_VALUE_MINUS_ZERO (VALUE)) \
- { \
- long t[2]; \
- REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
- fprintf (FILE, "\t.quad 0x%lx%08lx\n", \
- t[1] & 0xffffffff, t[0] & 0xffffffff); \
- } \
- else \
- { \
- char str[30]; \
- REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
- fprintf (FILE, "\t.%c_floating %s\n", (TARGET_FLOAT_VAX)?'g':'t', str); \
- } \
- }
-
-/* This is how to output an assembler line defining a `float' constant. */
-
-#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
- do { \
- long t; \
- REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
- fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
-} while (0)
-
-/* This is how to output an assembler line defining an `int' constant. */
-
-#define ASM_OUTPUT_INT(FILE,VALUE) \
-( fprintf (FILE, "\t.long "), \
- output_addr_const (FILE, (VALUE)), \
- fprintf (FILE, "\n"))
-
-/* This is how to output an assembler line defining a `long' constant. */
-
-#define ASM_OUTPUT_DOUBLE_INT(FILE,VALUE) \
-( fprintf (FILE, "\t.quad "), \
- output_addr_const (FILE, (VALUE)), \
- fprintf (FILE, "\n"))
-
-/* Likewise for `char' and `short' constants. */
-
-#define ASM_OUTPUT_SHORT(FILE,VALUE) \
- fprintf (FILE, "\t.word %d\n", \
- (int)(GET_CODE (VALUE) == CONST_INT \
- ? INTVAL (VALUE) & 0xffff : (abort (), 0)))
-
-#define ASM_OUTPUT_CHAR(FILE,VALUE) \
- fprintf (FILE, "\t.byte %d\n", \
- (int)(GET_CODE (VALUE) == CONST_INT \
- ? INTVAL (VALUE) & 0xff : (abort (), 0)))
-
/* We use the default ASCII-output routine, except that we don't write more
than 50 characters since the assembler doesn't support very long lines. */
#define ASM_OUTPUT_ASCII(MYFILE, MYSTRING, MYLENGTH) \
do { \
FILE *_hide_asm_out_file = (MYFILE); \
- unsigned char *_hide_p = (unsigned char *) (MYSTRING); \
+ const unsigned char *_hide_p = (const unsigned char *) (MYSTRING); \
int _hide_thissize = (MYLENGTH); \
int _size_so_far = 0; \
{ \
FILE *asm_out_file = _hide_asm_out_file; \
- unsigned char *p = _hide_p; \
+ const unsigned char *p = _hide_p; \
int thissize = _hide_thissize; \
int i; \
fprintf (asm_out_file, "\t.ascii \""); \
@@ -2132,11 +1927,10 @@ literal_section () \
fprintf (asm_out_file, "\\%o", c); \
/* After an octal-escape, if a digit follows, \
terminate one string constant and start another. \
- The Vax assembler fails to stop reading the escape \
+ The VAX assembler fails to stop reading the escape \
after three digits, so this is the only way we \
can get it to parse the data properly. */ \
- if (i < thissize - 1 \
- && p[i + 1] >= '0' && p[i + 1] <= '9') \
+ if (i < thissize - 1 && ISDIGIT (p[i + 1])) \
_size_so_far = 0, fprintf (asm_out_file, "\"\n\t.ascii \""); \
} \
} \
@@ -2145,11 +1939,6 @@ literal_section () \
} \
while (0)
-/* To get unaligned data, we have to turn off auto alignment. */
-#define UNALIGNED_SHORT_ASM_OP ".align 0\n\t.word"
-#define UNALIGNED_INT_ASM_OP ".align 0\n\t.long"
-#define UNALIGNED_DOUBLE_INT_ASM_OP ".align 0\n\t.quad"
-
/* This is how to output an insn to push a register on the stack.
It need not be very fast code. */
@@ -2166,11 +1955,6 @@ literal_section () \
(REGNO) > 32 ? "t" : "q", (REGNO) > 32 ? "f" : "", \
(REGNO) & 31);
-/* This is how to output an assembler line for a numeric constant byte. */
-
-#define ASM_OUTPUT_BYTE(FILE,VALUE) \
- fprintf (FILE, "\t.byte 0x%x\n", (int) ((VALUE) & 0xff))
-
/* This is how to output an element of a case-vector that is absolute.
(Alpha does not use such vectors, but we must define this macro anyway.) */
@@ -2179,7 +1963,7 @@ literal_section () \
/* 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, "\t.%s $L%d\n", TARGET_WINDOWS_NT ? "long" : "gprel32", \
+ fprintf (FILE, "\t.%s $L%d\n", TARGET_ABI_WINDOWS_NT ? "long" : "gprel32", \
(VALUE))
/* This is how to output an assembler line
@@ -2218,52 +2002,8 @@ literal_section () \
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
-
-/* Define the parentheses used to group arithmetic operations
- in assembler code. */
-
-#define ASM_OPEN_PAREN "("
-#define ASM_CLOSE_PAREN ")"
-
-/* 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 { \
- char *fn_name = XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0); \
- int reg; \
- \
- /* Mark end of prologue. */ \
- output_end_prologue (FILE); \
- \
- /* Rely on the assembler to macro expand a large delta. */ \
- reg = aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? 17 : 16; \
- fprintf (FILE, "\tlda $%d,%ld($%d)\n", reg, (long)(DELTA), reg); \
- \
- if (current_file_function_operand (XEXP (DECL_RTL (FUNCTION), 0))) \
- { \
- fprintf (FILE, "\tbr $31,$"); \
- assemble_name (FILE, fn_name); \
- fprintf (FILE, "..ng\n"); \
- } \
- else \
- { \
- fprintf (FILE, "\tjmp $31,"); \
- assemble_name (FILE, fn_name); \
- fputc ('\n', FILE); \
- } \
-} while (0)
-/* Define results of standard character escape sequences. */
-#define TARGET_BELL 007
-#define TARGET_BS 010
-#define TARGET_TAB 011
-#define TARGET_NEWLINE 012
-#define TARGET_VT 013
-#define TARGET_FF 014
-#define TARGET_CR 015
-
/* 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. */
@@ -2271,30 +2011,12 @@ do { \
#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
/* Determine which codes are valid without a following integer. These must
- not be alphabetic (the characters are chosen so that
- PRINT_OPERAND_PUNCT_VALID_P translates into a simple range change when
- using ASCII).
-
- & Generates fp-rounding mode suffix: nothing for normal, 'c' for
- chopped, 'm' for minus-infinity, and 'd' for dynamic rounding
- mode. alpha_fprm controls which suffix is generated.
-
- ' Generates trap-mode suffix for instructions that accept the
- su suffix only (cmpt et al).
-
- ` Generates trap-mode suffix for instructions that accept the
- v and sv suffix. The only instruction that needs this is cvtql.
-
- ( Generates trap-mode suffix for instructions that accept the
- v, sv, and svi suffix. The only instruction that needs this
- is cvttq.
+ not be alphabetic.
- ) Generates trap-mode suffix for instructions that accept the
- u, su, and sui suffix. This is the bulk of the IEEE floating
- point instructions (addt et al).
+ ~ Generates the name of the current function.
- + Generates trap-mode suffix for instructions that accept the
- sui suffix (cvtqt and cvtqs).
+ / Generates the instruction suffix. The TRAP_SUFFIX and ROUND_SUFFIX
+ attributes are examined to determine what is appropriate.
, Generates single precision suffix for floating point
instructions (s for IEEE, f for VAX)
@@ -2303,9 +2025,9 @@ do { \
instructions (t for IEEE, g for VAX)
*/
-#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
- ((CODE) == '&' || (CODE) == '`' || (CODE) == '\'' || (CODE) == '(' \
- || (CODE) == ')' || (CODE) == '+' || (CODE) == ',' || (CODE) == '-')
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+ ((CODE) == '/' || (CODE) == ',' || (CODE) == '-' || (CODE) == '~' \
+ || (CODE) == '#' || (CODE) == '*')
/* Print a memory address as an operand to reference that memory location. */
@@ -2330,23 +2052,46 @@ do { \
{"mode_width_operand", {CONST_INT}}, \
{"reg_or_fp0_operand", {SUBREG, REG, CONST_DOUBLE}}, \
{"alpha_comparison_operator", {EQ, LE, LT, LEU, LTU}}, \
+ {"alpha_zero_comparison_operator", {EQ, NE, LE, LT, LEU, LTU}}, \
{"alpha_swapped_comparison_operator", {EQ, GE, GT, GEU, GTU}}, \
{"signed_comparison_operator", {EQ, NE, LE, LT, GE, GT}}, \
+ {"alpha_fp_comparison_operator", {EQ, LE, LT, UNORDERED}}, \
{"divmod_operator", {DIV, MOD, UDIV, UMOD}}, \
{"fp0_operand", {CONST_DOUBLE}}, \
{"current_file_function_operand", {SYMBOL_REF}}, \
+ {"direct_call_operand", {SYMBOL_REF}}, \
+ {"local_symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \
+ {"small_symbolic_operand", {SYMBOL_REF, CONST}}, \
+ {"global_symbolic_operand", {SYMBOL_REF, CONST}}, \
{"call_operand", {REG, SYMBOL_REF}}, \
{"input_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
- SYMBOL_REF, CONST, LABEL_REF}}, \
+ SYMBOL_REF, CONST, LABEL_REF, HIGH}}, \
{"some_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
- SYMBOL_REF, CONST, LABEL_REF}}, \
+ SYMBOL_REF, CONST, LABEL_REF, HIGH}}, \
+ {"some_ni_operand", {SUBREG, REG, MEM}}, \
{"aligned_memory_operand", {MEM}}, \
{"unaligned_memory_operand", {MEM}}, \
{"reg_or_unaligned_mem_operand", {SUBREG, REG, MEM}}, \
{"any_memory_operand", {MEM}}, \
{"hard_fp_register_operand", {SUBREG, REG}}, \
+ {"hard_int_register_operand", {SUBREG, REG}}, \
{"reg_not_elim_operand", {SUBREG, REG}}, \
- {"reg_no_subreg_operand", {REG}},
+ {"reg_no_subreg_operand", {REG}}, \
+ {"addition_operation", {PLUS}}, \
+ {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"some_small_symbolic_mem_operand", {SET, PARALLEL}},
+
+/* Define the `__builtin_va_list' type for the ABI. */
+#define BUILD_VA_LIST_TYPE(VALIST) \
+ (VALIST) = alpha_build_va_list ()
+
+/* Implement `va_start' for varargs and stdarg. */
+#define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
+ alpha_va_start (stdarg, valist, nextarg)
+
+/* Implement `va_arg'. */
+#define EXPAND_BUILTIN_VA_ARG(valist, type) \
+ alpha_va_arg (valist, type)
/* Tell collect that the object format is ECOFF. */
#define OBJECT_FORMAT_COFF
@@ -2388,11 +2133,9 @@ extern long alpha_auto_offset;
#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) \
alpha_output_lineno (STREAM, LINE)
-extern void alpha_output_lineno ();
#define ASM_OUTPUT_SOURCE_FILENAME(STREAM, NAME) \
alpha_output_filename (STREAM, NAME)
-extern void alpha_output_filename ();
/* mips-tfile.c limits us to strings of one page. We must underestimate this
number, because the real length runs past this up to the next
@@ -2410,9 +2153,9 @@ extern void alpha_output_filename ();
that the ALPHA assembler does not choke. The mips-tfile program
will correctly put the stab into the object file. */
-#define ASM_STABS_OP ((TARGET_GAS) ? ".stabs" : " #.stabs")
-#define ASM_STABN_OP ((TARGET_GAS) ? ".stabn" : " #.stabn")
-#define ASM_STABD_OP ((TARGET_GAS) ? ".stabd" : " #.stabd")
+#define ASM_STABS_OP ((TARGET_GAS) ? "\t.stabs\t" : " #.stabs\t")
+#define ASM_STABN_OP ((TARGET_GAS) ? "\t.stabn\t" : " #.stabn\t")
+#define ASM_STABD_OP ((TARGET_GAS) ? "\t.stabd\t" : " #.stabd\t")
/* Forward references to tags are allowed. */
#define SDB_ALLOW_FORWARD_REFERENCES
@@ -2478,7 +2221,7 @@ do { \
mips-tdump.c to print them out.
These must match the corresponding definitions in gdb/mipsread.c.
- Unfortunately, gcc and gdb do not currently share any directories. */
+ Unfortunately, gcc and gdb do not currently share any directories. */
#define CODE_MASK 0x8F300
#define MIPS_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK)
@@ -2494,57 +2237,8 @@ do { \
#define ALIGN_SYMTABLE_OFFSET(OFFSET) (((OFFSET) + 7) & ~7)
-/* The linker will stick __main into the .init section. */
-#define HAS_INIT_SECTION
-#define LD_INIT_SWITCH "-init"
-#define LD_FINI_SWITCH "-fini"
-
/* The system headers under Alpha systems are generally C++-aware. */
#define NO_IMPLICIT_EXTERN_C
-/* Prototypes for alpha.c functions used in the md file & elsewhere. */
-extern struct rtx_def *get_unaligned_address ();
-extern void alpha_write_verstamp ();
-extern void alpha_reorg ();
-extern int check_float_value ();
-extern int direct_return ();
-extern int const48_operand ();
-extern int add_operand ();
-extern int and_operand ();
-extern int unaligned_memory_operand ();
-extern int zap_mask ();
-extern int current_file_function_operand ();
-extern int alpha_sa_size ();
-extern int alpha_adjust_cost ();
-extern void print_operand ();
-extern void print_operand_address ();
-extern int reg_or_0_operand ();
-extern int reg_or_8bit_operand ();
-extern int mul8_operand ();
-extern int reg_or_6bit_operand ();
-extern int alpha_comparison_operator ();
-extern int alpha_swapped_comparison_operator ();
-extern int sext_add_operand ();
-extern int cint8_operand ();
-extern int mode_mask_operand ();
-extern int or_operand ();
-extern int mode_width_operand ();
-extern int reg_or_fp0_operand ();
-extern int signed_comparison_operator ();
-extern int fp0_operand ();
-extern int some_operand ();
-extern int input_operand ();
-extern int divmod_operator ();
-extern int call_operand ();
-extern int reg_or_cint_operand ();
-extern int hard_fp_register_operand ();
-extern int reg_not_elim_operand ();
-extern void alpha_set_memflags ();
-extern int aligned_memory_operand ();
-extern void get_aligned_mem ();
-extern void alpha_expand_unaligned_load ();
-extern void alpha_expand_unaligned_store ();
-extern int alpha_expand_block_move ();
-extern int alpha_expand_block_clear ();
-extern void alpha_expand_prologue ();
-extern void alpha_expand_epilogue ();
+/* Generate calls to memcpy, etc., not bcopy, etc. */
+#define TARGET_MEM_FUNCTIONS 1
diff --git a/contrib/gcc/config/alpha/alpha.md b/contrib/gcc/config/alpha/alpha.md
index 6d075e9..b987de8 100644
--- a/contrib/gcc/config/alpha/alpha.md
+++ b/contrib/gcc/config/alpha/alpha.md
@@ -1,19 +1,20 @@
;; Machine description for DEC Alpha for GNU C compiler
-;; Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+;; 2000, 2001 Free Software Foundation, Inc.
;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
+;;
;; 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,
@@ -22,25 +23,46 @@
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;; Uses of UNSPEC in this file:
-;;
-;; 0 arg_home
-;; 1 cttz
-;; 2 insxh
-;; 3 mskxh
-;; 4 cvtlq
-;; 5 cvtql
-;; 6 nt_lda
-;;
+
+(define_constants
+ [(UNSPEC_ARG_HOME 0)
+ (UNSPEC_CTTZ 1)
+ (UNSPEC_INSXH 2)
+ (UNSPEC_MSKXH 3)
+ (UNSPEC_CVTQL 4)
+ (UNSPEC_NT_LDA 5)
+ (UNSPEC_UMK_LAUM 6)
+ (UNSPEC_UMK_LALM 7)
+ (UNSPEC_UMK_LAL 8)
+ (UNSPEC_UMK_LOAD_CIW 9)
+ (UNSPEC_LDGP2 10)
+ (UNSPEC_LITERAL 11)
+ (UNSPEC_LITUSE 12)
+ (UNSPEC_SIBCALL 13)
+ ])
+
;; UNSPEC_VOLATILE:
+
+(define_constants
+ [(UNSPECV_IMB 0)
+ (UNSPECV_BLOCKAGE 1)
+ (UNSPECV_SETJMPR 2) ; builtin_setjmp_receiver
+ (UNSPECV_LONGJMP 3) ; builtin_longjmp
+ (UNSPECV_TRAPB 4)
+ (UNSPECV_PSPL 5) ; prologue_stack_probe_loop
+ (UNSPECV_REALIGN 6)
+ (UNSPECV_EHR 7) ; exception_receiver
+ (UNSPECV_MCOUNT 8)
+ (UNSPECV_FORCE_MOV 9)
+ (UNSPECV_LDGP1 10)
+ (UNSPECV_PLDGP2 11) ; prologue ldgp
+ ])
+
+;; Where necessary, the suffixes _le and _be are used to distinguish between
+;; little-endian and big-endian patterns.
;;
-;; 0 imb
-;; 1 blockage
-;; 2 builtin_setjmp_receiver
-;; 3 builtin_longjmp
-;; 4 trapb
-;; 5 prologue_stack_probe_loop
-;; 6 realign
-;; 7 exception_receiver
+;; Note that the Unicos/Mk assembler does not support the following
+;; opcodes: mov, fmov, nop, fnop, unop.
;; Processor type -- this attribute must exactly match the processor_type
;; enumeration in alpha.h.
@@ -54,7 +76,8 @@
;; separately.
(define_attr "type"
- "ild,fld,ldsym,ist,fst,ibr,fbr,jsr,iadd,ilog,shift,icmov,fcmov,icmp,imul,fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
+ "ild,fld,ldsym,ist,fst,ibr,fbr,jsr,iadd,ilog,shift,icmov,fcmov,icmp,imul,\
+fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
(const_string "iadd"))
;; Describe a user's asm statement.
@@ -62,19 +85,42 @@
[(set_attr "type" "multi")])
;; Define the operand size an insn operates on. Used primarily by mul
-;; and div operations that have size dependant timings.
+;; and div operations that have size dependent timings.
-(define_attr "opsize" "si,di,udi" (const_string "di"))
+(define_attr "opsize" "si,di,udi"
+ (const_string "di"))
-;; The TRAP_TYPE attribute marks instructions that may generate traps
+;; The TRAP attribute marks instructions that may generate traps
;; (which are imprecise and may need a trapb if software completion
;; is desired).
-(define_attr "trap" "no,yes" (const_string "no"))
+(define_attr "trap" "no,yes"
+ (const_string "no"))
+
+;; The ROUND_SUFFIX attribute marks which instructions require a
+;; rounding-mode suffix. The value NONE indicates no suffix,
+;; the value NORMAL indicates a suffix controled by alpha_fprm.
+
+(define_attr "round_suffix" "none,normal,c"
+ (const_string "none"))
+
+;; The TRAP_SUFFIX attribute marks instructions requiring a trap-mode suffix:
+;; NONE no suffix
+;; SU accepts only /su (cmpt et al)
+;; SUI accepts only /sui (cvtqt and cvtqs)
+;; V_SV accepts /v and /sv (cvtql only)
+;; V_SV_SVI accepts /v, /sv and /svi (cvttq only)
+;; U_SU_SUI accepts /u, /su and /sui (most fp instructions)
+;;
+;; The actual suffix emitted is controled by alpha_fptm.
+
+(define_attr "trap_suffix" "none,su,sui,v_sv,v_sv_svi,u_su_sui"
+ (const_string "none"))
;; The length of an instruction sequence in bytes.
-(define_attr "length" "" (const_int 4))
+(define_attr "length" ""
+ (const_int 4))
;; On EV4 there are two classes of resources to consider: resources needed
;; to issue, and resources needed to execute. IBUS[01] are in the first
@@ -220,14 +266,14 @@
(and (eq_attr "cpu" "ev5")
(eq_attr "type" "fadd,fcmov,fmul,fcpys,fbr,fdiv"))
4 1)
-
+
(define_function_unit "ev5_fm" 1 0
(and (eq_attr "cpu" "ev5")
(eq_attr "type" "fmul"))
4 1)
; Add and cmov as you would expect; fbr never produces a result;
-; fdiv issues through fa to the divider,
+; fdiv issues through fa to the divider,
(define_function_unit "ev5_fa" 1 0
(and (eq_attr "cpu" "ev5")
(eq_attr "type" "fadd,fcmov,fbr,fdiv"))
@@ -239,20 +285,20 @@
(and (eq_attr "cpu" "ev5")
(and (eq_attr "type" "fdiv")
(eq_attr "opsize" "si")))
- 15 15) ; 15 to 31 data dependant
+ 15 15) ; 15 to 31 data dependent
(define_function_unit "fdiv" 1 0
(and (eq_attr "cpu" "ev5")
(and (eq_attr "type" "fdiv")
(eq_attr "opsize" "di")))
- 22 22) ; 22 to 60 data dependant
+ 22 22) ; 22 to 60 data dependent
;; EV6 scheduling. EV6 can issue 4 insns per clock.
;;
;; EV6 has two symmetric pairs ("clusters") of two asymetric integer units
;; ("upper" and "lower"), yielding pipe names U0, U1, L0, L1.
-;; Conditional moves decompose into two independant primitives, each
+;; Conditional moves decompose into two independent primitives, each
;; taking one cycle. Since ev6 is out-of-order, we can't see anything
;; but two cycles.
(define_function_unit "ev6_ebox" 4 0
@@ -337,7 +383,7 @@
;; For the FPU we are very similar to EV5, except there's no insn that
;; can issue to fm & fa, so we get to leave that out.
-
+
(define_function_unit "ev6_fm" 1 0
(and (eq_attr "cpu" "ev6")
(eq_attr "type" "fmul"))
@@ -388,24 +434,44 @@
;; sign-extend.
;; Handle 32-64 bit extension from memory to a floating point register
-;; specially, since this ocurrs frequently in int->double conversions.
-;; This is done with a define_split after reload converting the plain
-;; sign-extension into a load+unspec, which of course results in lds+cvtlq.
+;; specially, since this occurs frequently in int->double conversions.
;;
;; Note that while we must retain the =f case in the insn for reload's
;; benefit, it should be eliminated after reload, so we should never emit
;; code for that case. But we don't reject the possibility.
-(define_insn "extendsidi2"
- [(set (match_operand:DI 0 "register_operand" "=r,r,?f")
- (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,m")))]
+(define_expand "extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
""
+ "")
+
+(define_insn "*extendsidi2_nofix"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,*f,?*f")
+ (sign_extend:DI
+ (match_operand:SI 1 "nonimmediate_operand" "r,m,*f,m")))]
+ "! TARGET_FIX"
"@
addl %1,$31,%0
ldl %0,%1
+ cvtlq %1,%0
lds %0,%1\;cvtlq %0,%0"
- [(set_attr "type" "iadd,ild,fld")
- (set_attr "length" "*,*,8")])
+ [(set_attr "type" "iadd,ild,fadd,fld")
+ (set_attr "length" "*,*,*,8")])
+
+(define_insn "*extendsidi2_fix"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r,?*f,?*f")
+ (sign_extend:DI
+ (match_operand:SI 1 "nonimmediate_operand" "r,m,*f,*f,m")))]
+ "TARGET_FIX"
+ "@
+ addl %1,$31,%0
+ ldl %0,%1
+ ftois %1,%0
+ cvtlq %1,%0
+ lds %0,%1\;cvtlq %0,%0"
+ [(set_attr "type" "iadd,ild,ftoi,fadd,fld")
+ (set_attr "length" "*,*,*,*,8")])
;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here.
(define_split
@@ -413,15 +479,44 @@
(sign_extend:DI (match_operand:SI 1 "memory_operand" "")))]
"reload_completed"
[(set (match_dup 2) (match_dup 1))
- (set (match_dup 0) (unspec:DI [(match_dup 2)] 4))]
+ (set (match_dup 0) (sign_extend:DI (match_dup 2)))]
"operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]));")
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=f")
- (unspec:DI [(match_operand:SI 1 "register_operand" "f")] 4))]
- ""
- "cvtlq %1,%0"
- [(set_attr "type" "fadd")])
+;; Optimize sign-extension of SImode loads. This shows up in the wake of
+;; reload when converting fp->int.
+
+(define_peephole2
+ [(set (match_operand:SI 0 "hard_int_register_operand" "")
+ (match_operand:SI 1 "memory_operand" ""))
+ (set (match_operand:DI 2 "hard_int_register_operand" "")
+ (sign_extend:DI (match_dup 0)))]
+ "true_regnum (operands[0]) == true_regnum (operands[2])
+ || peep2_reg_dead_p (2, operands[0])"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "hard_int_register_operand" "")
+ (match_operand:SI 1 "hard_fp_register_operand" ""))
+ (set (match_operand:DI 2 "hard_int_register_operand" "")
+ (sign_extend:DI (match_dup 0)))]
+ "TARGET_FIX
+ && (true_regnum (operands[0]) == true_regnum (operands[2])
+ || peep2_reg_dead_p (2, operands[0]))"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "hard_fp_register_operand" "")
+ (sign_extend:DI (match_operand:SI 1 "hard_fp_register_operand" "")))
+ (set (match_operand:DI 2 "hard_int_register_operand" "")
+ (match_dup 0))]
+ "TARGET_FIX && peep2_reg_dead_p (2, operands[0])"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))]
+ "")
;; Do addsi3 the way expand_binop would do if we didn't have one. This
;; generates better code. We have the anonymous addsi3 pattern below in
@@ -431,7 +526,6 @@
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "")
(match_operand:SI 2 "add_operand" "")))]
""
- "
{
if (optimize)
{
@@ -448,9 +542,9 @@
emit_insn (gen_adddi3 (gen_lowpart (DImode, operands[0]), op1, op2));
DONE;
}
-}")
+})
-(define_insn ""
+(define_insn "*addsi_internal"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ,rJ,rJ")
(match_operand:SI 2 "add_operand" "rI,O,K,L")))]
@@ -468,7 +562,6 @@
"! add_operand (operands[2], SImode)"
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
- "
{
HOST_WIDE_INT val = INTVAL (operands[2]);
HOST_WIDE_INT low = (val & 0xffff) - 2 * (val & 0x8000);
@@ -476,9 +569,9 @@
operands[3] = GEN_INT (rest);
operands[4] = GEN_INT (low);
-}")
+})
-(define_insn ""
+(define_insn "*addsi_se"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(sign_extend:DI
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ")
@@ -491,7 +584,7 @@
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(sign_extend:DI
- (plus:SI (match_operand:SI 1 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "reg_not_elim_operand" "")
(match_operand:SI 2 "const_int_operand" ""))))
(clobber (match_operand:SI 3 "reg_not_elim_operand" ""))]
"! sext_add_operand (operands[2], SImode) && INTVAL (operands[2]) > 0
@@ -500,7 +593,6 @@
(set (match_dup 0) (sign_extend:DI (plus:SI (mult:SI (match_dup 3)
(match_dup 5))
(match_dup 1))))]
- "
{
HOST_WIDE_INT val = INTVAL (operands[2]) / 4;
int mult = 4;
@@ -510,7 +602,7 @@
operands[4] = GEN_INT (val);
operands[5] = GEN_INT (mult);
-}")
+})
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -523,57 +615,96 @@
""
[(set (match_dup 5) (match_dup 6))
(set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 7) (match_dup 4))))]
- "
{
operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode,
operands[2], operands[3]);
operands[7] = gen_lowpart (SImode, operands[5]);
-}")
+})
-(define_insn "adddi3"
- [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
- (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ,rJ,rJ")
- (match_operand:DI 2 "add_operand" "rI,O,K,L")))]
+(define_insn "addvsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ")
+ (match_operand:SI 2 "sext_add_operand" "rI,O")))
+ (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (plus:SI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
""
- "*
-{
- const char * const pattern[4] = {
- \"addq %r1,%2,%0\",
- \"subq %r1,%n2,%0\",
- \"lda %0,%2(%r1)\",
- \"ldah %0,%h2(%r1)\"
- };
+ "@
+ addlv %r1,%2,%0
+ sublv %r1,%n2,%0")
- /* The NT stack unwind code can't handle a subq to adjust the stack
- (that's a bug, but not one we can do anything about). As of NT4.0 SP3,
- the exception handling code will loop if a subq is used and an
- exception occurs.
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "add_operand" "")))]
+ ""
+ "")
- The 19980616 change to emit prologues as RTL also confused some
- versions of GDB, which also interprets prologues. This has been
- fixed as of GDB 4.18, but it does not harm to unconditionally
- use lda here. */
+(define_insn "*adddi_er_high_l"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (high:DI (match_operand:DI 2 "local_symbolic_operand" ""))))]
+ "TARGET_EXPLICIT_RELOCS"
+ "ldah %0,%2(%1)\t\t!gprelhigh")
- int which = which_alternative;
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (high:DI (match_operand:DI 1 "local_symbolic_operand" "")))]
+ "TARGET_EXPLICIT_RELOCS && reload_completed"
+ [(set (match_dup 0)
+ (plus:DI (match_dup 2) (high:DI (match_dup 1))))]
+ "operands[2] = pic_offset_table_rtx;")
- if (operands[0] == stack_pointer_rtx
- && GET_CODE (operands[2]) == CONST_INT
- && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))
- which = 2;
+;; We used to expend quite a lot of effort choosing addq/subq/lda.
+;; With complications like
+;;
+;; The NT stack unwind code can't handle a subq to adjust the stack
+;; (that's a bug, but not one we can do anything about). As of NT4.0 SP3,
+;; the exception handling code will loop if a subq is used and an
+;; exception occurs.
+;;
+;; The 19980616 change to emit prologues as RTL also confused some
+;; versions of GDB, which also interprets prologues. This has been
+;; fixed as of GDB 4.18, but it does not harm to unconditionally
+;; use lda here.
+;;
+;; and the fact that the three insns schedule exactly the same, it's
+;; just not worth the effort.
- return pattern[which];
-}")
+(define_insn "*adddi_internal"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%r,r,r")
+ (match_operand:DI 2 "add_operand" "r,K,L")))]
+ ""
+ "@
+ addq %1,%2,%0
+ lda %0,%2(%1)
+ ldah %0,%h2(%1)")
;; ??? Allow large constants when basing off the frame pointer or some
;; virtual register that may eliminate to the frame pointer. This is
;; done because register elimination offsets will change the hi/lo split,
;; and if we split before reload, we will require additional instructions.
-(define_insn ""
+(define_insn "*adddi_fp_hack"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_operand:DI 1 "reg_no_subreg_operand" "r")
(match_operand:DI 2 "const_int_operand" "n")))]
- "REG_OK_FP_BASE_P (operands[1])"
+ "NONSTRICT_REG_OK_FP_BASE_P (operands[1])
+ && INTVAL (operands[2]) >= 0
+ /* This is the largest constant an lda+ldah pair can add, minus
+ an upper bound on the displacement between SP and AP during
+ register elimination. See INITIAL_ELIMINATION_OFFSET. */
+ && INTVAL (operands[2])
+ < (0x7fff8000
+ - FIRST_PSEUDO_REGISTER * UNITS_PER_WORD
+ - ALPHA_ROUND(current_function_outgoing_args_size)
+ - (ALPHA_ROUND (get_frame_size ()
+ + max_reg_num () * UNITS_PER_WORD
+ + current_function_pretend_args_size)
+ - current_function_pretend_args_size))"
"#")
;; Don't do this if we are adjusting SP since we don't want to do it
@@ -588,17 +719,26 @@
&& operands[1] != arg_pointer_rtx"
[(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
- "
{
HOST_WIDE_INT val = INTVAL (operands[2]);
HOST_WIDE_INT low = (val & 0xffff) - 2 * (val & 0x8000);
HOST_WIDE_INT rest = val - low;
- operands[3] = GEN_INT (rest);
operands[4] = GEN_INT (low);
-}")
+ if (CONST_OK_FOR_LETTER_P (rest, 'L'))
+ operands[3] = GEN_INT (rest);
+ else if (! no_new_pseudos)
+ {
+ operands[3] = gen_reg_rtx (DImode);
+ emit_move_insn (operands[3], operands[2]);
+ emit_insn (gen_adddi3 (operands[0], operands[1], operands[3]));
+ DONE;
+ }
+ else
+ FAIL;
+})
-(define_insn ""
+(define_insn "*saddl"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(plus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r,r")
(match_operand:SI 2 "const48_operand" "I,I"))
@@ -608,7 +748,7 @@
s%2addl %1,%3,%0
s%2subl %1,%n3,%0")
-(define_insn ""
+(define_insn "*saddl_se"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(sign_extend:DI
(plus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r,r")
@@ -626,21 +766,20 @@
[(match_operand 2 "" "")
(match_operand 3 "" "")])
(match_operand:SI 4 "const48_operand" ""))
- (match_operand:SI 5 "add_operand" ""))))
+ (match_operand:SI 5 "sext_add_operand" ""))))
(clobber (match_operand:DI 6 "reg_not_elim_operand" ""))]
""
[(set (match_dup 6) (match_dup 7))
(set (match_dup 0)
(sign_extend:DI (plus:SI (mult:SI (match_dup 8) (match_dup 4))
(match_dup 5))))]
- "
{
operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode,
operands[2], operands[3]);
operands[8] = gen_lowpart (SImode, operands[6]);
-}")
+})
-(define_insn ""
+(define_insn "*saddq"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(plus:DI (mult:DI (match_operand:DI 1 "reg_not_elim_operand" "r,r")
(match_operand:DI 2 "const48_operand" "I,I"))
@@ -650,94 +789,19 @@
s%2addq %1,%3,%0
s%2subq %1,%n3,%0")
-;; These variants of the above insns can occur if the third operand
-;; is the frame pointer. This is a kludge, but there doesn't
-;; seem to be a way around it. Only recognize them while reloading.
-
-(define_insn ""
- [(set (match_operand:DI 0 "some_operand" "=&r")
- (plus:DI (plus:DI (match_operand:DI 1 "some_operand" "r")
- (match_operand:DI 2 "some_operand" "r"))
- (match_operand:DI 3 "some_operand" "rIOKL")))]
- "reload_in_progress"
- "#")
-
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (plus:DI (plus:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "register_operand" ""))
- (match_operand:DI 3 "add_operand" "")))]
- "reload_completed"
- [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
- (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))]
- "")
-
-(define_insn ""
- [(set (match_operand:SI 0 "some_operand" "=&r")
- (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "some_operand" "rJ")
- (match_operand:SI 2 "const48_operand" "I"))
- (match_operand:SI 3 "some_operand" "r"))
- (match_operand:SI 4 "some_operand" "rIOKL")))]
- "reload_in_progress"
- "#")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "r")
- (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "reg_or_0_operand" "")
- (match_operand:SI 2 "const48_operand" ""))
- (match_operand:SI 3 "register_operand" ""))
- (match_operand:SI 4 "add_operand" "rIOKL")))]
- "reload_completed"
- [(set (match_dup 0)
- (plus:SI (mult:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
- (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
- "")
-
-(define_insn ""
- [(set (match_operand:DI 0 "some_operand" "=&r")
- (sign_extend:DI
- (plus:SI (plus:SI
- (mult:SI (match_operand:SI 1 "some_operand" "rJ")
- (match_operand:SI 2 "const48_operand" "I"))
- (match_operand:SI 3 "some_operand" "r"))
- (match_operand:SI 4 "some_operand" "rIOKL"))))]
- "reload_in_progress"
- "#")
-
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (sign_extend:DI
- (plus:SI (plus:SI
- (mult:SI (match_operand:SI 1 "reg_or_0_operand" "")
- (match_operand:SI 2 "const48_operand" ""))
- (match_operand:SI 3 "register_operand" ""))
- (match_operand:SI 4 "add_operand" ""))))]
- "reload_completed"
- [(set (match_dup 5)
- (plus:SI (mult:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
- (set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 5) (match_dup 4))))]
- "operands[5] = gen_lowpart (SImode, operands[0]);")
-
-(define_insn ""
- [(set (match_operand:DI 0 "some_operand" "=&r")
- (plus:DI (plus:DI (mult:DI (match_operand:DI 1 "some_operand" "rJ")
- (match_operand:DI 2 "const48_operand" "I"))
- (match_operand:DI 3 "some_operand" "r"))
- (match_operand:DI 4 "some_operand" "rIOKL")))]
- "reload_in_progress"
- "#")
-
-(define_split
- [(set (match_operand:DI 0 "register_operand" "=")
- (plus:DI (plus:DI (mult:DI (match_operand:DI 1 "reg_or_0_operand" "")
- (match_operand:DI 2 "const48_operand" ""))
- (match_operand:DI 3 "register_operand" ""))
- (match_operand:DI 4 "add_operand" "")))]
- "reload_completed"
- [(set (match_dup 0)
- (plus:DI (mult:DI (match_dup 1) (match_dup 2)) (match_dup 3)))
- (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
- "")
+(define_insn "addvdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ")
+ (match_operand:DI 2 "sext_add_operand" "rI,O")))
+ (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (plus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ ""
+ "@
+ addqv %r1,%2,%0
+ subqv %r1,%n2,%0")
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -745,25 +809,42 @@
""
"subl $31,%1,%0")
-(define_insn ""
+(define_insn "*negsi_se"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (neg:SI
(match_operand:SI 1 "reg_or_8bit_operand" "rI"))))]
""
"subl $31,%1,%0")
+(define_insn "negvsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "register_operand" "r")))
+ (trap_if (ne (neg:DI (sign_extend:DI (match_dup 1)))
+ (sign_extend:DI (neg:SI (match_dup 1))))
+ (const_int 0))]
+ ""
+ "sublv $31,%1,%0")
+
(define_insn "negdi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(neg:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")))]
""
"subq $31,%1,%0")
+(define_insn "negvdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))
+ (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (neg:DI (match_dup 1))))
+ (const_int 0))]
+ ""
+ "subqv $31,%1,%0")
+
(define_expand "subsi3"
[(set (match_operand:SI 0 "register_operand" "")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "")
(match_operand:SI 2 "reg_or_8bit_operand" "")))]
""
- "
{
if (optimize)
{
@@ -780,22 +861,34 @@
emit_insn (gen_subdi3 (gen_lowpart (DImode, operands[0]), op1, op2));
DONE;
}
-} ")
+})
-(define_insn ""
+(define_insn "*subsi_internal"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
(match_operand:SI 2 "reg_or_8bit_operand" "rI")))]
""
"subl %r1,%2,%0")
-(define_insn ""
+(define_insn "*subsi_se"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
(match_operand:SI 2 "reg_or_8bit_operand" "rI"))))]
""
"subl %r1,%2,%0")
+(define_insn "subvsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
+ (match_operand:SI 2 "reg_or_8bit_operand" "rI")))
+ (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (minus:SI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ ""
+ "sublv %r1,%2,%0")
+
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -803,7 +896,7 @@
""
"subq %r1,%2,%0")
-(define_insn ""
+(define_insn "*ssubl"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r")
(match_operand:SI 2 "const48_operand" "I"))
@@ -811,7 +904,7 @@
""
"s%2subl %1,%3,%0")
-(define_insn ""
+(define_insn "*ssubl_se"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
(minus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r")
@@ -820,7 +913,7 @@
""
"s%2subl %1,%3,%0")
-(define_insn ""
+(define_insn "*ssubq"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (mult:DI (match_operand:DI 1 "reg_not_elim_operand" "r")
(match_operand:DI 2 "const48_operand" "I"))
@@ -828,25 +921,53 @@
""
"s%2subq %1,%3,%0")
+(define_insn "subvdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")))
+ (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (minus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ ""
+ "subqv %r1,%2,%0")
+
+;; The Unicos/Mk assembler doesn't support mull.
+
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
(match_operand:SI 2 "reg_or_8bit_operand" "rI")))]
- ""
+ "!TARGET_ABI_UNICOSMK"
"mull %r1,%2,%0"
[(set_attr "type" "imul")
(set_attr "opsize" "si")])
-(define_insn ""
+(define_insn "*mulsi_se"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI
(mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
(match_operand:SI 2 "reg_or_8bit_operand" "rI"))))]
- ""
+ "!TARGET_ABI_UNICOSMK"
"mull %r1,%2,%0"
[(set_attr "type" "imul")
(set_attr "opsize" "si")])
+(define_insn "mulvsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:SI 2 "reg_or_8bit_operand" "rI")))
+ (trap_if (ne (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (mult:SI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ "!TARGET_ABI_UNICOSMK"
+ "mullv %r1,%2,%0"
+ [(set_attr "type" "imul")
+ (set_attr "opsize" "si")])
+
(define_insn "muldi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(mult:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ")
@@ -855,6 +976,19 @@
"mulq %r1,%2,%0"
[(set_attr "type" "imul")])
+(define_insn "mulvdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")))
+ (trap_if (ne (mult:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (mult:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ ""
+ "mulqv %r1,%2,%0"
+ [(set_attr "type" "imul")])
+
(define_insn "umuldi3_highpart"
[(set (match_operand:DI 0 "register_operand" "=r")
(truncate:DI
@@ -869,7 +1003,7 @@
[(set_attr "type" "imul")
(set_attr "opsize" "udi")])
-(define_insn ""
+(define_insn "*umuldi3_highpart_const"
[(set (match_operand:DI 0 "register_operand" "=r")
(truncate:DI
(lshiftrt:TI
@@ -881,144 +1015,324 @@
[(set_attr "type" "imul")
(set_attr "opsize" "udi")])
-;; The divide and remainder operations always take their inputs from
-;; r24 and r25, put their output in r27, and clobber r23 and r28.
-
-;; ??? Force sign-extension here because some versions of OSF/1 don't
-;; do the right thing if the inputs are not properly sign-extended.
-;; But Linux, for instance, does not have this problem. Is it worth
-;; the complication here to eliminate the sign extension?
-;; Interix/NT has the same sign-extension problem.
+;; The divide and remainder operations take their inputs from r24 and
+;; r25, put their output in r27, and clobber r23 and r28 on all
+;; systems except Unicos/Mk. On Unicos, the standard library provides
+;; subroutines which use the standard calling convention and work on
+;; DImode operands.
+
+;; ??? Force sign-extension here because some versions of OSF/1 and
+;; Interix/NT don't do the right thing if the inputs are not properly
+;; sign-extended. But Linux, for instance, does not have this
+;; problem. Is it worth the complication here to eliminate the sign
+;; extension?
(define_expand "divsi3"
- [(set (reg:DI 24)
+ [(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
- (set (reg:DI 25)
+ (set (match_dup 4)
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
- (parallel [(set (reg:DI 27)
- (sign_extend:DI (div:SI (reg:DI 24) (reg:DI 25))))
+ (parallel [(set (match_dup 5)
+ (sign_extend:DI (div:SI (match_dup 3) (match_dup 4))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
- (set (match_operand:SI 0 "general_operand" "")
- (subreg:SI (reg:DI 27) 0))]
- "!TARGET_OPEN_VMS"
- "")
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (subreg:SI (match_dup 5) 0))]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
+{
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+})
(define_expand "udivsi3"
- [(set (reg:DI 24)
+ [(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
- (set (reg:DI 25)
+ (set (match_dup 4)
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
- (parallel [(set (reg:DI 27)
- (sign_extend:DI (udiv:SI (reg:DI 24) (reg:DI 25))))
+ (parallel [(set (match_dup 5)
+ (sign_extend:DI (udiv:SI (match_dup 3) (match_dup 4))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
- (set (match_operand:SI 0 "general_operand" "")
- (subreg:SI (reg:DI 27) 0))]
- "!TARGET_OPEN_VMS"
- "")
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (subreg:SI (match_dup 5) 0))]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
+{
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+})
(define_expand "modsi3"
- [(set (reg:DI 24)
+ [(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
- (set (reg:DI 25)
+ (set (match_dup 4)
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
- (parallel [(set (reg:DI 27)
- (sign_extend:DI (mod:SI (reg:DI 24) (reg:DI 25))))
+ (parallel [(set (match_dup 5)
+ (sign_extend:DI (mod:SI (match_dup 3) (match_dup 4))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
- (set (match_operand:SI 0 "general_operand" "")
- (subreg:SI (reg:DI 27) 0))]
- "!TARGET_OPEN_VMS"
- "")
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (subreg:SI (match_dup 5) 0))]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
+{
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+})
(define_expand "umodsi3"
- [(set (reg:DI 24)
+ [(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
- (set (reg:DI 25)
+ (set (match_dup 4)
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
- (parallel [(set (reg:DI 27)
- (sign_extend:DI (umod:SI (reg:DI 24) (reg:DI 25))))
+ (parallel [(set (match_dup 5)
+ (sign_extend:DI (umod:SI (match_dup 3) (match_dup 4))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
- (set (match_operand:SI 0 "general_operand" "")
- (subreg:SI (reg:DI 27) 0))]
- "!TARGET_OPEN_VMS"
- "")
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (subreg:SI (match_dup 5) 0))]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
+{
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+})
(define_expand "divdi3"
- [(set (reg:DI 24) (match_operand:DI 1 "input_operand" ""))
- (set (reg:DI 25) (match_operand:DI 2 "input_operand" ""))
- (parallel [(set (reg:DI 27)
- (div:DI (reg:DI 24)
- (reg:DI 25)))
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (div:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
(clobber (reg:DI 23))
- (clobber (reg:DI 28))])
- (set (match_operand:DI 0 "general_operand" "")
- (reg:DI 27))]
- "!TARGET_OPEN_VMS"
+ (clobber (reg:DI 28))])]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
"")
(define_expand "udivdi3"
- [(set (reg:DI 24) (match_operand:DI 1 "input_operand" ""))
- (set (reg:DI 25) (match_operand:DI 2 "input_operand" ""))
- (parallel [(set (reg:DI 27)
- (udiv:DI (reg:DI 24)
- (reg:DI 25)))
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (udiv:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
(clobber (reg:DI 23))
- (clobber (reg:DI 28))])
- (set (match_operand:DI 0 "general_operand" "")
- (reg:DI 27))]
- "!TARGET_OPEN_VMS"
+ (clobber (reg:DI 28))])]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
"")
(define_expand "moddi3"
- [(set (reg:DI 24) (match_operand:DI 1 "input_operand" ""))
- (set (reg:DI 25) (match_operand:DI 2 "input_operand" ""))
- (parallel [(set (reg:DI 27)
- (mod:DI (reg:DI 24)
- (reg:DI 25)))
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "register_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))]
+ "!TARGET_ABI_OPEN_VMS"
+{
+ if (TARGET_ABI_UNICOSMK)
+ emit_insn (gen_moddi3_umk (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_moddi3_dft (operands[0], operands[1], operands[2]));
+ DONE;
+})
+
+(define_expand "moddi3_dft"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (mod:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
(clobber (reg:DI 23))
- (clobber (reg:DI 28))])
- (set (match_operand:DI 0 "general_operand" "")
- (reg:DI 27))]
- "!TARGET_OPEN_VMS"
+ (clobber (reg:DI 28))])]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
"")
+;; On Unicos/Mk, we do as the system's C compiler does:
+;; compute the quotient, multiply and subtract.
+
+(define_expand "moddi3_umk"
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "register_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))]
+ "TARGET_ABI_UNICOSMK"
+{
+ rtx div, mul = gen_reg_rtx (DImode);
+
+ div = expand_binop (DImode, sdiv_optab, operands[1], operands[2],
+ NULL_RTX, 0, OPTAB_LIB);
+ div = force_reg (DImode, div);
+ emit_insn (gen_muldi3 (mul, operands[2], div));
+ emit_insn (gen_subdi3 (operands[0], operands[1], mul));
+ DONE;
+})
+
(define_expand "umoddi3"
- [(set (reg:DI 24) (match_operand:DI 1 "input_operand" ""))
- (set (reg:DI 25) (match_operand:DI 2 "input_operand" ""))
- (parallel [(set (reg:DI 27)
- (umod:DI (reg:DI 24)
- (reg:DI 25)))
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "register_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))]
+ "! TARGET_ABI_OPEN_VMS"
+{
+ if (TARGET_ABI_UNICOSMK)
+ emit_insn (gen_umoddi3_umk (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_umoddi3_dft (operands[0], operands[1], operands[2]));
+ DONE;
+})
+
+(define_expand "umoddi3_dft"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (umod:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
(clobber (reg:DI 23))
- (clobber (reg:DI 28))])
- (set (match_operand:DI 0 "general_operand" "")
- (reg:DI 27))]
- "!TARGET_OPEN_VMS"
+ (clobber (reg:DI 28))])]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
"")
+(define_expand "umoddi3_umk"
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "register_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))]
+ "TARGET_ABI_UNICOSMK"
+{
+ rtx div, mul = gen_reg_rtx (DImode);
+
+ div = expand_binop (DImode, udiv_optab, operands[1], operands[2],
+ NULL_RTX, 1, OPTAB_LIB);
+ div = force_reg (DImode, div);
+ emit_insn (gen_muldi3 (mul, operands[2], div));
+ emit_insn (gen_subdi3 (operands[0], operands[1], mul));
+ DONE;
+})
+
;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as
;; expanded by the assembler.
-(define_insn ""
- [(set (reg:DI 27)
- (sign_extend:DI (match_operator:SI 1 "divmod_operator"
- [(reg:DI 24) (reg:DI 25)])))
+
+(define_insn_and_split "*divmodsi_internal_er"
+ [(set (match_operand:DI 0 "register_operand" "=c")
+ (sign_extend:DI (match_operator:SI 3 "divmod_operator"
+ [(match_operand:DI 1 "register_operand" "a")
+ (match_operand:DI 2 "register_operand" "b")])))
(clobber (reg:DI 23))
(clobber (reg:DI 28))]
- "!TARGET_OPEN_VMS"
- "%E1 $24,$25,$27"
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS"
+ "ldq $27,__%E3($29)\t\t!literal!%#\;jsr $23,($27),__%E3\t\t!lituse_jsr!%#"
+ "&& reload_completed"
+ [(parallel [(set (match_dup 0)
+ (sign_extend:DI (match_dup 3)))
+ (use (match_dup 0))
+ (use (match_dup 4))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))])]
+{
+ const char *str;
+ switch (GET_CODE (operands[3]))
+ {
+ case DIV:
+ str = "__divl";
+ break;
+ case UDIV:
+ str = "__divlu";
+ break;
+ case MOD:
+ str = "__reml";
+ break;
+ case UMOD:
+ str = "__remlu";
+ break;
+ default:
+ abort ();
+ }
+ operands[4] = GEN_INT (alpha_next_sequence_number++);
+ emit_insn (gen_movdi_er_high_g (operands[0], pic_offset_table_rtx,
+ gen_rtx_SYMBOL_REF (DImode, str),
+ operands[4]));
+}
+ [(set_attr "type" "jsr")
+ (set_attr "length" "8")])
+
+(define_insn "*divmodsi_internal_er_1"
+ [(set (match_operand:DI 0 "register_operand" "=c")
+ (sign_extend:DI (match_operator:SI 3 "divmod_operator"
+ [(match_operand:DI 1 "register_operand" "a")
+ (match_operand:DI 2 "register_operand" "b")])))
+ (use (match_operand:DI 4 "register_operand" "c"))
+ (use (match_operand 5 "const_int_operand" ""))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS"
+ "jsr $23,($27),__%E3%J5"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "4")])
+
+(define_insn "*divmodsi_internal"
+ [(set (match_operand:DI 0 "register_operand" "=c")
+ (sign_extend:DI (match_operator:SI 3 "divmod_operator"
+ [(match_operand:DI 1 "register_operand" "a")
+ (match_operand:DI 2 "register_operand" "b")])))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
+ "%E3 %1,%2,%0"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "8")])
+
+(define_insn_and_split "*divmoddi_internal_er"
+ [(set (match_operand:DI 0 "register_operand" "=c")
+ (match_operator:DI 3 "divmod_operator"
+ [(match_operand:DI 1 "register_operand" "a")
+ (match_operand:DI 2 "register_operand" "b")]))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS"
+ "ldq $27,__%E3($29)\t\t!literal!%#\;jsr $23,($27),__%E3\t\t!lituse_jsr!%#"
+ "&& reload_completed"
+ [(parallel [(set (match_dup 0) (match_dup 3))
+ (use (match_dup 0))
+ (use (match_dup 4))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))])]
+{
+ const char *str;
+ switch (GET_CODE (operands[3]))
+ {
+ case DIV:
+ str = "__divq";
+ break;
+ case UDIV:
+ str = "__divqu";
+ break;
+ case MOD:
+ str = "__remq";
+ break;
+ case UMOD:
+ str = "__remqu";
+ break;
+ default:
+ abort ();
+ }
+ operands[4] = GEN_INT (alpha_next_sequence_number++);
+ emit_insn (gen_movdi_er_high_g (operands[0], pic_offset_table_rtx,
+ gen_rtx_SYMBOL_REF (DImode, str),
+ operands[4]));
+}
[(set_attr "type" "jsr")
(set_attr "length" "8")])
-(define_insn ""
- [(set (reg:DI 27)
- (match_operator:DI 1 "divmod_operator"
- [(reg:DI 24) (reg:DI 25)]))
+(define_insn "*divmoddi_internal_er_1"
+ [(set (match_operand:DI 0 "register_operand" "=c")
+ (match_operator:DI 3 "divmod_operator"
+ [(match_operand:DI 1 "register_operand" "a")
+ (match_operand:DI 2 "register_operand" "b")]))
+ (use (match_operand:DI 4 "register_operand" "c"))
+ (use (match_operand 5 "const_int_operand" ""))
(clobber (reg:DI 23))
(clobber (reg:DI 28))]
- "!TARGET_OPEN_VMS"
- "%E1 $24,$25,$27"
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS"
+ "jsr $23,($27),__%E3%J5"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "4")])
+
+(define_insn "*divmoddi_internal"
+ [(set (match_operand:DI 0 "register_operand" "=c")
+ (match_operator:DI 3 "divmod_operator"
+ [(match_operand:DI 1 "register_operand" "a")
+ (match_operand:DI 2 "register_operand" "b")]))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 28))]
+ "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
+ "%E3 %1,%2,%0"
[(set_attr "type" "jsr")
(set_attr "length" "8")])
@@ -1048,7 +1362,6 @@
"HOST_BITS_PER_WIDE_INT == 64 && ! and_operand (operands[2], DImode)"
[(set (match_dup 0) (and:DI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (and:DI (match_dup 0) (match_dup 4)))]
- "
{
unsigned HOST_WIDE_INT mask1 = INTVAL (operands[2]);
unsigned HOST_WIDE_INT mask2 = mask1;
@@ -1064,16 +1377,43 @@
operands[3] = GEN_INT (mask1);
operands[4] = GEN_INT (mask2);
-}")
+})
+
+(define_expand "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ ""
+{
+ if (! TARGET_BWX)
+ operands[1] = force_reg (QImode, operands[1]);
+})
-(define_insn "zero_extendqihi2"
+(define_insn "*zero_extendqihi2_bwx"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_BWX"
+ "@
+ and %1,0xff,%0
+ ldbu %0,%1"
+ [(set_attr "type" "ilog,ild")])
+
+(define_insn "*zero_extendqihi2_nobwx"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
- ""
+ "! TARGET_BWX"
"and %1,0xff,%0"
[(set_attr "type" "ilog")])
-(define_insn ""
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ ""
+{
+ if (! TARGET_BWX)
+ operands[1] = force_reg (QImode, operands[1]);
+})
+
+(define_insn "*zero_extendqisi2_bwx"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
"TARGET_BWX"
@@ -1082,20 +1422,23 @@
ldbu %0,%1"
[(set_attr "type" "ilog,ild")])
-(define_insn ""
+(define_insn "*zero_extendqisi2_nobwx"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
"! TARGET_BWX"
"and %1,0xff,%0"
[(set_attr "type" "ilog")])
-(define_expand "zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
+(define_expand "zero_extendqidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
- "")
+{
+ if (! TARGET_BWX)
+ operands[1] = force_reg (QImode, operands[1]);
+})
-(define_insn ""
+(define_insn "*zero_extendqidi2_bwx"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
"TARGET_BWX"
@@ -1104,20 +1447,23 @@
ldbu %0,%1"
[(set_attr "type" "ilog,ild")])
-(define_insn ""
+(define_insn "*zero_extendqidi2_nobwx"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:QI 1 "register_operand" "r")))]
"! TARGET_BWX"
"and %1,0xff,%0"
[(set_attr "type" "ilog")])
-
-(define_expand "zero_extendqidi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (zero_extend:DI (match_operand:QI 1 "register_operand" "")))]
+
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
""
- "")
-
-(define_insn ""
+{
+ if (! TARGET_BWX)
+ operands[1] = force_reg (HImode, operands[1]);
+})
+
+(define_insn "*zero_extendhisi2_bwx"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
"TARGET_BWX"
@@ -1126,20 +1472,23 @@
ldwu %0,%1"
[(set_attr "type" "shift,ild")])
-(define_insn ""
+(define_insn "*zero_extendhisi2_nobwx"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "register_operand" "r")))]
"! TARGET_BWX"
"zapnot %1,3,%0"
[(set_attr "type" "shift")])
-(define_expand "zero_extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "register_operand" "")))]
+(define_expand "zero_extendhidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "")))]
""
- "")
+{
+ if (! TARGET_BWX)
+ operands[1] = force_reg (HImode, operands[1]);
+})
-(define_insn ""
+(define_insn "*zero_extendhidi2_bwx"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
"TARGET_BWX"
@@ -1148,19 +1497,13 @@
ldwu %0,%1"
[(set_attr "type" "shift,ild")])
-(define_insn ""
+(define_insn "*zero_extendhidi2_nobwx"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:HI 1 "register_operand" "r")))]
""
"zapnot %1,3,%0"
[(set_attr "type" "shift")])
-(define_expand "zero_extendhidi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (zero_extend:DI (match_operand:HI 1 "register_operand" "")))]
- ""
- "")
-
(define_insn "zero_extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
@@ -1168,7 +1511,7 @@
"zapnot %1,15,%0"
[(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "andnotdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI"))
(match_operand:DI 2 "reg_or_0_operand" "rJ")))]
@@ -1193,7 +1536,7 @@
"ornot $31,%1,%0"
[(set_attr "type" "ilog")])
-(define_insn ""
+(define_insn "*iornot"
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI"))
(match_operand:DI 2 "reg_or_0_operand" "rJ")))]
@@ -1211,7 +1554,7 @@
eqv %r1,%N2,%0"
[(set_attr "type" "ilog")])
-(define_insn ""
+(define_insn "*xornot"
[(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (xor:DI (match_operand:DI 1 "register_operand" "%rJ")
(match_operand:DI 2 "register_operand" "rI"))))]
@@ -1219,37 +1562,28 @@
"eqv %r1,%2,%0"
[(set_attr "type" "ilog")])
-;; Handle the FFS insn iff we support CIX.
-;;
-;; These didn't make it into EV6 pass 2 as planned. Instead they
-;; cropped cttz/ctlz/ctpop from the old CIX and renamed it FIX for
-;; "Square Root and Floating Point Convert Extension".
-;;
-;; I'm assured that these insns will make it into EV67 (first pass
-;; due Summer 1999), presumably with a new AMASK bit, and presumably
-;; will still be named CIX.
+;; Handle the FFS insn iff we support CIX.
(define_expand "ffsdi2"
[(set (match_dup 2)
- (unspec [(match_operand:DI 1 "register_operand" "")] 1))
+ (unspec:DI [(match_operand:DI 1 "register_operand" "")] UNSPEC_CTTZ))
(set (match_dup 3)
(plus:DI (match_dup 2) (const_int 1)))
(set (match_operand:DI 0 "register_operand" "")
(if_then_else:DI (eq (match_dup 1) (const_int 0))
(const_int 0) (match_dup 3)))]
"TARGET_CIX"
- "
{
operands[2] = gen_reg_rtx (DImode);
operands[3] = gen_reg_rtx (DImode);
-}")
+})
-(define_insn ""
+(define_insn "*cttz"
[(set (match_operand:DI 0 "register_operand" "=r")
- (unspec [(match_operand:DI 1 "register_operand" "r")] 1))]
+ (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_CTTZ))]
"TARGET_CIX"
"cttz %1,%0"
- ; EV6 calls all mvi and cttz/ctlz/popc class imisc, so just
+ ; EV6 calls all mvi and cttz/ctlz/popc class imisc, so just
; reuse the existing type name.
[(set_attr "type" "mvi")])
@@ -1260,21 +1594,20 @@
(ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ,rJ")
(match_operand:DI 2 "reg_or_6bit_operand" "P,rS")))]
""
- "*
{
switch (which_alternative)
{
case 0:
if (operands[2] == const1_rtx)
- return \"addq %r1,%r1,%0\";
+ return "addq %r1,%r1,%0";
else
- return \"s%P2addq %r1,0,%0\";
+ return "s%P2addq %r1,0,%0";
case 1:
- return \"sll %r1,%2,%0\";
+ return "sll %r1,%2,%0";
default:
abort();
}
-}"
+}
[(set_attr "type" "iadd,shift")])
;; ??? The following pattern is made by combine, but earlier phases
@@ -1287,15 +1620,14 @@
;; (match_operand:DI 2 "const_int_operand" "P"))
;; 0)))]
;; "INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3"
-;; "*
;;{
;; if (operands[2] == const1_rtx)
-;; return \"addl %r1,%r1,%0\";
+;; return "addl %r1,%r1,%0";
;; else
-;; return \"s%P2addl %r1,0,%0\";
-;; }"
+;; return "s%P2addl %r1,0,%0";
+;;}
;; [(set_attr "type" "iadd")])
-
+
(define_insn "lshrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -1320,7 +1652,6 @@
(ashiftrt:DI (match_dup 2)
(const_int 56)))]
""
- "
{
if (TARGET_BWX)
{
@@ -1328,7 +1659,7 @@
force_reg (QImode, operands[1])));
DONE;
}
-
+
/* If we have an unaligned MEM, extend to DImode (which we do
specially) and then copy to the result. */
if (unaligned_memory_operand (operands[1], HImode))
@@ -1343,7 +1674,7 @@
operands[0] = gen_lowpart (DImode, operands[0]);
operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
-}")
+})
(define_insn "extendqidi2x"
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -1388,7 +1719,6 @@
(ashiftrt:DI (match_dup 2)
(const_int 56)))]
""
- "
{
if (TARGET_BWX)
{
@@ -1411,7 +1741,7 @@
operands[0] = gen_lowpart (DImode, operands[0]);
operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
-}")
+})
(define_expand "extendqidi2"
[(set (match_dup 2)
@@ -1421,7 +1751,6 @@
(ashiftrt:DI (match_dup 2)
(const_int 56)))]
""
- "
{
if (TARGET_BWX)
{
@@ -1443,7 +1772,7 @@
operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
-}")
+})
(define_expand "extendhisi2"
[(set (match_dup 2)
@@ -1453,7 +1782,6 @@
(ashiftrt:DI (match_dup 2)
(const_int 48)))]
""
- "
{
if (TARGET_BWX)
{
@@ -1476,7 +1804,7 @@
operands[0] = gen_lowpart (DImode, operands[0]);
operands[1] = gen_lowpart (DImode, force_reg (HImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
-}")
+})
(define_expand "extendhidi2"
[(set (match_dup 2)
@@ -1486,7 +1814,6 @@
(ashiftrt:DI (match_dup 2)
(const_int 48)))]
""
- "
{
if (TARGET_BWX)
{
@@ -1508,7 +1835,7 @@
operands[1] = gen_lowpart (DImode, force_reg (HImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
-}")
+})
;; Here's how we sign extend an unaligned byte and halfword. Doing this
;; as a pattern saves one instruction. The code is similar to that for
@@ -1516,48 +1843,120 @@
;;
;; Operand 1 is the address + 1 (+2 for HI), operand 0 is the result.
(define_expand "unaligned_extendqidi"
+ [(use (match_operand:QI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "address_operand" ""))]
+ ""
+{
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_unaligned_extendqidi_be (operands[0], operands[1]));
+ else
+ emit_insn (gen_unaligned_extendqidi_le (operands[0], operands[1]));
+ DONE;
+})
+
+(define_expand "unaligned_extendqidi_le"
[(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
(set (match_dup 3)
(mem:DI (and:DI (plus:DI (match_dup 2) (const_int -1))
(const_int -8))))
(set (match_dup 4)
(ashift:DI (match_dup 3)
- (minus:DI (const_int 56)
+ (minus:DI (const_int 64)
(ashift:DI
- (and:DI (plus:DI (match_dup 2) (const_int -1))
- (const_int 7))
+ (and:DI (match_dup 2) (const_int 7))
(const_int 3)))))
(set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
(ashiftrt:DI (match_dup 4) (const_int 56)))]
- ""
- "
-{ operands[2] = gen_reg_rtx (DImode);
+ "! WORDS_BIG_ENDIAN"
+{
+ operands[2] = gen_reg_rtx (DImode);
operands[3] = gen_reg_rtx (DImode);
operands[4] = gen_reg_rtx (DImode);
-}")
+})
+
+(define_expand "unaligned_extendqidi_be"
+ [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+ (set (match_dup 3) (plus:DI (match_dup 2) (const_int -1)))
+ (set (match_dup 4)
+ (mem:DI (and:DI (match_dup 3)
+ (const_int -8))))
+ (set (match_dup 5) (plus:DI (match_dup 2) (const_int -2)))
+ (set (match_dup 6)
+ (ashift:DI (match_dup 4)
+ (ashift:DI
+ (and:DI
+ (plus:DI (match_dup 5) (const_int 1))
+ (const_int 7))
+ (const_int 3))))
+ (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (ashiftrt:DI (match_dup 6) (const_int 56)))]
+ "WORDS_BIG_ENDIAN"
+{
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+ operands[6] = gen_reg_rtx (DImode);
+})
(define_expand "unaligned_extendhidi"
+ [(use (match_operand:QI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "address_operand" ""))]
+ ""
+{
+ operands[0] = gen_lowpart (DImode, operands[0]);
+ emit_insn ((WORDS_BIG_ENDIAN
+ ? gen_unaligned_extendhidi_be
+ : gen_unaligned_extendhidi_le) (operands[0], operands[1]));
+ DONE;
+})
+
+(define_expand "unaligned_extendhidi_le"
[(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
(set (match_dup 3)
(mem:DI (and:DI (plus:DI (match_dup 2) (const_int -2))
(const_int -8))))
(set (match_dup 4)
(ashift:DI (match_dup 3)
- (minus:DI (const_int 56)
+ (minus:DI (const_int 64)
(ashift:DI
- (and:DI (plus:DI (match_dup 2) (const_int -1))
- (const_int 7))
+ (and:DI (match_dup 2) (const_int 7))
(const_int 3)))))
- (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_dup 4) (const_int 48)))]
- ""
- "
-{ operands[2] = gen_reg_rtx (DImode);
+ "! WORDS_BIG_ENDIAN"
+{
+ operands[2] = gen_reg_rtx (DImode);
operands[3] = gen_reg_rtx (DImode);
operands[4] = gen_reg_rtx (DImode);
-}")
+})
-(define_insn ""
+(define_expand "unaligned_extendhidi_be"
+ [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+ (set (match_dup 3) (plus:DI (match_dup 2) (const_int -2)))
+ (set (match_dup 4)
+ (mem:DI (and:DI (match_dup 3)
+ (const_int -8))))
+ (set (match_dup 5) (plus:DI (match_dup 2) (const_int -3)))
+ (set (match_dup 6)
+ (ashift:DI (match_dup 4)
+ (ashift:DI
+ (and:DI
+ (plus:DI (match_dup 5) (const_int 1))
+ (const_int 7))
+ (const_int 3))))
+ (set (match_operand:DI 0 "register_operand" "")
+ (ashiftrt:DI (match_dup 6) (const_int 48)))]
+ "WORDS_BIG_ENDIAN"
+{
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+ operands[6] = gen_reg_rtx (DImode);
+})
+
+(define_insn "*extxl_const"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(match_operand:DI 2 "mode_width_operand" "n")
@@ -1566,83 +1965,164 @@
"ext%M2l %r1,%s3,%0"
[(set_attr "type" "shift")])
-(define_insn "extxl"
+(define_insn "extxl_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(match_operand:DI 2 "mode_width_operand" "n")
(ashift:DI (match_operand:DI 3 "reg_or_8bit_operand" "rI")
(const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "ext%M2l %r1,%3,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extxl_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (match_operand:DI 2 "mode_width_operand" "n")
+ (minus:DI
+ (const_int 56)
+ (ashift:DI
+ (match_operand:DI 3 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"ext%M2l %r1,%3,%0"
[(set_attr "type" "shift")])
;; Combine has some strange notion of preserving existing undefined behaviour
-;; in shifts larger than a word size. So capture these patterns that it
+;; in shifts larger than a word size. So capture these patterns that it
;; should have turned into zero_extracts.
-(define_insn ""
+(define_insn "*extxl_1_le"
[(set (match_operand:DI 0 "register_operand" "=r")
- (and (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
- (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int 3)))
+ (and:DI (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3)))
(match_operand:DI 3 "mode_mask_operand" "n")))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "ext%U3l %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "*extxl_1_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (lshiftrt:DI
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (minus:DI (const_int 56)
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3))))
+ (match_operand:DI 3 "mode_mask_operand" "n")))]
+ "WORDS_BIG_ENDIAN"
"ext%U3l %1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "*extql_2_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "extql %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "*extql_2_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lshiftrt:DI
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"extql %1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn "extqh"
+(define_insn "extqh_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI
(match_operand:DI 1 "reg_or_0_operand" "rJ")
- (minus:DI (const_int 56)
+ (minus:DI (const_int 64)
(ashift:DI
(and:DI
- (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int -1))
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 7))
(const_int 3)))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "extqh %r1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extqh_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (ashift:DI
+ (and:DI
+ (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 1))
+ (const_int 7))
+ (const_int 3))))]
+ "WORDS_BIG_ENDIAN"
"extqh %r1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn "extlh"
+(define_insn "extlh_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI
(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(const_int 2147483647))
- (minus:DI (const_int 56)
+ (minus:DI (const_int 64)
(ashift:DI
(and:DI
- (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int -1))
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 7))
(const_int 3)))))]
- ""
+ "! WORDS_BIG_ENDIAN"
"extlh %r1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn "extwh"
+(define_insn "extlh_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI
+ (ashift:DI
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (ashift:DI
+ (and:DI
+ (plus:DI
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 1))
+ (const_int 7))
+ (const_int 3)))
+ (const_int 2147483647)))]
+ "WORDS_BIG_ENDIAN"
+ "extlh %r1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extwh_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI
(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(const_int 65535))
- (minus:DI (const_int 56)
+ (minus:DI (const_int 64)
(ashift:DI
(and:DI
- (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int -1))
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 7))
(const_int 3)))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "extwh %r1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extwh_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI
+ (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (ashift:DI
+ (and:DI
+ (plus:DI
+ (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 1))
+ (const_int 7))
+ (const_int 3)))
+ (const_int 65535)))]
+ "WORDS_BIG_ENDIAN"
"extwh %r1,%2,%0"
[(set_attr "type" "shift")])
@@ -1667,12 +2147,12 @@
;; (match_dup 4)))]
;; "
;;{
-;; operands[6] = plus_constant (operands[3],
+;; operands[6] = plus_constant (operands[3],
;; INTVAL (operands[2]) / BITS_PER_UNIT);
;; operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT);
;;}")
-
-(define_insn ""
+
+(define_insn "*insbl_const"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
(match_operand:DI 2 "mul8_operand" "I")))]
@@ -1680,7 +2160,7 @@
"insbl %1,%s2,%0"
[(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "*inswl_const"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
(match_operand:DI 2 "mul8_operand" "I")))]
@@ -1688,7 +2168,7 @@
"inswl %1,%s2,%0"
[(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "*insll_const"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
(match_operand:DI 2 "mul8_operand" "I")))]
@@ -1696,46 +2176,86 @@
"insll %1,%s2,%0"
[(set_attr "type" "shift")])
-(define_insn "insbl"
+(define_insn "insbl_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "insbl %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "insbl_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
+ (minus:DI (const_int 56)
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"insbl %1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn "inswl"
+(define_insn "inswl_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "inswl %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "inswl_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
+ (minus:DI (const_int 56)
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"inswl %1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn "insll"
+(define_insn "insll_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
"insll %1,%2,%0"
[(set_attr "type" "shift")])
-(define_insn "insql"
+(define_insn "insll_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (minus:DI (const_int 56)
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
+ "insll %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "insql_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (match_operand:DI 1 "register_operand" "r")
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "insql %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "insql_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "r")
+ (minus:DI (const_int 56)
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"insql %1,%2,%0"
[(set_attr "type" "shift")])
;; Combine has this sometimes habit of moving the and outside of the
;; shift, making life more interesting.
-(define_insn ""
+(define_insn "*insxl"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "mul8_operand" "I"))
@@ -1748,21 +2268,20 @@
== (unsigned HOST_WIDE_INT) INTVAL (operands[3]))
|| ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2])
== (unsigned HOST_WIDE_INT) INTVAL (operands[3])))"
- "*
{
#if HOST_BITS_PER_WIDE_INT == 64
if ((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2])
== (unsigned HOST_WIDE_INT) INTVAL (operands[3]))
- return \"insbl %1,%s2,%0\";
+ return "insbl %1,%s2,%0";
if ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2])
== (unsigned HOST_WIDE_INT) INTVAL (operands[3]))
- return \"inswl %1,%s2,%0\";
+ return "inswl %1,%s2,%0";
if ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2])
== (unsigned HOST_WIDE_INT) INTVAL (operands[3]))
- return \"insll %1,%s2,%0\";
+ return "insll %1,%s2,%0";
#endif
abort();
-}"
+}
[(set_attr "type" "shift")])
;; We do not include the insXh insns because they are complex to express
@@ -1772,14 +2291,15 @@
(define_insn "insxh"
[(set (match_operand:DI 0 "register_operand" "=r")
- (unspec [(match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "mode_width_operand" "n")
- (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 2))]
+ (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "mode_width_operand" "n")
+ (match_operand:DI 3 "reg_or_8bit_operand" "rI")]
+ UNSPEC_INSXH))]
""
"ins%M2h %1,%3,%0"
[(set_attr "type" "shift")])
-(define_insn "mskxl"
+(define_insn "mskxl_le"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (ashift:DI
(match_operand:DI 2 "mode_mask_operand" "n")
@@ -1787,7 +2307,20 @@
(match_operand:DI 3 "reg_or_8bit_operand" "rI")
(const_int 3))))
(match_operand:DI 1 "reg_or_0_operand" "rJ")))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "msk%U2l %r1,%3,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "mskxl_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (not:DI (ashift:DI
+ (match_operand:DI 2 "mode_mask_operand" "n")
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (match_operand:DI 3 "reg_or_8bit_operand" "rI")
+ (const_int 3)))))
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")))]
+ "WORDS_BIG_ENDIAN"
"msk%U2l %r1,%3,%0"
[(set_attr "type" "shift")])
@@ -1798,12 +2331,29 @@
(define_insn "mskxh"
[(set (match_operand:DI 0 "register_operand" "=r")
- (unspec [(match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "mode_width_operand" "n")
- (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 3))]
+ (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "mode_width_operand" "n")
+ (match_operand:DI 3 "reg_or_8bit_operand" "rI")]
+ UNSPEC_MSKXH))]
""
"msk%M2h %1,%3,%0"
[(set_attr "type" "shift")])
+
+;; Prefer AND + NE over LSHIFTRT + AND.
+
+(define_insn_and_split "*ze_and_ne"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (const_int 1)
+ (match_operand 2 "const_int_operand" "I")))]
+ "(unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 8"
+ "#"
+ "(unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 8"
+ [(set (match_dup 0)
+ (and:DI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0)
+ (ne:DI (match_dup 0) (const_int 0)))]
+ "operands[3] = GEN_INT (1 << INTVAL (operands[2]));")
;; Floating-point operations. All the double-precision insns can extend
;; from single, so indicate that. The exception are the ones that simply
@@ -1816,6 +2366,13 @@
"cpys $f31,%R1,%0"
[(set_attr "type" "fcpys")])
+(define_insn "*nabssf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (abs:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
+ "TARGET_FP"
+ "cpysn $f31,%R1,%0"
+ [(set_attr "type" "fadd")])
+
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
@@ -1823,6 +2380,36 @@
"cpys $f31,%R1,%0"
[(set_attr "type" "fcpys")])
+(define_insn "*nabsdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (neg:DF (abs:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG"))))]
+ "TARGET_FP"
+ "cpysn $f31,%R1,%0"
+ [(set_attr "type" "fadd")])
+
+(define_expand "abstf2"
+ [(parallel [(set (match_operand:TF 0 "register_operand" "")
+ (neg:TF (match_operand:TF 1 "reg_or_fp0_operand" "")))
+ (use (match_dup 2))])]
+ "TARGET_HAS_XFLOATING_LIBS"
+{
+#if HOST_BITS_PER_WIDE_INT >= 64
+ operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63));
+#else
+ operands[2] = force_reg (DImode, immed_double_const (0, 0x80000000, DImode));
+#endif
+})
+
+(define_insn_and_split "*abstf_internal"
+ [(set (match_operand:TF 0 "register_operand" "=r")
+ (abs:TF (match_operand:TF 1 "reg_or_fp0_operand" "rG")))
+ (use (match_operand:DI 2 "register_operand" "r"))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+ "alpha_split_tfmode_frobsign (operands, gen_andnotdi3); DONE;")
+
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
@@ -1837,62 +2424,104 @@
"cpysn %R1,%R1,%0"
[(set_attr "type" "fadd")])
-(define_insn ""
+(define_expand "negtf2"
+ [(parallel [(set (match_operand:TF 0 "register_operand" "")
+ (neg:TF (match_operand:TF 1 "reg_or_fp0_operand" "")))
+ (use (match_dup 2))])]
+ "TARGET_HAS_XFLOATING_LIBS"
+{
+#if HOST_BITS_PER_WIDE_INT >= 64
+ operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63));
+#else
+ operands[2] = force_reg (DImode, immed_double_const (0, 0x80000000, DImode));
+#endif
+})
+
+(define_insn_and_split "*negtf_internal"
+ [(set (match_operand:TF 0 "register_operand" "=r")
+ (neg:TF (match_operand:TF 1 "reg_or_fp0_operand" "rG")))
+ (use (match_operand:DI 2 "register_operand" "r"))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+ "alpha_split_tfmode_frobsign (operands, gen_xordi3); DONE;")
+
+(define_insn "*addsf_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(plus:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "add%,%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "add%,%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "add%,%)%& %R1,%R2,%0"
+ "add%,%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*adddf_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(plus:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "add%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "add%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "add%-%)%& %R1,%R2,%0"
+ "add%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*adddf_ext1"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "add%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "add%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*adddf_ext2"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "%fG"))
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "add%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "add%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
+
+(define_expand "addtf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (PLUS, operands); DONE;")
;; Define conversion operators between DFmode and SImode, using the cvtql
;; instruction. To allow combine et al to do useful things, we keep the
@@ -1905,473 +2534,672 @@
(define_insn "*cvtql"
[(set (match_operand:SI 0 "register_operand" "=f")
- (unspec:SI [(match_operand:DI 1 "reg_or_fp0_operand" "fG")] 5))]
+ (unspec:SI [(match_operand:DI 1 "reg_or_fp0_operand" "fG")]
+ UNSPEC_CVTQL))]
"TARGET_FP"
- "cvtql%` %R1,%0"
+ "cvtql%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
-
-(define_split
- [(set (match_operand:SI 0 "memory_operand" "")
- (subreg:SI (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "")) 0))
- (clobber (match_scratch:DI 2 ""))
- (clobber (match_scratch:SI 3 ""))]
- "TARGET_FP && reload_completed"
- [(set (match_dup 2) (fix:DI (match_dup 1)))
- (set (match_dup 3) (unspec:SI [(match_dup 2)] 5))
- (set (match_dup 0) (match_dup 3))]
- "")
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "v_sv")])
-(define_split
- [(set (match_operand:SI 0 "memory_operand" "")
- (subreg:SI (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "")) 0))
- (clobber (match_scratch:DI 2 ""))]
- "TARGET_FP && reload_completed"
- [(set (match_dup 2) (fix:DI (match_dup 1)))
- (set (match_dup 3) (unspec:SI [(match_dup 2)] 5))
- (set (match_dup 0) (match_dup 3))]
- ;; Due to REG_CANNOT_CHANGE_SIZE issues, we cannot simply use SUBREG.
- "operands[3] = gen_rtx_REG (SImode, REGNO (operands[2]));")
-
-(define_insn ""
+(define_insn_and_split "*fix_truncdfsi_ieee"
[(set (match_operand:SI 0 "memory_operand" "=m")
(subreg:SI (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")) 0))
(clobber (match_scratch:DI 2 "=&f"))
(clobber (match_scratch:SI 3 "=&f"))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
"#"
+ "&& reload_completed"
+ [(set (match_dup 2) (fix:DI (match_dup 1)))
+ (set (match_dup 3) (unspec:SI [(match_dup 2)] UNSPEC_CVTQL))
+ (set (match_dup 0) (match_dup 3))]
+ ""
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
-(define_insn ""
+(define_insn_and_split "*fix_truncdfsi_internal"
[(set (match_operand:SI 0 "memory_operand" "=m")
(subreg:SI (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")) 0))
(clobber (match_scratch:DI 2 "=f"))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
"#"
+ "&& reload_completed"
+ [(set (match_dup 2) (fix:DI (match_dup 1)))
+ (set (match_dup 3) (unspec:SI [(match_dup 2)] UNSPEC_CVTQL))
+ (set (match_dup 0) (match_dup 3))]
+ ;; Due to REG_CANNOT_CHANGE_SIZE issues, we cannot simply use SUBREG.
+ "operands[3] = gen_rtx_REG (SImode, REGNO (operands[2]));"
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
-(define_insn ""
+(define_insn "*fix_truncdfdi_ieee"
[(set (match_operand:DI 0 "reg_no_subreg_operand" "=&f")
(fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cvt%-q%(c %R1,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cvt%-q%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "c")
+ (set_attr "trap_suffix" "v_sv_svi")])
(define_insn "fix_truncdfdi2"
[(set (match_operand:DI 0 "reg_no_subreg_operand" "=f")
(fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "cvt%-q%(c %R1,%0"
+ "cvt%-q%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "c")
+ (set_attr "trap_suffix" "v_sv_svi")])
;; Likewise between SFmode and SImode.
-(define_split
- [(set (match_operand:SI 0 "memory_operand" "")
- (subreg:SI (fix:DI (float_extend:DF
- (match_operand:SF 1 "reg_or_fp0_operand" ""))) 0))
- (clobber (match_scratch:DI 2 ""))
- (clobber (match_scratch:SI 3 ""))]
- "TARGET_FP && reload_completed"
- [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1))))
- (set (match_dup 3) (unspec:SI [(match_dup 2)] 5))
- (set (match_dup 0) (match_dup 3))]
- "")
-
-(define_split
- [(set (match_operand:SI 0 "memory_operand" "")
- (subreg:SI (fix:DI (float_extend:DF
- (match_operand:SF 1 "reg_or_fp0_operand" ""))) 0))
- (clobber (match_scratch:DI 2 ""))]
- "TARGET_FP && reload_completed"
- [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1))))
- (set (match_dup 3) (unspec:SI [(match_dup 2)] 5))
- (set (match_dup 0) (match_dup 3))]
- ;; Due to REG_CANNOT_CHANGE_SIZE issues, we cannot simply use SUBREG.
- "operands[3] = gen_rtx_REG (SImode, REGNO (operands[2]));")
-
-(define_insn ""
+(define_insn_and_split "*fix_truncsfsi_ieee"
[(set (match_operand:SI 0 "memory_operand" "=m")
(subreg:SI (fix:DI (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))) 0))
(clobber (match_scratch:DI 2 "=&f"))
(clobber (match_scratch:SI 3 "=&f"))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
"#"
+ "&& reload_completed"
+ [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1))))
+ (set (match_dup 3) (unspec:SI [(match_dup 2)] UNSPEC_CVTQL))
+ (set (match_dup 0) (match_dup 3))]
+ ""
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
-(define_insn ""
+(define_insn_and_split "*fix_truncsfsi_internal"
[(set (match_operand:SI 0 "memory_operand" "=m")
(subreg:SI (fix:DI (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))) 0))
(clobber (match_scratch:DI 2 "=f"))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
"#"
+ "&& reload_completed"
+ [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1))))
+ (set (match_dup 3) (unspec:SI [(match_dup 2)] UNSPEC_CVTQL))
+ (set (match_dup 0) (match_dup 3))]
+ ;; Due to REG_CANNOT_CHANGE_SIZE issues, we cannot simply use SUBREG.
+ "operands[3] = gen_rtx_REG (SImode, REGNO (operands[2]));"
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
-(define_insn ""
+(define_insn "*fix_truncsfdi_ieee"
[(set (match_operand:DI 0 "reg_no_subreg_operand" "=&f")
(fix:DI (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cvt%-q%(c %R1,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cvt%-q%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "c")
+ (set_attr "trap_suffix" "v_sv_svi")])
(define_insn "fix_truncsfdi2"
[(set (match_operand:DI 0 "reg_no_subreg_operand" "=f")
(fix:DI (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
"TARGET_FP"
- "cvt%-q%(c %R1,%0"
+ "cvt%-q%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "c")
+ (set_attr "trap_suffix" "v_sv_svi")])
-(define_insn ""
+(define_expand "fix_trunctfdi2"
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FIX, operands); DONE;")
+
+(define_insn "*floatdisf_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(float:SF (match_operand:DI 1 "reg_no_subreg_operand" "f")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cvtq%,%+%& %1,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cvtq%,%/ %1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "sui")])
(define_insn "floatdisf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float:SF (match_operand:DI 1 "reg_no_subreg_operand" "f")))]
"TARGET_FP"
- "cvtq%,%+%& %1,%0"
+ "cvtq%,%/ %1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "sui")])
-(define_insn ""
+(define_insn "*floatdidf_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(float:DF (match_operand:DI 1 "reg_no_subreg_operand" "f")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cvtq%-%+%& %1,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cvtq%-%/ %1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "sui")])
(define_insn "floatdidf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:DI 1 "reg_no_subreg_operand" "f")))]
"TARGET_FP"
- "cvtq%-%+%& %1,%0"
+ "cvtq%-%/ %1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "sui")])
+
+(define_expand "floatditf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:DI 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FLOAT, operands); DONE;")
+
+(define_expand "floatunsdisf2"
+ [(use (match_operand:SF 0 "register_operand" ""))
+ (use (match_operand:DI 1 "register_operand" ""))]
+ "TARGET_FP"
+ "alpha_emit_floatuns (operands); DONE;")
-(define_expand "extendsfdf2"
+(define_expand "floatunsdidf2"
[(use (match_operand:DF 0 "register_operand" ""))
- (use (match_operand:SF 1 "nonimmediate_operand" ""))]
+ (use (match_operand:DI 1 "register_operand" ""))]
+ "TARGET_FP"
+ "alpha_emit_floatuns (operands); DONE;")
+
+(define_expand "floatunsditf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:DI 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (UNSIGNED_FLOAT, operands); DONE;")
+
+(define_expand "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "")
+ (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))]
"TARGET_FP"
-"
{
- if (alpha_tp == ALPHA_TP_INSN)
- emit_insn (gen_extendsfdf2_tp (operands[0],
- force_reg (SFmode, operands[1])));
- else
- emit_insn (gen_extendsfdf2_no_tp (operands[0], operands[1]));
+ if (alpha_fptm >= ALPHA_FPTM_SU)
+ operands[1] = force_reg (SFmode, operands[1]);
+})
- DONE;
-}")
-;; FIXME
-(define_insn "extendsfdf2_tp"
+;; The Unicos/Mk assembler doesn't support cvtst, but we've already
+;; asserted that alpha_fptm == ALPHA_FPTM_N.
+
+(define_insn "*extendsfdf2_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
"cvtsts %1,%0"
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
-(define_insn "extendsfdf2_no_tp"
+(define_insn "*extendsfdf2_internal"
[(set (match_operand:DF 0 "register_operand" "=f,f,m")
(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m,f")))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
"@
- fmov %1,%0
+ cpys %1,%1,%0
ld%, %0,%1
st%- %1,%0"
- [(set_attr "type" "fcpys,fld,fst")
- (set_attr "trap" "yes")])
+ [(set_attr "type" "fcpys,fld,fst")])
-(define_insn ""
+(define_expand "extendsftf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:SF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+{
+ rtx tmp = gen_reg_rtx (DFmode);
+ emit_insn (gen_extendsfdf2 (tmp, operands[1]));
+ emit_insn (gen_extenddftf2 (operands[0], tmp));
+ DONE;
+})
+
+(define_expand "extenddftf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:DF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FLOAT_EXTEND, operands); DONE;")
+
+(define_insn "*truncdfsf2_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cvt%-%,%)%& %R1,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cvt%-%,%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "cvt%-%,%)%& %R1,%0"
+ "cvt%-%,%/ %R1,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_expand "trunctfdf2"
+ [(use (match_operand:DF 0 "register_operand" ""))
+ (use (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FLOAT_TRUNCATE, operands); DONE;")
+
+(define_expand "trunctfsf2"
+ [(use (match_operand:SF 0 "register_operand" ""))
+ (use (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_FP && TARGET_HAS_XFLOATING_LIBS"
+{
+ rtx tmpf, sticky, arg, lo, hi;
+
+ tmpf = gen_reg_rtx (DFmode);
+ sticky = gen_reg_rtx (DImode);
+ arg = copy_to_mode_reg (TFmode, operands[1]);
+ lo = gen_lowpart (DImode, arg);
+ hi = gen_highpart (DImode, arg);
+
+ /* Convert the low word of the TFmode value into a sticky rounding bit,
+ then or it into the low bit of the high word. This leaves the sticky
+ bit at bit 48 of the fraction, which is representable in DFmode,
+ which prevents rounding error in the final conversion to SFmode. */
+
+ emit_insn (gen_rtx_SET (VOIDmode, sticky,
+ gen_rtx_NE (DImode, lo, const0_rtx)));
+ emit_insn (gen_iordi3 (hi, hi, sticky));
+ emit_insn (gen_trunctfdf2 (tmpf, arg));
+ emit_insn (gen_truncdfsf2 (operands[0], tmpf));
+ DONE;
+})
+
+(define_insn "*divsf3_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "div%,%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "div%,%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
(set_attr "opsize" "si")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "div%,%)%& %R1,%R2,%0"
+ "div%,%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
(set_attr "opsize" "si")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*divdf3_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "div%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "div%-%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "div%-%)%& %R1,%R2,%0"
+ "div%-%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*divdf_ext1"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "div%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "div%-%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*divdf_ext2"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "div%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "div%-%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*divdf_ext3"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "div%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "div%-%/ %R1,%R2,%0"
[(set_attr "type" "fdiv")
- (set_attr "trap" "yes")])
-
-(define_insn ""
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
+
+(define_expand "divtf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (DIV, operands); DONE;")
+
+(define_insn "*mulsf3_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "mul%,%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "mul%,%/ %R1,%R2,%0"
[(set_attr "type" "fmul")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "mul%,%)%& %R1,%R2,%0"
+ "mul%,%/ %R1,%R2,%0"
[(set_attr "type" "fmul")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*muldf3_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(mult:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "mul%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "mul%-%/ %R1,%R2,%0"
[(set_attr "type" "fmul")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "mul%-%)%& %R1,%R2,%0"
+ "mul%-%/ %R1,%R2,%0"
[(set_attr "type" "fmul")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*muldf_ext1"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "mul%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "mul%-%/ %R1,%R2,%0"
[(set_attr "type" "fmul")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*muldf_ext2"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "%fG"))
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "mul%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "mul%-%/ %R1,%R2,%0"
[(set_attr "type" "fmul")
- (set_attr "trap" "yes")])
-
-(define_insn ""
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
+
+(define_expand "multf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (MULT, operands); DONE;")
+
+(define_insn "*subsf3_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "sub%,%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "sub%,%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "sub%,%)%& %R1,%R2,%0"
+ "sub%,%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*subdf3_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "sub%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "sub%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "sub%-%)%& %R1,%R2,%0"
+ "sub%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*subdf_ext1"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "sub%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "sub%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*subdf_ext2"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "sub%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "sub%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*subdf_ext3"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "sub%-%)%& %R1,%R2,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "sub%-%/ %R1,%R2,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
-
-(define_insn ""
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
+
+(define_expand "subtf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (MINUS, operands); DONE;")
+
+(define_insn "*sqrtsf2_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && TARGET_FIX && alpha_tp == ALPHA_TP_INSN"
- "sqrt%,%)%& %R1,%0"
+ "TARGET_FP && TARGET_FIX && alpha_fptm >= ALPHA_FPTM_SU"
+ "sqrt%,%/ %R1,%0"
[(set_attr "type" "fsqrt")
(set_attr "opsize" "si")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP && TARGET_FIX"
- "sqrt%,%)%& %R1,%0"
+ "sqrt%,%/ %R1,%0"
[(set_attr "type" "fsqrt")
(set_attr "opsize" "si")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
-(define_insn ""
+(define_insn "*sqrtdf2_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
(sqrt:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP && TARGET_FIX && alpha_tp == ALPHA_TP_INSN"
- "sqrt%-%)%& %R1,%0"
+ "TARGET_FP && TARGET_FIX && alpha_fptm >= ALPHA_FPTM_SU"
+ "sqrt%-%/ %R1,%0"
[(set_attr "type" "fsqrt")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(sqrt:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP && TARGET_FIX"
- "sqrt%-%)%& %1,%0"
+ "sqrt%-%/ %1,%0"
[(set_attr "type" "fsqrt")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "round_suffix" "normal")
+ (set_attr "trap_suffix" "u_su_sui")])
;; Next are all the integer comparisons, and conditional moves and branches
;; and some of the related define_expand's and define_split's.
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=r")
- (match_operator:DI 1 "alpha_comparison_operator"
- [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+(define_insn "*setcc_internal"
+ [(set (match_operand 0 "register_operand" "=r")
+ (match_operator 1 "alpha_comparison_operator"
+ [(match_operand:DI 2 "register_operand" "r")
(match_operand:DI 3 "reg_or_8bit_operand" "rI")]))]
- ""
- "cmp%C1 %r2,%3,%0"
+ "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT
+ && GET_MODE_SIZE (GET_MODE (operands[0])) <= 8
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])"
+ "cmp%C1 %2,%3,%0"
[(set_attr "type" "icmp")])
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=r")
- (match_operator:DI 1 "alpha_swapped_comparison_operator"
- [(match_operand:DI 2 "reg_or_8bit_operand" "rI")
+;; Yes, we can technically support reg_or_8bit_operand in operand 2,
+;; but that's non-canonical rtl and allowing that causes inefficiencies
+;; from cse on.
+(define_insn "*setcc_swapped_internal"
+ [(set (match_operand 0 "register_operand" "=r")
+ (match_operator 1 "alpha_swapped_comparison_operator"
+ [(match_operand:DI 2 "register_operand" "r")
(match_operand:DI 3 "reg_or_0_operand" "rJ")]))]
- ""
+ "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT
+ && GET_MODE_SIZE (GET_MODE (operands[0])) <= 8
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])"
"cmp%c1 %r3,%2,%0"
[(set_attr "type" "icmp")])
-;; This pattern exists so conditional moves of SImode values are handled.
-;; Comparisons are still done in DImode though.
+;; Use match_operator rather than ne directly so that we can match
+;; multiple integer modes.
+(define_insn "*setne_internal"
+ [(set (match_operand 0 "register_operand" "=r")
+ (match_operator 1 "signed_comparison_operator"
+ [(match_operand:DI 2 "register_operand" "r")
+ (const_int 0)]))]
+ "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT
+ && GET_MODE_SIZE (GET_MODE (operands[0])) <= 8
+ && GET_CODE (operands[1]) == NE
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])"
+ "cmpult $31,%2,%0"
+ [(set_attr "type" "icmp")])
+
+;; The mode folding trick can't be used with const_int operands, since
+;; reload needs to know the proper mode.
+;;
+;; Use add_operand instead of the more seemingly natural reg_or_8bit_operand
+;; in order to create more pairs of constants. As long as we're allowing
+;; two constants at the same time, and will have to reload one of them...
-(define_insn ""
+(define_insn "*movqicc_internal"
+ [(set (match_operand:QI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:QI
+ (match_operator 2 "signed_comparison_operator"
+ [(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J")
+ (match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")])
+ (match_operand:QI 1 "add_operand" "rI,0,rI,0")
+ (match_operand:QI 5 "add_operand" "0,rI,0,rI")))]
+ "(operands[3] == const0_rtx || operands[4] == const0_rtx)"
+ "@
+ cmov%C2 %r3,%1,%0
+ cmov%D2 %r3,%5,%0
+ cmov%c2 %r4,%1,%0
+ cmov%d2 %r4,%5,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movhicc_internal"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:HI
+ (match_operator 2 "signed_comparison_operator"
+ [(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J")
+ (match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")])
+ (match_operand:HI 1 "add_operand" "rI,0,rI,0")
+ (match_operand:HI 5 "add_operand" "0,rI,0,rI")))]
+ "(operands[3] == const0_rtx || operands[4] == const0_rtx)"
+ "@
+ cmov%C2 %r3,%1,%0
+ cmov%D2 %r3,%5,%0
+ cmov%c2 %r4,%1,%0
+ cmov%d2 %r4,%5,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movsicc_internal"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(if_then_else:SI
(match_operator 2 "signed_comparison_operator"
[(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J")
(match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")])
- (match_operand:SI 1 "reg_or_8bit_operand" "rI,0,rI,0")
- (match_operand:SI 5 "reg_or_8bit_operand" "0,rI,0,rI")))]
- "operands[3] == const0_rtx || operands[4] == const0_rtx"
+ (match_operand:SI 1 "add_operand" "rI,0,rI,0")
+ (match_operand:SI 5 "add_operand" "0,rI,0,rI")))]
+ "(operands[3] == const0_rtx || operands[4] == const0_rtx)"
"@
cmov%C2 %r3,%1,%0
cmov%D2 %r3,%5,%0
@@ -2379,15 +3207,15 @@
cmov%d2 %r4,%5,%0"
[(set_attr "type" "icmov")])
-(define_insn ""
+(define_insn "*movdicc_internal"
[(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
(if_then_else:DI
(match_operator 2 "signed_comparison_operator"
[(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J")
(match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")])
- (match_operand:DI 1 "reg_or_8bit_operand" "rI,0,rI,0")
- (match_operand:DI 5 "reg_or_8bit_operand" "0,rI,0,rI")))]
- "operands[3] == const0_rtx || operands[4] == const0_rtx"
+ (match_operand:DI 1 "add_operand" "rI,0,rI,0")
+ (match_operand:DI 5 "add_operand" "0,rI,0,rI")))]
+ "(operands[3] == const0_rtx || operands[4] == const0_rtx)"
"@
cmov%C2 %r3,%1,%0
cmov%D2 %r3,%5,%0
@@ -2395,7 +3223,52 @@
cmov%d2 %r4,%5,%0"
[(set_attr "type" "icmov")])
-(define_insn ""
+(define_insn "*movqicc_lbc"
+ [(set (match_operand:QI 0 "register_operand" "=r,r")
+ (if_then_else:QI
+ (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
+ (const_int 1)
+ (const_int 0))
+ (const_int 0))
+ (match_operand:QI 1 "reg_or_8bit_operand" "rI,0")
+ (match_operand:QI 3 "reg_or_8bit_operand" "0,rI")))]
+ ""
+ "@
+ cmovlbc %r2,%1,%0
+ cmovlbs %r2,%3,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movhicc_lbc"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI
+ (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
+ (const_int 1)
+ (const_int 0))
+ (const_int 0))
+ (match_operand:HI 1 "reg_or_8bit_operand" "rI,0")
+ (match_operand:HI 3 "reg_or_8bit_operand" "0,rI")))]
+ ""
+ "@
+ cmovlbc %r2,%1,%0
+ cmovlbs %r2,%3,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movsicc_lbc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI
+ (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
+ (const_int 1)
+ (const_int 0))
+ (const_int 0))
+ (match_operand:SI 1 "reg_or_8bit_operand" "rI,0")
+ (match_operand:SI 3 "reg_or_8bit_operand" "0,rI")))]
+ ""
+ "@
+ cmovlbc %r2,%1,%0
+ cmovlbs %r2,%3,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movdicc_lbc"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(if_then_else:DI
(eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
@@ -2410,7 +3283,52 @@
cmovlbs %r2,%3,%0"
[(set_attr "type" "icmov")])
-(define_insn ""
+(define_insn "*movqicc_lbs"
+ [(set (match_operand:QI 0 "register_operand" "=r,r")
+ (if_then_else:QI
+ (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
+ (const_int 1)
+ (const_int 0))
+ (const_int 0))
+ (match_operand:QI 1 "reg_or_8bit_operand" "rI,0")
+ (match_operand:QI 3 "reg_or_8bit_operand" "0,rI")))]
+ ""
+ "@
+ cmovlbs %r2,%1,%0
+ cmovlbc %r2,%3,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movhicc_lbs"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI
+ (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
+ (const_int 1)
+ (const_int 0))
+ (const_int 0))
+ (match_operand:HI 1 "reg_or_8bit_operand" "rI,0")
+ (match_operand:HI 3 "reg_or_8bit_operand" "0,rI")))]
+ ""
+ "@
+ cmovlbs %r2,%1,%0
+ cmovlbc %r2,%3,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movsicc_lbs"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI
+ (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
+ (const_int 1)
+ (const_int 0))
+ (const_int 0))
+ (match_operand:SI 1 "reg_or_8bit_operand" "rI,0")
+ (match_operand:SI 3 "reg_or_8bit_operand" "0,rI")))]
+ ""
+ "@
+ cmovlbs %r2,%1,%0
+ cmovlbc %r2,%3,%0"
+ [(set_attr "type" "icmov")])
+
+(define_insn "*movdicc_lbs"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(if_then_else:DI
(ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ")
@@ -2431,14 +3349,13 @@
[(set (match_operand:DI 0 "register_operand" "")
(abs:DI (match_operand:DI 1 "register_operand" "")))]
""
- "
-{ if (rtx_equal_p (operands[0], operands[1]))
+{
+ if (rtx_equal_p (operands[0], operands[1]))
emit_insn (gen_absdi2_same (operands[0], gen_reg_rtx (DImode)));
else
emit_insn (gen_absdi2_diff (operands[0], operands[1]));
-
DONE;
-}")
+})
(define_expand "absdi2_same"
[(set (match_operand:DI 1 "register_operand" "")
@@ -2463,7 +3380,7 @@
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(abs:DI (match_dup 0)))
- (clobber (match_operand:DI 2 "register_operand" ""))]
+ (clobber (match_operand:DI 1 "register_operand" ""))]
""
[(set (match_dup 1) (neg:DI (match_dup 0)))
(set (match_dup 0) (if_then_else:DI (ge (match_dup 0) (const_int 0))
@@ -2482,7 +3399,7 @@
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(neg:DI (abs:DI (match_dup 0))))
- (clobber (match_operand:DI 2 "register_operand" ""))]
+ (clobber (match_operand:DI 1 "register_operand" ""))]
""
[(set (match_dup 1) (neg:DI (match_dup 0)))
(set (match_dup 0) (if_then_else:DI (le (match_dup 0) (const_int 0))
@@ -2570,9 +3487,7 @@
(if_then_else:DI (eq (match_dup 3) (const_int 0))
(match_dup 1) (match_dup 2)))]
""
- "
-{ operands[3] = gen_reg_rtx (DImode);
-}")
+ { operands[3] = gen_reg_rtx (DImode); })
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -2585,7 +3500,7 @@
(match_dup 1) (match_dup 2)))]
"")
-(define_insn ""
+(define_insn "*smax_const0"
[(set (match_operand:DI 0 "register_operand" "=r")
(smax:DI (match_operand:DI 1 "register_operand" "0")
(const_int 0)))]
@@ -2601,9 +3516,7 @@
(if_then_else:DI (ne (match_dup 3) (const_int 0))
(match_dup 1) (match_dup 2)))]
""
- "
-{ operands[3] = gen_reg_rtx (DImode);
-}")
+ { operands[3] = gen_reg_rtx (DImode); })
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -2616,7 +3529,7 @@
(match_dup 1) (match_dup 2)))]
"")
-(define_insn ""
+(define_insn "*smin_const0"
[(set (match_operand:DI 0 "register_operand" "=r")
(smin:DI (match_operand:DI 1 "register_operand" "0")
(const_int 0)))]
@@ -2625,16 +3538,14 @@
[(set_attr "type" "icmov")])
(define_expand "umaxdi3"
- [(set (match_dup 3)
+ [(set (match_dup 3)
(leu:DI (match_operand:DI 1 "reg_or_0_operand" "")
(match_operand:DI 2 "reg_or_8bit_operand" "")))
(set (match_operand:DI 0 "register_operand" "")
(if_then_else:DI (eq (match_dup 3) (const_int 0))
(match_dup 1) (match_dup 2)))]
""
- "
-{ operands[3] = gen_reg_rtx (DImode);
-}")
+ "operands[3] = gen_reg_rtx (DImode);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -2655,9 +3566,7 @@
(if_then_else:DI (ne (match_dup 3) (const_int 0))
(match_dup 1) (match_dup 2)))]
""
- "
-{ operands[3] = gen_reg_rtx (DImode);
-}")
+ "operands[3] = gen_reg_rtx (DImode);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -2670,7 +3579,7 @@
(match_dup 1) (match_dup 2)))]
"")
-(define_insn ""
+(define_insn "*bcc_normal"
[(set (pc)
(if_then_else
(match_operator 1 "signed_comparison_operator"
@@ -2682,19 +3591,20 @@
"b%C1 %r2,%0"
[(set_attr "type" "ibr")])
-(define_insn ""
+(define_insn "*bcc_reverse"
[(set (pc)
(if_then_else
(match_operator 1 "signed_comparison_operator"
- [(const_int 0)
- (match_operand:DI 2 "register_operand" "r")])
- (label_ref (match_operand 0 "" ""))
- (pc)))]
+ [(match_operand:DI 2 "register_operand" "r")
+ (const_int 0)])
+
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
""
"b%c1 %2,%0"
[(set_attr "type" "ibr")])
-(define_insn ""
+(define_insn "*blbs_normal"
[(set (pc)
(if_then_else
(ne (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -2707,7 +3617,7 @@
"blbs %r1,%0"
[(set_attr "type" "ibr")])
-(define_insn ""
+(define_insn "*blbc_normal"
[(set (pc)
(if_then_else
(eq (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -2746,100 +3656,108 @@
"")
;; The following are the corresponding floating-point insns. Recall
-;; we need to have variants that expand the arguments from SF mode
+;; we need to have variants that expand the arguments from SFmode
;; to DFmode.
-(define_insn ""
+(define_insn "*cmpdf_ieee"
[(set (match_operand:DF 0 "register_operand" "=&f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_internal"
[(set (match_operand:DF 0 "register_operand" "=f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_ieee_ext1"
[(set (match_operand:DF 0 "register_operand" "=&f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_ext1"
[(set (match_operand:DF 0 "register_operand" "=f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_ieee_ext2"
[(set (match_operand:DF 0 "register_operand" "=&f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_ext2"
[(set (match_operand:DF 0 "register_operand" "=f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_ieee_ext3"
[(set (match_operand:DF 0 "register_operand" "=&f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
- "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*cmpdf_ext3"
[(set (match_operand:DF 0 "register_operand" "=f")
- (match_operator:DF 1 "alpha_comparison_operator"
+ (match_operator:DF 1 "alpha_fp_comparison_operator"
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
- "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
- "cmp%-%C1%' %R2,%R3,%0"
+ "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
+ "cmp%-%C1%/ %R2,%R3,%0"
[(set_attr "type" "fadd")
- (set_attr "trap" "yes")])
+ (set_attr "trap" "yes")
+ (set_attr "trap_suffix" "su")])
-(define_insn ""
+(define_insn "*movdfcc_internal"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (if_then_else:DF
+ (if_then_else:DF
(match_operator 3 "signed_comparison_operator"
[(match_operand:DF 4 "reg_or_fp0_operand" "fG,fG")
(match_operand:DF 2 "fp0_operand" "G,G")])
@@ -2851,9 +3769,9 @@
fcmov%D3 %R4,%R5,%0"
[(set_attr "type" "fcmov")])
-(define_insn ""
+(define_insn "*movsfcc_internal"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (if_then_else:SF
+ (if_then_else:SF
(match_operator 3 "signed_comparison_operator"
[(match_operand:DF 4 "reg_or_fp0_operand" "fG,fG")
(match_operand:DF 2 "fp0_operand" "G,G")])
@@ -2865,9 +3783,9 @@
fcmov%D3 %R4,%R5,%0"
[(set_attr "type" "fcmov")])
-(define_insn ""
+(define_insn "*movdfcc_ext1"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (if_then_else:DF
+ (if_then_else:DF
(match_operator 3 "signed_comparison_operator"
[(match_operand:DF 4 "reg_or_fp0_operand" "fG,fG")
(match_operand:DF 2 "fp0_operand" "G,G")])
@@ -2879,11 +3797,11 @@
fcmov%D3 %R4,%R5,%0"
[(set_attr "type" "fcmov")])
-(define_insn ""
+(define_insn "*movdfcc_ext2"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (if_then_else:DF
+ (if_then_else:DF
(match_operator 3 "signed_comparison_operator"
- [(float_extend:DF
+ [(float_extend:DF
(match_operand:SF 4 "reg_or_fp0_operand" "fG,fG"))
(match_operand:DF 2 "fp0_operand" "G,G")])
(match_operand:DF 1 "reg_or_fp0_operand" "fG,0")
@@ -2894,9 +3812,9 @@
fcmov%D3 %R4,%R5,%0"
[(set_attr "type" "fcmov")])
-(define_insn ""
+(define_insn "*movdfcc_ext3"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (if_then_else:SF
+ (if_then_else:SF
(match_operator 3 "signed_comparison_operator"
[(float_extend:DF
(match_operand:SF 4 "reg_or_fp0_operand" "fG,fG"))
@@ -2909,9 +3827,9 @@
fcmov%D3 %R4,%R5,%0"
[(set_attr "type" "fcmov")])
-(define_insn ""
+(define_insn "*movdfcc_ext4"
[(set (match_operand:DF 0 "register_operand" "=f,f")
- (if_then_else:DF
+ (if_then_else:DF
(match_operator 3 "signed_comparison_operator"
[(float_extend:DF
(match_operand:SF 4 "reg_or_fp0_operand" "fG,fG"))
@@ -2932,10 +3850,10 @@
(if_then_else:DF (eq (match_dup 3) (match_dup 4))
(match_dup 1) (match_dup 2)))]
"TARGET_FP"
- "
-{ operands[3] = gen_reg_rtx (DFmode);
+{
+ operands[3] = gen_reg_rtx (DFmode);
operands[4] = CONST0_RTX (DFmode);
-}")
+})
(define_expand "mindf3"
[(set (match_dup 3)
@@ -2945,10 +3863,10 @@
(if_then_else:DF (ne (match_dup 3) (match_dup 4))
(match_dup 1) (match_dup 2)))]
"TARGET_FP"
- "
-{ operands[3] = gen_reg_rtx (DFmode);
+{
+ operands[3] = gen_reg_rtx (DFmode);
operands[4] = CONST0_RTX (DFmode);
-}")
+})
(define_expand "maxsf3"
[(set (match_dup 3)
@@ -2958,10 +3876,10 @@
(if_then_else:SF (eq (match_dup 3) (match_dup 4))
(match_dup 1) (match_dup 2)))]
"TARGET_FP"
- "
-{ operands[3] = gen_reg_rtx (DFmode);
+{
+ operands[3] = gen_reg_rtx (DFmode);
operands[4] = CONST0_RTX (DFmode);
-}")
+})
(define_expand "minsf3"
[(set (match_dup 3)
@@ -2971,12 +3889,12 @@
(if_then_else:SF (ne (match_dup 3) (match_dup 4))
(match_dup 1) (match_dup 2)))]
"TARGET_FP"
- "
-{ operands[3] = gen_reg_rtx (DFmode);
+{
+ operands[3] = gen_reg_rtx (DFmode);
operands[4] = CONST0_RTX (DFmode);
-}")
+})
-(define_insn ""
+(define_insn "*fbcc_normal"
[(set (pc)
(if_then_else
(match_operator 1 "signed_comparison_operator"
@@ -2988,7 +3906,7 @@
"fb%C1 %R2,%0"
[(set_attr "type" "fbr")])
-(define_insn ""
+(define_insn "*fbcc_ext_normal"
[(set (pc)
(if_then_else
(match_operator 1 "signed_comparison_operator"
@@ -3008,25 +3926,34 @@
[(set (cc0) (compare (match_operand:DF 0 "reg_or_fp0_operand" "")
(match_operand:DF 1 "reg_or_fp0_operand" "")))]
"TARGET_FP"
- "
{
- alpha_compare_op0 = operands[0];
- alpha_compare_op1 = operands[1];
- alpha_compare_fp_p = 1;
+ alpha_compare.op0 = operands[0];
+ alpha_compare.op1 = operands[1];
+ alpha_compare.fp_p = 1;
DONE;
-}")
+})
+
+(define_expand "cmptf"
+ [(set (cc0) (compare (match_operand:TF 0 "general_operand" "")
+ (match_operand:TF 1 "general_operand" "")))]
+ "TARGET_HAS_XFLOATING_LIBS"
+{
+ alpha_compare.op0 = operands[0];
+ alpha_compare.op1 = operands[1];
+ alpha_compare.fp_p = 1;
+ DONE;
+})
(define_expand "cmpdi"
- [(set (cc0) (compare (match_operand:DI 0 "reg_or_0_operand" "")
- (match_operand:DI 1 "reg_or_8bit_operand" "")))]
+ [(set (cc0) (compare (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" "")))]
""
- "
{
- alpha_compare_op0 = operands[0];
- alpha_compare_op1 = operands[1];
- alpha_compare_fp_p = 0;
+ alpha_compare.op0 = operands[0];
+ alpha_compare.op1 = operands[1];
+ alpha_compare.fp_p = 0;
DONE;
-}")
+})
(define_expand "beq"
[(set (pc)
@@ -3108,130 +4035,93 @@
""
"{ operands[1] = alpha_emit_conditional_branch (GEU); }")
+(define_expand "bunordered"
+ [(set (pc)
+ (if_then_else (match_dup 1)
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = alpha_emit_conditional_branch (UNORDERED); }")
+
+(define_expand "bordered"
+ [(set (pc)
+ (if_then_else (match_dup 1)
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = alpha_emit_conditional_branch (ORDERED); }")
+
(define_expand "seq"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_EQ (DImode, alpha_compare_op0, alpha_compare_op1);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (EQ)) == NULL_RTX) FAIL; }")
(define_expand "sne"
[(set (match_operand:DI 0 "register_operand" "")
- (match_dup 1))
- (set (match_dup 0) (xor:DI (match_dup 0) (const_int 1)))]
+ (match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_EQ (DImode, alpha_compare_op0, alpha_compare_op1);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (NE)) == NULL_RTX) FAIL; }")
(define_expand "slt"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LT (DImode, alpha_compare_op0, alpha_compare_op1);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (LT)) == NULL_RTX) FAIL; }")
(define_expand "sle"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LE (DImode, alpha_compare_op0, alpha_compare_op1);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (LE)) == NULL_RTX) FAIL; }")
(define_expand "sgt"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LT (DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (GT)) == NULL_RTX) FAIL; }")
(define_expand "sge"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LE (DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (GE)) == NULL_RTX) FAIL; }")
(define_expand "sltu"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LTU (DImode, alpha_compare_op0, alpha_compare_op1);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (LTU)) == NULL_RTX) FAIL; }")
(define_expand "sleu"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LEU (DImode, alpha_compare_op0, alpha_compare_op1);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (LEU)) == NULL_RTX) FAIL; }")
(define_expand "sgtu"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
-
- operands[1] = gen_rtx_LTU (DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
-}")
+ "{ if ((operands[1] = alpha_emit_setcc (GTU)) == NULL_RTX) FAIL; }")
(define_expand "sgeu"
[(set (match_operand:DI 0 "register_operand" "")
(match_dup 1))]
""
- "
-{
- if (alpha_compare_fp_p)
- FAIL;
+ "{ if ((operands[1] = alpha_emit_setcc (GEU)) == NULL_RTX) FAIL; }")
- operands[1] = gen_rtx_LEU (DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
-}")
+(define_expand "sunordered"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_dup 1))]
+ ""
+ "{ if ((operands[1] = alpha_emit_setcc (UNORDERED)) == NULL_RTX) FAIL; }")
+
+(define_expand "sordered"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_dup 1))]
+ ""
+ "{ if ((operands[1] = alpha_emit_setcc (ORDERED)) == NULL_RTX) FAIL; }")
;; These are the main define_expand's used to make conditional moves.
@@ -3241,11 +4131,10 @@
(match_operand:SI 2 "reg_or_8bit_operand" "")
(match_operand:SI 3 "reg_or_8bit_operand" "")))]
""
- "
{
if ((operands[1] = alpha_emit_conditional_move (operands[1], SImode)) == 0)
FAIL;
-}")
+})
(define_expand "movdicc"
[(set (match_operand:DI 0 "register_operand" "")
@@ -3253,11 +4142,10 @@
(match_operand:DI 2 "reg_or_8bit_operand" "")
(match_operand:DI 3 "reg_or_8bit_operand" "")))]
""
- "
{
if ((operands[1] = alpha_emit_conditional_move (operands[1], DImode)) == 0)
FAIL;
-}")
+})
(define_expand "movsfcc"
[(set (match_operand:SF 0 "register_operand" "")
@@ -3265,11 +4153,10 @@
(match_operand:SF 2 "reg_or_8bit_operand" "")
(match_operand:SF 3 "reg_or_8bit_operand" "")))]
""
- "
{
if ((operands[1] = alpha_emit_conditional_move (operands[1], SFmode)) == 0)
FAIL;
-}")
+})
(define_expand "movdfcc"
[(set (match_operand:DF 0 "register_operand" "")
@@ -3277,11 +4164,10 @@
(match_operand:DF 2 "reg_or_8bit_operand" "")
(match_operand:DF 3 "reg_or_8bit_operand" "")))]
""
- "
{
if ((operands[1] = alpha_emit_conditional_move (operands[1], DFmode)) == 0)
FAIL;
-}")
+})
;; These define_split definitions are used in cases when comparisons have
;; not be stated in the correct way and we need to reverse the second
@@ -3313,8 +4199,8 @@
[(set (match_dup 6) (match_dup 7))
(set (match_dup 0)
(if_then_else:DI (match_dup 8) (match_dup 4) (match_dup 5)))]
- "
-{ enum rtx_code code = GET_CODE (operands[1]);
+{
+ enum rtx_code code = GET_CODE (operands[1]);
int unsignedp = (code == GEU || code == LEU || code == GTU || code == LTU);
/* If we are comparing for equality with a constant and that constant
@@ -3355,7 +4241,7 @@
operands[2], operands[3]);
operands[8] = gen_rtx_EQ (VOIDmode, operands[6], const0_rtx);
}
-}")
+})
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -3371,8 +4257,8 @@
[(set (match_dup 6) (match_dup 7))
(set (match_dup 0)
(if_then_else:DI (match_dup 8) (match_dup 4) (match_dup 5)))]
- "
-{ enum rtx_code code = GET_CODE (operands[1]);
+{
+ enum rtx_code code = GET_CODE (operands[1]);
int unsignedp = (code == GEU || code == LEU || code == GTU || code == LTU);
rtx tem;
@@ -3380,7 +4266,7 @@
&& ! (extended_count (operands[2], DImode, unsignedp) >= 1
&& extended_count (operands[3], DImode, unsignedp) >= 1)))
FAIL;
-
+
if (GET_CODE (operands[3]) == CONST_INT)
tem = gen_rtx_PLUS (SImode, operands[2],
GEN_INT (- INTVAL (operands[3])));
@@ -3390,7 +4276,7 @@
operands[7] = gen_rtx_SIGN_EXTEND (DImode, tem);
operands[8] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
operands[6], const0_rtx);
-}")
+})
(define_split
[(set (pc)
@@ -3404,8 +4290,8 @@
"operands[3] != const0_rtx"
[(set (match_dup 4) (match_dup 5))
(set (pc) (if_then_else (match_dup 6) (label_ref (match_dup 0)) (pc)))]
- "
-{ enum rtx_code code = GET_CODE (operands[1]);
+{
+ enum rtx_code code = GET_CODE (operands[1]);
int unsignedp = (code == GEU || code == LEU || code == GTU || code == LTU);
if (code == NE || code == EQ
@@ -3433,7 +4319,7 @@
operands[2], operands[3]);
operands[6] = gen_rtx_EQ (VOIDmode, operands[4], const0_rtx);
}
-}")
+})
(define_split
[(set (pc)
@@ -3448,26 +4334,26 @@
&& (GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)"
[(set (match_dup 4) (match_dup 5))
(set (pc) (if_then_else (match_dup 6) (label_ref (match_dup 0)) (pc)))]
- "
-{ rtx tem;
+{
+ rtx tem;
if (GET_CODE (operands[3]) == CONST_INT)
tem = gen_rtx_PLUS (SImode, operands[2],
GEN_INT (- INTVAL (operands[3])));
else
tem = gen_rtx_MINUS (SImode, operands[2], operands[3]);
-
+
operands[5] = gen_rtx_SIGN_EXTEND (DImode, tem);
operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
operands[4], const0_rtx);
-}")
+})
;; We can convert such things as "a > 0xffff" to "t = a & ~ 0xffff; t != 0".
;; This eliminates one, and sometimes two, insns when the AND can be done
;; with a ZAP.
(define_split
[(set (match_operand:DI 0 "register_operand" "")
- (match_operator 1 "comparison_operator"
+ (match_operator:DI 1 "comparison_operator"
[(match_operand:DI 2 "register_operand" "")
(match_operand:DI 3 "const_int_operand" "")]))
(clobber (match_operand:DI 4 "register_operand" ""))]
@@ -3478,69 +4364,299 @@
&& extended_count (operands[2], DImode, 1) > 0))"
[(set (match_dup 4) (and:DI (match_dup 2) (match_dup 5)))
(set (match_dup 0) (match_dup 6))]
- "
{
operands[5] = GEN_INT (~ INTVAL (operands[3]));
operands[6] = gen_rtx_fmt_ee (((GET_CODE (operands[1]) == GTU
|| GET_CODE (operands[1]) == GT)
? NE : EQ),
DImode, operands[4], const0_rtx);
-}")
+})
+
+;; Prefer to use cmp and arithmetic when possible instead of a cmove.
+
+(define_split
+ [(set (match_operand 0 "register_operand" "")
+ (if_then_else (match_operator 1 "signed_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "")
+ (const_int 0)])
+ (match_operand 3 "const_int_operand" "")
+ (match_operand 4 "const_int_operand" "")))]
+ ""
+ [(const_int 0)]
+{
+ if (alpha_split_conditional_move (GET_CODE (operands[1]), operands[0],
+ operands[2], operands[3], operands[4]))
+ DONE;
+ else
+ FAIL;
+})
+
+;; ??? Why combine is allowed to create such non-canonical rtl, I don't know.
+;; Oh well, we match it in movcc, so it must be partially our fault.
+(define_split
+ [(set (match_operand 0 "register_operand" "")
+ (if_then_else (match_operator 1 "signed_comparison_operator"
+ [(const_int 0)
+ (match_operand:DI 2 "reg_or_0_operand" "")])
+ (match_operand 3 "const_int_operand" "")
+ (match_operand 4 "const_int_operand" "")))]
+ ""
+ [(const_int 0)]
+{
+ if (alpha_split_conditional_move (swap_condition (GET_CODE (operands[1])),
+ operands[0], operands[2], operands[3],
+ operands[4]))
+ DONE;
+ else
+ FAIL;
+})
+
+(define_insn_and_split "*cmp_sadd_di"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (if_then_else:DI
+ (match_operator 1 "alpha_zero_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+ (const_int 0)])
+ (match_operand:DI 3 "const48_operand" "I")
+ (const_int 0))
+ (match_operand:DI 4 "sext_add_operand" "rIO")))
+ (clobber (match_scratch:DI 5 "=r"))]
+ ""
+ "#"
+ "! no_new_pseudos || reload_completed"
+ [(set (match_dup 5)
+ (match_op_dup:DI 1 [(match_dup 2) (const_int 0)]))
+ (set (match_dup 0)
+ (plus:DI (mult:DI (match_dup 5) (match_dup 3))
+ (match_dup 4)))]
+{
+ if (! no_new_pseudos)
+ operands[5] = gen_reg_rtx (DImode);
+ else if (reg_overlap_mentioned_p (operands[5], operands[4]))
+ operands[5] = operands[0];
+})
+
+(define_insn_and_split "*cmp_sadd_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (if_then_else:SI
+ (match_operator 1 "alpha_zero_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+ (const_int 0)])
+ (match_operand:SI 3 "const48_operand" "I")
+ (const_int 0))
+ (match_operand:SI 4 "sext_add_operand" "rIO")))
+ (clobber (match_scratch:SI 5 "=r"))]
+ ""
+ "#"
+ "! no_new_pseudos || reload_completed"
+ [(set (match_dup 5)
+ (match_op_dup:SI 1 [(match_dup 2) (const_int 0)]))
+ (set (match_dup 0)
+ (plus:SI (mult:SI (match_dup 5) (match_dup 3))
+ (match_dup 4)))]
+{
+ if (! no_new_pseudos)
+ operands[5] = gen_reg_rtx (DImode);
+ else if (reg_overlap_mentioned_p (operands[5], operands[4]))
+ operands[5] = operands[0];
+})
+
+(define_insn_and_split "*cmp_sadd_sidi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI
+ (plus:SI (if_then_else:SI
+ (match_operator 1 "alpha_zero_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+ (const_int 0)])
+ (match_operand:SI 3 "const48_operand" "I")
+ (const_int 0))
+ (match_operand:SI 4 "sext_add_operand" "rIO"))))
+ (clobber (match_scratch:SI 5 "=r"))]
+ ""
+ "#"
+ "! no_new_pseudos || reload_completed"
+ [(set (match_dup 5)
+ (match_op_dup:SI 1 [(match_dup 2) (const_int 0)]))
+ (set (match_dup 0)
+ (sign_extend:DI (plus:SI (mult:SI (match_dup 5) (match_dup 3))
+ (match_dup 4))))]
+{
+ if (! no_new_pseudos)
+ operands[5] = gen_reg_rtx (DImode);
+ else if (reg_overlap_mentioned_p (operands[5], operands[4]))
+ operands[5] = operands[0];
+})
+
+(define_insn_and_split "*cmp_ssub_di"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (if_then_else:DI
+ (match_operator 1 "alpha_zero_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+ (const_int 0)])
+ (match_operand:DI 3 "const48_operand" "I")
+ (const_int 0))
+ (match_operand:DI 4 "reg_or_8bit_operand" "rI")))
+ (clobber (match_scratch:DI 5 "=r"))]
+ ""
+ "#"
+ "! no_new_pseudos || reload_completed"
+ [(set (match_dup 5)
+ (match_op_dup:DI 1 [(match_dup 2) (const_int 0)]))
+ (set (match_dup 0)
+ (minus:DI (mult:DI (match_dup 5) (match_dup 3))
+ (match_dup 4)))]
+{
+ if (! no_new_pseudos)
+ operands[5] = gen_reg_rtx (DImode);
+ else if (reg_overlap_mentioned_p (operands[5], operands[4]))
+ operands[5] = operands[0];
+})
+
+(define_insn_and_split "*cmp_ssub_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (if_then_else:SI
+ (match_operator 1 "alpha_zero_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+ (const_int 0)])
+ (match_operand:SI 3 "const48_operand" "I")
+ (const_int 0))
+ (match_operand:SI 4 "reg_or_8bit_operand" "rI")))
+ (clobber (match_scratch:SI 5 "=r"))]
+ ""
+ "#"
+ "! no_new_pseudos || reload_completed"
+ [(set (match_dup 5)
+ (match_op_dup:SI 1 [(match_dup 2) (const_int 0)]))
+ (set (match_dup 0)
+ (minus:SI (mult:SI (match_dup 5) (match_dup 3))
+ (match_dup 4)))]
+{
+ if (! no_new_pseudos)
+ operands[5] = gen_reg_rtx (DImode);
+ else if (reg_overlap_mentioned_p (operands[5], operands[4]))
+ operands[5] = operands[0];
+})
+
+(define_insn_and_split "*cmp_ssub_sidi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI
+ (minus:SI (if_then_else:SI
+ (match_operator 1 "alpha_zero_comparison_operator"
+ [(match_operand:DI 2 "reg_or_0_operand" "rJ")
+ (const_int 0)])
+ (match_operand:SI 3 "const48_operand" "I")
+ (const_int 0))
+ (match_operand:SI 4 "reg_or_8bit_operand" "rI"))))
+ (clobber (match_scratch:SI 5 "=r"))]
+ ""
+ "#"
+ "! no_new_pseudos || reload_completed"
+ [(set (match_dup 5)
+ (match_op_dup:SI 1 [(match_dup 2) (const_int 0)]))
+ (set (match_dup 0)
+ (sign_extend:DI (minus:SI (mult:SI (match_dup 5) (match_dup 3))
+ (match_dup 4))))]
+{
+ if (! no_new_pseudos)
+ operands[5] = gen_reg_rtx (DImode);
+ else if (reg_overlap_mentioned_p (operands[5], operands[4]))
+ operands[5] = operands[0];
+})
;; Here are the CALL and unconditional branch insns. Calls on NT and OSF
;; work differently, so we have different patterns for each.
+;; On Unicos/Mk a call information word (CIW) must be generated for each
+;; call. The CIW contains information about arguments passed in registers
+;; and is stored in the caller's SSIB. Its offset relative to the beginning
+;; of the SSIB is passed in $25. Handling this properly is quite complicated
+;; in the presence of inlining since the CIWs for calls performed by the
+;; inlined function must be stored in the SSIB of the function it is inlined
+;; into as well. We encode the CIW in an unspec and append it to the list
+;; of the CIWs for the current function only when the instruction for loading
+;; $25 is generated.
+
(define_expand "call"
[(use (match_operand:DI 0 "" ""))
(use (match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(use (match_operand 3 "" ""))]
""
- "
-{ if (TARGET_WINDOWS_NT)
+{
+ if (TARGET_ABI_WINDOWS_NT)
emit_call_insn (gen_call_nt (operands[0], operands[1]));
- else if (TARGET_OPEN_VMS)
+ else if (TARGET_ABI_OPEN_VMS)
emit_call_insn (gen_call_vms (operands[0], operands[2]));
+ else if (TARGET_ABI_UNICOSMK)
+ emit_call_insn (gen_call_umk (operands[0], operands[2]));
else
emit_call_insn (gen_call_osf (operands[0], operands[1]));
-
DONE;
-}")
+})
+
+(define_expand "sibcall"
+ [(parallel [(call (mem:DI (match_operand 0 "" ""))
+ (match_operand 1 "" ""))
+ (unspec [(reg:DI 29)] UNSPEC_SIBCALL)])]
+ "TARGET_ABI_OSF"
+{
+ if (GET_CODE (operands[0]) != MEM)
+ abort ();
+ operands[0] = XEXP (operands[0], 0);
+})
(define_expand "call_osf"
[(parallel [(call (mem:DI (match_operand 0 "" ""))
(match_operand 1 "" ""))
- (clobber (reg:DI 27))
+ (use (reg:DI 29))
(clobber (reg:DI 26))])]
""
- "
-{ if (GET_CODE (operands[0]) != MEM)
+{
+ if (GET_CODE (operands[0]) != MEM)
abort ();
operands[0] = XEXP (operands[0], 0);
-
- if (GET_CODE (operands[0]) != SYMBOL_REF
- && ! (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 27))
- {
- rtx tem = gen_rtx_REG (DImode, 27);
- emit_move_insn (tem, operands[0]);
- operands[0] = tem;
- }
-}")
+ if (! call_operand (operands[0], Pmode))
+ operands[0] = copy_to_mode_reg (Pmode, operands[0]);
+})
(define_expand "call_nt"
[(parallel [(call (mem:DI (match_operand 0 "" ""))
(match_operand 1 "" ""))
(clobber (reg:DI 26))])]
""
- "
-{ if (GET_CODE (operands[0]) != MEM)
+{
+ if (GET_CODE (operands[0]) != MEM)
abort ();
operands[0] = XEXP (operands[0], 0);
if (GET_CODE (operands[0]) != SYMBOL_REF && GET_CODE (operands[0]) != REG)
operands[0] = force_reg (DImode, operands[0]);
-}")
+})
+
+;; Calls on Unicos/Mk are always indirect.
+;; op 0: symbol ref for called function
+;; op 1: CIW for $25 represented by an unspec
+
+(define_expand "call_umk"
+ [(parallel [(call (mem:DI (match_operand 0 "" ""))
+ (match_operand 1 "" ""))
+ (use (reg:DI 25))
+ (clobber (reg:DI 26))])]
+ ""
+{
+ if (GET_CODE (operands[0]) != MEM)
+ abort ();
+
+ /* Always load the address of the called function into a register;
+ load the CIW in $25. */
+
+ operands[0] = XEXP (operands[0], 0);
+ if (GET_CODE (operands[0]) != REG)
+ operands[0] = force_reg (DImode, operands[0]);
+
+ emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]);
+})
;;
;; call openvms/alpha
@@ -3555,8 +4671,8 @@
(use (reg:DI 26))
(clobber (reg:DI 27))])]
""
- "
-{ if (GET_CODE (operands[0]) != MEM)
+{
+ if (GET_CODE (operands[0]) != MEM)
abort ();
operands[0] = XEXP (operands[0], 0);
@@ -3568,23 +4684,9 @@
emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]);
if (GET_CODE (operands[0]) == SYMBOL_REF)
{
- extern char *savealloc ();
- char *linksym, *symbol = XSTR (operands[0], 0);
- rtx linkage;
-
- if (*symbol == '*')
- symbol++;
- linksym = savealloc (strlen (symbol) + 6);
-
- alpha_need_linkage (symbol, 0);
-
- linksym[0] = '$';
- strcpy (linksym+1, symbol);
- strcat (linksym, \"..lk\");
- linkage = gen_rtx_SYMBOL_REF (Pmode, linksym);
+ rtx linkage = alpha_need_linkage (XSTR (operands[0], 0), 0);
emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage));
-
operands[2]
= validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8)));
}
@@ -3592,11 +4694,10 @@
{
emit_move_insn (gen_rtx_REG (Pmode, 26),
gen_rtx_MEM (Pmode, plus_constant (operands[0], 8)));
-
operands[2] = operands[0];
}
-}")
+})
(define_expand "call_value"
[(use (match_operand 0 "" ""))
@@ -3605,39 +4706,48 @@
(use (match_operand 3 "" ""))
(use (match_operand 4 "" ""))]
""
- "
-{ if (TARGET_WINDOWS_NT)
+{
+ if (TARGET_ABI_WINDOWS_NT)
emit_call_insn (gen_call_value_nt (operands[0], operands[1], operands[2]));
- else if (TARGET_OPEN_VMS)
+ else if (TARGET_ABI_OPEN_VMS)
emit_call_insn (gen_call_value_vms (operands[0], operands[1],
operands[3]));
+ else if (TARGET_ABI_UNICOSMK)
+ emit_call_insn (gen_call_value_umk (operands[0], operands[1],
+ operands[3]));
else
emit_call_insn (gen_call_value_osf (operands[0], operands[1],
operands[2]));
DONE;
-}")
+})
+
+(define_expand "sibcall_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand 1 "" ""))
+ (match_operand 2 "" "")))
+ (unspec [(reg:DI 29)] UNSPEC_SIBCALL)])]
+ "TARGET_ABI_OSF"
+{
+ if (GET_CODE (operands[1]) != MEM)
+ abort ();
+ operands[1] = XEXP (operands[1], 0);
+})
(define_expand "call_value_osf"
[(parallel [(set (match_operand 0 "" "")
(call (mem:DI (match_operand 1 "" ""))
(match_operand 2 "" "")))
- (clobber (reg:DI 27))
+ (use (reg:DI 29))
(clobber (reg:DI 26))])]
""
- "
-{ if (GET_CODE (operands[1]) != MEM)
+{
+ if (GET_CODE (operands[1]) != MEM)
abort ();
operands[1] = XEXP (operands[1], 0);
-
- if (GET_CODE (operands[1]) != SYMBOL_REF
- && ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27))
- {
- rtx tem = gen_rtx_REG (DImode, 27);
- emit_move_insn (tem, operands[1]);
- operands[1] = tem;
- }
-}")
+ if (! call_operand (operands[1], Pmode))
+ operands[1] = copy_to_mode_reg (Pmode, operands[1]);
+})
(define_expand "call_value_nt"
[(parallel [(set (match_operand 0 "" "")
@@ -3645,14 +4755,14 @@
(match_operand 2 "" "")))
(clobber (reg:DI 26))])]
""
- "
-{ if (GET_CODE (operands[1]) != MEM)
+{
+ if (GET_CODE (operands[1]) != MEM)
abort ();
operands[1] = XEXP (operands[1], 0);
if (GET_CODE (operands[1]) != SYMBOL_REF && GET_CODE (operands[1]) != REG)
operands[1] = force_reg (DImode, operands[1]);
-}")
+})
(define_expand "call_value_vms"
[(parallel [(set (match_operand 0 "" "")
@@ -3663,8 +4773,8 @@
(use (reg:DI 26))
(clobber (reg:DI 27))])]
""
- "
-{ if (GET_CODE (operands[1]) != MEM)
+{
+ if (GET_CODE (operands[1]) != MEM)
abort ();
operands[1] = XEXP (operands[1], 0);
@@ -3676,22 +4786,9 @@
emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]);
if (GET_CODE (operands[1]) == SYMBOL_REF)
{
- extern char *savealloc ();
- char *linksym, *symbol = XSTR (operands[1], 0);
- rtx linkage;
-
- if (*symbol == '*')
- symbol++;
- linksym = savealloc (strlen (symbol) + 6);
-
- alpha_need_linkage (symbol, 0);
- linksym[0] = '$';
- strcpy (linksym+1, symbol);
- strcat (linksym, \"..lk\");
- linkage = gen_rtx_SYMBOL_REF (Pmode, linksym);
+ rtx linkage = alpha_need_linkage (XSTR (operands[1], 0), 0);
emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage));
-
operands[3]
= validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8)));
}
@@ -3699,92 +4796,208 @@
{
emit_move_insn (gen_rtx_REG (Pmode, 26),
gen_rtx_MEM (Pmode, plus_constant (operands[1], 8)));
-
operands[3] = operands[1];
}
-}")
+})
+
+(define_expand "call_value_umk"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand 1 "" ""))
+ (match_operand 2 "" "")))
+ (use (reg:DI 25))
+ (clobber (reg:DI 26))])]
+ ""
+{
+ if (GET_CODE (operands[1]) != MEM)
+ abort ();
+
+ operands[1] = XEXP (operands[1], 0);
+ if (GET_CODE (operands[1]) != REG)
+ operands[1] = force_reg (DImode, operands[1]);
-(define_insn ""
- [(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,i"))
+ emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]);
+})
+
+(define_insn "*call_osf_1_er"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s"))
(match_operand 1 "" ""))
- (clobber (reg:DI 27))
+ (use (reg:DI 29))
(clobber (reg:DI 26))]
- "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS"
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
"@
- jsr $26,($27),0\;ldgp $29,0($26)
+ jsr $26,(%0),0\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*
bsr $26,$%0..ng
- jsr $26,%0\;ldgp $29,0($26)"
+ ldq $27,%0($29)\t\t!literal!%#\;jsr $26,($27),%0\t\t!lituse_jsr!%#\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"
[(set_attr "type" "jsr")
(set_attr "length" "12,*,16")])
-
-(define_insn ""
- [(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,i"))
+
+;; We must use peep2 instead of a split because we need accurate life
+;; information for $gp. Consider the case of { bar(); while (1); }.
+(define_peephole2
+ [(parallel [(call (mem:DI (match_operand:DI 0 "call_operand" ""))
+ (match_operand 1 "" ""))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))])]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed
+ && ! current_file_function_operand (operands[0], Pmode)
+ && peep2_regno_dead_p (1, 29)"
+ [(parallel [(call (mem:DI (match_dup 2))
+ (match_dup 1))
+ (set (reg:DI 26) (plus:DI (pc) (const_int 4)))
+ (unspec_volatile [(reg:DI 29)] UNSPECV_BLOCKAGE)
+ (use (match_dup 0))
+ (use (match_dup 3))])]
+{
+ if (CONSTANT_P (operands[0]))
+ {
+ operands[2] = gen_rtx_REG (Pmode, 27);
+ operands[3] = GEN_INT (alpha_next_sequence_number++);
+ emit_insn (gen_movdi_er_high_g (operands[2], pic_offset_table_rtx,
+ operands[0], operands[3]));
+ }
+ else
+ {
+ operands[2] = operands[0];
+ operands[0] = const0_rtx;
+ operands[3] = const0_rtx;
+ }
+})
+
+(define_peephole2
+ [(parallel [(call (mem:DI (match_operand:DI 0 "call_operand" ""))
+ (match_operand 1 "" ""))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))])]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed
+ && ! current_file_function_operand (operands[0], Pmode)
+ && ! peep2_regno_dead_p (1, 29)"
+ [(parallel [(call (mem:DI (match_dup 2))
+ (match_dup 1))
+ (set (reg:DI 26) (plus:DI (pc) (const_int 4)))
+ (unspec_volatile [(reg:DI 29)] UNSPECV_BLOCKAGE)
+ (use (match_dup 0))
+ (use (match_dup 4))])
+ (set (reg:DI 29)
+ (unspec_volatile:DI [(reg:DI 26) (match_dup 3)] UNSPECV_LDGP1))
+ (set (reg:DI 29)
+ (unspec:DI [(reg:DI 29) (match_dup 3)] UNSPEC_LDGP2))]
+{
+ if (CONSTANT_P (operands[0]))
+ {
+ operands[2] = gen_rtx_REG (Pmode, 27);
+ operands[4] = GEN_INT (alpha_next_sequence_number++);
+ emit_insn (gen_movdi_er_high_g (operands[2], pic_offset_table_rtx,
+ operands[0], operands[4]));
+ }
+ else
+ {
+ operands[2] = operands[0];
+ operands[0] = const0_rtx;
+ operands[4] = const0_rtx;
+ }
+ operands[3] = GEN_INT (alpha_next_sequence_number++);
+})
+
+;; We add a blockage unspec_volatile to prevent insns from moving down
+;; from above the call to in between the call and the ldah gpdisp.
+
+(define_insn "*call_osf_2_er"
+ [(call (mem:DI (match_operand:DI 0 "register_operand" "c"))
+ (match_operand 1 "" ""))
+ (set (reg:DI 26) (plus:DI (pc) (const_int 4)))
+ (unspec_volatile [(reg:DI 29)] UNSPECV_BLOCKAGE)
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "const_int_operand" ""))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "jsr $26,(%0),%2%J3"
+ [(set_attr "type" "jsr")])
+
+(define_insn "*call_osf_1_noreturn"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s"))
(match_operand 1 "" ""))
+ (use (reg:DI 29))
(clobber (reg:DI 26))]
- "TARGET_WINDOWS_NT"
+ "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
"@
- jsr $26,(%0)
- bsr $26,%0
+ jsr $26,($27),0
+ bsr $26,$%0..ng
jsr $26,%0"
[(set_attr "type" "jsr")
- (set_attr "length" "*,*,12")])
-
-(define_insn ""
- [(call (mem:DI (match_operand:DI 0 "call_operand" "r,i"))
- (match_operand 1 "" ""))
- (use (match_operand:DI 2 "general_operand" "r,m"))
- (use (reg:DI 25))
- (use (reg:DI 26))
- (clobber (reg:DI 27))]
- "TARGET_OPEN_VMS"
- "@
- mov %2,$27\;jsr $26,0\;ldq $27,0($29)
- ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)"
- [(set_attr "type" "jsr")
- (set_attr "length" "12,16")])
+ (set_attr "length" "*,*,8")])
-(define_insn ""
- [(set (match_operand 0 "register_operand" "=rf,rf,rf")
- (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,i"))
- (match_operand 2 "" "")))
- (clobber (reg:DI 27))
+(define_insn "*call_osf_1"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s"))
+ (match_operand 1 "" ""))
+ (use (reg:DI 29))
(clobber (reg:DI 26))]
- "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS"
+ "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
"@
jsr $26,($27),0\;ldgp $29,0($26)
- bsr $26,$%1..ng
- jsr $26,%1\;ldgp $29,0($26)"
+ bsr $26,$%0..ng
+ jsr $26,%0\;ldgp $29,0($26)"
[(set_attr "type" "jsr")
(set_attr "length" "12,*,16")])
-(define_insn ""
- [(set (match_operand 0 "register_operand" "=rf,rf,rf")
- (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,i"))
- (match_operand 2 "" "")))
+;; Note that the DEC assembler expands "jmp foo" with $at, which
+;; doesn't do what we want.
+(define_insn "*sibcall_osf_1_er"
+ [(call (mem:DI (match_operand:DI 0 "symbolic_operand" "R,s"))
+ (match_operand 1 "" ""))
+ (unspec [(reg:DI 29)] UNSPEC_SIBCALL)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ br $31,$%0..ng
+ ldq $27,%0($29)\t\t!literal!%#\;jmp $31,($27),%0\t\t!lituse_jsr!%#"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,8")])
+
+(define_insn "*sibcall_osf_1"
+ [(call (mem:DI (match_operand:DI 0 "symbolic_operand" "R,s"))
+ (match_operand 1 "" ""))
+ (unspec [(reg:DI 29)] UNSPEC_SIBCALL)]
+ "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ br $31,$%0..ng
+ lda $27,%0\;jmp $31,($27),%0"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,8")])
+
+(define_insn "*call_nt_1"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,s"))
+ (match_operand 1 "" ""))
(clobber (reg:DI 26))]
- "TARGET_WINDOWS_NT"
+ "TARGET_ABI_WINDOWS_NT"
"@
- jsr $26,(%1)
- bsr $26,%1
- jsr $26,%1"
+ jsr $26,(%0)
+ bsr $26,%0
+ jsr $26,%0"
[(set_attr "type" "jsr")
(set_attr "length" "*,*,12")])
-(define_insn ""
- [(set (match_operand 0 "register_operand" "")
- (call (mem:DI (match_operand:DI 1 "call_operand" "r,i"))
- (match_operand 2 "" "")))
- (use (match_operand:DI 3 "general_operand" "r,m"))
+(define_insn "*call_vms_1"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "r,s"))
+ (match_operand 1 "" ""))
+ (use (match_operand:DI 2 "nonimmediate_operand" "r,m"))
(use (reg:DI 25))
(use (reg:DI 26))
(clobber (reg:DI 27))]
- "TARGET_OPEN_VMS"
+ "TARGET_ABI_OPEN_VMS"
"@
- mov %3,$27\;jsr $26,0\;ldq $27,0($29)
- ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)"
+ mov %2,$27\;jsr $26,0\;ldq $27,0($29)
+ ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)"
[(set_attr "type" "jsr")
(set_attr "length" "12,16")])
+(define_insn "*call_umk_1"
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "r"))
+ (match_operand 1 "" ""))
+ (use (reg:DI 25))
+ (clobber (reg:DI 26))]
+ "TARGET_ABI_UNICOSMK"
+ "jsr $26,(%0)"
+ [(set_attr "type" "jsr")])
+
;; Call subroutine returning any type.
(define_expand "untyped_call"
@@ -3793,11 +5006,10 @@
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
- "
{
int i;
- emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
@@ -3812,13 +5024,13 @@
emit_insn (gen_blockage ());
DONE;
-}")
+})
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
(define_insn "blockage"
- [(unspec_volatile [(const_int 0)] 1)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
""
""
[(set_attr "length" "0")])
@@ -3830,18 +5042,14 @@
"br $31,%l0"
[(set_attr "type" "ibr")])
-(define_insn "return"
+(define_expand "return"
[(return)]
"direct_return ()"
- "ret $31,($26),1"
- [(set_attr "type" "ibr")])
+ "")
-;; Use a different pattern for functions which have non-trivial
-;; epilogues so as not to confuse jump and reorg.
-(define_insn "return_internal"
- [(use (reg:DI 26))
- (return)]
- ""
+(define_insn "*return_internal"
+ [(return)]
+ "reload_completed"
"ret $31,($26),1"
[(set_attr "type" "ibr")])
@@ -3852,155 +5060,43 @@
[(set_attr "type" "ibr")])
(define_expand "tablejump"
- [(use (match_operand:SI 0 "register_operand" ""))
- (use (match_operand:SI 1 "" ""))]
+ [(parallel [(set (pc)
+ (match_operand 0 "register_operand" ""))
+ (use (label_ref:DI (match_operand 1 "" "")))])]
""
- "
{
- if (TARGET_WINDOWS_NT)
- emit_jump_insn (gen_tablejump_nt (operands[0], operands[1]));
- else if (TARGET_OPEN_VMS)
- emit_jump_insn (gen_tablejump_vms (operands[0], operands[1]));
- else
- emit_jump_insn (gen_tablejump_osf (operands[0], operands[1]));
-
- DONE;
-}")
-
-(define_expand "tablejump_osf"
- [(set (match_dup 3)
- (sign_extend:DI (match_operand:SI 0 "register_operand" "")))
- (parallel [(set (pc)
- (plus:DI (match_dup 3)
- (label_ref:DI (match_operand 1 "" ""))))
- (clobber (match_scratch:DI 2 "=r"))])]
- ""
- "
-{ operands[3] = gen_reg_rtx (DImode); }")
-
-(define_expand "tablejump_nt"
- [(set (match_dup 3)
- (sign_extend:DI (match_operand:SI 0 "register_operand" "")))
- (parallel [(set (pc)
- (match_dup 3))
- (use (label_ref (match_operand 1 "" "")))])]
- ""
- "
-{ operands[3] = gen_reg_rtx (DImode); }")
-
-;;
-;; tablejump, openVMS way
-;; op 0: offset
-;; op 1: label preceding jump-table
-;;
-(define_expand "tablejump_vms"
- [(set (match_dup 2)
- (match_operand:DI 0 "register_operand" ""))
- (set (pc)
- (plus:DI (match_dup 2)
- (label_ref:DI (match_operand 1 "" ""))))]
- ""
- "
-{ operands[2] = gen_reg_rtx (DImode); }")
-
-(define_insn ""
- [(set (pc)
- (plus:DI (match_operand:DI 0 "register_operand" "r")
- (label_ref:DI (match_operand 1 "" ""))))
- (clobber (match_scratch:DI 2 "=r"))]
- "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && next_active_insn (insn) != 0
- && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
- && PREV_INSN (next_active_insn (insn)) == operands[1]"
- "*
-{ rtx best_label = 0;
- rtx jump_table_insn = next_active_insn (operands[1]);
-
- if (GET_CODE (jump_table_insn) == JUMP_INSN
- && GET_CODE (PATTERN (jump_table_insn)) == ADDR_DIFF_VEC)
+ if (TARGET_ABI_WINDOWS_NT)
{
- rtx jump_table = PATTERN (jump_table_insn);
- int n_labels = XVECLEN (jump_table, 1);
- int best_count = -1;
- int i, j;
-
- for (i = 0; i < n_labels; i++)
- {
- int count = 1;
-
- for (j = i + 1; j < n_labels; j++)
- if (XEXP (XVECEXP (jump_table, 1, i), 0)
- == XEXP (XVECEXP (jump_table, 1, j), 0))
- count++;
-
- if (count > best_count)
- best_count = count, best_label = XVECEXP (jump_table, 1, i);
- }
+ rtx dest = gen_reg_rtx (DImode);
+ emit_insn (gen_extendsidi2 (dest, operands[0]));
+ operands[0] = dest;
}
-
- if (best_label)
+ else if (TARGET_ABI_OSF)
{
- operands[3] = best_label;
- return \"addq %0,$29,%2\;jmp $31,(%2),%3\";
+ rtx dest = gen_reg_rtx (DImode);
+ emit_insn (gen_extendsidi2 (dest, operands[0]));
+ emit_insn (gen_adddi3 (dest, pic_offset_table_rtx, dest));
+ operands[0] = dest;
}
- else
- return \"addq %0,$29,%2\;jmp $31,(%2),0\";
-}"
- [(set_attr "type" "ibr")
- (set_attr "length" "8")])
+})
-(define_insn ""
+(define_insn "*tablejump_osf_nt_internal"
[(set (pc)
(match_operand:DI 0 "register_operand" "r"))
- (use (label_ref (match_operand 1 "" "")))]
- "TARGET_WINDOWS_NT && next_active_insn (insn) != 0
- && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
- && PREV_INSN (next_active_insn (insn)) == operands[1]"
- "*
-{ rtx best_label = 0;
- rtx jump_table_insn = next_active_insn (operands[1]);
-
- if (GET_CODE (jump_table_insn) == JUMP_INSN
- && GET_CODE (PATTERN (jump_table_insn)) == ADDR_DIFF_VEC)
- {
- rtx jump_table = PATTERN (jump_table_insn);
- int n_labels = XVECLEN (jump_table, 1);
- int best_count = -1;
- int i, j;
-
- for (i = 0; i < n_labels; i++)
- {
- int count = 1;
-
- for (j = i + 1; j < n_labels; j++)
- if (XEXP (XVECEXP (jump_table, 1, i), 0)
- == XEXP (XVECEXP (jump_table, 1, j), 0))
- count++;
-
- if (count > best_count)
- best_count = count, best_label = XVECEXP (jump_table, 1, i);
- }
- }
-
- if (best_label)
- {
- operands[2] = best_label;
- return \"jmp $31,(%0),%2\";
- }
- else
- return \"jmp $31,(%0),0\";
-}"
+ (use (label_ref:DI (match_operand 1 "" "")))]
+ "(TARGET_ABI_OSF || TARGET_ABI_WINDOWS_NT)
+ && alpha_tablejump_addr_vec (insn)"
+{
+ operands[2] = alpha_tablejump_best_label (insn);
+ return "jmp $31,(%0),%2";
+}
[(set_attr "type" "ibr")])
-;;
-;; op 0 is table offset
-;; op 1 is table label
-;;
-
-(define_insn ""
+(define_insn "*tablejump_internal"
[(set (pc)
- (plus:DI (match_operand 0 "register_operand" "r")
- (label_ref (match_operand 1 "" ""))))]
- "TARGET_OPEN_VMS"
+ (match_operand:DI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
"jmp $31,(%0),0"
[(set_attr "type" "ibr")])
@@ -4011,7 +5107,7 @@
;; if we need a GP. Use ibr instead since it has the same EV5 scheduling
;; characteristics.
(define_insn "imb"
- [(unspec_volatile [(const_int 0)] 0)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_IMB)]
""
"call_pal 0x86"
[(set_attr "type" "ibr")])
@@ -4020,31 +5116,31 @@
;; are done via define_expand. Start with the floating-point insns, since
;; they are simpler.
-(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,r,r,m,m")
- (match_operand:SF 1 "input_operand" "fG,m,rG,m,fG,r"))]
- "! TARGET_FIX
+(define_insn "*movsf_nofix"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m")
+ (match_operand:SF 1 "input_operand" "fG,m,*rG,m,fG,*r"))]
+ "TARGET_FPREGS && ! TARGET_FIX
&& (register_operand (operands[0], SFmode)
|| reg_or_fp0_operand (operands[1], SFmode))"
"@
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%, %0,%1
- mov %r1,%0
+ bis $31,%r1,%0
ldl %0,%1
st%, %R1,%0
stl %r1,%0"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist")])
-(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,r,r,m,m,f,*r")
- (match_operand:SF 1 "input_operand" "fG,m,rG,m,fG,r,r,*f"))]
- "TARGET_FIX
+(define_insn "*movsf_fix"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m,f,*r")
+ (match_operand:SF 1 "input_operand" "fG,m,*rG,m,fG,*r,*r,f"))]
+ "TARGET_FPREGS && TARGET_FIX
&& (register_operand (operands[0], SFmode)
|| reg_or_fp0_operand (operands[1], SFmode))"
"@
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%, %0,%1
- mov %r1,%0
+ bis $31,%r1,%0
ldl %0,%1
st%, %R1,%0
stl %r1,%0
@@ -4052,31 +5148,43 @@
ftois %1,%0"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist,itof,ftoi")])
-(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,r,r,m,m")
- (match_operand:DF 1 "input_operand" "fG,m,rG,m,fG,r"))]
- "! TARGET_FIX
+(define_insn "*movsf_nofp"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:SF 1 "input_operand" "rG,m,r"))]
+ "! TARGET_FPREGS
+ && (register_operand (operands[0], SFmode)
+ || reg_or_fp0_operand (operands[1], SFmode))"
+ "@
+ bis $31,%r1,%0
+ ldl %0,%1
+ stl %r1,%0"
+ [(set_attr "type" "ilog,ild,ist")])
+
+(define_insn "*movdf_nofix"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m")
+ (match_operand:DF 1 "input_operand" "fG,m,*rG,m,fG,*r"))]
+ "TARGET_FPREGS && ! TARGET_FIX
&& (register_operand (operands[0], DFmode)
|| reg_or_fp0_operand (operands[1], DFmode))"
"@
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%- %0,%1
- mov %r1,%0
+ bis $31,%r1,%0
ldq %0,%1
st%- %R1,%0
stq %r1,%0"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist")])
-(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,r,r,m,m,f,*r")
- (match_operand:DF 1 "input_operand" "fG,m,rG,m,fG,r,r,*f"))]
- "TARGET_FIX
+(define_insn "*movdf_fix"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m,f,*r")
+ (match_operand:DF 1 "input_operand" "fG,m,*rG,m,fG,*r,*r,f"))]
+ "TARGET_FPREGS && TARGET_FIX
&& (register_operand (operands[0], DFmode)
|| reg_or_fp0_operand (operands[1], DFmode))"
"@
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%- %0,%1
- mov %r1,%0
+ bis $31,%r1,%0
ldq %0,%1
st%- %R1,%0
stq %r1,%0
@@ -4084,157 +5192,183 @@
ftoit %1,%0"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist,itof,ftoi")])
+(define_insn "*movdf_nofp"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:DF 1 "input_operand" "rG,m,r"))]
+ "! TARGET_FPREGS
+ && (register_operand (operands[0], DFmode)
+ || reg_or_fp0_operand (operands[1], DFmode))"
+ "@
+ bis $31,%r1,%0
+ ldq %0,%1
+ stq %r1,%0"
+ [(set_attr "type" "ilog,ild,ist")])
+
+;; Subregs suck for register allocation. Pretend we can move TFmode
+;; data between general registers until after reload.
+
+(define_insn_and_split "*movtf_internal"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=r,o")
+ (match_operand:TF 1 "input_operand" "roG,rG"))]
+ "register_operand (operands[0], TFmode)
+ || reg_or_fp0_operand (operands[1], TFmode)"
+ "#"
+ "reload_completed"
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 1) (match_dup 3))]
+{
+ alpha_split_tfmode_pair (operands);
+ if (reg_overlap_mentioned_p (operands[0], operands[3]))
+ {
+ rtx tmp;
+ tmp = operands[0], operands[0] = operands[1], operands[1] = tmp;
+ tmp = operands[2], operands[2] = operands[3], operands[3] = tmp;
+ }
+})
+
(define_expand "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
- "
{
if (GET_CODE (operands[0]) == MEM
&& ! reg_or_fp0_operand (operands[1], SFmode))
operands[1] = force_reg (SFmode, operands[1]);
-}")
+})
(define_expand "movdf"
[(set (match_operand:DF 0 "nonimmediate_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
- "
{
if (GET_CODE (operands[0]) == MEM
&& ! reg_or_fp0_operand (operands[1], DFmode))
operands[1] = force_reg (DFmode, operands[1]);
-}")
+})
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,f,f,m")
- (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,fJ,m,f"))]
- "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && ! TARGET_FIX
+(define_expand "movtf"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
+ (match_operand:TF 1 "general_operand" ""))]
+ ""
+{
+ if (GET_CODE (operands[0]) == MEM
+ && ! reg_or_fp0_operand (operands[1], TFmode))
+ operands[1] = force_reg (TFmode, operands[1]);
+})
+
+(define_insn "*movsi_nofix"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,*f,*f,m")
+ (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,*fJ,m,*f"))]
+ "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK) && ! TARGET_FIX
&& (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))"
"@
- mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ bis $31,%r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
ldl %0,%1
stl %r1,%0
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%, %0,%1
st%, %R1,%0"
[(set_attr "type" "ilog,iadd,iadd,ild,ist,fcpys,fld,fst")])
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,f,f,m,r,*f")
- (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,fJ,m,f,f,*r"))]
- "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && TARGET_FIX
+(define_insn "*movsi_fix"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,*f,*f,m,r,*f")
+ (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,*fJ,m,*f,*f,r"))]
+ "TARGET_ABI_OSF && TARGET_FIX
&& (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))"
"@
- mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ bis $31,%r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
ldl %0,%1
stl %r1,%0
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%, %0,%1
st%, %R1,%0
ftois %1,%0
itofs %1,%0"
[(set_attr "type" "ilog,iadd,iadd,ild,ist,fcpys,fld,fst,ftoi,itof")])
-(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f,m")
- (match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ,fJ,m,f"))]
- "(TARGET_WINDOWS_NT || TARGET_OPEN_VMS)
+(define_insn "*movsi_nt_vms"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,m")
+ (match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,m,*f"))]
+ "(TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS)
&& (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))"
"@
- mov %1,%0
+ bis $31,%1,%0
lda %0,%1
ldah %0,%h1
lda %0,%1
ldl %0,%1
stl %r1,%0
- fmov %R1,%0
+ cpys %R1,%R1,%0
ld%, %0,%1
st%, %R1,%0"
[(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,f")
- (match_operand:HI 1 "input_operand" "rJ,n,fJ"))]
+(define_insn "*movhi_nobwx"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (match_operand:HI 1 "input_operand" "rJ,n"))]
"! TARGET_BWX
&& (register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode))"
"@
- mov %r1,%0
- lda %0,%L1
- fmov %R1,%0"
- [(set_attr "type" "ilog,iadd,fcpys")])
+ bis $31,%r1,%0
+ lda %0,%L1($31)"
+ [(set_attr "type" "ilog,iadd")])
-(define_insn ""
- [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m,f")
- (match_operand:HI 1 "input_operand" "rJ,n,m,rJ,fJ"))]
+(define_insn "*movhi_bwx"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m")
+ (match_operand:HI 1 "input_operand" "rJ,n,m,rJ"))]
"TARGET_BWX
&& (register_operand (operands[0], HImode)
|| reg_or_0_operand (operands[1], HImode))"
"@
- mov %r1,%0
- lda %0,%L1
+ bis $31,%r1,%0
+ lda %0,%L1($31)
ldwu %0,%1
- stw %r1,%0
- fmov %R1,%0"
- [(set_attr "type" "ilog,iadd,ild,ist,fcpys")])
+ stw %r1,%0"
+ [(set_attr "type" "ilog,iadd,ild,ist")])
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,f")
- (match_operand:QI 1 "input_operand" "rJ,n,fJ"))]
+(define_insn "*movqi_nobwx"
+ [(set (match_operand:QI 0 "register_operand" "=r,r")
+ (match_operand:QI 1 "input_operand" "rJ,n"))]
"! TARGET_BWX
&& (register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode))"
"@
- mov %r1,%0
- lda %0,%L1
- fmov %R1,%0"
- [(set_attr "type" "ilog,iadd,fcpys")])
+ bis $31,%r1,%0
+ lda %0,%L1($31)"
+ [(set_attr "type" "ilog,iadd")])
-(define_insn ""
- [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,f")
- (match_operand:QI 1 "input_operand" "rJ,n,m,rJ,fJ"))]
+(define_insn "*movqi_bwx"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m")
+ (match_operand:QI 1 "input_operand" "rJ,n,m,rJ"))]
"TARGET_BWX
&& (register_operand (operands[0], QImode)
|| reg_or_0_operand (operands[1], QImode))"
"@
- mov %r1,%0
- lda %0,%L1
+ bis $31,%r1,%0
+ lda %0,%L1($31)
ldbu %0,%1
- stb %r1,%0
- fmov %R1,%0"
- [(set_attr "type" "ilog,iadd,ild,ist,fcpys")])
+ stb %r1,%0"
+ [(set_attr "type" "ilog,iadd,ild,ist")])
;; We do two major things here: handle mem->mem and construct long
;; constants.
(define_expand "movsi"
- [(set (match_operand:SI 0 "general_operand" "")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
- "
{
- if (GET_CODE (operands[0]) == MEM
- && ! reg_or_0_operand (operands[1], SImode))
- operands[1] = force_reg (SImode, operands[1]);
-
- if (! CONSTANT_P (operands[1]) || input_operand (operands[1], SImode))
- ;
- else if (GET_CODE (operands[1]) == CONST_INT)
- {
- operands[1]
- = alpha_emit_set_const (operands[0], SImode, INTVAL (operands[1]), 3);
- if (rtx_equal_p (operands[0], operands[1]))
- DONE;
- }
-}")
+ if (alpha_expand_mov (SImode, operands))
+ DONE;
+})
;; Split a load of a large constant into the appropriate two-insn
;; sequence.
@@ -4245,126 +5379,267 @@
"! add_operand (operands[1], SImode)"
[(set (match_dup 0) (match_dup 2))
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))]
- "
-{ rtx tem
+{
+ rtx tem
= alpha_emit_set_const (operands[0], SImode, INTVAL (operands[1]), 2);
if (tem == operands[0])
DONE;
else
FAIL;
-}")
+})
-(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,m,f,f,Q")
- (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,fJ,Q,f"))]
- "! TARGET_FIX
+;; Split the load of an address into a four-insn sequence on Unicos/Mk.
+;; Always generate a REG_EQUAL note for the last instruction to facilitate
+;; optimisations. If the symbolic operand is a label_ref, generate REG_LABEL
+;; notes and update LABEL_NUSES because this is not done automatically.
+;; Labels may be incorrectly deleted if we don't do this.
+;;
+;; Describing what the individual instructions do correctly is too complicated
+;; so use UNSPECs for each of the three parts of an address.
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "symbolic_operand" ""))]
+ "TARGET_ABI_UNICOSMK && reload_completed"
+ [(const_int 0)]
+{
+ rtx insn1, insn2, insn3;
+
+ insn1 = emit_insn (gen_umk_laum (operands[0], operands[1]));
+ emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
+ insn2 = emit_insn (gen_umk_lalm (operands[0], operands[0], operands[1]));
+ insn3 = emit_insn (gen_umk_lal (operands[0], operands[0], operands[1]));
+ REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+ REG_NOTES (insn3));
+ if (GET_CODE (operands[1]) == LABEL_REF)
+ {
+ rtx label;
+
+ label = XEXP (operands[1], 0);
+ REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn1));
+ REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn2));
+ REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn3));
+ LABEL_NUSES (label) += 3;
+ }
+ DONE;
+})
+
+;; Instructions for loading the three parts of an address on Unicos/Mk.
+
+(define_insn "umk_laum"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
+ UNSPEC_UMK_LAUM))]
+ "TARGET_ABI_UNICOSMK"
+ "laum %r0,%t1($31)"
+ [(set_attr "type" "iadd")])
+
+(define_insn "umk_lalm"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
+ UNSPEC_UMK_LALM)))]
+ "TARGET_ABI_UNICOSMK"
+ "lalm %r0,%t2(%r1)"
+ [(set_attr "type" "iadd")])
+
+(define_insn "umk_lal"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
+ UNSPEC_UMK_LAL)))]
+ "TARGET_ABI_UNICOSMK"
+ "lal %r0,%t2(%r1)"
+ [(set_attr "type" "iadd")])
+
+;; Add a new call information word to the current function's list of CIWs
+;; and load its index into $25. Doing it here ensures that the CIW will be
+;; associated with the correct function even in the presence of inlining.
+
+(define_insn "*umk_load_ciw"
+ [(set (reg:DI 25)
+ (unspec:DI [(match_operand 0 "" "")] UNSPEC_UMK_LOAD_CIW))]
+ "TARGET_ABI_UNICOSMK"
+{
+ operands[0] = unicosmk_add_call_info_word (operands[0]);
+ return "lda $25,%0";
+}
+ [(set_attr "type" "iadd")])
+
+(define_insn "*movdi_er_low_l"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "local_symbolic_operand" "")))]
+ "TARGET_EXPLICIT_RELOCS"
+{
+ if (true_regnum (operands[1]) == 29)
+ return "lda %0,%2(%1)\t\t!gprel";
+ else
+ return "lda %0,%2(%1)\t\t!gprellow";
+})
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "small_symbolic_operand" ""))]
+ "TARGET_EXPLICIT_RELOCS && reload_completed"
+ [(set (match_dup 0)
+ (lo_sum:DI (match_dup 2) (match_dup 1)))]
+ "operands[2] = pic_offset_table_rtx;")
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "local_symbolic_operand" ""))]
+ "TARGET_EXPLICIT_RELOCS && reload_completed"
+ [(set (match_dup 0)
+ (plus:DI (match_dup 2) (high:DI (match_dup 1))))
+ (set (match_dup 0)
+ (lo_sum:DI (match_dup 0) (match_dup 1)))]
+ "operands[2] = pic_offset_table_rtx;")
+
+(define_split
+ [(match_operand 0 "some_small_symbolic_mem_operand" "")]
+ "TARGET_EXPLICIT_RELOCS && reload_completed"
+ [(match_dup 0)]
+ "operands[0] = split_small_symbolic_mem_operand (operands[0]);")
+
+(define_insn "movdi_er_high_g"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "global_symbolic_operand" "")
+ (match_operand 3 "const_int_operand" "")]
+ UNSPEC_LITERAL))]
+ "TARGET_EXPLICIT_RELOCS"
+{
+ if (INTVAL (operands[3]) == 0)
+ return "ldq %0,%2(%1)\t\t!literal";
+ else
+ return "ldq %0,%2(%1)\t\t!literal!%3";
+}
+ [(set_attr "type" "ldsym")])
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "global_symbolic_operand" ""))]
+ "TARGET_EXPLICIT_RELOCS && reload_completed"
+ [(set (match_dup 0)
+ (unspec:DI [(match_dup 2)
+ (match_dup 1)
+ (const_int 0)] UNSPEC_LITERAL))]
+ "operands[2] = pic_offset_table_rtx;")
+
+(define_insn "*movdi_er_nofix"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,m,rJ,*fJ,Q,*f"))]
+ "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
"@
mov %r1,%0
- lda %0,%1
- ldah %0,%h1
- lda %0,%1
+ lda %0,%1($31)
+ ldah %0,%h1($31)
+ #
+ #
ldq%A1 %0,%1
stq%A0 %r1,%0
fmov %R1,%0
ldt %0,%1
stt %R1,%0"
- [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
+ [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
-(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,m,f,f,Q,r,*f")
- (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,fJ,Q,f,f,*r"))]
- "TARGET_FIX
+;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should
+;; have been split up by the rules above but we shouldn't reject the
+;; possibility of them getting through.
+
+(define_insn "*movdi_nofix"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,m,rJ,*fJ,Q,*f"))]
+ "! TARGET_FIX
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
"@
- mov %r1,%0
- lda %0,%1
- ldah %0,%h1
+ bis $31,%r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
+ laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0)
lda %0,%1
ldq%A1 %0,%1
stq%A0 %r1,%0
+ cpys %R1,%R1,%0
+ ldt %0,%1
+ stt %R1,%0"
+ [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,ild,ist,fcpys,fld,fst")
+ (set_attr "length" "*,*,*,16,*,*,*,*,*,*")])
+
+(define_insn "*movdi_er_fix"
+ [(set (match_operand:DI 0 "nonimmediate_operand"
+ "=r,r,r,r,r,r, m, *f,*f, Q, r,*f")
+ (match_operand:DI 1 "input_operand"
+ "rJ,K,L,T,s,m,rJ,*fJ, Q,*f,*f, r"))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_FIX
+ && (register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))"
+ "@
+ mov %r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
+ #
+ #
+ ldq%A1 %0,%1
+ stq%A0 %r1,%0
fmov %R1,%0
ldt %0,%1
stt %R1,%0
ftoit %1,%0
itoft %1,%0"
+ [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")])
+
+(define_insn "*movdi_fix"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q,r,*f")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f,*f,r"))]
+ "! TARGET_EXPLICIT_RELOCS && TARGET_FIX
+ && (register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))"
+ "@
+ bis $31,%r1,%0
+ lda %0,%1($31)
+ ldah %0,%h1($31)
+ lda %0,%1
+ ldq%A1 %0,%1
+ stq%A0 %r1,%0
+ cpys %R1,%R1,%0
+ ldt %0,%1
+ stt %R1,%0
+ ftoit %1,%0
+ itoft %1,%0"
[(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")])
+;; VMS needs to set up "vms_base_regno" for unwinding. This move
+;; often appears dead to the life analysis code, at which point we
+;; abort for emitting dead prologue instructions. Force this live.
+
+(define_insn "force_movdi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")]
+ UNSPECV_FORCE_MOV))]
+ ""
+ "mov %1,%0"
+ [(set_attr "type" "ilog")])
+
;; We do three major things here: handle mem->mem, put 64-bit constants in
;; memory, and construct long 32-bit constants.
(define_expand "movdi"
- [(set (match_operand:DI 0 "general_operand" "")
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
- "
{
- rtx tem;
-
- if (GET_CODE (operands[0]) == MEM
- && ! reg_or_0_operand (operands[1], DImode))
- operands[1] = force_reg (DImode, operands[1]);
-
- if (! CONSTANT_P (operands[1]) || input_operand (operands[1], DImode))
- ;
- else if (GET_CODE (operands[1]) == CONST_INT
- && (tem = alpha_emit_set_const (operands[0], DImode,
- INTVAL (operands[1]), 3)) != 0)
- {
- if (rtx_equal_p (tem, operands[0]))
- DONE;
- else
- operands[1] = tem;
- }
- else if (CONSTANT_P (operands[1]))
- {
- if (TARGET_BUILD_CONSTANTS)
- {
- HOST_WIDE_INT i0, i1;
-
- if (GET_CODE (operands[1]) == CONST_INT)
- {
- i0 = INTVAL (operands[1]);
- i1 = -(i0 < 0);
- }
- else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
-#if HOST_BITS_PER_WIDE_INT >= 64
- i0 = CONST_DOUBLE_LOW (operands[1]);
- i1 = -(i0 < 0);
-#else
- i0 = CONST_DOUBLE_LOW (operands[1]);
- i1 = CONST_DOUBLE_HIGH (operands[1]);
-#endif
- }
- else
- abort();
-
- tem = alpha_emit_set_long_const (operands[0], i0, i1);
- if (rtx_equal_p (tem, operands[0]))
- DONE;
- else
- operands[1] = tem;
- }
- else
- {
- operands[1] = force_const_mem (DImode, operands[1]);
- if (reload_in_progress)
- {
- emit_move_insn (operands[0], XEXP (operands[1], 0));
- operands[1] = copy_rtx (operands[1]);
- XEXP (operands[1], 0) = operands[0];
- }
- else
- operands[1] = validize_mem (operands[1]);
- }
- }
- else
- abort ();
-}")
+ if (alpha_expand_mov (DImode, operands))
+ DONE;
+})
;; Split a load of a large constant into the appropriate two-insn
;; sequence.
@@ -4375,15 +5650,15 @@
"! add_operand (operands[1], DImode)"
[(set (match_dup 0) (match_dup 2))
(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))]
- "
-{ rtx tem
+{
+ rtx tem
= alpha_emit_set_const (operands[0], DImode, INTVAL (operands[1]), 2);
if (tem == operands[0])
DONE;
else
FAIL;
-}")
+})
;; These are the partial-word cases.
;;
@@ -4401,10 +5676,10 @@
(zero_extract:DI (subreg:DI (match_dup 3) 0)
(const_int 8)
(match_operand:DI 2 "const_int_operand" "")))]
-
+
""
"")
-
+
(define_expand "aligned_loadhi"
[(set (match_operand:SI 3 "register_operand" "")
(match_operand:SI 1 "memory_operand" ""))
@@ -4412,17 +5687,34 @@
(zero_extract:DI (subreg:DI (match_dup 3) 0)
(const_int 16)
(match_operand:DI 2 "const_int_operand" "")))]
-
+
""
"")
-
+
;; Similar for unaligned loads, where we use the sequence from the
-;; Alpha Architecture manual.
+;; Alpha Architecture manual. We have to distinguish between little-endian
+;; and big-endian systems as the sequences are different.
;;
;; Operand 1 is the address. Operands 2 and 3 are temporaries, where
;; operand 3 can overlap the input and output registers.
(define_expand "unaligned_loadqi"
+ [(use (match_operand:QI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "address_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))
+ (use (match_operand:DI 3 "register_operand" ""))]
+ ""
+{
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_unaligned_loadqi_be (operands[0], operands[1],
+ operands[2], operands[3]));
+ else
+ emit_insn (gen_unaligned_loadqi_le (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+})
+
+(define_expand "unaligned_loadqi_le"
[(set (match_operand:DI 2 "register_operand" "")
(mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
(const_int -8))))
@@ -4432,10 +5724,41 @@
(zero_extract:DI (match_dup 2)
(const_int 8)
(ashift:DI (match_dup 3) (const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "unaligned_loadqi_be"
+ [(set (match_operand:DI 2 "register_operand" "")
+ (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
+ (const_int -8))))
+ (set (match_operand:DI 3 "register_operand" "")
+ (match_dup 1))
+ (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (zero_extract:DI (match_dup 2)
+ (const_int 8)
+ (minus:DI
+ (const_int 56)
+ (ashift:DI (match_dup 3) (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"")
(define_expand "unaligned_loadhi"
+ [(use (match_operand:QI 0 "register_operand" ""))
+ (use (match_operand:DI 1 "address_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))
+ (use (match_operand:DI 3 "register_operand" ""))]
+ ""
+{
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_unaligned_loadhi_be (operands[0], operands[1],
+ operands[2], operands[3]));
+ else
+ emit_insn (gen_unaligned_loadhi_le (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+})
+
+(define_expand "unaligned_loadhi_le"
[(set (match_operand:DI 2 "register_operand" "")
(mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
(const_int -8))))
@@ -4445,11 +5768,26 @@
(zero_extract:DI (match_dup 2)
(const_int 16)
(ashift:DI (match_dup 3) (const_int 3))))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "unaligned_loadhi_be"
+ [(set (match_operand:DI 2 "register_operand" "")
+ (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
+ (const_int -8))))
+ (set (match_operand:DI 3 "register_operand" "")
+ (plus:DI (match_dup 1) (const_int 1)))
+ (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (zero_extract:DI (match_dup 2)
+ (const_int 16)
+ (minus:DI
+ (const_int 56)
+ (ashift:DI (match_dup 3) (const_int 3)))))]
+ "WORDS_BIG_ENDIAN"
"")
;; Storing an aligned byte or word requires two temporaries. Operand 0 is the
-;; aligned SImode MEM. Operand 1 is the register containing the
+;; aligned SImode MEM. Operand 1 is the register containing the
;; byte or word to store. Operand 2 is the number of bits within the word that
;; the value should be placed. Operands 3 and 4 are SImode temporaries.
@@ -4465,10 +5803,10 @@
(ior:DI (subreg:DI (match_dup 4) 0) (subreg:DI (match_dup 3) 0)))
(set (match_dup 0) (match_dup 4))]
""
- "
-{ operands[5] = GEN_INT (~ (GET_MODE_MASK (GET_MODE (operands[1]))
+{
+ operands[5] = GEN_INT (~ (GET_MODE_MASK (GET_MODE (operands[1]))
<< INTVAL (operands[2])));
-}")
+})
;; For the unaligned byte and halfword cases, we use code similar to that
;; in the ;; Architecture book, but reordered to lower the number of registers
@@ -4478,6 +5816,25 @@
;; operand 2 can be that register.
(define_expand "unaligned_storeqi"
+ [(use (match_operand:DI 0 "address_operand" ""))
+ (use (match_operand:QI 1 "register_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))
+ (use (match_operand:DI 3 "register_operand" ""))
+ (use (match_operand:DI 4 "register_operand" ""))]
+ ""
+{
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_unaligned_storeqi_be (operands[0], operands[1],
+ operands[2], operands[3],
+ operands[4]));
+ else
+ emit_insn (gen_unaligned_storeqi_le (operands[0], operands[1],
+ operands[2], operands[3],
+ operands[4]));
+ DONE;
+})
+
+(define_expand "unaligned_storeqi_le"
[(set (match_operand:DI 3 "register_operand" "")
(mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
(const_int -8))))
@@ -4493,10 +5850,50 @@
(set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
(set (mem:DI (and:DI (match_dup 0) (const_int -8)))
(match_dup 4))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "unaligned_storeqi_be"
+ [(set (match_operand:DI 3 "register_operand" "")
+ (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
+ (const_int -8))))
+ (set (match_operand:DI 2 "register_operand" "")
+ (match_dup 0))
+ (set (match_dup 3)
+ (and:DI (not:DI (ashift:DI (const_int 255)
+ (minus:DI (const_int 56)
+ (ashift:DI (match_dup 2) (const_int 3)))))
+ (match_dup 3)))
+ (set (match_operand:DI 4 "register_operand" "")
+ (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" ""))
+ (minus:DI (const_int 56)
+ (ashift:DI (match_dup 2) (const_int 3)))))
+ (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
+ (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
+ (match_dup 4))]
+ "WORDS_BIG_ENDIAN"
"")
(define_expand "unaligned_storehi"
+ [(use (match_operand:DI 0 "address_operand" ""))
+ (use (match_operand:HI 1 "register_operand" ""))
+ (use (match_operand:DI 2 "register_operand" ""))
+ (use (match_operand:DI 3 "register_operand" ""))
+ (use (match_operand:DI 4 "register_operand" ""))]
+ ""
+{
+ if (WORDS_BIG_ENDIAN)
+ emit_insn (gen_unaligned_storehi_be (operands[0], operands[1],
+ operands[2], operands[3],
+ operands[4]));
+ else
+ emit_insn (gen_unaligned_storehi_le (operands[0], operands[1],
+ operands[2], operands[3],
+ operands[4]));
+ DONE;
+})
+
+(define_expand "unaligned_storehi_le"
[(set (match_operand:DI 3 "register_operand" "")
(mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
(const_int -8))))
@@ -4512,7 +5909,29 @@
(set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
(set (mem:DI (and:DI (match_dup 0) (const_int -8)))
(match_dup 4))]
- ""
+ "! WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "unaligned_storehi_be"
+ [(set (match_operand:DI 3 "register_operand" "")
+ (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
+ (const_int -8))))
+ (set (match_operand:DI 2 "register_operand" "")
+ (plus:DI (match_dup 0) (const_int 1)))
+ (set (match_dup 3)
+ (and:DI (not:DI (ashift:DI
+ (const_int 65535)
+ (minus:DI (const_int 56)
+ (ashift:DI (match_dup 2) (const_int 3)))))
+ (match_dup 3)))
+ (set (match_operand:DI 4 "register_operand" "")
+ (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" ""))
+ (minus:DI (const_int 56)
+ (ashift:DI (match_dup 2) (const_int 3)))))
+ (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
+ (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
+ (match_dup 4))]
+ "WORDS_BIG_ENDIAN"
"")
;; Here are the define_expand's for QI and HI moves that use the above
@@ -4520,241 +5939,26 @@
;; registers for reload.
(define_expand "movqi"
- [(set (match_operand:QI 0 "general_operand" "")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
- "
{
- if (TARGET_BWX)
- {
- if (GET_CODE (operands[0]) == MEM
- && ! reg_or_0_operand (operands[1], QImode))
- operands[1] = force_reg (QImode, operands[1]);
-
- if (GET_CODE (operands[1]) == CONST_INT
- && ! input_operand (operands[1], QImode))
- {
- operands[1] = alpha_emit_set_const (operands[0], QImode,
- INTVAL (operands[1]), 3);
-
- if (rtx_equal_p (operands[0], operands[1]))
- DONE;
- }
-
- goto def;
- }
-
- /* If the output is not a register, the input must be. */
- if (GET_CODE (operands[0]) == MEM)
- operands[1] = force_reg (QImode, operands[1]);
-
- /* Handle four memory cases, unaligned and aligned for either the input
- or the output. The only case where we can be called during reload is
- for aligned loads; all other cases require temporaries. */
-
- if (GET_CODE (operands[1]) == MEM
- || (GET_CODE (operands[1]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[1])) == MEM)
- || (reload_in_progress && GET_CODE (operands[1]) == REG
- && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
- || (reload_in_progress && GET_CODE (operands[1]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[1])) == REG
- && REGNO (SUBREG_REG (operands[1])) >= FIRST_PSEUDO_REGISTER))
- {
- if (aligned_memory_operand (operands[1], QImode))
- {
- if (reload_in_progress)
- {
- emit_insn (gen_reload_inqi_help
- (operands[0], operands[1],
- gen_rtx_REG (SImode, REGNO (operands[0]))));
- }
- else
- {
- rtx aligned_mem, bitnum;
- rtx scratch = gen_reg_rtx (SImode);
-
- get_aligned_mem (operands[1], &aligned_mem, &bitnum);
-
- emit_insn (gen_aligned_loadqi (operands[0], aligned_mem, bitnum,
- scratch));
- }
- }
- else
- {
- /* Don't pass these as parameters since that makes the generated
- code depend on parameter evaluation order which will cause
- bootstrap failures. */
-
- rtx temp1 = gen_reg_rtx (DImode);
- rtx temp2 = gen_reg_rtx (DImode);
- rtx seq
- = gen_unaligned_loadqi (operands[0],
- get_unaligned_address (operands[1], 0),
- temp1, temp2);
-
- alpha_set_memflags (seq, operands[1]);
- emit_insn (seq);
- }
-
- DONE;
- }
-
- else if (GET_CODE (operands[0]) == MEM
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == MEM)
- || (reload_in_progress && GET_CODE (operands[0]) == REG
- && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
- || (reload_in_progress && GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
- {
- if (aligned_memory_operand (operands[0], QImode))
- {
- rtx aligned_mem, bitnum;
- rtx temp1 = gen_reg_rtx (SImode);
- rtx temp2 = gen_reg_rtx (SImode);
-
- get_aligned_mem (operands[0], &aligned_mem, &bitnum);
-
- emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
- temp1, temp2));
- }
- else
- {
- rtx temp1 = gen_reg_rtx (DImode);
- rtx temp2 = gen_reg_rtx (DImode);
- rtx temp3 = gen_reg_rtx (DImode);
- rtx seq
- = gen_unaligned_storeqi (get_unaligned_address (operands[0], 0),
- operands[1], temp1, temp2, temp3);
-
- alpha_set_memflags (seq, operands[0]);
- emit_insn (seq);
- }
- DONE;
- }
- def:;
-}")
+ if (TARGET_BWX
+ ? alpha_expand_mov (QImode, operands)
+ : alpha_expand_mov_nobwx (QImode, operands))
+ DONE;
+})
(define_expand "movhi"
- [(set (match_operand:HI 0 "general_operand" "")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
- "
{
- if (TARGET_BWX)
- {
- if (GET_CODE (operands[0]) == MEM
- && ! reg_or_0_operand (operands[1], HImode))
- operands[1] = force_reg (HImode, operands[1]);
-
- if (GET_CODE (operands[1]) == CONST_INT
- && ! input_operand (operands[1], HImode))
- {
- operands[1] = alpha_emit_set_const (operands[0], HImode,
- INTVAL (operands[1]), 3);
-
- if (rtx_equal_p (operands[0], operands[1]))
- DONE;
- }
-
- goto def;
- }
-
- /* If the output is not a register, the input must be. */
- if (GET_CODE (operands[0]) == MEM)
- operands[1] = force_reg (HImode, operands[1]);
-
- /* Handle four memory cases, unaligned and aligned for either the input
- or the output. The only case where we can be called during reload is
- for aligned loads; all other cases require temporaries. */
-
- if (GET_CODE (operands[1]) == MEM
- || (GET_CODE (operands[1]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[1])) == MEM)
- || (reload_in_progress && GET_CODE (operands[1]) == REG
- && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
- || (reload_in_progress && GET_CODE (operands[1]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[1])) == REG
- && REGNO (SUBREG_REG (operands[1])) >= FIRST_PSEUDO_REGISTER))
- {
- if (aligned_memory_operand (operands[1], HImode))
- {
- if (reload_in_progress)
- {
- emit_insn (gen_reload_inhi_help
- (operands[0], operands[1],
- gen_rtx_REG (SImode, REGNO (operands[0]))));
- }
- else
- {
- rtx aligned_mem, bitnum;
- rtx scratch = gen_reg_rtx (SImode);
-
- get_aligned_mem (operands[1], &aligned_mem, &bitnum);
-
- emit_insn (gen_aligned_loadhi (operands[0], aligned_mem, bitnum,
- scratch));
- }
- }
- else
- {
- /* Don't pass these as parameters since that makes the generated
- code depend on parameter evaluation order which will cause
- bootstrap failures. */
-
- rtx temp1 = gen_reg_rtx (DImode);
- rtx temp2 = gen_reg_rtx (DImode);
- rtx seq
- = gen_unaligned_loadhi (operands[0],
- get_unaligned_address (operands[1], 0),
- temp1, temp2);
-
- alpha_set_memflags (seq, operands[1]);
- emit_insn (seq);
- }
-
- DONE;
- }
-
- else if (GET_CODE (operands[0]) == MEM
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == MEM)
- || (reload_in_progress && GET_CODE (operands[0]) == REG
- && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
- || (reload_in_progress && GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
- {
- if (aligned_memory_operand (operands[0], HImode))
- {
- rtx aligned_mem, bitnum;
- rtx temp1 = gen_reg_rtx (SImode);
- rtx temp2 = gen_reg_rtx (SImode);
-
- get_aligned_mem (operands[0], &aligned_mem, &bitnum);
-
- emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
- temp1, temp2));
- }
- else
- {
- rtx temp1 = gen_reg_rtx (DImode);
- rtx temp2 = gen_reg_rtx (DImode);
- rtx temp3 = gen_reg_rtx (DImode);
- rtx seq
- = gen_unaligned_storehi (get_unaligned_address (operands[0], 0),
- operands[1], temp1, temp2, temp3);
-
- alpha_set_memflags (seq, operands[0]);
- emit_insn (seq);
- }
-
- DONE;
- }
- def:;
-}")
+ if (TARGET_BWX
+ ? alpha_expand_mov (HImode, operands)
+ : alpha_expand_mov_nobwx (HImode, operands))
+ DONE;
+})
;; Here are the versions for reload. Note that in the unaligned cases
;; we know that the operand must not be a pseudo-register because stack
@@ -4765,7 +5969,6 @@
(match_operand:QI 1 "any_memory_operand" "m")
(match_operand:TI 2 "register_operand" "=&r")])]
"! TARGET_BWX"
- "
{
rtx scratch, seq;
@@ -4796,14 +5999,13 @@
}
emit_insn (seq);
DONE;
-}")
+})
(define_expand "reload_inhi"
[(parallel [(match_operand:HI 0 "register_operand" "=r")
(match_operand:HI 1 "any_memory_operand" "m")
(match_operand:TI 2 "register_operand" "=&r")])]
"! TARGET_BWX"
- "
{
rtx scratch, seq;
@@ -4812,7 +6014,7 @@
if (aligned_memory_operand (operands[1], HImode))
{
- seq = gen_reload_inhi_help (operands[0], operands[1],
+ seq = gen_reload_inhi_help (operands[0], operands[1],
gen_rtx_REG (SImode, REGNO (operands[2])));
}
else
@@ -4834,14 +6036,13 @@
}
emit_insn (seq);
DONE;
-}")
+})
(define_expand "reload_outqi"
[(parallel [(match_operand:QI 0 "any_memory_operand" "=m")
(match_operand:QI 1 "register_operand" "r")
(match_operand:TI 2 "register_operand" "=&r")])]
"! TARGET_BWX"
- "
{
if (GET_CODE (operands[0]) != MEM)
abort ();
@@ -4870,14 +6071,13 @@
emit_insn (seq);
}
DONE;
-}")
+})
(define_expand "reload_outhi"
[(parallel [(match_operand:HI 0 "any_memory_operand" "=m")
(match_operand:HI 1 "register_operand" "r")
(match_operand:TI 2 "register_operand" "=&r")])]
"! TARGET_BWX"
- "
{
if (GET_CODE (operands[0]) != MEM)
abort ();
@@ -4906,103 +6106,101 @@
emit_insn (seq);
}
DONE;
-}")
+})
;; Helpers for the above. The way reload is structured, we can't
;; always get a proper address for a stack slot during reload_foo
;; expansion, so we must delay our address manipulations until after.
(define_insn "reload_inqi_help"
- [(set (match_operand:QI 0 "register_operand" "r")
+ [(set (match_operand:QI 0 "register_operand" "=r")
(match_operand:QI 1 "memory_operand" "m"))
- (clobber (match_operand:SI 2 "register_operand" "r"))]
+ (clobber (match_operand:SI 2 "register_operand" "=r"))]
"! TARGET_BWX && (reload_in_progress || reload_completed)"
"#")
(define_insn "reload_inhi_help"
- [(set (match_operand:HI 0 "register_operand" "r")
+ [(set (match_operand:HI 0 "register_operand" "=r")
(match_operand:HI 1 "memory_operand" "m"))
- (clobber (match_operand:SI 2 "register_operand" "r"))]
+ (clobber (match_operand:SI 2 "register_operand" "=r"))]
"! TARGET_BWX && (reload_in_progress || reload_completed)"
"#")
(define_insn "reload_outqi_help"
- [(set (match_operand:QI 0 "memory_operand" "m")
+ [(set (match_operand:QI 0 "memory_operand" "=m")
(match_operand:QI 1 "register_operand" "r"))
- (clobber (match_operand:SI 2 "register_operand" "r"))
- (clobber (match_operand:SI 3 "register_operand" "r"))]
+ (clobber (match_operand:SI 2 "register_operand" "=r"))
+ (clobber (match_operand:SI 3 "register_operand" "=r"))]
"! TARGET_BWX && (reload_in_progress || reload_completed)"
"#")
(define_insn "reload_outhi_help"
- [(set (match_operand:HI 0 "memory_operand" "m")
+ [(set (match_operand:HI 0 "memory_operand" "=m")
(match_operand:HI 1 "register_operand" "r"))
- (clobber (match_operand:SI 2 "register_operand" "r"))
- (clobber (match_operand:SI 3 "register_operand" "r"))]
+ (clobber (match_operand:SI 2 "register_operand" "=r"))
+ (clobber (match_operand:SI 3 "register_operand" "=r"))]
"! TARGET_BWX && (reload_in_progress || reload_completed)"
"#")
(define_split
- [(set (match_operand:QI 0 "register_operand" "r")
- (match_operand:QI 1 "memory_operand" "m"))
- (clobber (match_operand:SI 2 "register_operand" "r"))]
+ [(set (match_operand:QI 0 "register_operand" "")
+ (match_operand:QI 1 "memory_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))]
"! TARGET_BWX && reload_completed"
[(const_int 0)]
- "
{
rtx aligned_mem, bitnum;
get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+
emit_insn (gen_aligned_loadqi (operands[0], aligned_mem, bitnum,
operands[2]));
DONE;
-}")
-
+})
+
(define_split
- [(set (match_operand:HI 0 "register_operand" "r")
- (match_operand:HI 1 "memory_operand" "m"))
- (clobber (match_operand:SI 2 "register_operand" "r"))]
+ [(set (match_operand:HI 0 "register_operand" "")
+ (match_operand:HI 1 "memory_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))]
"! TARGET_BWX && reload_completed"
[(const_int 0)]
- "
{
rtx aligned_mem, bitnum;
get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+
emit_insn (gen_aligned_loadhi (operands[0], aligned_mem, bitnum,
operands[2]));
DONE;
-}")
-
+})
+
(define_split
- [(set (match_operand:QI 0 "memory_operand" "m")
- (match_operand:QI 1 "register_operand" "r"))
- (clobber (match_operand:SI 2 "register_operand" "r"))
- (clobber (match_operand:SI 3 "register_operand" "r"))]
+ [(set (match_operand:QI 0 "memory_operand" "")
+ (match_operand:QI 1 "register_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (match_operand:SI 3 "register_operand" ""))]
"! TARGET_BWX && reload_completed"
[(const_int 0)]
- "
{
rtx aligned_mem, bitnum;
get_aligned_mem (operands[0], &aligned_mem, &bitnum);
emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
operands[2], operands[3]));
DONE;
-}")
+})
(define_split
- [(set (match_operand:HI 0 "memory_operand" "m")
- (match_operand:HI 1 "register_operand" "r"))
- (clobber (match_operand:SI 2 "register_operand" "r"))
- (clobber (match_operand:SI 3 "register_operand" "r"))]
+ [(set (match_operand:HI 0 "memory_operand" "")
+ (match_operand:HI 1 "register_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (match_operand:SI 3 "register_operand" ""))]
"! TARGET_BWX && reload_completed"
[(const_int 0)]
- "
{
rtx aligned_mem, bitnum;
get_aligned_mem (operands[0], &aligned_mem, &bitnum);
emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
operands[2], operands[3]));
DONE;
-}")
+})
;; Bit field extract patterns which use ext[wlq][lh]
@@ -5012,8 +6210,9 @@
(match_operand:DI 2 "immediate_operand" "")
(match_operand:DI 3 "immediate_operand" "")))]
""
- "
{
+ int ofs;
+
/* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
if (INTVAL (operands[3]) % 8 != 0
|| (INTVAL (operands[2]) != 16
@@ -5026,19 +6225,30 @@
if (GET_CODE (operands[1]) != MEM)
FAIL;
+ /* The bit number is relative to the mode of operand 1 which is
+ usually QImode (this might actually be a bug in expmed.c). Note
+ that the bit number is negative in big-endian mode in this case.
+ We have to convert that to the offset. */
+ if (WORDS_BIG_ENDIAN)
+ ofs = GET_MODE_BITSIZE (GET_MODE (operands[1]))
+ - INTVAL (operands[2]) - INTVAL (operands[3]);
+ else
+ ofs = INTVAL (operands[3]);
+
+ ofs = ofs / 8;
+
alpha_expand_unaligned_load (operands[0], operands[1],
INTVAL (operands[2]) / 8,
- INTVAL (operands[3]) / 8, 1);
+ ofs, 1);
DONE;
-}")
+})
(define_expand "extzv"
[(set (match_operand:DI 0 "register_operand" "")
- (zero_extract:DI (match_operand:DI 1 "general_operand" "")
+ (zero_extract:DI (match_operand:DI 1 "nonimmediate_operand" "")
(match_operand:DI 2 "immediate_operand" "")
(match_operand:DI 3 "immediate_operand" "")))]
""
- "
{
/* We can do 8, 16, 32 and 64 bit fields, if aligned on byte boundaries. */
if (INTVAL (operands[3]) % 8 != 0
@@ -5050,16 +6260,30 @@
if (GET_CODE (operands[1]) == MEM)
{
+ int ofs;
+
/* Fail 8 bit fields, falling back on a simple byte load. */
if (INTVAL (operands[2]) == 8)
FAIL;
+ /* The bit number is relative to the mode of operand 1 which is
+ usually QImode (this might actually be a bug in expmed.c). Note
+ that the bit number is negative in big-endian mode in this case.
+ We have to convert that to the offset. */
+ if (WORDS_BIG_ENDIAN)
+ ofs = GET_MODE_BITSIZE (GET_MODE (operands[1]))
+ - INTVAL (operands[2]) - INTVAL (operands[3]);
+ else
+ ofs = INTVAL (operands[3]);
+
+ ofs = ofs / 8;
+
alpha_expand_unaligned_load (operands[0], operands[1],
INTVAL (operands[2]) / 8,
- INTVAL (operands[3]) / 8, 0);
+ ofs, 0);
DONE;
}
-}")
+})
(define_expand "insv"
[(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "")
@@ -5067,8 +6291,9 @@
(match_operand:DI 2 "immediate_operand" ""))
(match_operand:DI 3 "register_operand" ""))]
""
- "
{
+ int ofs;
+
/* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
if (INTVAL (operands[2]) % 8 != 0
|| (INTVAL (operands[1]) != 16
@@ -5081,13 +6306,22 @@
if (GET_CODE (operands[0]) != MEM)
FAIL;
- alpha_expand_unaligned_store (operands[0], operands[3],
- INTVAL (operands[1]) / 8,
- INTVAL (operands[2]) / 8);
- DONE;
-}")
+ /* The bit number is relative to the mode of operand 1 which is
+ usually QImode (this might actually be a bug in expmed.c). Note
+ that the bit number is negative in big-endian mode in this case.
+ We have to convert that to the offset. */
+ if (WORDS_BIG_ENDIAN)
+ ofs = GET_MODE_BITSIZE (GET_MODE (operands[0]))
+ - INTVAL (operands[1]) - INTVAL (operands[2]);
+ else
+ ofs = INTVAL (operands[2]);
+ ofs = ofs / 8;
+ alpha_expand_unaligned_store (operands[0], operands[3],
+ INTVAL (operands[1]) / 8, ofs);
+ DONE;
+})
;; Block move/clear, see alpha.c for more details.
;; Argument 0 is the destination
@@ -5096,52 +6330,49 @@
;; Argument 3 is the alignment
(define_expand "movstrqi"
- [(parallel [(set (match_operand:BLK 0 "general_operand" "")
- (match_operand:BLK 1 "general_operand" ""))
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
(use (match_operand:DI 2 "immediate_operand" ""))
(use (match_operand:DI 3 "immediate_operand" ""))])]
""
- "
{
if (alpha_expand_block_move (operands))
DONE;
else
FAIL;
-}")
+})
(define_expand "clrstrqi"
- [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand:DI 1 "immediate_operand" ""))
(use (match_operand:DI 2 "immediate_operand" ""))])]
""
- "
{
if (alpha_expand_block_clear (operands))
DONE;
else
FAIL;
-}")
+})
;; Subroutine of stack space allocation. Perform a stack probe.
(define_expand "probe_stack"
[(set (match_dup 1) (match_operand:DI 0 "const_int_operand" ""))]
""
- "
{
operands[1] = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx,
INTVAL (operands[0])));
MEM_VOLATILE_P (operands[1]) = 1;
operands[0] = const0_rtx;
-}")
+})
;; This is how we allocate stack space. If we are allocating a
;; constant amount of space and we know it is less than 4096
;; bytes, we need do nothing.
;;
;; If it is more than 4096 bytes, we need to probe the stack
-;; periodically.
+;; periodically.
(define_expand "allocate_stack"
[(set (reg:DI 30)
(plus:DI (reg:DI 30)
@@ -5149,7 +6380,6 @@
(set (match_operand:DI 0 "register_operand" "=r")
(match_dup 2))]
""
- "
{
if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) < 32768)
@@ -5198,8 +6428,6 @@
emit_insn (gen_adddi3 (tmp, tmp, GEN_INT(-8192)));
emit_insn (gen_cmpdi (tmp, want));
emit_jump_insn (gen_bgtu (loop_label));
- if (obey_regdecls)
- gen_rtx_USE (VOIDmode, tmp);
memref = gen_rtx_MEM (DImode, want);
MEM_VOLATILE_P (memref) = 1;
@@ -5212,74 +6440,150 @@
emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
DONE;
}
-}")
+})
;; This is used by alpha_expand_prolog to do the same thing as above,
;; except we cannot at that time generate new basic blocks, so we hide
;; the loop in this one insn.
(define_insn "prologue_stack_probe_loop"
- [(unspec_volatile [(match_operand 0 "register_operand" "r")
- (match_operand 1 "register_operand" "r")] 5)]
+ [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "register_operand" "r")]
+ UNSPECV_PSPL)]
""
- "*
{
operands[2] = gen_label_rtx ();
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (operands[2]));
- return \"stq $31,-8192(%1)\;subq %0,1,%0\;lda %1,-8192(%1)\;bne %0,%l2\";
-}"
+ return "stq $31,-8192(%1)\;subq %0,1,%0\;lda %1,-8192(%1)\;bne %0,%l2";
+}
[(set_attr "length" "16")
(set_attr "type" "multi")])
(define_expand "prologue"
[(clobber (const_int 0))]
""
- "alpha_expand_prologue (); DONE;")
+{
+ alpha_expand_prologue ();
+ DONE;
+})
+
+;; These take care of emitting the ldgp insn in the prologue. This will be
+;; an lda/ldah pair and we want to align them properly. So we have two
+;; unspec_volatile insns, the first of which emits the ldgp assembler macro
+;; and the second of which emits nothing. However, both are marked as type
+;; IADD (the default) so the alignment code in alpha.c does the right thing
+;; with them.
+
+(define_expand "prologue_ldgp"
+ [(set (match_dup 0)
+ (unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1))
+ (set (match_dup 0)
+ (unspec_volatile:DI [(match_dup 0) (match_dup 2)] UNSPECV_PLDGP2))]
+ ""
+{
+ operands[0] = pic_offset_table_rtx;
+ operands[1] = gen_rtx_REG (Pmode, 27);
+ operands[2] = (TARGET_EXPLICIT_RELOCS
+ ? GEN_INT (alpha_next_sequence_number++)
+ : const0_rtx);
+})
+
+(define_insn "*ldgp_er_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "")]
+ UNSPECV_LDGP1))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "ldah %0,0(%1)\t\t!gpdisp!%2")
+
+(define_insn "*ldgp_er_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "")]
+ UNSPEC_LDGP2))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "lda %0,0(%1)\t\t!gpdisp!%2")
+
+(define_insn "*prologue_ldgp_er_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "")]
+ UNSPECV_PLDGP2))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "lda %0,0(%1)\t\t!gpdisp!%2\n$%~..ng:")
+
+(define_insn "*prologue_ldgp_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "")]
+ UNSPECV_LDGP1))]
+ ""
+ "ldgp %0,0(%1)\n$%~..ng:")
+
+(define_insn "*prologue_ldgp_2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "")]
+ UNSPECV_PLDGP2))]
+ ""
+ "")
+
+;; The _mcount profiling hook has special calling conventions, and
+;; does not clobber all the registers that a normal call would. So
+;; hide the fact this is a call at all.
+
+(define_insn "prologue_mcount"
+ [(unspec_volatile [(const_int 0)] UNSPECV_MCOUNT)]
+ ""
+{
+ if (TARGET_EXPLICIT_RELOCS)
+ /* Note that we cannot use a lituse_jsr reloc, since _mcount
+ cannot be called via the PLT. */
+ return "ldq $28,_mcount($29)\t\t!literal\;jsr $28,($28),_mcount";
+ else
+ return "lda $28,_mcount\;jsr $28,($28),_mcount";
+}
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
(define_insn "init_fp"
- [(set (match_operand:DI 0 "register_operand" "r")
+ [(set (match_operand:DI 0 "register_operand" "=r")
(match_operand:DI 1 "register_operand" "r"))
- (clobber (mem:BLK (match_operand:DI 2 "register_operand" "r")))]
+ (clobber (mem:BLK (match_operand:DI 2 "register_operand" "=r")))]
""
- "mov %1,%0")
+ "bis $31,%1,%0")
(define_expand "epilogue"
- [(clobber (const_int 0))]
+ [(return)]
""
- "alpha_expand_epilogue (); DONE;")
+{
+ alpha_expand_epilogue ();
+})
-(define_expand "eh_epilogue"
- [(use (match_operand:DI 0 "register_operand" "r"))
- (use (match_operand:DI 1 "register_operand" "r"))
- (use (match_operand:DI 2 "register_operand" "r"))]
- "! TARGET_OPEN_VMS"
- "
+(define_expand "sibcall_epilogue"
+ [(return)]
+ "TARGET_ABI_OSF"
{
- alpha_eh_epilogue_sp_ofs = operands[1];
- if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 26)
- {
- rtx ra = gen_rtx_REG (Pmode, 26);
- emit_move_insn (ra, operands[2]);
- operands[2] = ra;
- }
-}")
+ alpha_expand_epilogue ();
+ DONE;
+})
;; In creating a large stack frame, NT _must_ use ldah+lda to load
;; the frame size into a register. We use this pattern to ensure
;; we get lda instead of addq.
(define_insn "nt_lda"
- [(set (match_operand:DI 0 "register_operand" "r")
+ [(set (match_operand:DI 0 "register_operand" "=r")
(unspec:DI [(match_dup 0)
- (match_operand:DI 1 "const_int_operand" "n")] 6))]
+ (match_operand:DI 1 "const_int_operand" "n")]
+ UNSPEC_NT_LDA))]
""
"lda %0,%1(%0)")
(define_expand "builtin_longjmp"
- [(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)]
- "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
- "
+ [(use (match_operand:DI 0 "register_operand" "r"))]
+ "TARGET_ABI_OSF"
{
/* The elements of the buffer are, in order: */
rtx fp = gen_rtx_MEM (Pmode, operands[0]);
@@ -5297,41 +6601,123 @@
/* Load the label we are jumping through into $27 so that we know
where to look for it when we get back to setjmp's function for
restoring the gp. */
- emit_indirect_jump (pv);
+ emit_jump_insn (gen_builtin_longjmp_internal (pv));
+ emit_barrier ();
DONE;
-}")
+})
-(define_insn "builtin_setjmp_receiver"
- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] 2)]
- "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT && TARGET_AS_CAN_SUBTRACT_LABELS"
- "\\n$LSJ%=:\;ldgp $29,$LSJ%=-%l0($27)"
- [(set_attr "length" "8")
- (set_attr "type" "multi")])
+;; This is effectively a copy of indirect_jump, but constrained such
+;; that register renaming cannot foil our cunning plan with $27.
+(define_insn "builtin_longjmp_internal"
+ [(set (pc)
+ (unspec_volatile [(match_operand:DI 0 "register_operand" "c")]
+ UNSPECV_LONGJMP))]
+ ""
+ "jmp $31,(%0),0"
+ [(set_attr "type" "ibr")])
-(define_insn ""
- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] 2)]
- "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
- "br $29,$LSJ%=\\n$LSJ%=:\;ldgp $29,0($29)"
+(define_insn "*builtin_setjmp_receiver_er_sl_1"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && TARGET_AS_CAN_SUBTRACT_LABELS"
+ "lda $27,$LSJ%=-%l0($27)\n$LSJ%=:")
+
+(define_insn "*builtin_setjmp_receiver_er_1"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "br $27,$LSJ%=\n$LSJ%=:"
+ [(set_attr "type" "ibr")])
+
+(define_split
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF
+ && prev_nonnote_insn (insn) == operands[0]"
+ [(const_int 0)]
+ "DONE;")
+
+(define_insn "*builtin_setjmp_receiver_1"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_ABI_OSF"
+ "br $27,$LSJ%=\n$LSJ%=:\;ldgp $29,0($27)"
[(set_attr "length" "12")
(set_attr "type" "multi")])
-(define_insn "exception_receiver"
- [(unspec_volatile [(const_int 0)] 7)]
- "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
- "br $29,$LSJ%=\\n$LSJ%=:\;ldgp $29,0($29)"
- [(set_attr "length" "12")
+(define_expand "builtin_setjmp_receiver_er"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)
+ (set (match_dup 1)
+ (unspec_volatile:DI [(match_dup 2) (match_dup 3)] UNSPECV_LDGP1))
+ (set (match_dup 1)
+ (unspec:DI [(match_dup 1) (match_dup 3)] UNSPEC_LDGP2))]
+ ""
+{
+ operands[1] = pic_offset_table_rtx;
+ operands[2] = gen_rtx_REG (Pmode, 27);
+ operands[3] = GEN_INT (alpha_next_sequence_number++);
+})
+
+(define_expand "builtin_setjmp_receiver"
+ [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)]
+ "TARGET_ABI_OSF"
+{
+ if (TARGET_EXPLICIT_RELOCS)
+ {
+ emit_insn (gen_builtin_setjmp_receiver_er (operands[0]));
+ DONE;
+ }
+})
+
+(define_expand "exception_receiver_er"
+ [(set (match_dup 0)
+ (unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1))
+ (set (match_dup 0)
+ (unspec:DI [(match_dup 0) (match_dup 2)] UNSPEC_LDGP2))]
+ ""
+{
+ operands[0] = pic_offset_table_rtx;
+ operands[1] = gen_rtx_REG (Pmode, 26);
+ operands[2] = GEN_INT (alpha_next_sequence_number++);
+})
+
+(define_expand "exception_receiver"
+ [(unspec_volatile [(match_dup 0)] UNSPECV_EHR)]
+ "TARGET_ABI_OSF"
+{
+ if (TARGET_LD_BUGGY_LDGP)
+ operands[0] = alpha_gp_save_rtx ();
+ else if (TARGET_EXPLICIT_RELOCS)
+ {
+ emit_insn (gen_exception_receiver_er ());
+ DONE;
+ }
+ else
+ operands[0] = const0_rtx;
+})
+
+(define_insn "*exception_receiver_1"
+ [(unspec_volatile [(const_int 0)] UNSPECV_EHR)]
+ "! TARGET_LD_BUGGY_LDGP"
+ "ldgp $29,0($26)"
+ [(set_attr "length" "8")
(set_attr "type" "multi")])
+(define_insn "*exception_receiver_2"
+ [(unspec_volatile [(match_operand:DI 0 "nonimmediate_operand" "r,m")]
+ UNSPECV_EHR)]
+ "TARGET_LD_BUGGY_LDGP"
+ "@
+ bis $31,%0,$29
+ ldq $29,%0"
+ [(set_attr "type" "ilog,ild")])
+
(define_expand "nonlocal_goto_receiver"
- [(unspec_volatile [(const_int 0)] 1)
+ [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
(set (reg:DI 27) (mem:DI (reg:DI 29)))
- (unspec_volatile [(const_int 0)] 1)
+ (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
(use (reg:DI 27))]
- "TARGET_OPEN_VMS"
+ "TARGET_ABI_OPEN_VMS"
"")
(define_insn "arg_home"
- [(unspec [(const_int 0)] 0)
+ [(unspec [(const_int 0)] UNSPEC_ARG_HOME)
(use (reg:DI 1))
(use (reg:DI 25))
(use (reg:DI 16))
@@ -5350,66 +6736,335 @@
(clobber (reg:DI 24))
(clobber (reg:DI 25))
(clobber (reg:DI 0))]
- "TARGET_OPEN_VMS"
+ "TARGET_ABI_OPEN_VMS"
"lda $0,OTS$HOME_ARGS\;ldq $0,8($0)\;jsr $0,OTS$HOME_ARGS"
[(set_attr "length" "16")
(set_attr "type" "multi")])
-;; Close the trap shadow of preceeding instructions. This is generated
+;; Load the CIW into r2 for calling __T3E_MISMATCH
+
+(define_expand "umk_mismatch_args"
+ [(set:DI (match_dup 1) (mem:DI (plus:DI (reg:DI 15) (const_int -16))))
+ (set:DI (match_dup 2) (mem:DI (plus:DI (match_dup 1) (const_int -32))))
+ (set:DI (reg:DI 1) (match_operand:DI 0 "const_int_operand" ""))
+ (set:DI (match_dup 3) (plus:DI (mult:DI (reg:DI 25)
+ (const_int 8))
+ (match_dup 2)))
+ (set:DI (reg:DI 2) (mem:DI (match_dup 3)))]
+ "TARGET_ABI_UNICOSMK"
+{
+ operands[1] = gen_reg_rtx (DImode);
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+})
+
+(define_insn "arg_home_umk"
+ [(unspec [(const_int 0)] UNSPEC_ARG_HOME)
+ (use (reg:DI 1))
+ (use (reg:DI 2))
+ (use (reg:DI 16))
+ (use (reg:DI 17))
+ (use (reg:DI 18))
+ (use (reg:DI 19))
+ (use (reg:DI 20))
+ (use (reg:DI 21))
+ (use (reg:DI 48))
+ (use (reg:DI 49))
+ (use (reg:DI 50))
+ (use (reg:DI 51))
+ (use (reg:DI 52))
+ (use (reg:DI 53))
+ (clobber (mem:BLK (const_int 0)))
+ (parallel [
+ (clobber (reg:DI 22))
+ (clobber (reg:DI 23))
+ (clobber (reg:DI 24))
+ (clobber (reg:DI 0))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DI 3))
+ (clobber (reg:DI 4))
+ (clobber (reg:DI 5))
+ (clobber (reg:DI 6))
+ (clobber (reg:DI 7))
+ (clobber (reg:DI 8))])]
+ "TARGET_ABI_UNICOSMK"
+ "laum $4,__T3E_MISMATCH($31)\;sll $4,32,$4\;lalm $4,__T3E_MISMATCH($4)\;lal $4,__T3E_MISMATCH($4)\;jsr $3,($4)"
+ [(set_attr "length" "16")
+ (set_attr "type" "multi")])
+
+;; Prefetch data.
+;;
+;; On EV4, these instructions are nops -- no load occurs.
+;;
+;; On EV5, these instructions act as a normal load, and thus can trap
+;; if the address is invalid. The OS may (or may not) handle this in
+;; the entMM fault handler and suppress the fault. If so, then this
+;; has the effect of a read prefetch instruction.
+;;
+;; On EV6, these become official prefetch instructions.
+
+(define_insn "prefetch"
+ [(prefetch (match_operand:DI 0 "address_operand" "p")
+ (match_operand:DI 1 "const_int_operand" "n")
+ (match_operand:DI 2 "const_int_operand" "n"))]
+ "TARGET_FIXUP_EV5_PREFETCH || TARGET_CPU_EV6"
+{
+ /* Interpret "no temporal locality" as this data should be evicted once
+ it is used. The "evict next" alternatives load the data into the cache
+ and leave the LRU eviction counter pointing to that block. */
+ static const char * const alt[2][2] = {
+ {
+ "lds $f31,%a0", /* read, evict next */
+ "ldl $31,%a0", /* read, evict last */
+ },
+ {
+ "ldt $f31,%a0", /* write, evict next */
+ "ldq $31,%a0", /* write, evict last */
+ }
+ };
+
+ bool write = INTVAL (operands[1]) != 0;
+ bool lru = INTVAL (operands[2]) != 0;
+
+ return alt[write][lru];
+}
+ [(set_attr "type" "ild")])
+
+;; Close the trap shadow of preceding instructions. This is generated
;; by alpha_reorg.
(define_insn "trapb"
- [(unspec_volatile [(const_int 0)] 4)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_TRAPB)]
""
"trapb"
[(set_attr "type" "misc")])
-;; No-op instructions used by machine-dependant reorg to preserve
+;; No-op instructions used by machine-dependent reorg to preserve
;; alignment for instruction issue.
+;; The Unicos/Mk assembler does not support these opcodes.
(define_insn "nop"
[(const_int 0)]
""
- "nop"
+ "bis $31,$31,$31"
[(set_attr "type" "ilog")])
(define_insn "fnop"
[(const_int 1)]
"TARGET_FP"
- "fnop"
+ "cpys $f31,$f31,$f31"
[(set_attr "type" "fcpys")])
(define_insn "unop"
[(const_int 2)]
""
- "unop")
+ "ldq_u $31,0($30)")
+
+;; On Unicos/Mk we use a macro for aligning code.
(define_insn "realign"
- [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] 6)]
+ [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
+ UNSPECV_REALIGN)]
""
- ".align %0 #realign")
-
-;; Peepholes go at the end.
+{
+ if (TARGET_ABI_UNICOSMK)
+ return "gcc@code@align %0";
+ else
+ return ".align %0 #realign";
+})
+
+;; The call patterns are at the end of the file because their
+;; wildcard operand0 interferes with nice recognition.
+
+(define_insn "*call_value_osf_1_er"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s"))
+ (match_operand 2 "" "")))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ jsr $26,(%1),0\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*
+ bsr $26,$%1..ng
+ ldq $27,%1($29)\t\t!literal!%#\;jsr $26,($27),0\t\t!lituse_jsr!%#\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,*,16")])
+
+;; We must use peep2 instead of a split because we need accurate life
+;; information for $gp. Consider the case of { bar(); while (1); }.
+(define_peephole2
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" ""))
+ (match_operand 2 "" "")))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))])]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed
+ && ! current_file_function_operand (operands[1], Pmode)
+ && peep2_regno_dead_p (1, 29)"
+ [(parallel [(set (match_dup 0)
+ (call (mem:DI (match_dup 3))
+ (match_dup 2)))
+ (set (reg:DI 26) (plus:DI (pc) (const_int 4)))
+ (unspec_volatile [(reg:DI 29)] UNSPECV_BLOCKAGE)
+ (use (match_dup 1))
+ (use (match_dup 4))])]
+{
+ if (CONSTANT_P (operands[1]))
+ {
+ operands[3] = gen_rtx_REG (Pmode, 27);
+ operands[4] = GEN_INT (alpha_next_sequence_number++);
+ emit_insn (gen_movdi_er_high_g (operands[3], pic_offset_table_rtx,
+ operands[1], operands[4]));
+ }
+ else
+ {
+ operands[3] = operands[1];
+ operands[1] = const0_rtx;
+ operands[4] = const0_rtx;
+ }
+})
+
+(define_peephole2
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" ""))
+ (match_operand 2 "" "")))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))])]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed
+ && ! current_file_function_operand (operands[1], Pmode)
+ && ! peep2_regno_dead_p (1, 29)"
+ [(parallel [(set (match_dup 0)
+ (call (mem:DI (match_dup 3))
+ (match_dup 2)))
+ (set (reg:DI 26) (plus:DI (pc) (const_int 4)))
+ (unspec_volatile [(reg:DI 29)] UNSPECV_BLOCKAGE)
+ (use (match_dup 1))
+ (use (match_dup 5))])
+ (set (reg:DI 29)
+ (unspec_volatile:DI [(reg:DI 26) (match_dup 4)] UNSPECV_LDGP1))
+ (set (reg:DI 29)
+ (unspec:DI [(reg:DI 29) (match_dup 4)] UNSPEC_LDGP2))]
+{
+ if (CONSTANT_P (operands[1]))
+ {
+ operands[3] = gen_rtx_REG (Pmode, 27);
+ operands[5] = GEN_INT (alpha_next_sequence_number++);
+ emit_insn (gen_movdi_er_high_g (operands[3], pic_offset_table_rtx,
+ operands[1], operands[5]));
+ }
+ else
+ {
+ operands[3] = operands[1];
+ operands[1] = const0_rtx;
+ operands[5] = const0_rtx;
+ }
+ operands[4] = GEN_INT (alpha_next_sequence_number++);
+})
+
+;; We add a blockage unspec_volatile to prevent insns from moving down
+;; from above the call to in between the call and the ldah gpdisp.
+(define_insn "*call_value_osf_2_er"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "register_operand" "c"))
+ (match_operand 2 "" "")))
+ (set (reg:DI 26)
+ (plus:DI (pc) (const_int 4)))
+ (unspec_volatile [(reg:DI 29)] UNSPECV_BLOCKAGE)
+ (use (match_operand 3 "" ""))
+ (use (match_operand 4 "const_int_operand" ""))]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "jsr $26,(%1),%3%J4"
+ [(set_attr "type" "jsr")])
+
+(define_insn "*call_value_osf_1_noreturn"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s"))
+ (match_operand 2 "" "")))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))]
+ "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ "@
+ jsr $26,($27),0
+ bsr $26,$%1..ng
+ jsr $26,%1"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,*,8")])
+
+(define_insn "*call_value_osf_1"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s"))
+ (match_operand 2 "" "")))
+ (use (reg:DI 29))
+ (clobber (reg:DI 26))]
+ "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ jsr $26,($27),0\;ldgp $29,0($26)
+ bsr $26,$%1..ng
+ jsr $26,%1\;ldgp $29,0($26)"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,*,16")])
+
+(define_insn "*sibcall_value_osf_1_er"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "symbolic_operand" "R,s"))
+ (match_operand 2 "" "")))
+ (unspec [(reg:DI 29)] UNSPEC_SIBCALL)]
+ "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ br $31,$%1..ng
+ ldq $27,%1($29)\t\t!literal!%#\;jmp $31,($27),%1\t\t!lituse_jsr!%#"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,8")])
+
+(define_insn "*sibcall_value_osf_1"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "symbolic_operand" "R,s"))
+ (match_operand 2 "" "")))
+ (unspec [(reg:DI 29)] UNSPEC_SIBCALL)]
+ "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF"
+ "@
+ br $31,$%1..ng
+ lda $27,%1\;jmp $31,($27),%1"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,8")])
+
+(define_insn "*call_value_nt_1"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,s"))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 26))]
+ "TARGET_ABI_WINDOWS_NT"
+ "@
+ jsr $26,(%1)
+ bsr $26,%1
+ jsr $26,%1"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,*,12")])
+
+(define_insn "*call_value_vms_1"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "r,s"))
+ (match_operand 2 "" "")))
+ (use (match_operand:DI 3 "nonimmediate_operand" "r,m"))
+ (use (reg:DI 25))
+ (use (reg:DI 26))
+ (clobber (reg:DI 27))]
+ "TARGET_ABI_OPEN_VMS"
+ "@
+ mov %3,$27\;jsr $26,0\;ldq $27,0($29)
+ ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,16")])
+
+(define_insn "*call_value_umk"
+ [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "r"))
+ (match_operand 2 "" "")))
+ (use (reg:DI 25))
+ (clobber (reg:DI 26))]
+ "TARGET_ABI_UNICOSMK"
+ "jsr $26,(%1)"
+ [(set_attr "type" "jsr")])
-;; Optimize sign-extension of SImode loads. This shows up in the wake of
-;; reload when converting fp->int.
-;;
-;; ??? What to do now that we actually care about the packing and
-;; alignment of instructions? Perhaps reload can be enlightened, or
-;; the peephole pass moved up after reload but before sched2?
-;
-;(define_peephole
-; [(set (match_operand:SI 0 "register_operand" "=r")
-; (match_operand:SI 1 "memory_operand" "m"))
-; (set (match_operand:DI 2 "register_operand" "=r")
-; (sign_extend:DI (match_dup 0)))]
-; "dead_or_set_p (insn, operands[0])"
-; "ldl %2,%1")
-;
-;(define_peephole
-; [(set (match_operand:SI 0 "register_operand" "=r")
-; (match_operand:SI 1 "hard_fp_register_operand" "f"))
-; (set (match_operand:DI 2 "register_operand" "=r")
-; (sign_extend:DI (match_dup 0)))]
-; "TARGET_FIX && dead_or_set_p (insn, operands[0])"
-; "ftois %1,%2")
diff --git a/contrib/gcc/config/alpha/alpha32.h b/contrib/gcc/config/alpha/alpha32.h
index 3cbcfe1..8d9df0b 100644
--- a/contrib/gcc/config/alpha/alpha32.h
+++ b/contrib/gcc/config/alpha/alpha32.h
@@ -30,13 +30,13 @@ 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. */
-#undef TARGET_WINDOWS_NT
-#define TARGET_WINDOWS_NT 1
+#undef TARGET_ABI_WINDOWS_NT
+#define TARGET_ABI_WINDOWS_NT 1
/* WinNT (and thus Interix) use unsigned int */
#define SIZE_TYPE "unsigned int"
-/* Pointer is 32 bits but the hardware has 64-bit addresses, sign extended. */
+/* Pointer is 32 bits but the hardware has 64-bit addresses, sign extended. */
#undef POINTER_SIZE
#define POINTER_SIZE 32
#define POINTERS_EXTEND_UNSIGNED 0
@@ -71,34 +71,15 @@ Boston, MA 02111-1307, USA. */
#undef TRAMPOLINE_SIZE
#define TRAMPOLINE_SIZE 24
+/* The alignment of a trampoline, in bits. */
+
+#undef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT 32
+
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
- CXT is an RTX for the static chain value for the function. */
+ CXT is an RTX for the static chain value for the function. */
#undef INITIALIZE_TRAMPOLINE
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
alpha_initialize_trampoline (TRAMP, FNADDR, CXT, 20, 16, 12)
-
-/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
- Used for C++ multiple inheritance. */
-
-#undef ASM_OUTPUT_MI_THUNK
-#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
-do { \
- char *op, *fn_name = XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0); \
- int reg; \
- \
- /* Mark end of prologue. */ \
- output_end_prologue (FILE); \
- \
- /* Rely on the assembler to macro expand a large delta. */ \
- reg = aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? 17 : 16; \
- fprintf (FILE, "\tlda $%d,%ld($%d)\n", reg, (long)(DELTA), reg); \
- \
- op = "jsr"; \
- if (current_file_function_operand (XEXP (DECL_RTL (FUNCTION), 0))) \
- op = "br"; \
- fprintf (FILE, "\t%s $31,", op); \
- assemble_name (FILE, fn_name); \
- fputc ('\n', FILE); \
-} while (0)
diff --git a/contrib/gcc/config/alpha/crtfastmath.c b/contrib/gcc/config/alpha/crtfastmath.c
new file mode 100644
index 0000000..4651ee7
--- /dev/null
+++ b/contrib/gcc/config/alpha/crtfastmath.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ * Contributed by Richard Henderson (rth@redhat.com)
+ *
+ * This file 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.
+ *
+ * In addition to the permissions in the GNU General Public License, the
+ * Free Software Foundation gives you unlimited permission to link the
+ * compiled version of this file with other programs, and to distribute
+ * those programs without any restriction coming from the use of this
+ * file. (The General Public License restrictions do apply in other
+ * respects; for example, they cover modification of the file, and
+ * distribution when not linked into another program.)
+ *
+ * This file 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 this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * As a special exception, if you link this library with files
+ * compiled with GCC to produce an executable, this does not cause
+ * the resulting executable to be covered by the GNU General Public License.
+ * This exception does not however invalidate any other reasons why
+ * the executable file might be covered by the GNU General Public License.
+ */
+
+/* Assume OSF/1 compatible interfaces. */
+
+extern void __ieee_set_fp_control (unsigned long int);
+
+#define IEEE_MAP_DMZ (1UL<<12) /* Map denorm inputs to zero */
+#define IEEE_MAP_UMZ (1UL<<13) /* Map underflowed outputs to zero */
+
+static void __attribute__((constructor))
+set_fast_math (void)
+{
+ __ieee_set_fp_control (IEEE_MAP_DMZ | IEEE_MAP_UMZ);
+}
diff --git a/contrib/gcc/config/alpha/elf.h b/contrib/gcc/config/alpha/elf.h
index 6cea3da..cf33a9e 100644
--- a/contrib/gcc/config/alpha/elf.h
+++ b/contrib/gcc/config/alpha/elf.h
@@ -1,5 +1,6 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha w/ELF.
- Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
Contributed by Richard Henderson (rth@tamu.edu).
This file is part of GNU CC.
@@ -23,21 +24,24 @@ Boston, MA 02111-1307, USA. */
#undef EXTENDED_COFF
#define OBJECT_FORMAT_ELF
+/* ??? Move all SDB stuff from alpha.h to osf.h. */
+#undef SDB_DEBUGGING_INFO
+
#define DBX_DEBUGGING_INFO
#define DWARF2_DEBUGGING_INFO
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
#undef ASM_FINAL_SPEC
-#undef CC1_SPEC
+#undef CC1_SPEC
#define CC1_SPEC "%{G*}"
-#undef ASM_SPEC
-#define ASM_SPEC "%{G*} %{relax:-relax} %{gdwarf*:-no-mdebug}"
+#undef ASM_SPEC
+#define ASM_SPEC "%{G*} %{relax:-relax} %{!gstabs*:-no-mdebug}%{gstabs*:-mdebug}"
-#undef LINK_SPEC
+#undef LINK_SPEC
#define LINK_SPEC "-m elf64alpha %{G*} %{relax:-relax} \
%{O*:-O3} %{!O*:-O1} \
%{shared:-shared} \
@@ -48,62 +52,46 @@ Boston, MA 02111-1307, USA. */
%{static:-static}}"
/* Output at beginning of assembler file. */
-#undef ASM_FILE_START
+#undef ASM_FILE_START
#define ASM_FILE_START(FILE) \
do { \
- if (write_symbols != DWARF2_DEBUG) \
+ if (write_symbols == DBX_DEBUG) \
{ \
alpha_write_verstamp (FILE); \
output_file_directive (FILE, main_input_filename); \
} \
fprintf (FILE, "\t.set noat\n"); \
fprintf (FILE, "\t.set noreorder\n"); \
+ if (TARGET_EXPLICIT_RELOCS) \
+ fprintf (FILE, "\t.set nomacro\n"); \
if (TARGET_BWX | TARGET_MAX | TARGET_FIX | TARGET_CIX) \
{ \
fprintf (FILE, "\t.arch %s\n", \
- (alpha_cpu == PROCESSOR_EV6 ? "ev6" \
+ (TARGET_CPU_EV6 ? "ev6" \
: TARGET_MAX ? "pca56" : "ev56")); \
} \
} while (0)
-extern void output_file_directive ();
-
-/* Attach a special .ident directive to the end of the file to identify
- the version of GCC which compiled this code. The format of the
- .ident string is patterned after the ones produced by native svr4
- C compilers. */
-
-#define IDENT_ASM_OP ".ident"
-
-#ifdef IDENTIFY_WITH_IDENT
-#define ASM_IDENTIFY_GCC(FILE) /* nothing */
-#define ASM_IDENTIFY_LANGUAGE(FILE) \
- fprintf(FILE, "\t%s \"GCC (%s) %s\"\n", IDENT_ASM_OP, \
- lang_identify(), version_string)
-#else
-#define ASM_FILE_END(FILE) \
-do { \
- if (!flag_no_ident) \
- fprintf ((FILE), "\t%s\t\"GCC: (GNU) %s\"\n", \
- IDENT_ASM_OP, version_string); \
- } while (0)
-#endif
+#undef IDENT_ASM_OP
+#define IDENT_ASM_OP "\t.ident\t"
/* Allow #sccs in preprocessor. */
#define SCCS_DIRECTIVE
/* Output #ident as a .ident. */
+#undef ASM_OUTPUT_IDENT
#define ASM_OUTPUT_IDENT(FILE, NAME) \
- fprintf (FILE, "\t%s\t\"%s\"\n", IDENT_ASM_OP, NAME);
+ fprintf (FILE, "%s\"%s\"\n", IDENT_ASM_OP, NAME);
/* This is how to allocate empty space in some section. The .zero
pseudo-op is used for this on most svr4 assemblers. */
-#define SKIP_ASM_OP ".zero"
+#undef SKIP_ASM_OP
+#define SKIP_ASM_OP "\t.zero\t"
-#undef ASM_OUTPUT_SKIP
-#define ASM_OUTPUT_SKIP(FILE,SIZE) \
- fprintf (FILE, "\t%s\t%u\n", SKIP_ASM_OP, (SIZE))
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE, SIZE) \
+ fprintf (FILE, "%s%u\n", SKIP_ASM_OP, (SIZE))
/* Output the label which precedes a jumptable. Note that for all svr4
systems where we actually generate jumptables (which is to say every
@@ -113,15 +101,16 @@ do { \
make sure that the location counter for the .rodata section gets pro-
perly re-aligned prior to the actual beginning of the jump table. */
-#define ALIGN_ASM_OP ".align"
+#undef ALIGN_ASM_OP
+#define ALIGN_ASM_OP "\t.align\t"
#ifndef ASM_OUTPUT_BEFORE_CASE_LABEL
-#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \
+#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) \
ASM_OUTPUT_ALIGN ((FILE), 2);
#endif
-#undef ASM_OUTPUT_CASE_LABEL
-#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, JUMPTABLE) \
do { \
ASM_OUTPUT_BEFORE_CASE_LABEL (FILE, PREFIX, NUM, JUMPTABLE) \
ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \
@@ -131,6 +120,7 @@ do { \
library routines (e.g. .udiv) be explicitly declared as .globl
in each assembly file where they are referenced. */
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
ASM_GLOBALIZE_LABEL (FILE, XSTR (FUN, 0))
@@ -139,12 +129,13 @@ do { \
the linker seems to want the alignment of data objects
to depend on their types. We do exactly that here. */
-#define COMMON_ASM_OP ".comm"
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP "\t.comm\t"
-#undef ASM_OUTPUT_ALIGNED_COMMON
+#undef ASM_OUTPUT_ALIGNED_COMMON
#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
do { \
- fprintf ((FILE), "\t%s\t", COMMON_ASM_OP); \
+ fprintf ((FILE), "%s", COMMON_ASM_OP); \
assemble_name ((FILE), (NAME)); \
fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
} while (0)
@@ -154,21 +145,21 @@ do { \
the linker seems to want the alignment of data objects
to depend on their types. We do exactly that here. */
-#undef ASM_OUTPUT_ALIGNED_LOCAL
+#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
if ((SIZE) <= g_switch_value) \
sbss_section(); \
else \
bss_section(); \
- fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ fprintf (FILE, "%s", TYPE_ASM_OP); \
assemble_name (FILE, NAME); \
putc (',', FILE); \
fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
putc ('\n', FILE); \
if (!flag_inhibit_size_directive) \
{ \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ fprintf (FILE, "%s", SIZE_ASM_OP); \
assemble_name (FILE, NAME); \
fprintf (FILE, ",%d\n", (SIZE)); \
} \
@@ -177,11 +168,6 @@ do { \
ASM_OUTPUT_SKIP((FILE), (SIZE)); \
} while (0)
-/* This is the pseudo-op used to generate a 64-bit word of data with a
- specific value in some section. */
-
-#define INT_ASM_OP ".quad"
-
/* Biggest alignment supported by the object file format of this
machine. Use this macro to limit the alignment which can be
specified using the `__attribute__ ((aligned (N)))' construct. If
@@ -191,6 +177,7 @@ do { \
we could only potentially get to 2^60 on suitible hosts. Due to other
considerations in varasm, we must restrict this to what fits in an int. */
+#undef MAX_OFILE_ALIGNMENT
#define MAX_OFILE_ALIGNMENT \
(1 << (HOST_BITS_PER_INT < 64 ? HOST_BITS_PER_INT - 2 : 62))
@@ -198,8 +185,8 @@ do { \
values from a double-quoted string WITHOUT HAVING A TERMINATING NUL
AUTOMATICALLY APPENDED. This is the same for most svr4 assemblers. */
-#undef ASCII_DATA_ASM_OP
-#define ASCII_DATA_ASM_OP ".ascii"
+#undef ASCII_DATA_ASM_OP
+#define ASCII_DATA_ASM_OP "\t.ascii\t"
/* Support const sections and the ctors and dtors sections for g++.
Note that there appears to be two different ways to support const
@@ -209,32 +196,18 @@ do { \
EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and
SELECT_RTX_SECTION. We do both here just to be on the safe side. */
+#undef USE_CONST_SECTION
#define USE_CONST_SECTION 1
-#define CONST_SECTION_ASM_OP ".section\t.rodata"
-
-/* Define the pseudo-ops used to switch to the .ctors and .dtors sections.
-
- Note that we want to give these sections the SHF_WRITE attribute
- because these sections will actually contain data (i.e. tables of
- addresses of functions in the current root executable or shared library
- file) and, in the case of a shared library, the relocatable addresses
- will have to be properly resolved/relocated (and then written into) by
- the dynamic linker when it actually attaches the given shared library
- to the executing process. (Note that on SVR4, you may wish to use the
- `-z text' option to the ELF linker, when building a shared library, as
- an additional check that you are doing everything right. But if you do
- use the `-z text' option when building a shared library, you will get
- errors unless the .ctors and .dtors sections are marked as writable
- via the SHF_WRITE attribute.) */
-
-#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"aw\""
-#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
+#undef CONST_SECTION_ASM_OP
+#define CONST_SECTION_ASM_OP "\t.section\t.rodata"
-/* Handle the small data sections. */
-#define BSS_SECTION_ASM_OP ".section\t.bss"
-#define SBSS_SECTION_ASM_OP ".section\t.sbss,\"aw\""
-#define SDATA_SECTION_ASM_OP ".section\t.sdata,\"aw\""
+#undef BSS_SECTION_ASM_OP
+#define BSS_SECTION_ASM_OP "\t.section\t.bss"
+#undef SBSS_SECTION_ASM_OP
+#define SBSS_SECTION_ASM_OP "\t.section\t.sbss,\"aw\""
+#undef SDATA_SECTION_ASM_OP
+#define SDATA_SECTION_ASM_OP "\t.section\t.sdata,\"aw\""
/* On svr4, we *do* have support for the .init and .fini sections, and we
can put stuff in there to be executed before and after `main'. We let
@@ -242,123 +215,226 @@ do { \
The definitions say how to change sections to the .init and .fini
sections. This is the same for all known svr4 assemblers. */
-#define INIT_SECTION_ASM_OP ".section\t.init"
-#define FINI_SECTION_ASM_OP ".section\t.fini"
+#undef INIT_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP "\t.section\t.init"
+#undef FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP "\t.section\t.fini"
+
+#ifdef HAVE_GAS_SUBSECTION_ORDERING
+
+#define ASM_SECTION_START_OP "\t.subsection\t-1"
+
+/* Output assembly directive to move to the beginning of current section. */
+#define ASM_OUTPUT_SECTION_START(FILE) \
+ fprintf ((FILE), "%s\n", ASM_SECTION_START_OP)
+
+#endif
/* A default list of other sections which we might be "in" at any given
time. For targets that use additional sections (e.g. .tdesc) you
should override this definition in the target-specific file which
includes this file. */
-#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_const, in_ctors, in_dtors, in_sbss, in_sdata
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_sbss, in_sdata
/* A default list of extra section function definitions. For targets
that use additional sections (e.g. .tdesc) you should override this
definition in the target-specific file which includes this file. */
-#undef EXTRA_SECTION_FUNCTIONS
+#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
CONST_SECTION_FUNCTION \
- SECTION_FUNCTION_TEMPLATE(ctors_section, in_ctors, CTORS_SECTION_ASM_OP) \
- SECTION_FUNCTION_TEMPLATE(dtors_section, in_dtors, DTORS_SECTION_ASM_OP) \
SECTION_FUNCTION_TEMPLATE(sbss_section, in_sbss, SBSS_SECTION_ASM_OP) \
SECTION_FUNCTION_TEMPLATE(sdata_section, in_sdata, SDATA_SECTION_ASM_OP)
-#undef READONLY_DATA_SECTION
-#define READONLY_DATA_SECTION() const_section ()
+extern void sbss_section PARAMS ((void));
+extern void sdata_section PARAMS ((void));
-extern void text_section ();
+#undef READONLY_DATA_SECTION
+#define READONLY_DATA_SECTION() const_section ()
-#define CONST_SECTION_FUNCTION \
-void \
-const_section () \
-{ \
- if (!USE_CONST_SECTION) \
- text_section(); \
- else if (in_section != in_const) \
- { \
- fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \
- in_section = in_const; \
- } \
+#undef CONST_SECTION_FUNCTION
+#define CONST_SECTION_FUNCTION \
+void \
+const_section () \
+{ \
+ if (!USE_CONST_SECTION) \
+ text_section(); \
+ else if (in_section != in_const) \
+ { \
+ fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \
+ in_section = in_const; \
+ } \
}
-#define SECTION_FUNCTION_TEMPLATE(FN, ENUM, OP) \
-void FN () \
-{ \
- if (in_section != ENUM) \
- { \
- fprintf (asm_out_file, "%s\n", OP); \
- in_section = ENUM; \
- } \
+#undef SECTION_FUNCTION_TEMPLATE
+#define SECTION_FUNCTION_TEMPLATE(FN, ENUM, OP) \
+void FN () \
+{ \
+ if (in_section != ENUM) \
+ { \
+ fprintf (asm_out_file, "%s\n", OP); \
+ in_section = ENUM; \
+ } \
}
-
-/* Switch into a generic section.
- This is currently only used to support section attributes.
-
- We make the section read-only and executable for a function decl,
- read-only for a const data decl, and writable for a non-const data decl. */
-#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
- fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, \
- (DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \
- (DECL) && DECL_READONLY_SECTION (DECL, RELOC) ? "a" : "aw")
-
-
-/* A C statement (sans semicolon) to output an element in the table of
- global constructors. */
-#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
- do { \
- ctors_section (); \
- fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, "\n"); \
- } while (0)
-
-/* A C statement (sans semicolon) to output an element in the table of
- global destructors. */
-#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
- do { \
- dtors_section (); \
- fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, "\n"); \
- } while (0)
+/* Switch into a generic section. */
+#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section
/* A C statement or statements to switch to the appropriate
section for output of DECL. DECL is either a `VAR_DECL' node
or a constant of some sort. RELOC indicates whether forming
- the initial value of DECL requires link-time relocations. */
-
-#define SELECT_SECTION(DECL,RELOC) \
-{ \
- if (TREE_CODE (DECL) == STRING_CST) \
+ the initial value of DECL requires link-time relocations.
+
+ Set SECNUM to:
+ 0 .text
+ 1 .rodata
+ 2 .data
+ 3 .sdata
+ 4 .bss
+ 5 .sbss
+*/
+
+#define DO_SELECT_SECTION(SECNUM, DECL, RELOC) \
+ do \
+ { \
+ HOST_WIDE_INT size; \
+ SECNUM = 1; \
+ if (TREE_CODE (DECL) == FUNCTION_DECL) \
+ { \
+ SECNUM = 0; \
+ break; \
+ } \
+ else if (TREE_CODE (DECL) == STRING_CST) \
+ { \
+ if (flag_writable_strings) \
+ SECNUM = 2; \
+ else \
+ SECNUM = 0x101; \
+ break; \
+ } \
+ else if (TREE_CODE (DECL) == VAR_DECL) \
+ { \
+ if (DECL_INITIAL (DECL) == NULL \
+ || DECL_INITIAL (DECL) == error_mark_node) \
+ SECNUM = 4; \
+ else if ((flag_pic && RELOC) \
+ || ! TREE_READONLY (DECL) \
+ || TREE_SIDE_EFFECTS (DECL) \
+ || ! TREE_CONSTANT (DECL_INITIAL (DECL))) \
+ SECNUM = 2; \
+ else if (flag_merge_constants >= 2) \
+ { \
+ /* C and C++ don't allow different variables to \
+ share the same location. -fmerge-all-constants\
+ allows even that (at the expense of not \
+ conforming). */ \
+ if (TREE_CODE (DECL_INITIAL (DECL)) == STRING_CST)\
+ SECNUM = 0x201; \
+ else \
+ SECNUM = 0x301; \
+ } \
+ } \
+ else if (TREE_CODE (DECL) == CONSTRUCTOR) \
+ { \
+ if ((flag_pic && RELOC) \
+ || TREE_SIDE_EFFECTS (DECL) \
+ || ! TREE_CONSTANT (DECL)) \
+ SECNUM = 2; \
+ } \
+ \
+ /* Select small data sections based on size. */ \
+ size = int_size_in_bytes (TREE_TYPE (DECL)); \
+ if (size >= 0 && size <= g_switch_value) \
+ { \
+ if ((SECNUM & 0xff) >= 2) \
+ SECNUM += 1; \
+ /* Move readonly data to .sdata only if -msmall-data. */ \
+ /* ??? Consider .sdata.{lit4,lit8} as \
+ SHF_MERGE|SHF_ALPHA_GPREL. */ \
+ else if (TARGET_SMALL_DATA) \
+ SECNUM = 3; \
+ } \
+ } \
+ while (0)
+
+#undef SELECT_SECTION
+#define SELECT_SECTION(DECL, RELOC, ALIGN) \
+ do \
+ { \
+ typedef void (*sec_fn) PARAMS ((void)); \
+ static sec_fn const sec_functions[6] = \
+ { \
+ text_section, \
+ const_section, \
+ data_section, \
+ sdata_section, \
+ bss_section, \
+ sbss_section \
+ }; \
+ \
+ int sec; \
+ \
+ DO_SELECT_SECTION (sec, DECL, RELOC); \
+ \
+ switch (sec) \
+ { \
+ case 0x101: \
+ mergeable_string_section (DECL, ALIGN, 0); \
+ break; \
+ case 0x201: \
+ mergeable_string_section (DECL_INITIAL (DECL),\
+ ALIGN, 0); \
+ break; \
+ case 0x301: \
+ mergeable_constant_section (DECL_MODE (DECL), \
+ ALIGN, 0); \
+ break; \
+ default: \
+ (*sec_functions[sec]) (); \
+ break; \
+ } \
+ } \
+ while (0)
+
+#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1)
+
+#undef UNIQUE_SECTION
+#define UNIQUE_SECTION(DECL, RELOC) \
+ do \
{ \
- if (! flag_writable_strings) \
- const_section (); \
- else \
- data_section (); \
- } \
- else if (TREE_CODE (DECL) == VAR_DECL) \
- { \
- if ((flag_pic && RELOC) \
- || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
- || !DECL_INITIAL (DECL) \
- || (DECL_INITIAL (DECL) != error_mark_node \
- && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
- { \
- int size = int_size_in_bytes (TREE_TYPE (DECL)); \
- if (size >= 0 && size <= g_switch_value) \
- sdata_section (); \
- else \
- data_section (); \
- } \
- else \
- const_section (); \
+ static const char * const prefixes[6][2] = \
+ { \
+ { ".text.", ".gnu.linkonce.t." }, \
+ { ".rodata.", ".gnu.linkonce.r." }, \
+ { ".data.", ".gnu.linkonce.d." }, \
+ { ".sdata.", ".gnu.linkonce.s." }, \
+ { ".bss.", ".gnu.linkonce.b." }, \
+ { ".sbss.", ".gnu.linkonce.sb." } \
+ }; \
+ \
+ int nlen, plen, sec; \
+ const char *name, *prefix; \
+ char *string; \
+ \
+ DO_SELECT_SECTION (sec, DECL, RELOC); \
+ \
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \
+ STRIP_NAME_ENCODING (name, name); \
+ nlen = strlen (name); \
+ \
+ prefix = prefixes[sec & 0xff][DECL_ONE_ONLY(DECL)]; \
+ plen = strlen (prefix); \
+ \
+ string = alloca (nlen + plen + 1); \
+ \
+ memcpy (string, prefix, plen); \
+ memcpy (string + plen, name, nlen + 1); \
+ \
+ DECL_SECTION_NAME (DECL) = build_string (nlen + plen, string); \
} \
- else \
- const_section (); \
-}
+ while (0)
/* A C statement or statements to switch to the appropriate
section for output of RTX in mode MODE. RTX is some kind
@@ -366,8 +442,15 @@ void FN () \
in the case of a `const_int' rtx. Currently, these always
go into the const section. */
-#undef SELECT_RTX_SECTION
-#define SELECT_RTX_SECTION(MODE,RTX) const_section()
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE, RTX, ALIGN) \
+do { \
+ if (TARGET_SMALL_DATA && GET_MODE_SIZE (MODE) <= g_switch_value) \
+ /* ??? Consider .sdata.{lit4,lit8} as SHF_MERGE|SHF_ALPHA_GPREL. */ \
+ sdata_section (); \
+ else \
+ mergeable_constant_section((MODE), (ALIGN), 0); \
+} while (0)
/* Define the strings used for the special svr4 .type and .size directives.
These strings generally do not vary from one system running svr4 to
@@ -375,18 +458,22 @@ void FN () \
different pseudo-op names for these, they may be overridden in the
file which includes this one. */
-#define TYPE_ASM_OP ".type"
-#define SIZE_ASM_OP ".size"
+#undef TYPE_ASM_OP
+#define TYPE_ASM_OP "\t.type\t"
+#undef SIZE_ASM_OP
+#define SIZE_ASM_OP "\t.size\t"
/* This is how we tell the assembler that a symbol is weak. */
-#define ASM_WEAKEN_LABEL(FILE,NAME) \
+#undef ASM_WEAKEN_LABEL
+#define ASM_WEAKEN_LABEL(FILE, NAME) \
do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
fputc ('\n', FILE); } while (0)
/* This is how we tell the assembler that two symbols have the same value. */
-#define ASM_OUTPUT_DEF(FILE,NAME1,NAME2) \
+#undef ASM_OUTPUT_DEF
+#define ASM_OUTPUT_DEF(FILE, NAME1, NAME2) \
do { assemble_name(FILE, NAME1); \
fputs(" = ", FILE); \
assemble_name(FILE, NAME2); \
@@ -398,6 +485,7 @@ void FN () \
is just a default. You may need to override it in your machine-
specific tm.h file (depending upon the particulars of your assembler). */
+#undef TYPE_OPERAND_FMT
#define TYPE_OPERAND_FMT "@%s"
/* Write the extra assembler code needed to declare a function's result.
@@ -415,22 +503,28 @@ void FN () \
/* Write the extra assembler code needed to declare an object properly. */
-#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
- do { \
- fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
- assemble_name (FILE, NAME); \
- putc (',', FILE); \
- fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
- putc ('\n', FILE); \
- size_directive_output = 0; \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
- { \
- size_directive_output = 1; \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
- } \
- ASM_OUTPUT_LABEL(FILE, NAME); \
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
+ do { \
+ HOST_WIDE_INT size; \
+ fprintf (FILE, "%s", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ size_directive_output = 0; \
+ if (!flag_inhibit_size_directive \
+ && DECL_SIZE (DECL) \
+ && (size = int_size_in_bytes (TREE_TYPE (DECL))) > 0) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "%s", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fputc (',', FILE); \
+ fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, size); \
+ fputc ('\n', FILE); \
+ } \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
} while (0)
/* Output the size directive for a decl in rest_of_decl_compilation
@@ -439,23 +533,26 @@ void FN () \
size_directive_output was set
by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */
+#undef ASM_FINISH_DECLARE_OBJECT
#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
-do { \
- char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
- && ! AT_END && TOP_LEVEL \
- && DECL_INITIAL (DECL) == error_mark_node \
- && !size_directive_output) \
- { \
- size_directive_output = 1; \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, name); \
- putc (',', FILE); \
- fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \
- int_size_in_bytes (TREE_TYPE (DECL))); \
- putc ('\n', FILE); \
- } \
-} while (0)
+ do { \
+ const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ HOST_WIDE_INT size; \
+ if (!flag_inhibit_size_directive \
+ && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output \
+ && (size = int_size_in_bytes (TREE_TYPE (DECL))) > 0) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "%s", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fputc (',', FILE); \
+ fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, size); \
+ fputc ('\n', FILE); \
+ } \
+ } while (0)
/* A table of bytes codes used by the ASM_OUTPUT_ASCII and
ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table
@@ -471,6 +568,7 @@ do { \
the i386) don't know about that. Also, we don't use \v
since some versions of gas, such as 2.2 did not accept it. */
+#undef ESCAPES
#define ESCAPES \
"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
@@ -492,28 +590,29 @@ do { \
If your target assembler doesn't support the .string directive, you
should define this to zero. */
+#undef STRING_LIMIT
#define STRING_LIMIT ((unsigned) 256)
-#define STRING_ASM_OP ".string"
+#undef STRING_ASM_OP
+#define STRING_ASM_OP "\t.string\t"
/* GAS is the only Alpha/ELF assembler. */
-#undef TARGET_GAS
+#undef TARGET_GAS
#define TARGET_GAS (1)
/* Provide a STARTFILE_SPEC appropriate for ELF. Here we add the
(even more) magical crtbegin.o file which provides part of the
- support for getting C++ file-scope static object constructed before
- entering `main'.
+ support for getting C++ file-scope static object constructed
+ before entering `main'.
- Don't bother seeing crtstuff.c -- there is absolutely no hope of
- getting that file to understand multiple GPs. GNU Libc provides a
- hand-coded version that is used on Linux; it could be copied here
- if there is ever a need. */
+ Don't bother seeing crtstuff.c -- there is absolutely no hope
+ of getting that file to understand multiple GPs. We provide a
+ hand-coded assembly version. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC \
"%{!shared: \
%{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}\
- crti.o%s crtbegin.o%s"
+ crti.o%s %{shared:crtbeginS.o%s}%{!shared:crtbegin.o%s}"
/* Provide a ENDFILE_SPEC appropriate for ELF. Here we tack on the
magical crtend.o file which provides part of the support for
@@ -522,13 +621,49 @@ do { \
#undef ENDFILE_SPEC
#define ENDFILE_SPEC \
- "crtend.o%s crtn.o%s"
+ "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
+ %{shared:crtendS.o%s}%{!shared:crtend.o%s} crtn.o%s"
/* We support #pragma. */
#define HANDLE_SYSV_PRAGMA
-/* Undo the auto-alignment stuff from alpha.h. ELF has unaligned data
- pseudos natively. */
-#undef UNALIGNED_SHORT_ASM_OP
-#undef UNALIGNED_INT_ASM_OP
-#undef UNALIGNED_DOUBLE_INT_ASM_OP
+/* Select a format to encode pointers in exception handling data. CODE
+ is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
+ true if the symbol may be affected by dynamic relocations.
+
+ Since application size is already constrained to <2GB by the form of
+ the ldgp relocation, we can use a 32-bit pc-relative relocation to
+ static data. Dynamic data is accessed indirectly to allow for read
+ only EH sections. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
+ (((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4)
+
+/* If defined, a C statement to be executed just prior to the output of
+ assembler code for INSN. */
+#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \
+ (alpha_this_literal_sequence_number = 0, \
+ alpha_this_gpdisp_sequence_number = 0)
+extern int alpha_this_literal_sequence_number;
+extern int alpha_this_gpdisp_sequence_number;
+
+/* Since the bits of the _init and _fini function is spread across
+ many object files, each potentially with its own GP, we must assume
+ we need to load our GP. Further, the .init/.fini section can
+ easily be more than 4MB away from the function to call so we can't
+ use bsr. */
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+ asm (SECTION_OP "\n" \
+" br $29,1f\n" \
+"1: ldgp $29,0($29)\n" \
+" unop\n" \
+" jsr $26," USER_LABEL_PREFIX #FUNC "\n" \
+" .align 3\n" \
+" .previous");
+
+/* If we have the capability create headers for efficient EH lookup.
+ As of Jan 2002, only glibc 2.2.4 can actually make use of this, but
+ I imagine that other systems will catch up. In the meantime, it
+ doesn't harm to make sure that the data exists to be used later. */
+#if defined(HAVE_LD_EH_FRAME_HDR)
+#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
+#endif
diff --git a/contrib/gcc/config/alpha/freebsd.h b/contrib/gcc/config/alpha/freebsd.h
index 24567a6..351fb84 100644
--- a/contrib/gcc/config/alpha/freebsd.h
+++ b/contrib/gcc/config/alpha/freebsd.h
@@ -1,103 +1,91 @@
-/* XXX */
-/*
- * This file was derived from source obtained from NetBSD/Alpha which
- * is publicly available for ftp. The patch was developed by cgd@netbsd.org
- * during the time he worked at CMU. He claims that CMU own this patch
- * to gcc and that they have not (and will not) release the patch for
- * incorporation in FSF sources. We are supposedly able to use the patch,
- * but we are not allowed to forward it back to FSF for inclusion in
- * their source releases.
- *
- * This all has me (jb@freebsd.org) confused because (a) I see no copyright
- * messages that tell me that use is restricted; and (b) I expected that
- * the patch was originally developed from other files which are subject
- * to GPL.
- *
- * Use of this file is restricted until its CMU ownership is tested.
- */
+/* Definitions for DEC Alpha/AXP running FreeBSD using the ELF format
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ Contributed by David E. O'Brien <obrien@FreeBSD.org> and BSDi.
+
+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. */
+
+
+/* Provide a CPP_SPEC appropriate for FreeBSD/alpha. Besides the dealing with
+ the GCC option `-posix', and PIC issues as on all FreeBSD platforms, we must
+ deal with the Alpha's FP issues. */
+
+#undef CPP_SPEC
+#define CPP_SPEC "%(cpp_cpu) \
+ %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} \
+ %{posix:-D_POSIX_SOURCE} \
+ %{mieee:-D_IEEE_FP} \
+ %{mieee-with-inexact:-D_IEEE_FP -D_IEEE_FP_INEXACT}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "-m elf64alpha %{G*} %{relax:-relax} \
+ %{p:%e`-p' not supported; use `-pg' and gprof(1)} \
+ %{Wl,*:%*} \
+ %{assert*} %{R*} %{rpath*} %{defsym*} \
+ %{shared:-Bshareable %{h*} %{soname*}} \
+ %{symbolic:-Bsymbolic} \
+ %{!shared: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \
+ %{static:-Bstatic}}"
+
+/* Provide an ASM_SPEC appropriate for a FreeBSD/Alpha target. This differs
+ from the generic FreeBSD ASM_SPEC in that no special handling of PIC is
+ necessary on the Alpha. */
+/* Per Richard Henderson <rth@cygnus.com>, it is better to use the `.arch'
+ directive in the assembly file. alpha/elf.h gives us this in
+ "ASM_FILE_START".
+#undef ASM_SPEC
+#define ASM_SPEC " %| %{mcpu=*:-m%*}"
+*/
+
+
+/************************[ Target stuff ]***********************************/
+
+/* Define the actual types of some ANSI-mandated types.
+ Needs to agree with <machine/ansi.h>. GCC defaults come from c-decl.c,
+ c-common.c, and config/<arch>/<arch>.h. */
+
+/* alpha.h gets this wrong for FreeBSD. We use the GCC defaults instead. */
+#undef WCHAR_TYPE
+
+#undef WCHAR_UNSIGNED
+#define WCHAR_UNSIGNED 0
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (FreeBSD/alpha ELF)");
+
+#define TARGET_ELF 1
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_FP | MASK_FPREGS | MASK_GAS)
-#include "alpha/alpha.h"
-
-#undef WCHAR_TYPE
-#define WCHAR_TYPE "int"
-
-#undef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE 32
-
-/* FreeBSD-specific things: */
-
-#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-D__FreeBSD__ -D__alpha__ -D__alpha"
-
-/* Look for the include files in the system-defined places. */
-
-#undef GPLUSPLUS_INCLUDE_DIR
-#define GPLUSPLUS_INCLUDE_DIR "/usr/include/g++"
-
-#undef GCC_INCLUDE_DIR
-#define GCC_INCLUDE_DIR "/usr/include"
-
-#undef INCLUDE_DEFAULTS
-#define INCLUDE_DEFAULTS \
- { \
- { GPLUSPLUS_INCLUDE_DIR, 1, 1 }, \
- { GCC_INCLUDE_DIR, 0, 0 }, \
- { 0, 0, 0 } \
- }
-
-
-/* Under FreeBSD, the normal location of the `ld' and `as' programs is the
- /usr/bin directory. */
-
-#undef MD_EXEC_PREFIX
-#define MD_EXEC_PREFIX "/usr/bin/"
-
-/* Under FreeBSD, the normal location of the various *crt*.o files is the
- /usr/lib directory. */
-
-#undef MD_STARTFILE_PREFIX
-#define MD_STARTFILE_PREFIX "/usr/lib/"
-
-
-/* Provide a CPP_SPEC appropriate for FreeBSD. Current we just deal with
- the GCC option `-posix'. */
-
-#undef CPP_SPEC
-#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}"
-
-/* Provide an ASM_SPEC appropriate for FreeBSD. */
-
-#undef ASM_SPEC
-#define ASM_SPEC " %|"
-
-#undef ASM_FINAL_SPEC
-
-/* Provide a LIB_SPEC appropriate for FreeBSD. Just select the appropriate
- libc, depending on whether we're doing profiling. */
-
-#undef LIB_SPEC
-#define LIB_SPEC "%{!shared:%{!pg:%{!pthread:-lc}%{pthread:-lpthread -lc}}%{pg:%{!pthread:-lc_p}%{pthread:-lpthread_p -lc_p}}}"
-
-/* Provide a LINK_SPEC appropriate for FreeBSD. Here we provide support
- for the special GCC options -static, -assert, and -nostdlib. */
-
-#undef LINK_SPEC
-#define LINK_SPEC \
- "%{!nostdlib:%{!r*:%{!e*:-e __start}}} -dc -dp %{static:-Bstatic} %{assert*}"
-
-/* Output assembler code to FILE to increment profiler label # LABELNO
- for profiling a function entry. Under FreeBSD/Alpha, the assembler does
- nothing special with -pg. */
-
-#undef FUNCTION_PROFILER
-#define FUNCTION_PROFILER(FILE, LABELNO) \
- fputs ("\tjsr $28,_mcount\n", (FILE)); /* at */
+#undef HAS_INIT_SECTION
/* Show that we need a GP when profiling. */
-#define TARGET_PROFILING_NEEDS_GP
+#undef TARGET_PROFILING_NEEDS_GP
+#define TARGET_PROFILING_NEEDS_GP 1
-#define bsd4_4
-#undef HAS_INIT_SECTION
+/* This is the char to use for continuation (in case we need to turn
+ continuation back on). */
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#undef DBX_CONTIN_CHAR
+#define DBX_CONTIN_CHAR '?'
diff --git a/contrib/gcc/config/alpha/lib1funcs.asm b/contrib/gcc/config/alpha/lib1funcs.asm
index e63180a..6bea231 100644
--- a/contrib/gcc/config/alpha/lib1funcs.asm
+++ b/contrib/gcc/config/alpha/lib1funcs.asm
@@ -8,11 +8,12 @@ later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file. (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -21,14 +22,8 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* As a special exception, if you link this library with other files,
- some of which are compiled with GCC, to produce an executable,
- this library does not by itself cause the resulting executable
- to be covered by the GNU General Public License.
- This exception does not however invalidate any other reasons why
- the executable file might be covered by the GNU General Public License. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This had to be written in assembler because the division functions
use a non-standard calling convention.
diff --git a/contrib/gcc/config/alpha/linux-elf.h b/contrib/gcc/config/alpha/linux-elf.h
index fc07127..6430059 100644
--- a/contrib/gcc/config/alpha/linux-elf.h
+++ b/contrib/gcc/config/alpha/linux-elf.h
@@ -37,11 +37,6 @@ Boston, MA 02111-1307, USA. */
#endif
#ifndef USE_GNULIBC_1
-#undef DEFAULT_VTABLE_THUNKS
-#define DEFAULT_VTABLE_THUNKS 1
-#endif
-
-#ifndef USE_GNULIBC_1
#undef LIB_SPEC
#define LIB_SPEC \
"%{shared:-lc}%{!shared:%{pthread:-lpthread }%{profile:-lc_p}%{!profile:-lc}} "
diff --git a/contrib/gcc/config/alpha/linux.h b/contrib/gcc/config/alpha/linux.h
index b8eb9e9..8a1b93f 100644
--- a/contrib/gcc/config/alpha/linux.h
+++ b/contrib/gcc/config/alpha/linux.h
@@ -25,22 +25,84 @@ Boston, MA 02111-1307, USA. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES \
-"-Dlinux -Dunix -Asystem(linux) -D_LONGLONG -D__alpha__ " \
+"-Dlinux -Dunix -Asystem=linux -D_LONGLONG -D__alpha__ " \
SUB_CPP_PREDEFINES
-#undef LIB_SPEC
-#define LIB_SPEC "%{pg:-lgmon} %{pg:-lc_p} %{!pg:-lc}"
-
-/* Generate calls to memcpy, etc., not bcopy, etc. */
-#define TARGET_MEM_FUNCTIONS 1
+/* The GNU C++ standard library requires that these macros be defined. */
+#undef CPLUSPLUS_CPP_SPEC
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
-#undef FUNCTION_PROFILER
-#define FUNCTION_PROFILER(FILE, LABELNO) \
- fputs ("\tlda $28,_mcount\n\tjsr $28,($28),_mcount\n", (FILE))
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{shared: -lc} \
+ %{!shared: %{pthread:-lpthread} \
+ %{profile:-lc_p} %{!profile: -lc}}"
/* Show that we need a GP when profiling. */
+#undef TARGET_PROFILING_NEEDS_GP
#define TARGET_PROFILING_NEEDS_GP 1
/* Don't care about faults in the prologue. */
#undef TARGET_CAN_FAULT_IN_PROLOGUE
#define TARGET_CAN_FAULT_IN_PROLOGUE 1
+
+/* OS fixes up EV5 data fault on prefetch. */
+#undef TARGET_FIXUP_EV5_PREFETCH
+#define TARGET_FIXUP_EV5_PREFETCH 1
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+/* Define this so that all GNU/Linux targets handle the same pragmas. */
+#define HANDLE_PRAGMA_PACK_PUSH_POP
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+#ifdef IN_LIBGCC2
+#include <signal.h>
+#include <sys/ucontext.h>
+#endif
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
+ do { \
+ unsigned int *pc_ = (CONTEXT)->ra; \
+ struct sigcontext *sc_; \
+ long new_cfa_, i_; \
+ \
+ if (pc_[0] != 0x47fe0410 /* mov $30,$16 */ \
+ || pc_[2] != 0x00000083 /* callsys */) \
+ break; \
+ if (pc_[1] == 0x201f0067) /* lda $0,NR_sigreturn */ \
+ sc_ = (CONTEXT)->cfa; \
+ else if (pc_[1] == 0x201f015f) /* lda $0,NR_rt_sigreturn */ \
+ { \
+ struct rt_sigframe { \
+ struct siginfo info; \
+ struct ucontext uc; \
+ } *rt_ = (CONTEXT)->cfa; \
+ sc_ = &rt_->uc.uc_mcontext; \
+ } \
+ else \
+ break; \
+ new_cfa_ = sc_->sc_regs[30]; \
+ (FS)->cfa_how = CFA_REG_OFFSET; \
+ (FS)->cfa_reg = 30; \
+ (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa; \
+ for (i_ = 0; i_ < 30; ++i_) \
+ { \
+ (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[i_].loc.offset \
+ = (long)&sc_->sc_regs[i_] - new_cfa_; \
+ } \
+ for (i_ = 0; i_ < 31; ++i_) \
+ { \
+ (FS)->regs.reg[i_+32].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[i_+32].loc.offset \
+ = (long)&sc_->sc_fpregs[i_] - new_cfa_; \
+ } \
+ (FS)->regs.reg[31].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[31].loc.offset = (long)&sc_->sc_pc - new_cfa_; \
+ (FS)->retaddr_column = 31; \
+ goto SUCCESS; \
+ } while (0)
diff --git a/contrib/gcc/config/alpha/netbsd.h b/contrib/gcc/config/alpha/netbsd.h
index 5189064..7eacce2 100644
--- a/contrib/gcc/config/alpha/netbsd.h
+++ b/contrib/gcc/config/alpha/netbsd.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler,
for Alpha NetBSD systems.
- Copyright (C) 1998 Free Software Foundation, Inc.
+ Copyright (C) 1998, 2002 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -23,17 +23,75 @@ Boston, MA 02111-1307, USA. */
#define TARGET_DEFAULT (MASK_FP | MASK_FPREGS | MASK_GAS)
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-D_LONGLONG -Dnetbsd -Dunix " SUB_CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-D__NetBSD__ -D__ELF__ -Asystem=unix -Asystem=NetBSD"
-#undef LIB_SPEC
-#define LIB_SPEC "%{pg:-lgmon} %{pg:-lc_p} %{!pg:-lc}"
-/* Generate calls to memcpy, etc., not bcopy, etc. */
-#define TARGET_MEM_FUNCTIONS
+/* Show that we need a GP when profiling. */
+#undef TARGET_PROFILING_NEEDS_GP
+#define TARGET_PROFILING_NEEDS_GP 1
-#undef FUNCTION_PROFILER
-#define FUNCTION_PROFILER(FILE, LABELNO) \
- fputs ("\tlda $28,_mcount\n\tjsr $28,($28),_mcount\n", (FILE))
-/* Show that we need a GP when profiling. */
-#define TARGET_PROFILING_NEEDS_GP
+/* Provide a CPP_SPEC appropriate for NetBSD/alpha. In addition to
+ the standard NetBSD specs, we also handle Alpha FP mode indications. */
+
+#undef CPP_SPEC
+#define CPP_SPEC \
+ "%{mieee:-D_IEEE_FP} \
+ %{mieee-with-inexact:-D_IEEE_FP -D_IEEE_FP_INEXACT} \
+ %(cpp_cpu) %(cpp_subtarget)"
+
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC \
+ "%{posix:-D_POSIX_SOURCE}"
+
+
+/* Provide a LINK_SPEC appropriate for a NetBSD/alpha ELF target.
+ This is a copy of LINK_SPEC from <netbsd-elf.h> tweaked for
+ the alpha target. */
+
+#undef LINK_SPEC
+#define LINK_SPEC \
+ "%{G*} %{relax:-relax} \
+ %{O*:-O3} %{!O*:-O1} \
+ %{assert*} %{R*} \
+ %{shared:-shared} \
+ %{!shared: \
+ -dc -dp \
+ %{!nostdlib: \
+ %{!r*: \
+ %{!e*:-e __start}}} \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /usr/libexec/ld.elf_so}} \
+ %{static:-static}}"
+
+
+/* Provide an ENDFILE_SPEC appropriate for NetBSD/alpha ELF. Here we
+ add crtend.o, which provides part of the support for getting
+ C++ file-scope static objects deconstructed after exiting "main".
+
+ We also need to handle the GCC option `-ffast-math'. */
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{ffast-math|funsafe-math-optimizations:crtfm%O%s} \
+ %{!shared:crtend%O%s} %{shared:crtendS%O%s}"
+
+
+/* Make gcc agree with <machine/ansi.h> */
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_UNSIGNED
+#define WCHAR_UNSIGNED 0
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+#undef WINT_TYPE
+#define WINT_TYPE "int"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (NetBSD/alpha ELF)");
diff --git a/contrib/gcc/config/alpha/openbsd.h b/contrib/gcc/config/alpha/openbsd.h
index 60591d5..3424112 100644
--- a/contrib/gcc/config/alpha/openbsd.h
+++ b/contrib/gcc/config/alpha/openbsd.h
@@ -41,7 +41,7 @@ Boston, MA 02111-1307, USA. */
"%{!nostdlib:%{!r*:%{!e*:-e __start}}} -dc -dp %{assert*}"
/* run-time target specifications */
-#define CPP_PREDEFINES "-D__unix__ -D__ANSI_COMPAT -Asystem(unix) \
+#define CPP_PREDEFINES "-D__unix__ -D__ANSI_COMPAT -Asystem=unix \
-D__OpenBSD__ -D__alpha__ -D__alpha"
/* Layout of source language data types. */
@@ -100,8 +100,8 @@ Boston, MA 02111-1307, USA. */
fprintf (FILE, "\t.set noat\n"); \
if (TARGET_SUPPORT_ARCH) \
fprintf (FILE, "\t.arch %s\n", \
- alpha_cpu == PROCESSOR_EV6 ? "ev6" \
- : (alpha_cpu == PROCESSOR_EV5 \
+ TARGET_CPU_EV6 ? "ev6" \
+ : (TARGET_CPU_EV5 \
? (TARGET_MAX ? "pca56" : TARGET_BWX ? "ev56" : "ev5") \
: "ev4")); \
\
diff --git a/contrib/gcc/config/alpha/osf.h b/contrib/gcc/config/alpha/osf.h
index 5054444..250974c 100644
--- a/contrib/gcc/config/alpha/osf.h
+++ b/contrib/gcc/config/alpha/osf.h
@@ -1,5 +1,6 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha on OSF/1.
- Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001
+ Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -24,11 +25,21 @@ Boston, MA 02111-1307, USA. */
#undef TARGET_AS_CAN_SUBTRACT_LABELS
#define TARGET_AS_CAN_SUBTRACT_LABELS 1
+/* The GEM libraries for X_float are present, though not used by C. */
+
+#undef TARGET_HAS_XFLOATING_LIBS
+#define TARGET_HAS_XFLOATING_LIBS 1
+
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "\
-Dunix -D__osf__ -D_LONGLONG -DSYSTYPE_BSD \
--D_SYSTYPE_BSD -Asystem(unix) -Asystem(xpg4)"
+-D_SYSTYPE_BSD -Asystem=unix -Asystem=xpg4"
+
+/* Tru64 UNIX V5 requires additional definitions for 16 byte long double
+ support. Empty by default. */
+
+#define CPP_XFLOAT_SPEC ""
/* Accept DEC C flags for multithreaded programs. We use _PTHREAD_USE_D4
instead of PTHREAD_USE_D4 since both have the same effect and the former
@@ -36,7 +47,7 @@ Boston, MA 02111-1307, USA. */
#undef CPP_SUBTARGET_SPEC
#define CPP_SUBTARGET_SPEC \
-"%{pthread|threads:-D_REENTRANT} %{threads:-D_PTHREAD_USE_D4}"
+"%{pthread|threads:-D_REENTRANT} %{threads:-D_PTHREAD_USE_D4} %(cpp_xfloat)"
/* Under OSF4, -p and -pg require -lprof1, and -lprof1 requires -lpdf. */
@@ -46,15 +57,20 @@ Boston, MA 02111-1307, USA. */
/* Pass "-G 8" to ld because Alpha's CC does. Pass -O3 if we are
optimizing, -O1 if we are not. Pass -shared, -non_shared or
- -call_shared as appropriate. Also pass -pg. */
+ -call_shared as appropriate. Pass -hidden_symbol so that our
+ constructor and call-frame data structures are not accidentally
+ overridden. */
#define LINK_SPEC \
"-G 8 %{O*:-O3} %{!O*:-O1} %{static:-non_shared} \
- %{!static:%{shared:-shared} %{!shared:-call_shared}} %{pg} %{taso} \
- %{rpath*}"
+ %{!static:%{shared:-shared -hidden_symbol _GLOBAL_*} \
+ %{!shared:-call_shared}} %{pg} %{taso} %{rpath*}"
#define STARTFILE_SPEC \
"%{!shared:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}"
+#define ENDFILE_SPEC \
+ "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s}"
+
#define MD_STARTFILE_PREFIX "/usr/lib/cmplrs/cc/"
#define ASM_FILE_START(FILE) \
@@ -65,18 +81,22 @@ Boston, MA 02111-1307, USA. */
fprintf (FILE, "\t.set noat\n"); \
if (TARGET_SUPPORT_ARCH) \
fprintf (FILE, "\t.arch %s\n", \
- alpha_cpu == PROCESSOR_EV6 ? "ev6" \
- : (alpha_cpu == PROCESSOR_EV5 \
+ TARGET_CPU_EV6 ? "ev6" \
+ : (TARGET_CPU_EV5 \
? (TARGET_MAX ? "pca56" : TARGET_BWX ? "ev56" : "ev5") \
: "ev4")); \
\
ASM_OUTPUT_SOURCE_FILENAME (FILE, main_input_filename); \
}
+/* Tru64 UNIX V5.1 requires a special as flag. Empty by default. */
+
+#define ASM_OLDAS_SPEC ""
+
/* No point in running CPP on our assembler output. */
#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GAS) != 0
/* Don't pass -g to GNU as, because some versions don't accept this option. */
-#define ASM_SPEC "%{malpha-as:-g} -nocpp %{pg}"
+#define ASM_SPEC "%{malpha-as:-g %(asm_oldas)} -nocpp %{pg}"
#else
/* In OSF/1 v3.2c, the assembler by default does not output file names which
causes mips-tfile to fail. Passing -g to the assembler fixes this problem.
@@ -85,7 +105,7 @@ Boston, MA 02111-1307, USA. */
if the user does not specify -g. If we don't pass -g, then mips-tfile
will need to be fixed to work in this case. Pass -O0 since some
optimization are broken and don't help us anyway. */
-#define ASM_SPEC "%{!mgas:-g} -nocpp %{pg} -O0"
+#define ASM_SPEC "%{!mgas:-g %(asm_oldas)} -nocpp %{pg} -O0"
#endif
/* Specify to run a post-processor, mips-tfile after the assembler
@@ -114,6 +134,11 @@ Boston, MA 02111-1307, USA. */
#endif
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+ { "cpp_xfloat", CPP_XFLOAT_SPEC }, \
+ { "asm_oldas", ASM_OLDAS_SPEC }
+
/* Indicate that we have a stamp.h to use. */
#ifndef CROSS_COMPILE
#define HAVE_STAMP_H 1
@@ -122,10 +147,13 @@ Boston, MA 02111-1307, USA. */
/* Attempt to turn on access permissions for the stack. */
#define TRANSFER_FROM_TRAMPOLINE \
+extern void __enable_execute_stack PARAMS ((void *)); \
+ \
void \
__enable_execute_stack (addr) \
void *addr; \
{ \
+ extern int mprotect PARAMS ((const void *, size_t, int)); \
long size = getpagesize (); \
long mask = ~(size-1); \
char *page = (char *) (((long) addr) & mask); \
@@ -135,3 +163,49 @@ __enable_execute_stack (addr) \
if (mprotect (page, end - page, 7) < 0) \
perror ("mprotect of trampoline code"); \
}
+
+/* Digital UNIX V4.0E (1091)/usr/include/sys/types.h 4.3.49.9 1997/08/14 */
+#define SIZE_TYPE "long unsigned int"
+#define PTRDIFF_TYPE "long int"
+
+/* The linker will stick __main into the .init section. */
+#define HAS_INIT_SECTION
+#define LD_INIT_SWITCH "-init"
+#define LD_FINI_SWITCH "-fini"
+
+/* Select a format to encode pointers in exception handling data. CODE
+ is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
+ true if the symbol may be affected by dynamic relocations.
+
+ We really ought to be using the SREL32 relocations that ECOFF has,
+ but no version of the native assembler supports creating such things,
+ and Compaq has no plans to rectify this. Worse, the dynamic loader
+ cannot handle unaligned relocations, so we have to make sure that
+ things get padded appropriately. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
+ (TARGET_GAS \
+ ? (((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4) \
+ : DW_EH_PE_aligned)
+
+/* This is how we tell the assembler that a symbol is weak. */
+
+#define ASM_OUTPUT_WEAK_ALIAS(FILE, NAME, VALUE) \
+ do \
+ { \
+ ASM_GLOBALIZE_LABEL (FILE, NAME); \
+ fputs ("\t.weakext\t", FILE); \
+ assemble_name (FILE, NAME); \
+ if (VALUE) \
+ { \
+ fputc (' ', FILE); \
+ assemble_name (FILE, VALUE); \
+ } \
+ fputc ('\n', FILE); \
+ } \
+ while (0)
+
+#define ASM_WEAKEN_LABEL(FILE, NAME) ASM_OUTPUT_WEAK_ALIAS(FILE, NAME, 0)
+
+/* Handle #pragma weak and #pragma pack. */
+#undef HANDLE_SYSV_PRAGMA
+#define HANDLE_SYSV_PRAGMA 1
diff --git a/contrib/gcc/config/alpha/osf2or3.h b/contrib/gcc/config/alpha/osf2or3.h
index 5abdb0e..9d8c8f5 100644
--- a/contrib/gcc/config/alpha/osf2or3.h
+++ b/contrib/gcc/config/alpha/osf2or3.h
@@ -24,7 +24,9 @@ Boston, MA 02111-1307, USA. */
#define LIB_SPEC "%{p:-lprof1} %{pg:-lprof1} %{a:-lprof2} -lc"
/* As of OSF 3.2, as still can't subtract adjacent labels. */
-
#undef TARGET_AS_CAN_SUBTRACT_LABELS
#define TARGET_AS_CAN_SUBTRACT_LABELS 0
+/* The frame unwind data requires the ability to subtract labels. */
+#undef DWARF2_UNWIND_INFO
+#define DWARF2_UNWIND_INFO 0
diff --git a/contrib/gcc/config/alpha/osf5.h b/contrib/gcc/config/alpha/osf5.h
new file mode 100644
index 0000000..c832c57
--- /dev/null
+++ b/contrib/gcc/config/alpha/osf5.h
@@ -0,0 +1,54 @@
+/* Definitions of target machine for GNU compiler, for DEC Alpha on Tru64 5.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+ 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. */
+
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 128
+
+/* Tru64 UNIX V5 has a 16 byte long double type and requires __X_FLOAT to be
+ defined to get the appropriate prototypes for the long double functions
+ in <math.h>. */
+
+#undef CPP_XFLOAT_SPEC
+#define CPP_XFLOAT_SPEC "-D__X_FLOAT"
+
+/* In Tru64 UNIX V5.1, Compaq introduced a new assembler
+ (/usr/lib/cmplrs/cc/adu) which currently (versions between 3.04.29 and
+ 3.04.32) breaks mips-tfile. Passing the undocumented -oldas flag reverts
+ to using the old assembler (/usr/lib/cmplrs/cc/as[01]).
+
+ The V5.0 and V5.0A assemblers silently ignore -oldas, so it can be
+ specified here.
+
+ It is clearly not desirable to depend on this undocumented flag, and
+ Compaq wants -oldas to go away soon, but until they have released a
+ new adu that works with mips-tfile, this is the only option.
+
+ In some versions of the DTK, the assembler driver invokes ld after
+ assembly. This has been fixed in current versions, but adding -c
+ works as expected for all versions. */
+
+#undef ASM_OLDAS_SPEC
+#define ASM_OLDAS_SPEC "-oldas -c"
+
+/* The linker appears to perform invalid code optimizations that result
+ in the ldgp emitted for the exception_receiver pattern being incorrectly
+ linked. */
+#undef TARGET_LD_BUGGY_LDGP
+#define TARGET_LD_BUGGY_LDGP 1
diff --git a/contrib/gcc/config/alpha/qrnnd.asm b/contrib/gcc/config/alpha/qrnnd.asm
new file mode 100644
index 0000000..d6373ec
--- /dev/null
+++ b/contrib/gcc/config/alpha/qrnnd.asm
@@ -0,0 +1,163 @@
+ # Alpha 21064 __udiv_qrnnd
+ # Copyright (C) 1992, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+ # This file is part of GCC.
+
+ # The GNU MP Library 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 of the License, or (at your
+ # option) any later version.
+
+ # In addition to the permissions in the GNU General Public License, the
+ # Free Software Foundation gives you unlimited permission to link the
+ # compiled version of this file with other programs, and to distribute
+ # those programs without any restriction coming from the use of this
+ # file. (The General Public License restrictions do apply in other
+ # respects; for example, they cover modification of the file, and
+ # distribution when not linked into another program.)
+
+ # This file 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 Library General Public
+ # License for more details.
+
+ # You should have received a copy of the GNU General Public License
+ # along with GCC; see the file COPYING. If not, write to the
+ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ # MA 02111-1307, USA.
+
+ .set noreorder
+ .set noat
+
+ .text
+
+ .globl __udiv_qrnnd
+ .ent __udiv_qrnnd
+__udiv_qrnnd:
+ .frame $30,0,$26,0
+ .prologue 0
+
+#define cnt $2
+#define tmp $3
+#define rem_ptr $16
+#define n1 $17
+#define n0 $18
+#define d $19
+#define qb $20
+#define AT $at
+
+ ldiq cnt,16
+ blt d,$largedivisor
+
+$loop1: cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule d,n1,qb
+ subq n1,d,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule d,n1,qb
+ subq n1,d,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule d,n1,qb
+ subq n1,d,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule d,n1,qb
+ subq n1,d,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ subq cnt,1,cnt
+ bgt cnt,$loop1
+ stq n1,0(rem_ptr)
+ bis $31,n0,$0
+ ret $31,($26),1
+
+$largedivisor:
+ and n0,1,$4
+
+ srl n0,1,n0
+ sll n1,63,tmp
+ or tmp,n0,n0
+ srl n1,1,n1
+
+ and d,1,$6
+ srl d,1,$5
+ addq $5,$6,$5
+
+$loop2: cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule $5,n1,qb
+ subq n1,$5,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule $5,n1,qb
+ subq n1,$5,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule $5,n1,qb
+ subq n1,$5,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ cmplt n0,0,tmp
+ addq n1,n1,n1
+ bis n1,tmp,n1
+ addq n0,n0,n0
+ cmpule $5,n1,qb
+ subq n1,$5,tmp
+ cmovne qb,tmp,n1
+ bis n0,qb,n0
+ subq cnt,1,cnt
+ bgt cnt,$loop2
+
+ addq n1,n1,n1
+ addq $4,n1,n1
+ bne $6,$Odd
+ stq n1,0(rem_ptr)
+ bis $31,n0,$0
+ ret $31,($26),1
+
+$Odd:
+ /* q' in n0. r' in n1 */
+ addq n1,n0,n1
+
+ cmpult n1,n0,tmp # tmp := carry from addq
+ subq n1,d,AT
+ addq n0,tmp,n0
+ cmovne tmp,AT,n1
+
+ cmpult n1,d,tmp
+ addq n0,1,AT
+ cmoveq tmp,AT,n0
+ subq n1,d,AT
+ cmoveq tmp,AT,n1
+
+ stq n1,0(rem_ptr)
+ bis $31,n0,$0
+ ret $31,($26),1
+
+ .end __udiv_qrnnd
diff --git a/contrib/gcc/config/alpha/t-alpha b/contrib/gcc/config/alpha/t-alpha
new file mode 100644
index 0000000..d0b58d6
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-alpha
@@ -0,0 +1,2 @@
+# This is a support routine for longlong.h, used by libgcc2.c.
+LIB2FUNCS_EXTRA = $(srcdir)/config/alpha/qrnnd.asm
diff --git a/contrib/gcc/config/alpha/t-crtfm b/contrib/gcc/config/alpha/t-crtfm
new file mode 100644
index 0000000..7076b51
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-crtfm
@@ -0,0 +1,4 @@
+EXTRA_PARTS += crtfastmath.o
+
+crtfastmath.o: $(srcdir)/config/alpha/crtfastmath.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -c -o crtfastmath.o $(srcdir)/config/alpha/crtfastmath.c
diff --git a/contrib/gcc/config/alpha/t-ieee b/contrib/gcc/config/alpha/t-ieee
index a1f93db..fe549df 100644
--- a/contrib/gcc/config/alpha/t-ieee
+++ b/contrib/gcc/config/alpha/t-ieee
@@ -1,6 +1,2 @@
# All alphas get an IEEE complaint set of libraries.
-MULTILIB_OPTIONS = mieee
-MULTILIB_DIRNAMES = ieee
-
-LIBGCC = stmp-multilib
-INSTALL_LIBGCC = install-multilib
+TARGET_LIBGCC2_CFLAGS += -mieee
diff --git a/contrib/gcc/config/alpha/t-interix b/contrib/gcc/config/alpha/t-interix
index d6d80e9..3d570c6 100644
--- a/contrib/gcc/config/alpha/t-interix
+++ b/contrib/gcc/config/alpha/t-interix
@@ -1,16 +1,7 @@
# t-interix
# System headers will track gcc's needs.
-# Even LANG_EXTRA_HEADERS may be temporary.
-USER_H=$(LANG_EXTRA_HEADERS)
-
-# We don't want this one either.
-INSTALL_ASSERT_H=
-
-
-
-CROSS_LIBGCC1 = libgcc1-asm.a
-LIBGCC1 = libgcc1-asm.a
+USER_H=
LIB1ASMSRC = alpha/lib1funcs.asm
LIB1ASMFUNCS = _divqu _divq _divlu _divl _remqu _remq _remlu _reml
diff --git a/contrib/gcc/config/alpha/t-osf4 b/contrib/gcc/config/alpha/t-osf4
new file mode 100644
index 0000000..e9c451b
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-osf4
@@ -0,0 +1,22 @@
+# Compile crtbeginS.o and crtendS.o with pic.
+CRTSTUFF_T_CFLAGS_S = -fPIC
+
+# Compile libgcc2.a with pic.
+TARGET_LIBGCC2_CFLAGS = -fPIC
+
+# Build a shared libgcc library.
+SHLIB_EXT = .so
+SHLIB_NAME = @shlib_base_name@.so
+SHLIB_SONAME = @shlib_base_name@.so.1
+SHLIB_OBJS = @shlib_objs@
+
+SHLIB_LINK = $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -shared -nodefaultlibs \
+ -Wl,-msym -Wl,-set_version,gcc.1 -Wl,-soname,$(SHLIB_SONAME) \
+ -o $(SHLIB_NAME) @multilib_flags@ $(SHLIB_OBJS) -lc && \
+ rm -f $(SHLIB_SONAME) && \
+ $(LN_S) $(SHLIB_NAME) $(SHLIB_SONAME)
+# $(slibdir) double quoted to protect it from expansion while building
+# libgcc.mk. We want this delayed until actual install time.
+SHLIB_INSTALL = $(INSTALL_DATA) $(SHLIB_NAME) $$(slibdir)/$(SHLIB_SONAME); \
+ rm -f $$(slibdir)/$(SHLIB_NAME); \
+ $(LN_S) $(SHLIB_SONAME) $$(slibdir)/$(SHLIB_NAME)
diff --git a/contrib/gcc/config/alpha/t-unicosmk b/contrib/gcc/config/alpha/t-unicosmk
new file mode 100644
index 0000000..9c52b98
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-unicosmk
@@ -0,0 +1,2 @@
+# This file is empty for now.
+
diff --git a/contrib/gcc/config/alpha/t-vms b/contrib/gcc/config/alpha/t-vms
index 12ac240..5057c31 100644
--- a/contrib/gcc/config/alpha/t-vms
+++ b/contrib/gcc/config/alpha/t-vms
@@ -1,6 +1,22 @@
-# Do not build libgcc1.
-LIBGCC1 =
-CROSS_LIBGCC1 =
+LIB2FUNCS_EXTRA = $(srcdir)/config/alpha/vms_tramp.asm
-LIB2FUNCS_EXTRA = tramp.s
+# VMS_EXTRA_PARTS is defined in x-vms and represent object files that
+# are only needed for VMS targets, but can only be compiled on a VMS host
+# (because they need DEC C).
+EXTRA_PARTS = vms-dwarf2.o vms-dwarf2eh.o $(VMS_EXTRA_PARTS)
+
+# This object must be linked with in order to make the executable debuggable.
+# vms-ld handles it automatically when passed -g.
+vms-dwarf2.o : $(srcdir)/config/alpha/vms-dwarf2.asm
+ gcc -c -x assembler $< -o $@
+
+vms-dwarf2eh.o : $(srcdir)/config/alpha/vms-dwarf2eh.asm
+ gcc -c -x assembler $< -o $@
+
+# Assemble startup files.
+vcrt0.o: $(CRT0_S) $(GCC_PASSES)
+ decc -c /names=as_is $(srcdir)/config/alpha/vms-crt0.c -o vcrt0.o
+
+pcrt0.o: $(CRT0_S) $(GCC_PASSES)
+ decc -c /names=as_is $(srcdir)/config/alpha/vms-psxcrt0.c -o pcrt0.o
diff --git a/contrib/gcc/config/alpha/t-vms64 b/contrib/gcc/config/alpha/t-vms64
new file mode 100644
index 0000000..e3fc3be
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-vms64
@@ -0,0 +1,8 @@
+# Assemble startup files.
+vcrt0.o: $(CRT0_S) $(GCC_PASSES)
+ decc -c /names=as_is /pointer_size=64 \
+ $(srcdir)/config/alpha/vms-crt0-64.c -o vcrt0.o
+
+pcrt0.o: $(CRT0_S) $(GCC_PASSES)
+ decc -c /names=as_is /pointer_size=64 \
+ $(srcdir)/config/alpha/vms-psxcrt0-64.c -o pcrt0.o
diff --git a/contrib/gcc/config/alpha/unicosmk.h b/contrib/gcc/config/alpha/unicosmk.h
new file mode 100644
index 0000000..65ab319
--- /dev/null
+++ b/contrib/gcc/config/alpha/unicosmk.h
@@ -0,0 +1,626 @@
+/* Definitions of target machine for GNU compiler, for DEC Alpha on Cray
+ T3E running Unicos/Mk.
+ Copyright (C) 2001
+ Free Software Foundation, Inc.
+ Contributed by Roman Lechtchinsky (rl@cs.tu-berlin.de)
+
+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. */
+
+#undef TARGET_ABI_UNICOSMK
+#define TARGET_ABI_UNICOSMK 1
+
+/* CAM requires a slash before floating-pointing instruction suffixes. */
+
+#undef TARGET_AS_SLASH_BEFORE_SUFFIX
+#define TARGET_AS_SLASH_BEFORE_SUFFIX 1
+
+/* The following defines are necessary for the standard headers to work
+ correctly. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D__unix=1 -D_UNICOS=205 -D_CRAY=1 -D_CRAYT3E=1 -D_CRAYMPP=1 -D_CRAYIEEE=1 -D_ADDR64=1 -D_LD64=1 -D__UNICOSMK__ -D__INT_MAX__=9223372036854775807 -D__SHRT_MAX__=2147483647"
+
+/* Disable software floating point emulation because it requires a 16-bit
+ type which we do not have. */
+
+#ifndef __GNUC__
+#undef REAL_ARITHMETIC
+#endif
+
+#define SHORT_TYPE_SIZE 32
+
+#undef INT_TYPE_SIZE
+#define INT_TYPE_SIZE 64
+
+/* This is consistent with the definition Cray CC uses. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 64
+
+/*
+#define SIZE_TYPE "unsigned int"
+#define PTRDIFF_TYPE "int"
+*/
+
+/* Alphas are operated in big endian mode on the Cray T3E. */
+
+#undef BITS_BIG_ENDIAN
+#undef BYTES_BIG_ENDIAN
+#undef WORDS_BIG_ENDIAN
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 1
+#define WORDS_BIG_ENDIAN 1
+
+
+/* Every structure's size must be a multiple of this. */
+
+#undef STRUCTURE_SIZE_BOUNDARY
+#define STRUCTURE_SIZE_BOUNDARY 64
+
+/* No data type wants to be aligned rounder than this. */
+
+#undef BIGGEST_ALIGNMENT
+#define BIGGEST_ALIGNMENT 256
+
+/* Include the frame pointer in fixed_regs and call_used_regs as it can't be
+ used as a general-purpose register even in frameless functions.
+ ??? The global_regs hack is needed for now because -O2 sometimes tries to
+ eliminate $15 increments/decrements in frameless functions. */
+
+#undef CONDITIONAL_REGISTER_USAGE
+#define CONDITIONAL_REGISTER_USAGE \
+ do { \
+ fixed_regs[15] = 1; \
+ call_used_regs[15] = 1; \
+ global_regs[15] = 1; \
+ } while(0)
+
+/* The stack frame grows downward. */
+
+#define FRAME_GROWS_DOWNWARD
+
+/* Define the offset between two registers, one to be eliminated, and the
+ other its replacement, at the start of a routine. This is somewhat
+ complicated on the T3E which is why we use a function. */
+
+extern int unicosmk_initial_elimination_offset PARAMS ((int, int));
+
+#undef INITIAL_ELIMINATION_OFFSET
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ do { \
+ (OFFSET) = unicosmk_initial_elimination_offset ((FROM), (TO)); \
+ } while (0)
+
+
+/* Define this if stack space is still allocated for a parameter passed
+ in a register. On the T3E, stack space is preallocated for all outgoing
+ arguments, including those passed in registers. To avoid problems, we
+ assume that at least 48 bytes (i.e. enough space for all arguments passed
+ in registers) are allocated. */
+
+#define REG_PARM_STACK_SPACE(DECL) 48
+#define OUTGOING_REG_PARM_STACK_SPACE
+
+/* If an argument can't be passed in registers even though not all argument
+ registers have been used yet, it is passed on the stack in the space
+ preallocated for these registers. */
+
+#define STACK_PARMS_IN_REG_PARM_AREA
+
+/* This evaluates to nonzero if we do not know how to pass TYPE solely in
+ registers. This is the case for all arguments that do not fit in two
+ registers. */
+
+#define MUST_PASS_IN_STACK(MODE,TYPE) \
+ ((TYPE) != 0 \
+ && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
+ || (TREE_ADDRESSABLE (TYPE) || ALPHA_ARG_SIZE (MODE, TYPE, 0) > 2)))
+
+/* 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.
+
+ On Unicos/Mk, this is a structure that contains various information for
+ the static subroutine information block (SSIB) and the call information
+ word (CIW). */
+
+typedef struct {
+
+ /* The overall number of arguments. */
+ int num_args;
+
+ /* The overall size of the arguments in words. */
+ int num_arg_words;
+
+ /* The number of words passed in registers. */
+ int num_reg_words;
+
+ /* If an argument must be passed in the stack, all subsequent arguments
+ must be passed there, too. This flag indicates whether this is the
+ case. */
+ int force_stack;
+
+ /* This array indicates whether a word is passed in an integer register or
+ a floating point one. */
+
+ /* For each of the 6 register arguments, the corresponding flag in this
+ array indicates whether the argument is passed in an integer or a
+ floating point register. */
+ int reg_args_type[6];
+
+} unicosmk_arg_info;
+
+#undef CUMULATIVE_ARGS
+#define CUMULATIVE_ARGS unicosmk_arg_info
+
+/* 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. */
+
+#undef INIT_CUMULATIVE_ARGS
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
+ do { (CUM).num_args = 0; \
+ (CUM).num_arg_words = 0; \
+ (CUM).num_reg_words = 0; \
+ (CUM).force_stack = 0; \
+ } while(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.)
+
+ On Unicos/Mk, at most 6 words can be passed in registers. Structures
+ which fit in two words are passed in registers, larger structures are
+ passed on stack. */
+
+#undef FUNCTION_ARG_ADVANCE
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+do { \
+ int size; \
+ \
+ size = ALPHA_ARG_SIZE (MODE, TYPE, NAMED); \
+ \
+ if (size > 2 || MUST_PASS_IN_STACK (MODE, TYPE) \
+ || (CUM).num_reg_words + size > 6) \
+ (CUM).force_stack = 1; \
+ \
+ if (! (CUM).force_stack) \
+ { \
+ int i; \
+ int isfloat; \
+ isfloat = (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \
+ || GET_MODE_CLASS (MODE) == MODE_FLOAT); \
+ for (i = 0; i < size; i++) \
+ { \
+ (CUM).reg_args_type[(CUM).num_reg_words] = isfloat; \
+ ++(CUM).num_reg_words; \
+ } \
+ } \
+ (CUM).num_arg_words += size; \
+ ++(CUM).num_args; \
+} while(0)
+
+/* We want the default definition for this.
+ ??? In fact, we should delete the definition from alpha.h as it
+ corresponds to the default definition for little-endian machines. */
+
+#undef FUNCTION_ARG_PADDING
+
+/* An argument is passed either entirely in registers or entirely on stack. */
+
+#undef FUNCTION_ARG_PARTIAL_NREGS
+/* #define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) 0 */
+
+/* Perform any needed actions needed for a function that is receiving a
+ variable number of arguments.
+
+ On Unicos/Mk, the standard subroutine __T3E_MISMATCH stores all register
+ arguments on the stack. Unfortunately, it doesn't always store the first
+ one (i.e. the one that arrives in $16 or $f16). This is not a problem
+ with stdargs as we always have at least one named argument there. This is
+ not always the case when varargs.h is used, however. In such cases, we
+ have to store the first argument ourselves. We use the information from
+ the CIW to determine whether the first argument arrives in $16 or $f16. */
+
+#undef SETUP_INCOMING_VARARGS
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+{ if ((CUM).num_reg_words < 6) \
+ { \
+ if (! (NO_RTL)) \
+ { \
+ int start; \
+ \
+ start = (CUM).num_reg_words; \
+ if (!current_function_varargs || start == 0) \
+ ++start; \
+ \
+ emit_insn (gen_umk_mismatch_args (GEN_INT (start))); \
+ if (current_function_varargs && (CUM).num_reg_words == 0) \
+ { \
+ rtx tmp; \
+ rtx int_label, end_label; \
+ \
+ tmp = gen_reg_rtx (DImode); \
+ emit_move_insn (tmp, \
+ gen_rtx_ZERO_EXTRACT (DImode, \
+ gen_rtx_REG (DImode, 2),\
+ (GEN_INT (1)), \
+ (GEN_INT (7)))); \
+ int_label = gen_label_rtx (); \
+ end_label = gen_label_rtx (); \
+ emit_insn (gen_cmpdi (tmp, GEN_INT (0))); \
+ emit_jump_insn (gen_beq (int_label)); \
+ emit_move_insn (gen_rtx_MEM (DFmode, virtual_incoming_args_rtx),\
+ gen_rtx_REG (DFmode, 48)); \
+ emit_jump (end_label); \
+ emit_label (int_label); \
+ emit_move_insn (gen_rtx_MEM (DImode, virtual_incoming_args_rtx),\
+ gen_rtx_REG (DImode, 16)); \
+ emit_label (end_label); \
+ } \
+ emit_insn (gen_arg_home_umk ()); \
+ } \
+ \
+ PRETEND_SIZE = 0; \
+ } \
+}
+
+/* This ensures that $15 increments/decrements in leaf functions won't get
+ eliminated. */
+
+#undef EPILOGUE_USES
+#define EPILOGUE_USES(REGNO) ((REGNO) == 26 || (REGNO) == 15)
+
+/* Machine-specific function data. */
+
+struct machine_function
+{
+ /* List of call information words for calls from this function. */
+ struct rtx_def *first_ciw;
+ struct rtx_def *last_ciw;
+ int ciw_count;
+
+ /* List of deferred case vectors. */
+ struct rtx_def *addr_list;
+};
+
+/* Would have worked, only the stack doesn't seem to be executable
+#undef TRAMPOLINE_TEMPLATE
+#define TRAMPOLINE_TEMPLATE(FILE) \
+do { fprintf (FILE, "\tbr $1,0\n"); \
+ fprintf (FILE, "\tldq $0,12($1)\n"); \
+ fprintf (FILE, "\tldq $1,20($1)\n"); \
+ fprintf (FILE, "\tjmp $31,(r0)\n"); \
+ fprintf (FILE, "\tbis $31,$31,$31\n"); \
+ fprintf (FILE, "\tbis $31,$31,$31\n"); \
+} while (0) */
+
+/* We don't support nested functions (yet). */
+
+#undef TRAMPOLINE_TEMPLATE
+#define TRAMPOLINE_TEMPLATE(FILE) abort ()
+
+/* Specify the machine mode that this machine uses for the index in the
+ tablejump instruction. On Unicos/Mk, we don't support relative case
+ vectors yet, thus the entries should be absolute addresses. */
+
+#undef CASE_VECTOR_MODE
+#define CASE_VECTOR_MODE DImode
+
+#undef CASE_VECTOR_PC_RELATIVE
+
+/* Define this as 1 if `char' should by default be signed; else as 0. */
+/* #define DEFAULT_SIGNED_CHAR 1 */
+
+/* The Cray assembler is really weird with respect to sections. It has only
+ named sections and you can't reopen a section once it has been closed.
+ This means that we have to generate unique names whenever we want to
+ reenter the text or the data section. The following is a rather bad hack
+ as TEXT_SECTION_ASM_OP and DATA_SECTION_ASM_OP are supposed to be
+ constants. */
+
+#undef TEXT_SECTION_ASM_OP
+#define TEXT_SECTION_ASM_OP unicosmk_text_section ()
+
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP unicosmk_data_section ()
+
+/* There are ni read-only sections on Unicos/Mk. */
+
+#undef READONLY_DATA_SECTION
+#define READONLY_DATA_SECTION data_section
+
+/* Define extra sections for common data and SSIBs (static subroutine
+ information blocks). The actual section header is output by the callers
+ of these functions. */
+
+#undef EXTRA_SECTIONS
+#undef EXTRA_SECTION_FUNCTIONS
+
+#define EXTRA_SECTIONS in_common, in_ssib
+#define EXTRA_SECTION_FUNCTIONS \
+COMMON_SECTION \
+SSIB_SECTION
+
+extern void common_section PARAMS ((void));
+#define COMMON_SECTION \
+void \
+common_section () \
+{ \
+ in_section = in_common; \
+}
+
+extern void ssib_section PARAMS ((void));
+#define SSIB_SECTION \
+void \
+ssib_section () \
+{ \
+ in_section = in_ssib; \
+}
+
+/* A C expression which evaluates to true if declshould be placed into a
+ unique section for some target-specific reason. On Unicos/Mk, functions
+ and public variables are always placed in unique sections. */
+
+/*
+#define UNIQUE_SECTION_P(DECL) (TREE_PUBLIC (DECL) \
+ || TREE_CODE (DECL) == FUNCTION_DECL)
+*/
+#define UNIQUE_SECTION(DECL, RELOC) unicosmk_unique_section (DECL, RELOC)
+
+/* This outputs text to go at the start of an assembler file. */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) unicosmk_asm_file_start (FILE)
+
+/* This outputs text to go at the end of an assembler file. */
+
+#undef ASM_FILE_END
+#define ASM_FILE_END(FILE) unicosmk_asm_file_end (FILE)
+
+/* We take care of that in ASM_FILE_START. */
+
+#undef ASM_OUTPUT_SOURCE_FILENAME
+
+/* There is no directive for declaring a label as global. Instead, an
+ additional colon must be appended when the label is defined. */
+
+#undef ASM_GLOBALIZE_LABEL
+#define ASM_GLOBALIZE_LABEL(FILE,NAME)
+
+/* This is how to output a label for a jump table. Arguments are the same as
+ for ASM_OUTPUT_INTERNAL_LABEL, except the insn for the jump table is
+ passed. */
+
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN) \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM)
+
+/* CAM has some restrictions with respect to string literals. It won't
+ accept lines with more that 256 characters which means that we have
+ to split long strings. Moreover, it only accepts escape sequences of
+ the form \nnn in the range 0 to 127. We generate .byte directives for
+ escapes characters greater than 127. And finally, ` must be escaped. */
+
+#undef ASM_OUTPUT_ASCII
+#define ASM_OUTPUT_ASCII(MYFILE, MYSTRING, MYLENGTH) \
+ do { \
+ FILE *_hide_asm_out_file = (MYFILE); \
+ const unsigned char *_hide_p = (const unsigned char *) (MYSTRING); \
+ int _hide_thissize = (MYLENGTH); \
+ int _size_so_far = 0; \
+ { \
+ FILE *asm_out_file = _hide_asm_out_file; \
+ const unsigned char *p = _hide_p; \
+ int thissize = _hide_thissize; \
+ int in_ascii = 0; \
+ int i; \
+ \
+ for (i = 0; i < thissize; i++) \
+ { \
+ register int c = p[i]; \
+ \
+ if (c > 127) \
+ { \
+ if (in_ascii) \
+ { \
+ fprintf (asm_out_file, "\"\n"); \
+ in_ascii = 0; \
+ } \
+ \
+ fprintf (asm_out_file, "\t.byte\t%d\n", c); \
+ } \
+ else \
+ { \
+ if (! in_ascii) \
+ { \
+ fprintf (asm_out_file, "\t.ascii\t\""); \
+ in_ascii = 1; \
+ _size_so_far = 0; \
+ } \
+ else if (_size_so_far >= 64) \
+ { \
+ fprintf (asm_out_file, "\"\n\t.ascii\t\""); \
+ _size_so_far = 0; \
+ } \
+ \
+ if (c == '\"' || c == '\\' || c == '`') \
+ putc ('\\', asm_out_file); \
+ if (c >= ' ') \
+ putc (c, asm_out_file); \
+ else \
+ fprintf (asm_out_file, "\\%.3o", c); \
+ ++ _size_so_far; \
+ } \
+ } \
+ if (in_ascii) \
+ fprintf (asm_out_file, "\"\n"); \
+ } \
+ } while(0)
+
+/* This is how to output an element of a case-vector that is absolute. */
+
+#undef ASM_OUTPUT_ADDR_VEC_ELT
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ fprintf (FILE, "\t.quad $L%d\n", (VALUE))
+
+/* This is how to output an element of a case-vector that is relative.
+ (Unicos/Mk does not use such vectors yet). */
+
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) abort ()
+
+/* We can't output case vectors in the same section as the function code
+ because CAM doesn't allow data definitions in code sections. Thus, we
+ simply record the case vectors and put them in a separate section after
+ the function. */
+
+#define ASM_OUTPUT_ADDR_VEC(LAB,VEC) \
+ unicosmk_defer_case_vector ((LAB),(VEC))
+
+#define ASM_OUTPUT_ADDR_DIFF_VEC(LAB,VEC) abort ()
+
+/* This is how to output an assembler line that says to advance the location
+ counter to a multiple of 2**LOG bytes. Annoyingly, CAM always uses zeroes
+ to fill the unused space which does not work in code sections. We have to
+ be careful not to use the .align directive in code sections. */
+
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(STREAM,LOG) unicosmk_output_align (STREAM, LOG)
+
+/* This is how to advance the location counter by SIZE bytes. */
+
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(STREAM,SIZE) \
+ fprintf ((STREAM), "\t.byte\t0:%d\n", (SIZE));
+
+/* This says how to output an assembler line to define a global common
+ symbol. We need the alignment information because it has to be supplied
+ in the section header. */
+
+#undef ASM_OUTPUT_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
+ unicosmk_output_common ((FILE), (NAME), (SIZE), (ALIGN))
+
+/* This says how to output an assembler line to define a local symbol. */
+
+#undef ASM_OUTPUT_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+ do { data_section (); \
+ fprintf (FILE, "\t.align\t%d\n", floor_log2 ((ALIGN) / BITS_PER_UNIT));\
+ ASM_OUTPUT_LABEL ((FILE), (NAME)); \
+ fprintf (FILE, "\t.byte 0:%d\n", SIZE); \
+ } while (0)
+
+/* CAM does not allow us to declare a symbol as external first and then
+ define it in the same file later. Thus, we keep a list of all external
+ references, remove all symbols defined locally from it and output it at
+ the end of the asm file. */
+
+#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) \
+ unicosmk_add_extern ((NAME))
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(STREAM,SYMREF) \
+ unicosmk_add_extern (XSTR ((SYMREF), 0))
+
+/* This is how to declare an object. We don't have to output anything if
+ it is a global variable because those go into unique `common' sections
+ and the section name is globally visible. For local variables, we simply
+ output the label. In any case, we have to record that no extern
+ declaration should be generated for the symbol. */
+
+#define ASM_DECLARE_OBJECT_NAME(STREAM,NAME,DECL) \
+ do { tree name_tree; \
+ name_tree = get_identifier ((NAME)); \
+ TREE_ASM_WRITTEN (name_tree) = 1; \
+ if (!TREE_PUBLIC (DECL)) \
+ { \
+ assemble_name (STREAM, NAME); \
+ fputs (":\n", STREAM); \
+ } \
+ } while(0)
+
+/*
+#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \
+ unicosmk_output_section_name ((STREAM), (DECL), (NAME), (RELOC))
+*/
+
+/* Switch into a generic section. */
+#define TARGET_ASM_NAMED_SECTION unicosmk_asm_named_section
+
+#undef ASM_OUTPUT_MAX_SKIP_ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM,POWER,MAXSKIP)
+
+/* We have to define these because we do not use the floating-point
+ emulation. Unfortunately, atof does not accept hex literals. */
+
+#ifndef REAL_ARITHMETIC
+#define REAL_VALUE_ATOF(x,s) atof(x)
+#define REAL_VALUE_HTOF(x,s) atof(x)
+#endif
+
+#undef NM_FLAGS
+
+#undef OBJECT_FORMAT_COFF
+
+/* We cannot generate debugging information on Unicos/Mk. */
+
+#undef SDB_DEBUGGING_INFO
+#undef MIPS_DEBUGGING_INFO
+#undef DBX_DEBUGGING_INFO
+#undef DWARF_DEBUGGING_INFO
+#undef DWARF2_DEBUGGING_INFO
+#undef DWARF2_UNWIND_INFO
+#undef INCOMING_RETURN_ADDR_RTX
+
+
+/* We use the functions provided by the system library for integer
+ division. */
+
+#undef UDIVDI3_LIBCALL
+#undef DIVDI3_LIBCALL
+#define UDIVDI3_LIBCALL "$uldiv"
+#define DIVDI3_LIBCALL "$sldiv"
+
+/* This is necessary to prevent gcc from generating calls to __divsi3. */
+
+#define INIT_TARGET_OPTABS \
+ do { \
+ sdiv_optab->handlers[(int) SImode].libfunc = NULL_RTX; \
+ udiv_optab->handlers[(int) SImode].libfunc = NULL_RTX; \
+ } while (0)
+
+#undef ASM_OUTPUT_SOURCE_LINE
+
+/* We don't need a start file. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+/* These are the libraries we have to link with.
+ ??? The Craylibs directory should be autoconfed. */
+#undef LIB_SPEC
+#define LIB_SPEC "-L/opt/ctl/craylibs/craylibs -lu -lm -lc -lsma"
+
+#undef BUILD_VA_LIST_TYPE
+#undef EXPAND_BUILTIN_VA_START
+#undef EXPAND_BUILTIN_VA_ARG
+
+#define EH_FRAME_IN_DATA_SECTION 1
diff --git a/contrib/gcc/config/alpha/va_list.h b/contrib/gcc/config/alpha/va_list.h
index c9ab2b0..df58ed0 100644
--- a/contrib/gcc/config/alpha/va_list.h
+++ b/contrib/gcc/config/alpha/va_list.h
@@ -1,6 +1,9 @@
/* A replacement for Digital Unix's <va_list.h>. */
-#include <va-alpha.h>
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+typedef __builtin_va_list __gnuc_va_list;
+#endif
#if !defined(_VA_LIST) && !defined(_HIDDEN_VA_LIST)
#define _VA_LIST
diff --git a/contrib/gcc/config/alpha/vms-cc.c b/contrib/gcc/config/alpha/vms-cc.c
new file mode 100644
index 0000000..a171b1c
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-cc.c
@@ -0,0 +1,379 @@
+/* VMS DEC C wrapper.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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. */
+
+/* This program is a wrapper around the VMS DEC C compiler.
+ It translates Unix style command line options into corresponding
+ VMS style qualifiers and then spawns the DEC C compiler. */
+
+#include "config.h"
+#include "system.h"
+
+#undef PATH_SEPARATOR
+#undef PATH_SEPARATOR_STR
+#define PATH_SEPARATOR ','
+#define PATH_SEPARATOR_STR ","
+
+/* These can be set by command line arguments */
+int verbose = 0;
+int save_temps = 0;
+
+int comp_arg_max = -1;
+const char **comp_args = 0;
+int comp_arg_index = -1;
+char *objfilename = 0;
+
+char *system_search_dirs = (char *) "";
+char *search_dirs;
+
+char *default_defines = (char *) "";
+char *defines;
+
+/* Translate a Unix syntax directory specification into VMS syntax.
+ If indicators of VMS syntax found, return input string. */
+static char *to_host_dir_spec PARAMS ((char *));
+
+/* Translate a Unix syntax file specification into VMS syntax.
+ If indicators of VMS syntax found, return input string. */
+static char *to_host_file_spec PARAMS ((char *));
+
+/* Add a translated arg to the list to be passed to DEC CC */
+static void addarg PARAMS ((const char *));
+
+/* Preprocess the number of args in P_ARGC and contained in ARGV.
+ Look for special flags, etc. that must be handled first. */
+static void preprocess_args PARAMS ((int *, char **));
+
+/* Process the number of args in P_ARGC and contained in ARGV. Look
+ for special flags, etc. that must be handled for the VMS compiler. */
+static void process_args PARAMS ((int *, char **));
+
+/* Action routine called by decc$to_vms */
+static int translate_unix PARAMS ((char *, int));
+
+int main PARAMS ((int, char **));
+
+/* Add the argument contained in STR to the list of arguments to pass to the
+ compiler. */
+
+static void
+addarg (str)
+ const char *str;
+{
+ int i;
+
+ if (++comp_arg_index >= comp_arg_max)
+ {
+ const char **new_comp_args
+ = (const char **) xcalloc (comp_arg_max + 1000, sizeof (char *));
+
+ for (i = 0; i <= comp_arg_max; i++)
+ new_comp_args [i] = comp_args [i];
+
+ if (comp_args)
+ free (comp_args);
+
+ comp_arg_max += 1000;
+ comp_args = new_comp_args;
+ }
+
+ comp_args [comp_arg_index] = str;
+}
+
+static void
+preprocess_args (p_argc, argv)
+ int *p_argc;
+ char *argv[];
+{
+ int i;
+
+ for (i = 1; i < *p_argc; i++)
+ {
+ if (strcmp (argv[i], "-o") == 0)
+ {
+ char *buff, *ptr;
+ int out_len;
+
+ i++;
+ ptr = to_host_file_spec (argv[i]);
+ objfilename = xstrdup (ptr);
+ out_len = strlen (ptr);
+ buff = xmalloc (out_len + 6);
+
+ strcpy (buff, "/obj=");
+ strcat (buff, ptr);
+ addarg (buff);
+ }
+ }
+}
+
+static void
+process_args (p_argc, argv)
+ int *p_argc;
+ char *argv[];
+{
+ int i;
+
+ for (i = 1; i < *p_argc; i++)
+ {
+ if (strlen (argv[i]) < 2)
+ continue;
+
+ if (strncmp (argv[i], "-I", 2) == 0)
+ {
+ char *ptr;
+ int new_len, search_dirs_len;
+
+ ptr = to_host_dir_spec (&argv[i][2]);
+ new_len = strlen (ptr);
+ search_dirs_len = strlen (search_dirs);
+
+ search_dirs = xrealloc (search_dirs, search_dirs_len + new_len + 2);
+ if (search_dirs_len > 0)
+ strcat (search_dirs, PATH_SEPARATOR_STR);
+ strcat (search_dirs, ptr);
+ }
+ else if (strncmp (argv[i], "-D", 2) == 0)
+ {
+ char *ptr;
+ int new_len, defines_len;
+
+ ptr = &argv[i][2];
+ new_len = strlen (ptr);
+ defines_len = strlen (defines);
+
+ defines = xrealloc (defines, defines_len + new_len + 4);
+ if (defines_len > 0)
+ strcat (defines, ",");
+
+ strcat (defines, "\"");
+ strcat (defines, ptr);
+ strcat (defines, "\"");
+ }
+ else if (strcmp (argv[i], "-v") == 0)
+ verbose = 1;
+ else if (strcmp (argv[i], "-g0") == 0)
+ addarg ("/nodebug");
+ else if (strcmp (argv[i], "-O0") == 0)
+ addarg ("/noopt");
+ else if (strncmp (argv[i], "-g", 2) == 0)
+ addarg ("/debug");
+ else if (strcmp (argv[i], "-E") == 0)
+ addarg ("/preprocess");
+ else if (strcmp (argv[i], "-save-temps") == 0)
+ save_temps = 1;
+ }
+}
+
+/* The main program. Spawn the VMS DEC C compiler after fixing up the
+ Unix-like flags and args to be what VMS DEC C wants. */
+
+typedef struct dsc {unsigned short len, mbz; char *adr; } Descr;
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ char cwdev [128], *devptr;
+ int devlen;
+ char *cwd = getcwd (0, 1024);
+
+ devptr = strchr (cwd, ':');
+ devlen = (devptr - cwd) + 1;
+ strncpy (cwdev, cwd, devlen);
+ cwdev [devlen] = '\0';
+
+ search_dirs = xmalloc (strlen (system_search_dirs) + 1);
+ strcpy (search_dirs, system_search_dirs);
+
+ defines = xmalloc (strlen (default_defines) + 1);
+ strcpy (defines, default_defines);
+
+ addarg ("cc");
+ preprocess_args (&argc , argv);
+ process_args (&argc , argv);
+
+ if (strlen (search_dirs) > 0)
+ {
+ addarg ("/include=(");
+ addarg (search_dirs);
+ addarg (")");
+ }
+
+ if (strlen (defines) > 0)
+ {
+ addarg ("/define=(");
+ addarg (defines);
+ addarg (")");
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ int arg_len = strlen (argv[i]);
+
+ if (strcmp (argv[i], "-o") == 0)
+ i++;
+ else if (strcmp (argv[i], "-v" ) == 0
+ || strcmp (argv[i], "-E") == 0
+ || strcmp (argv[i], "-c") == 0
+ || strncmp (argv[i], "-g", 2 ) == 0
+ || strncmp (argv[i], "-O", 2 ) == 0
+ || strcmp (argv[i], "-save-temps") == 0
+ || (arg_len > 2 && strncmp (argv[i], "-I", 2) == 0)
+ || (arg_len > 2 && strncmp (argv[i], "-D", 2) == 0))
+ ;
+
+ /* Unix style file specs and VMS style switches look alike, so assume
+ an arg consisting of one and only one slash, and that being first, is
+ really a switch. */
+ else if ((argv[i][0] == '/') && (strchr (&argv[i][1], '/') == 0))
+ addarg (argv[i]);
+ else
+ {
+ /* Assume filename arg */
+ char buff [256], *ptr;
+ int buff_len;
+
+ ptr = to_host_file_spec (argv[i]);
+ arg_len = strlen (ptr);
+
+ if (ptr[0] == '[')
+ sprintf (buff, "%s%s", cwdev, ptr);
+ else if (strchr (ptr, ':'))
+ sprintf (buff, "%s", ptr);
+ else
+ sprintf (buff, "%s%s", cwd, ptr);
+
+ buff_len = strlen (buff);
+ ptr = xmalloc (buff_len + 1);
+
+ strcpy (ptr, buff);
+ addarg (ptr);
+ }
+ }
+
+ addarg (NULL);
+
+ if (verbose)
+ {
+ int i;
+
+ for (i = 0; i < comp_arg_index; i++)
+ printf ("%s ", comp_args [i]);
+
+ putchar ('\n');
+ }
+
+ {
+ int i;
+ int len = 0;
+
+ for (i = 0; comp_args[i]; i++)
+ len = len + strlen (comp_args[i]) + 1;
+
+ {
+ char *allargs = (char *) alloca (len + 1);
+ Descr cmd;
+ int status;
+ int status1 = 1;
+
+ for (i = 0; i < len + 1; i++)
+ allargs [i] = 0;
+
+ for (i = 0; comp_args [i]; i++)
+ {
+ strcat (allargs, comp_args [i]);
+ strcat (allargs, " ");
+ }
+
+ cmd.adr = allargs;
+ cmd.len = len;
+ cmd.mbz = 0;
+
+ i = LIB$SPAWN (&cmd, 0, 0, 0, 0, 0, &status);
+
+ if ((i & 1) != 1)
+ {
+ LIB$SIGNAL (i);
+ exit (1);
+ }
+
+ if ((status & 1) == 1 && (status1 & 1) == 1)
+ exit (0);
+
+ exit (1);
+ }
+ }
+}
+
+static char new_host_filespec [255];
+static char new_host_dirspec [255];
+static char filename_buff [256];
+
+static int
+translate_unix (name, type)
+ char *name;
+ int type ATTRIBUTE_UNUSED;
+{
+ strcpy (filename_buff, name);
+ return 0;
+}
+
+static char *
+to_host_dir_spec (dirspec)
+ char *dirspec;
+{
+ int len = strlen (dirspec);
+
+ strcpy (new_host_dirspec, dirspec);
+
+ if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
+ return new_host_dirspec;
+
+ while (len > 1 && new_host_dirspec [len-1] == '/')
+ {
+ new_host_dirspec [len-1] = 0;
+ len--;
+ }
+
+ decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
+ strcpy (new_host_dirspec, filename_buff);
+
+ return new_host_dirspec;
+
+}
+
+static char *
+to_host_file_spec (filespec)
+ char *filespec;
+{
+ strcpy (new_host_filespec, "");
+ if (strchr (filespec, ']') || strchr (filespec, ':'))
+ strcpy (new_host_filespec, filespec);
+ else
+ {
+ decc$to_vms (filespec, translate_unix, 1, 1);
+ strcpy (new_host_filespec, filename_buff);
+ }
+
+ return new_host_filespec;
+}
diff --git a/contrib/gcc/config/alpha/vms-crt0-64.c b/contrib/gcc/config/alpha/vms-crt0-64.c
new file mode 100644
index 0000000..4120a6b
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-crt0-64.c
@@ -0,0 +1,99 @@
+/* VMS 64bit crt0 returning VMS style condition codes .
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+#if !defined(__DECC)
+You Lose! This file can only be compiled with DEC C.
+#else
+
+/* This file can only be compiled with DEC C, due the the call to
+ lib$establish and the pragmas pointer_size. */
+
+#pragma __pointer_size short
+
+#include <stdlib.h>
+#include <string.h>
+#include <ssdef.h>
+
+extern void decc$main ();
+
+extern int main ();
+
+static int
+handler (sigargs, mechargs)
+ void *sigargs;
+ void *mechargs;
+{
+ return SS$_RESIGNAL;
+}
+
+int
+__main (arg1, arg2, arg3, image_file_desc, arg5, arg6)
+ void *arg1, *arg2, *arg3;
+ void *image_file_desc;
+ void *arg5, *arg6;
+{
+ int argc;
+ char **argv;
+ char **envp;
+
+#pragma __pointer_size long
+
+ int i;
+ char **long_argv;
+ char **long_envp;
+
+#pragma __pointer_size short
+
+ lib$establish (handler);
+ decc$main (arg1, arg2, arg3, image_file_desc,
+ arg5, arg6, &argc, &argv, &envp);
+
+#pragma __pointer_size long
+
+ /* Reallocate argv with 64 bit pointers. */
+ long_argv = (char **) malloc (sizeof (char *) * (argc + 1));
+
+ for (i = 0; i < argc; i++)
+ long_argv[i] = strdup (argv[i]);
+
+ long_argv[argc] = (char *) 0;
+
+ long_envp = (char **) malloc (sizeof (char *) * 5);
+
+ for (i = 0; envp[i]; i++)
+ long_envp[i] = strdup (envp[i]);
+
+ long_envp[i] = (char *) 0;
+
+#pragma __pointer_size short
+
+ return main (argc, long_argv, long_envp);
+}
+#endif
diff --git a/contrib/gcc/config/alpha/vms-crt0.c b/contrib/gcc/config/alpha/vms-crt0.c
new file mode 100644
index 0000000..e75bc02
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-crt0.c
@@ -0,0 +1,71 @@
+/* VMS crt0 returning VMS style condition codes .
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+#if !defined(__DECC)
+You Lose! This file can only be compiled with DEC C.
+#else
+
+/* This file can only be compiled with DEC C, due the the call to
+ lib$establish. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ssdef.h>
+
+extern void decc$main ();
+
+extern int main ();
+
+static int
+handler (sigargs, mechargs)
+ void *sigargs;
+ void *mechargs;
+{
+ return SS$_RESIGNAL;
+}
+
+int
+__main (arg1, arg2, arg3, image_file_desc, arg5, arg6)
+ void *arg1, *arg2, *arg3;
+ void *image_file_desc;
+ void *arg5, *arg6;
+{
+ int argc;
+ char **argv;
+ char **envp;
+
+ lib$establish (handler);
+
+ decc$main(arg1, arg2, arg3, image_file_desc, arg5, arg6,
+ &argc, &argv, &envp);
+
+ return main (argc, argv, envp);
+}
+#endif
diff --git a/contrib/gcc/config/alpha/vms-dwarf2.asm b/contrib/gcc/config/alpha/vms-dwarf2.asm
new file mode 100644
index 0000000..a94ae24
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-dwarf2.asm
@@ -0,0 +1,82 @@
+/* VMS dwarf2 section sequentializer.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+/* Linking with this file forces Dwarf2 debug sections to be
+ sequentially loaded by the VMS linker, enabling GDB to read them. */
+
+.section .debug_abbrev,NOWRT
+ .align 0
+ .globl $dwarf2.debug_abbrev
+$dwarf2.debug_abbrev:
+
+.section .debug_aranges,NOWRT
+ .align 0
+ .globl $dwarf2.debug_aranges
+$dwarf2.debug_aranges:
+
+.section .debug_frame,NOWRT
+ .align 0
+ .globl $dwarf2.debug_frame
+$dwarf2.debug_frame:
+
+.section .debug_info,NOWRT
+ .align 0
+ .globl $dwarf2.debug_info
+$dwarf2.debug_info:
+
+.section .debug_line,NOWRT
+ .align 0
+ .globl $dwarf2.debug_line
+$dwarf2.debug_line:
+
+.section .debug_loc,NOWRT
+ .align 0
+ .globl $dwarf2.debug_loc
+$dwarf2.debug_loc:
+
+.section .debug_macinfo,NOWRT
+ .align 0
+ .globl $dwarf2.debug_macinfo
+$dwarf2.debug_macinfo:
+
+.section .debug_pubnames,NOWRT
+ .align 0
+ .globl $dwarf2.debug_pubnames
+$dwarf2.debug_pubnames:
+
+.section .debug_str,NOWRT
+ .align 0
+ .globl $dwarf2.debug_str
+$dwarf2.debug_str:
+
+.section .debug_zzzzzz,NOWRT
+ .align 0
+ .globl $dwarf2.debug_zzzzzz
+$dwarf2.debug_zzzzzz:
diff --git a/contrib/gcc/config/alpha/vms-dwarf2eh.asm b/contrib/gcc/config/alpha/vms-dwarf2eh.asm
new file mode 100644
index 0000000..22f7050
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-dwarf2eh.asm
@@ -0,0 +1,37 @@
+/* VMS dwarf2 exception handling section sequentializer.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+/* Linking with this file forces the Dwarf2 EH section to be
+ individually loaded by the VMS linker an the unwinder to read it. */
+
+.section .eh_frame,NOWRT
+ .align 0
+ .global __EH_FRAME_BEGIN__
+__EH_FRAME_BEGIN__:
diff --git a/contrib/gcc/config/alpha/vms-ld.c b/contrib/gcc/config/alpha/vms-ld.c
new file mode 100644
index 0000000..83ceaf9
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-ld.c
@@ -0,0 +1,777 @@
+/* VMS linker wrapper.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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. */
+
+/* This program is a wrapper around the VMS linker.
+ It translates Unix style command line options into corresponding
+ VMS style qualifiers and then spawns the VMS linker. */
+
+#include "config.h"
+#include "system.h"
+
+typedef struct dsc {unsigned short len, mbz; char *adr; } Descr;
+
+#undef PATH_SEPARATOR
+#undef PATH_SEPARATOR_STR
+#define PATH_SEPARATOR ','
+#define PATH_SEPARATOR_STR ","
+
+/* Local variable declarations. */
+
+/* File specification for vms-dwarf2.o. */
+static char *vmsdwarf2spec = 0;
+
+/* File specification for vms-dwarf2eh.o. */
+static char *vmsdwarf2ehspec = 0;
+
+/* verbose = 1 if -v passed. */
+static int verbose = 0;
+
+/* save_temps = 1 if -save-temps passed. */
+static int save_temps = 0;
+
+/* By default don't generate executable file if there are errors
+ in the link. Override with --noinhibit-exec. */
+static int inhibit_exec = 1;
+
+/* debug = 1 if -g passed. */
+static int debug = 0;
+
+/* By default prefer to link with shareable image libraries.
+ Override with -static. */
+static int staticp = 0;
+
+/* By default generate an executable, not a shareable image library.
+ Override with -shared. */
+static int share = 0;
+
+/* Remember if IDENTIFICATION given on command line. */
+static int ident = 0;
+
+/* Keep track of arg translations. */
+static int link_arg_max = -1;
+static const char **link_args = 0;
+static int link_arg_index = -1;
+
+/* Keep track of filenames */
+static char optfilefullname [267];
+static char *sharefilename = 0;
+static char *exefilename = 0;
+
+/* System search dir list. Leave blank since link handles this
+ internally. */
+static char *system_search_dirs = "";
+
+/* Search dir list passed on command line (with -L). */
+static char *search_dirs;
+
+/* Local function declarations. */
+
+/* Add STR to the list of arguments to pass to the linker. Expand the list as
+ necessary to accommodate. */
+static void addarg PARAMS ((const char *));
+
+/* Check to see if NAME is a regular file, i.e. not a directory */
+static int is_regular_file PARAMS ((char *));
+
+/* Translate a Unix syntax file specification FILESPEC into VMS syntax.
+ If indicators of VMS syntax found, return input string. */
+static char *to_host_file_spec PARAMS ((char *));
+
+/* Locate the library named LIB_NAME in the set of paths PATH_VAL. */
+static char *locate_lib PARAMS ((char *, char *));
+
+/* Given a library name NAME, i.e. foo, Look for libfoo.lib and then
+ libfoo.a in the set of directories we are allowed to search in. */
+static const char *expand_lib PARAMS ((char *));
+
+/* Preprocess the number of args P_ARGC in ARGV.
+ Look for special flags, etc. that must be handled first. */
+static void preprocess_args PARAMS ((int *, char **));
+
+/* Preprocess the number of args P_ARGC in ARGV. Look for
+ special flags, etc. that must be handled for the VMS linker. */
+static void process_args PARAMS ((int *, char **));
+
+/* Action routine called by decc$to_vms. NAME is a file name or
+ directory name. TYPE is unused. */
+static int translate_unix PARAMS ((char *, int));
+
+int main PARAMS ((int, char **));
+
+static void
+addarg (str)
+ const char *str;
+{
+ int i;
+
+ if (++link_arg_index >= link_arg_max)
+ {
+ const char **new_link_args
+ = (const char **) xcalloc (link_arg_max + 1000, sizeof (char *));
+
+ for (i = 0; i <= link_arg_max; i++)
+ new_link_args [i] = link_args [i];
+
+ if (link_args)
+ free (link_args);
+
+ link_arg_max += 1000;
+ link_args = new_link_args;
+ }
+
+ link_args [link_arg_index] = str;
+}
+
+static char *
+locate_lib (lib_name, path_val)
+ char *lib_name;
+ char *path_val;
+{
+ int lib_len = strlen (lib_name);
+ char *eptr, *sptr;
+
+ for (sptr = path_val; *sptr; sptr = eptr)
+ {
+ char *buf, *ptr;
+
+ while (*sptr == PATH_SEPARATOR)
+ sptr ++;
+
+ eptr = strchr (sptr, PATH_SEPARATOR);
+ if (eptr == 0)
+ eptr = strchr (sptr, 0);
+
+ buf = alloca ((eptr-sptr) + lib_len + 4 + 2);
+ strncpy (buf, sptr, eptr-sptr);
+ buf [eptr-sptr] = 0;
+ strcat (buf, "/");
+ strcat (buf, lib_name);
+ ptr = strchr (buf, 0);
+
+ if (debug || staticp)
+ {
+ /* For debug or static links, look for shareable image libraries
+ last. */
+ strcpy (ptr, ".a");
+ if (is_regular_file (buf))
+ return xstrdup (to_host_file_spec (buf));
+
+ strcpy (ptr, ".olb");
+ if (is_regular_file (buf))
+ return xstrdup (to_host_file_spec (buf));
+
+ strcpy (ptr, ".exe");
+ if (is_regular_file (buf))
+ return xstrdup (to_host_file_spec (buf));
+ }
+ else
+ {
+ /* Otherwise look for shareable image libraries first. */
+ strcpy (ptr, ".exe");
+ if (is_regular_file (buf))
+ return xstrdup (to_host_file_spec (buf));
+
+ strcpy (ptr, ".a");
+ if (is_regular_file (buf))
+ return xstrdup (to_host_file_spec (buf));
+
+ strcpy (ptr, ".olb");
+ if (is_regular_file (buf))
+ return xstrdup (to_host_file_spec (buf));
+ }
+ }
+
+ return 0;
+}
+
+static const char *
+expand_lib (name)
+ char *name;
+{
+ char *lib, *lib_path;
+
+ if (strcmp (name, "c") == 0)
+ /* IEEE VAX C compatible library for non-prefixed (e.g. no DECC$)
+ C RTL functions. */
+ return "sys$library:vaxcrtltx.olb";
+
+ else if (strcmp (name, "m") == 0)
+ /* No separate library for math functions */
+ return "";
+
+ else
+ {
+ lib = xmalloc (strlen (name) + 14);
+
+ strcpy (lib, "lib");
+ strcat (lib, name);
+ lib_path = locate_lib (lib, search_dirs);
+
+ if (lib_path)
+ return lib_path;
+ }
+
+ fprintf (stderr,
+ "Couldn't locate library: lib%s.exe, lib%s.a or lib%s.olb\n",
+ name, name, name);
+
+ exit (1);
+}
+
+static int
+is_regular_file (name)
+ char *name;
+{
+ int ret;
+ struct stat statbuf;
+
+ ret = stat (name, &statbuf);
+ return !ret && S_ISREG (statbuf.st_mode);
+}
+
+static void
+preprocess_args (p_argc, argv)
+ int *p_argc;
+ char **argv;
+{
+ int i;
+
+ for (i = 1; i < *p_argc; i++)
+ if (strlen (argv[i]) >= 6 && strncmp (argv[i], "-shared", 7) == 0)
+ share = 1;
+
+ for (i = 1; i < *p_argc; i++)
+ if (strcmp (argv[i], "-o") == 0)
+ {
+ char *buff, *ptr;
+ int out_len;
+ int len;
+
+ i++;
+ ptr = to_host_file_spec (argv[i]);
+ exefilename = xstrdup (ptr);
+ out_len = strlen (ptr);
+ buff = xmalloc (out_len + 18);
+
+ if (share)
+ strcpy (buff, "/share=");
+ else
+ strcpy (buff, "/exe=");
+
+ strcat (buff, ptr);
+ addarg (buff);
+
+ if (share)
+ {
+ sharefilename = xmalloc (out_len+5);
+ if (ptr == strchr (argv[i], ']'))
+ strcpy (sharefilename, ++ptr);
+ else if (ptr == strchr (argv[i], ':'))
+ strcpy (sharefilename, ++ptr);
+ else if (ptr == strrchr (argv[i], '/'))
+ strcpy (sharefilename, ++ptr);
+ else
+ strcpy (sharefilename, argv[i]);
+
+ len = strlen (sharefilename);
+ if (strncasecmp (&sharefilename[len-4], ".exe", 4) == 0)
+ sharefilename[len-4] = 0;
+
+ for (ptr = sharefilename; *ptr; ptr++)
+ *ptr = TOUPPER (*ptr);
+ }
+ }
+}
+
+static void
+process_args (p_argc, argv)
+ int *p_argc;
+ char **argv;
+{
+ int i;
+
+ for (i = 1; i < *p_argc; i++)
+ {
+ if (strlen (argv[i]) < 2)
+ continue;
+
+ if (strncmp (argv[i], "-L", 2) == 0)
+ {
+ char *nbuff, *ptr;
+ int new_len, search_dirs_len;
+
+ ptr = &argv[i][2];
+ new_len = strlen (ptr);
+ search_dirs_len = strlen (search_dirs);
+
+ nbuff = xmalloc (new_len + 1);
+ strcpy (nbuff, ptr);
+
+ /* Remove trailing slashes. */
+ while (new_len > 1 && nbuff [new_len - 1] == '/')
+ {
+ nbuff [new_len - 1] = 0;
+ new_len--;
+ }
+
+ search_dirs = xrealloc (search_dirs, search_dirs_len + new_len + 2);
+ if (search_dirs_len > 0)
+ strcat (search_dirs, PATH_SEPARATOR_STR);
+
+ strcat (search_dirs, nbuff);
+ free (nbuff);
+ }
+
+ /* -v turns on verbose option here and is passed on to gcc. */
+ else if (strcmp (argv[i], "-v") == 0)
+ verbose = 1;
+ else if (strcmp (argv[i], "-g0") == 0)
+ addarg ("/notraceback");
+ else if (strncmp (argv[i], "-g", 2) == 0)
+ {
+ addarg ("/debug");
+ debug = 1;
+ }
+ else if (strcmp (argv[i], "-static") == 0)
+ staticp = 1;
+ else if (strcmp (argv[i], "-map") == 0)
+ {
+ char *buff, *ptr;
+
+ buff = xmalloc (strlen (exefilename) + 5);
+ strcpy (buff, exefilename);
+ ptr = strchr (buff, '.');
+ if (ptr)
+ *ptr = 0;
+
+ strcat (buff, ".map");
+ addarg ("/map=");
+ addarg (buff);
+ addarg ("/full");
+ }
+ else if (strcmp (argv[i], "-save-temps") == 0)
+ save_temps = 1;
+ else if (strcmp (argv[i], "--noinhibit-exec") == 0)
+ inhibit_exec = 0;
+ }
+}
+
+/* The main program. Spawn the VMS linker after fixing up the Unix-like flags
+ and args to be what the VMS linker wants. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ char cwdev [128], *devptr;
+ int devlen;
+ int optfd;
+ FILE *optfile;
+ char *cwd = getcwd (0, 1024);
+ char *optfilename;
+
+ devptr = strchr (cwd, ':');
+ devlen = (devptr - cwd) + 1;
+ strncpy (cwdev, cwd, devlen);
+ cwdev [devlen] = '\0';
+
+ search_dirs = xmalloc (strlen (system_search_dirs) + 1);
+ strcpy (search_dirs, system_search_dirs);
+
+ addarg ("link");
+
+ /* Pass to find args that have to be append first. */
+ preprocess_args (&argc , argv);
+
+ /* Pass to find the rest of the args. */
+ process_args (&argc , argv);
+
+ /* Create a temp file to hold args, otherwise we can easily exceed the VMS
+ command line length limits. */
+ optfilename = alloca (strlen ("LDXXXXXX") + 1);
+ strcpy (optfilename, "LDXXXXXX");
+ optfd = mkstemp (optfilename);
+ getcwd (optfilefullname, 256, 1); /* VMS style cwd. */
+ strcat (optfilefullname, optfilename);
+ strcat (optfilefullname, ".");
+ optfile = fdopen (optfd, "w");
+
+ /* Write out the IDENTIFICATION argument first so that it can be overridden
+ by an options file. */
+ for (i = 1; i < argc; i++)
+ {
+ int arg_len = strlen (argv[i]);
+
+ if (arg_len > 6 && strncasecmp (argv[i], "IDENT=", 6) == 0)
+ {
+ /* Comes from command line. If present will always appear before
+ IDENTIFICATION=... and will override. */
+
+ if (!ident)
+ ident = 1;
+ }
+ else if (arg_len > 15
+ && strncasecmp (argv[i], "IDENTIFICATION=", 15) == 0)
+ {
+ /* Comes from pragma Ident (). */
+
+ if (!ident)
+ {
+ fprintf (optfile, "case_sensitive=yes\n");
+ fprintf (optfile, "IDENTIFICATION=\"%15.15s\"\n", &argv[i][15]);
+ fprintf (optfile, "case_sensitive=NO\n");
+ ident = 1;
+ }
+ }
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ int arg_len = strlen (argv[i]);
+
+ if (strcmp (argv[i], "-o") == 0)
+ i++;
+ else if (arg_len > 2 && strncmp (argv[i], "-l", 2) == 0)
+ {
+ const char *libname = expand_lib (&argv[i][2]);
+ const char *ext;
+ int len;
+
+ if ((len = strlen (libname)) > 0)
+ {
+ char buff [256];
+
+ if (len > 4 && strcasecmp (&libname [len-4], ".exe") == 0)
+ ext = "/shareable";
+ else
+ ext = "/library";
+
+ if (libname[0] == '[')
+ sprintf (buff, "%s%s", cwdev, libname);
+ else
+ sprintf (buff, "%s", libname);
+
+ fprintf (optfile, "%s%s\n", buff, ext);
+ }
+ }
+
+ else if (strcmp (argv[i], "-v" ) == 0
+ || strncmp (argv[i], "-g", 2 ) == 0
+ || strcmp (argv[i], "-static" ) == 0
+ || strcmp (argv[i], "-map" ) == 0
+ || strcmp (argv[i], "-save-temps") == 0
+ || strcmp (argv[i], "--noinhibit-exec") == 0
+ || (arg_len > 2 && strncmp (argv[i], "-L", 2) == 0)
+ || (arg_len >= 6 && strncmp (argv[i], "-share", 6) == 0))
+ ;
+ else if (arg_len > 1 && argv[i][0] == '@')
+ {
+ FILE *atfile;
+ char *ptr, *ptr1;
+ struct stat statbuf;
+ char *buff;
+ int len;
+
+ if (stat (&argv[i][1], &statbuf))
+ {
+ fprintf (stderr, "Couldn't open linker response file: %s\n",
+ &argv[i][1]);
+ exit (1);
+ }
+
+ buff = xmalloc (statbuf.st_size + 1);
+ atfile = fopen (&argv[i][1], "r");
+ fgets (buff, statbuf.st_size + 1, atfile);
+ fclose (atfile);
+
+ len = strlen (buff);
+ if (buff [len - 1] == '\n')
+ {
+ buff [len - 1] = 0;
+ len--;
+ }
+
+ ptr = buff;
+
+ do
+ {
+ ptr1 = strchr (ptr, ' ');
+ if (ptr1)
+ *ptr1 = 0;
+ ptr = to_host_file_spec (ptr);
+ if (ptr[0] == '[')
+ fprintf (optfile, "%s%s\n", cwdev, ptr);
+ else
+ fprintf (optfile, "%s\n", ptr);
+ ptr = ptr1 + 1;
+ } while (ptr1);
+ }
+
+ /* Unix style file specs and VMS style switches look alike, so assume an
+ arg consisting of one and only one slash, and that being first, is
+ really a switch. */
+ else if ((argv[i][0] == '/') && (strchr (&argv[i][1], '/') == 0))
+ addarg (argv[i]);
+ else if (arg_len > 4
+ && strncasecmp (&argv[i][arg_len-4], ".OPT", 4) == 0)
+ {
+ FILE *optfile1;
+ char buff [256];
+
+ optfile1 = fopen (argv[i], "r");
+ while (fgets (buff, 256, optfile1))
+ fputs (buff, optfile);
+
+ fclose (optfile1);
+ }
+ else if (arg_len > 7 && strncasecmp (argv[i], "GSMATCH", 7) == 0)
+ fprintf (optfile, "%s\n", argv[i]);
+ else if (arg_len > 6 && strncasecmp (argv[i], "IDENT=", 6) == 0)
+ {
+ /* Comes from command line and will override pragma. */
+ fprintf (optfile, "case_sensitive=yes\n");
+ fprintf (optfile, "IDENT=\"%15.15s\"\n", &argv[i][6]);
+ fprintf (optfile, "case_sensitive=NO\n");
+ ident = 1;
+ }
+ else if (arg_len > 15
+ && strncasecmp (argv[i], "IDENTIFICATION=", 15) == 0)
+ ;
+ else
+ {
+ /* Assume filename arg. */
+ const char *addswitch = "";
+ char buff [256];
+ int buff_len;
+ int is_cld = 0;
+
+ argv[i] = to_host_file_spec (argv[i]);
+ arg_len = strlen (argv[i]);
+
+ if (arg_len > 4 && strcasecmp (&argv[i][arg_len-4], ".exe") == 0)
+ addswitch = "/shareable";
+
+ if (arg_len > 4 && strcasecmp (&argv[i][arg_len-4], ".cld") == 0)
+ {
+ addswitch = "/shareable";
+ is_cld = 1;
+ }
+
+ if (arg_len > 2 && strcasecmp (&argv[i][arg_len-2], ".a") == 0)
+ addswitch = "/lib";
+
+ if (arg_len > 4 && strcasecmp (&argv[i][arg_len-4], ".olb") == 0)
+ addswitch = "/lib";
+
+ if (argv[i][0] == '[')
+ sprintf (buff, "%s%s%s\n", cwdev, argv[i], addswitch);
+ else if (strchr (argv[i], ':'))
+ sprintf (buff, "%s%s\n", argv[i], addswitch);
+ else
+ sprintf (buff, "%s%s%s\n", cwd, argv[i], addswitch);
+
+ buff_len = strlen (buff);
+
+ if (buff_len >= 15
+ && strcasecmp (&buff[buff_len - 15], "vms-dwarf2eh.o\n") == 0)
+ vmsdwarf2ehspec = xstrdup (buff);
+ else if (buff_len >= 13
+ && strcasecmp (&buff[buff_len - 13],"vms-dwarf2.o\n") == 0)
+ vmsdwarf2spec = xstrdup (buff);
+ else if (is_cld)
+ {
+ addarg (buff);
+ addarg (",");
+ }
+ else
+ fprintf (optfile, buff);
+ }
+ }
+
+#if 0
+ if (share)
+ fprintf (optfile, "symbol_vector=(main=procedure)\n");
+#endif
+
+ if (vmsdwarf2ehspec)
+ {
+ fprintf (optfile, "case_sensitive=yes\n");
+ fprintf (optfile, "cluster=DWARF2eh,,,%s", vmsdwarf2ehspec);
+ fprintf (optfile, "collect=DWARF2eh,eh_frame\n");
+ fprintf (optfile, "case_sensitive=NO\n");
+ }
+
+ if (debug && vmsdwarf2spec)
+ {
+ fprintf (optfile, "case_sensitive=yes\n");
+ fprintf (optfile, "cluster=DWARF2debug,,,%s", vmsdwarf2spec);
+ fprintf (optfile, "collect=DWARF2debug,debug_abbrev,debug_aranges,-\n");
+ fprintf (optfile, " debug_frame,debug_info,debug_line,debug_loc,-\n");
+ fprintf (optfile, " debug_macinfo,debug_pubnames,debug_str,-\n");
+ fprintf (optfile, " debug_zzzzzz\n");
+ fprintf (optfile, "case_sensitive=NO\n");
+ }
+
+ if (debug && share)
+ {
+ fprintf (optfile, "case_sensitive=yes\n");
+ fprintf (optfile, "symbol_vector=(-\n");
+ fprintf (optfile,
+ "%s$DWARF2.DEBUG_ABBREV/$dwarf2.debug_abbrev=DATA,-\n",
+ sharefilename);
+ fprintf (optfile,
+ "%s$DWARF2.DEBUG_ARANGES/$dwarf2.debug_aranges=DATA,-\n",
+ sharefilename);
+ fprintf (optfile, "%s$DWARF2.DEBUG_FRAME/$dwarf2.debug_frame=DATA,-\n",
+ sharefilename);
+ fprintf (optfile, "%s$DWARF2.DEBUG_INFO/$dwarf2.debug_info=DATA,-\n",
+ sharefilename);
+ fprintf (optfile, "%s$DWARF2.DEBUG_LINE/$dwarf2.debug_line=DATA,-\n",
+ sharefilename);
+ fprintf (optfile, "%s$DWARF2.DEBUG_LOC/$dwarf2.debug_loc=DATA,-\n",
+ sharefilename);
+ fprintf (optfile,
+ "%s$DWARF2.DEBUG_MACINFO/$dwarf2.debug_macinfo=DATA,-\n",
+ sharefilename);
+ fprintf (optfile,
+ "%s$DWARF2.DEBUG_PUBNAMES/$dwarf2.debug_pubnames=DATA,-\n",
+ sharefilename);
+ fprintf (optfile, "%s$DWARF2.DEBUG_STR/$dwarf2.debug_str=DATA,-\n",
+ sharefilename);
+ fprintf (optfile, "%s$DWARF2.DEBUG_ZZZZZZ/$dwarf2.debug_zzzzzz=DATA)\n",
+ sharefilename);
+ fprintf (optfile, "case_sensitive=NO\n");
+ }
+
+ fclose (optfile);
+ addarg (optfilefullname);
+ addarg ("/opt");
+
+ addarg (NULL);
+
+ if (verbose)
+ {
+ int i;
+
+ for (i = 0; i < link_arg_index; i++)
+ printf ("%s ", link_args [i]);
+ putchar ('\n');
+ }
+
+ {
+ int i;
+ int len = 0;
+
+ for (i = 0; link_args[i]; i++)
+ len = len + strlen (link_args[i]) + 1;
+
+ {
+ char *allargs = (char *) alloca (len + 1);
+ Descr cmd;
+ int status;
+ int status1 = 1;
+
+ for (i = 0; i < len + 1; i++)
+ allargs [i] = 0;
+
+ for (i = 0; link_args [i]; i++)
+ {
+ strcat (allargs, link_args [i]);
+ strcat (allargs, " ");
+ }
+
+ cmd.adr = allargs;
+ cmd.len = len;
+ cmd.mbz = 0;
+
+ i = LIB$SPAWN (&cmd, 0, 0, 0, 0, 0, &status);
+ if ((i & 1) != 1)
+ {
+ LIB$SIGNAL (i);
+ exit (1);
+ }
+
+ if (debug && !share)
+ {
+ strcpy (allargs, "@gnu:[bin]set_exe ");
+ strcat (allargs, exefilename);
+ strcat (allargs, " /nodebug /silent");
+ len = strlen (allargs);
+ cmd.adr = allargs;
+ cmd.len = len;
+ cmd.mbz = 0;
+
+ if (verbose)
+ printf (allargs);
+
+ i = LIB$SPAWN (&cmd, 0, 0, 0, 0, 0, &status1);
+
+ if ((i & 1) != 1)
+ {
+ LIB$SIGNAL (i);
+ exit (1);
+ }
+ }
+
+ if (!save_temps)
+ remove (optfilefullname);
+
+ if ((status & 1) == 1 && (status1 & 1) == 1)
+ exit (0);
+
+ if (exefilename && inhibit_exec == 1)
+ remove (exefilename);
+
+ exit (1);
+ }
+ }
+}
+
+static char new_host_filespec [255];
+static char filename_buff [256];
+
+static int
+translate_unix (name, type)
+ char *name;
+ int type ATTRIBUTE_UNUSED;
+{
+ strcpy (filename_buff, name);
+ return 0;
+}
+
+static char *
+to_host_file_spec (filespec)
+ char *filespec;
+{
+ strcpy (new_host_filespec, "");
+ if (strchr (filespec, ']') || strchr (filespec, ':'))
+ strcpy (new_host_filespec, filespec);
+ else
+ {
+ decc$to_vms (filespec, translate_unix, 1, 1);
+ strcpy (new_host_filespec, filename_buff);
+ }
+
+ return new_host_filespec;
+}
diff --git a/contrib/gcc/config/alpha/vms-psxcrt0-64.c b/contrib/gcc/config/alpha/vms-psxcrt0-64.c
new file mode 100644
index 0000000..be3e70d
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-psxcrt0-64.c
@@ -0,0 +1,128 @@
+/* VMS 64bit crt0 returning Unix style condition codes .
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+#if !defined(__DECC)
+You Lose! This file can only be compiled with DEC C.
+#else
+
+/* This file can only be compiled with DEC C, due the the call to
+ lib$establish and the pragmas pointer_size. */
+
+#pragma __pointer_size short
+
+#include <stdlib.h>
+#include <string.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#include <errnodef.h>
+
+extern void decc$main ();
+extern int main ();
+
+static int
+handler (sigargs, mechargs)
+ void *sigargs;
+ void *mechargs;
+{
+ return SS$_RESIGNAL;
+}
+
+int
+__main (arg1, arg2, arg3, image_file_desc, arg5, arg6)
+ void *arg1, *arg2, *arg3;
+ void *image_file_desc;
+ void *arg5, *arg6)
+{
+ int argc;
+ char **argv;
+ char **envp;
+
+#pragma __pointer_size long
+
+ int i;
+ char **long_argv;
+ char **long_envp;
+ int status;
+
+#pragma __pointer_size short
+
+ lib$establish (handler);
+ decc$main (arg1, arg2, arg3, image_file_desc,
+ arg5, arg6, &argc, &argv, &envp);
+
+#pragma __pointer_size long
+
+ /* Reallocate argv with 64 bit pointers. */
+ long_argv = (char **) malloc (sizeof (char *) * (argc + 1));
+
+ for (i = 0; i < argc; i++)
+ long_argv[i] = strdup (argv[i]);
+
+ long_argv[argc] = (char *) 0;
+
+ long_envp = (char **) malloc (sizeof (char *) * 5);
+
+ for (i = 0; envp[i]; i++)
+ long_envp[i] = strdup (envp[i]);
+
+ long_envp[i] = (char *) 0;
+
+#pragma __pointer_size short
+
+ status = main (argc, long_argv, long_envp);
+
+ /* Map into a range of 0 - 255. */
+ status = status & 255;
+
+ if (status > 0)
+ {
+ int save_status = status;
+
+ status = C$_EXIT1 + ((status - 1) << STS$V_MSG_NO);
+
+ /* An exit failure status requires a "severe" error. All status values
+ are defined in errno with a successful (1) severity but can be
+ changed to an error (2) severity by adding 1. In addition for
+ compatibility with UNIX exit() routines we inhibit a run-time error
+ message from being generated on exit(1). */
+
+ if (save_status == 1)
+ {
+ status++;
+ status |= STS$M_INHIB_MSG;
+ }
+ }
+
+ if (status == 0)
+ status = SS$_NORMAL;
+
+ return status;
+}
+#endif
diff --git a/contrib/gcc/config/alpha/vms-psxcrt0.c b/contrib/gcc/config/alpha/vms-psxcrt0.c
new file mode 100644
index 0000000..cdf5ced
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-psxcrt0.c
@@ -0,0 +1,99 @@
+/* VMS crt0 returning Unix style condition codes .
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+#if !defined(__DECC)
+You Lose! This file can only be compiled with DEC C.
+#else
+
+/* This file can only be compiled with DEC C, due the the call to
+ lib$establish. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#include <errnodef.h>
+
+extern void decc$main ();
+extern int main ();
+
+static int
+handler (sigargs, mechargs)
+ void *sigargs;
+ void *mechargs;
+{
+ return SS$_RESIGNAL;
+}
+
+int
+__main (arg1, arg2, arg3, image_file_desc, arg5, arg6)
+ void *arg1, *arg2, *arg3;
+ void *image_file_desc;
+ void *arg5, *arg6;
+{
+ int argc;
+ char **argv;
+ char **envp;
+ int status;
+
+ lib$establish (handler);
+ decc$main (arg1, arg2, arg3, image_file_desc, arg5, arg6,
+ &argc, &argv, &envp);
+
+ status = main (argc, argv, envp);
+
+ /* Map into a range of 0 - 255. */
+ status = status & 255;
+
+ if (status > 0)
+ {
+ int save_status = status;
+
+ status = C$_EXIT1 + ((status - 1) << STS$V_MSG_NO);
+
+ /* An exit failure status requires a "severe" error
+ All status values are defined in errno with a successful
+ (1) severity but can be changed to an error (2) severity by adding 1.
+ In addition for compatibility with UNIX exit() routines we inhibit
+ a run-time error message from being generated on exit(1). */
+
+ if (save_status == 1)
+ {
+ status++;
+ status |= STS$M_INHIB_MSG;
+ }
+ }
+
+ if (status == 0)
+ status = SS$_NORMAL;
+
+ return status;
+}
+#endif
diff --git a/contrib/gcc/config/alpha/vms.h b/contrib/gcc/config/alpha/vms.h
index 44388b2..a01556e 100644
--- a/contrib/gcc/config/alpha/vms.h
+++ b/contrib/gcc/config/alpha/vms.h
@@ -1,5 +1,6 @@
/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002
+ Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,7 +19,8 @@ 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. */
-#define OPEN_VMS 1
+#define TARGET_OBJECT_SUFFIX ".obj"
+#define TARGET_EXECUTABLE_SUFFIX ".exe"
/* This enables certain macros in alpha.h, which will make an indirect
reference to an external symbol an invalid address. This needs to be
@@ -31,7 +33,7 @@ Boston, MA 02111-1307, USA. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES \
-"-D__ALPHA -Dvms -DVMS -D__vms__ -D__VMS__ -Asystem(vms)"
+"-D__ALPHA -Dvms -DVMS -D__vms__ -D__VMS__ -Asystem=vms"
#undef CPP_SUBTARGET_SPEC
#define CPP_SUBTARGET_SPEC "\
@@ -39,38 +41,13 @@ Boston, MA 02111-1307, USA. */
%{mfloat-vax:-D__G_FLOAT} \
%{!mfloat-vax:-D__IEEE_FLOAT}"
-/* Under OSF4, -p and -pg require -lprof1, and -lprof1 requires -lpdf. */
-
-#define LIB_SPEC "%{p:-lprof1 -lpdf} %{pg:-lprof1 -lpdf} %{a:-lprof2} -lc"
-
-/* Pass "-G 8" to ld because Alpha's CC does. Pass -O3 if we are
- optimizing, -O1 if we are not. Pass -shared, -non_shared or
- -call_shared as appropriate. Also pass -pg. */
-#define LINK_SPEC \
- "-G 8 %{O*:-O3} %{!O*:-O1} %{static:-non_shared} \
- %{!static:%{shared:-shared} %{!shared:-call_shared}} %{pg} %{taso} \
- %{rpath*}"
-
-/* We allow $'s in identifiers unless -ansi is used .. */
-
-#define DOLLARS_IN_IDENTIFIERS 2
-
-/* These match the definitions used in DECCRTL, the VMS C run-time library
-
-#define SIZE_TYPE "unsigned int"
-#define PTRDIFF_TYPE "int"
-*/
-
-/* Use memcpy for structure copying, and so forth. */
-#define TARGET_MEM_FUNCTIONS
-
/* By default, allow $ to be part of an identifier. */
#define DOLLARS_IN_IDENTIFIERS 2
#undef TARGET_DEFAULT
#define TARGET_DEFAULT (MASK_FP|MASK_FPREGS|MASK_GAS)
-#undef TARGET_OPEN_VMS
-#define TARGET_OPEN_VMS 1
+#undef TARGET_ABI_OPEN_VMS
+#define TARGET_ABI_OPEN_VMS 1
#undef TARGET_NAME
#define TARGET_NAME "OpenVMS/Alpha"
@@ -82,14 +59,12 @@ Boston, MA 02111-1307, USA. */
#define STRUCT_VALUE 0
#undef PCC_STATIC_STRUCT_RETURN
-/* no floating emulation. */
-#undef REAL_ARITHMETIC
-
-/* "long" is 32 bits. */
+/* "long" is 32 bits, but 64 bits for Ada. */
#undef LONG_TYPE_SIZE
#define LONG_TYPE_SIZE 32
+#define ADA_LONG_TYPE_SIZE 64
-/* Pointer is 32 bits but the hardware has 64-bit addresses, sign extended. */
+/* Pointer is 32 bits but the hardware has 64-bit addresses, sign extended. */
#undef POINTER_SIZE
#define POINTER_SIZE 32
#define POINTERS_EXTEND_UNSIGNED 0
@@ -110,9 +85,57 @@ Boston, MA 02111-1307, USA. */
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+/* List the order in which to allocate registers. Each register must be
+ listed once, even those in FIXED_REGISTERS.
+
+ We allocate in the following order:
+ $f1 (nonsaved floating-point register)
+ $f10-$f15 (likewise)
+ $f22-$f30 (likewise)
+ $f21-$f16 (likewise, but input args)
+ $f0 (nonsaved, but return value)
+ $f2-$f9 (saved floating-point registers)
+ $1 (nonsaved integer registers)
+ $22-$25 (likewise)
+ $28 (likewise)
+ $0 (likewise, but return value)
+ $21-$16 (likewise, but input args)
+ $27 (procedure value in OSF, nonsaved in NT)
+ $2-$8 (saved integer registers)
+ $9-$14 (saved integer registers)
+ $26 (return PC)
+ $15 (frame pointer)
+ $29 (global pointer)
+ $30, $31, $f31 (stack pointer and always zero/ap & fp) */
+
+#undef REG_ALLOC_ORDER
+#define REG_ALLOC_ORDER \
+ {33, \
+ 42, 43, 44, 45, 46, 47, \
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, \
+ 53, 52, 51, 50, 49, 48, \
+ 32, \
+ 34, 35, 36, 37, 38, 39, 40, 41, \
+ 1, \
+ 22, 23, 24, 25, \
+ 28, \
+ 0, \
+ 21, 20, 19, 18, 17, 16, \
+ 27, \
+ 2, 3, 4, 5, 6, 7, 8, \
+ 9, 10, 11, 12, 13, 14, \
+ 26, \
+ 15, \
+ 29, \
+ 30, 31, 63 }
+
#undef HARD_FRAME_POINTER_REGNUM
#define HARD_FRAME_POINTER_REGNUM 29
+/* Define registers used by the epilogue and return instruction. */
+#undef EPILOGUE_USES
+#define EPILOGUE_USES(REGNO) ((REGNO) == 26 || (REGNO) == 29)
+
#undef CAN_ELIMINATE
#define CAN_ELIMINATE(FROM, TO) \
((TO) != STACK_POINTER_REGNUM || ! alpha_using_fp ())
@@ -126,6 +149,8 @@ Boston, MA 02111-1307, USA. */
+ get_frame_size () \
+ current_function_pretend_args_size) \
- current_function_pretend_args_size); \
+ else \
+ abort(); \
if ((TO) == STACK_POINTER_REGNUM) \
(OFFSET) += ALPHA_ROUND (current_function_outgoing_args_size); \
}
@@ -143,7 +168,7 @@ Boston, MA 02111-1307, USA. */
Thus 6 or more means all following args should go on the stack. */
enum avms_arg_type {I64, FF, FD, FG, FS, FT};
-typedef struct {char num_args; enum avms_arg_type atypes[6];} avms_arg_info;
+typedef struct {int num_args; enum avms_arg_type atypes[6];} avms_arg_info;
#undef CUMULATIVE_ARGS
#define CUMULATIVE_ARGS avms_arg_info
@@ -158,41 +183,6 @@ typedef struct {char num_args; enum avms_arg_type atypes[6];} avms_arg_info;
(CUM).atypes[0] = (CUM).atypes[1] = (CUM).atypes[2] = I64; \
(CUM).atypes[3] = (CUM).atypes[4] = (CUM).atypes[5] = I64;
-/* 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.) */
-
-extern enum avms_arg_type alpha_arg_type ();
-
-/* Determine where to put an argument to a function.
- Value is zero to push the argument on the stack,
- or a hard register in which to store the argument.
-
- MODE is the argument's machine mode (or VOIDmode for no more args).
- TYPE is the data type of the argument (as a tree).
- This is null for libcalls where that information may
- not be available.
- CUM is a variable of type CUMULATIVE_ARGS which gives info about
- the preceding args and about the function being called.
- NAMED is nonzero if this argument is a named parameter
- (otherwise it is an extra parameter matching an ellipsis).
-
- On Alpha the first 6 words of args are normally in registers
- and the rest are pushed. */
-
-extern struct rtx_def *alpha_arg_info_reg_val ();
-#undef FUNCTION_ARG
-#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
-((MODE) == VOIDmode ? alpha_arg_info_reg_val (CUM) \
- : ((CUM.num_args) < 6 && ! MUST_PASS_IN_STACK (MODE, TYPE) \
- ? gen_rtx(REG, (MODE), \
- ((CUM).num_args + 16 \
- + ((TARGET_FPREGS \
- && (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \
- || GET_MODE_CLASS (MODE) == MODE_FLOAT)) \
- * 32))) \
- : 0))
-
#undef FUNCTION_ARG_ADVANCE
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
if (MUST_PASS_IN_STACK (MODE, TYPE)) \
@@ -234,7 +224,7 @@ extern struct rtx_def *alpha_arg_info_reg_val ();
However, if NO registers need to be saved, don't allocate any space.
This is not only because we won't need the space, but because AP includes
the current_pretend_args_size and we don't want to mess up any
- ap-relative addresses already made. */
+ ap-relative addresses already made. */
#undef SETUP_INCOMING_VARARGS
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
@@ -242,7 +232,7 @@ extern struct rtx_def *alpha_arg_info_reg_val ();
{ \
if (! (NO_RTL)) \
{ \
- emit_move_insn (gen_rtx (REG, DImode, 1), \
+ emit_move_insn (gen_rtx_REG (DImode, 1), \
virtual_incoming_args_rtx); \
emit_insn (gen_arg_home ()); \
} \
@@ -251,6 +241,10 @@ extern struct rtx_def *alpha_arg_info_reg_val ();
} \
}
+/* ABI has stack checking, but it's broken. */
+#undef STACK_CHECK_BUILTIN
+#define STACK_CHECK_BUILTIN 0
+
#undef ASM_FILE_START
#define ASM_FILE_START(FILE) \
{ \
@@ -260,33 +254,14 @@ extern struct rtx_def *alpha_arg_info_reg_val ();
ASM_OUTPUT_SOURCE_FILENAME (FILE, main_input_filename); \
}
-#undef ASM_OUTPUT_FLOAT
-#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
- { \
- if (REAL_VALUE_ISINF (VALUE) \
- || REAL_VALUE_ISNAN (VALUE) \
- || REAL_VALUE_MINUS_ZERO (VALUE)) \
- { \
- long t; \
- REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
- fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
- } \
- else \
- { \
- char str[30]; \
- REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
- fprintf (FILE, "\t.%c_floating %s\n", (TARGET_FLOAT_VAX)?'f':'s', str); \
- } \
- }
-
-#define LINK_SECTION_ASM_OP ".link"
-#define READONLY_SECTION_ASM_OP ".rdata"
-#define LITERALS_SECTION_ASM_OP ".literals"
-#define CTORS_SECTION_ASM_OP ".ctors"
-#define DTORS_SECTION_ASM_OP ".dtors"
+#define LINK_SECTION_ASM_OP "\t.link"
+#define READONLY_SECTION_ASM_OP "\t.rdata"
+#define LITERALS_SECTION_ASM_OP "\t.literals"
+#define CTORS_SECTION_ASM_OP "\t.ctors"
+#define DTORS_SECTION_ASM_OP "\t.dtors"
#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_link, in_rdata, in_literals, in_ctors, in_dtors
+#define EXTRA_SECTIONS in_link, in_rdata, in_literals
#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
@@ -316,26 +291,12 @@ literals_section () \
fprintf (asm_out_file, "%s\n", LITERALS_SECTION_ASM_OP); \
in_section = in_literals; \
} \
-} \
-void \
-ctors_section () \
-{ \
- if (in_section != in_ctors) \
- { \
- fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
- in_section = in_ctors; \
- } \
-} \
-void \
-dtors_section () \
-{ \
- if (in_section != in_dtors) \
- { \
- fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
- in_section = in_dtors; \
- } \
}
+extern void readonly_section PARAMS ((void));
+extern void link_section PARAMS ((void));
+extern void literals_section PARAMS ((void));
+
#undef ASM_OUTPUT_ADDR_DIFF_ELT
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) abort ()
@@ -359,17 +320,16 @@ dtors_section () \
/* This says how to output assembler code to declare an
uninitialized external linkage data object. */
-#define COMMON_ASM_OP ".comm"
+#define COMMON_ASM_OP "\t.comm\t"
#undef ASM_OUTPUT_ALIGNED_COMMON
#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
do { \
- fprintf ((FILE), "\t%s\t", COMMON_ASM_OP); \
+ fprintf ((FILE), "%s", COMMON_ASM_OP); \
assemble_name ((FILE), (NAME)); \
fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
} while (0)
-#define NO_MD_PROTOTYPES
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts.
@@ -377,8 +337,7 @@ do { \
The trampoline should set the static chain pointer to value placed
into the trampoline and should branch to the specified routine.
Note that $27 has been set to the address of the trampoline, so we can
- use it for addressability of the two data items. Trampolines are always
- aligned to FUNCTION_BOUNDARY, which is 64 bits. */
+ use it for addressability of the two data items. */
#undef TRAMPOLINE_TEMPLATE
#define TRAMPOLINE_TEMPLATE(FILE) \
@@ -393,6 +352,11 @@ do { \
#undef TRAMPOLINE_SIZE
#define TRAMPOLINE_SIZE 32
+/* The alignment of a trampoline, in bits. */
+
+#undef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT 64
+
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
CXT is an RTX for the static chain value for the function. */
@@ -401,35 +365,69 @@ do { \
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
alpha_initialize_trampoline (TRAMP, FNADDR, CXT, 16, 24, -1)
-/* A C statement (sans semicolon) to output an element in the table of
- global constructors. */
-#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
- do { \
- ctors_section (); \
- fprintf (FILE, "\t.quad "); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, "\n"); \
- } while (0)
-
-/* A C statement (sans semicolon) to output an element in the table of
- global destructors. */
-#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
- do { \
- dtors_section (); \
- fprintf (FILE, "\t.quad "); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, "\n"); \
- } while (0)
-
-#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \
- (vms_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
-extern int vms_valid_decl_attribute_p ();
+/* Control how constructors and destructors are emitted. */
+#define TARGET_ASM_CONSTRUCTOR vms_asm_out_constructor
+#define TARGET_ASM_DESTRUCTOR vms_asm_out_destructor
#undef SDB_DEBUGGING_INFO
#undef MIPS_DEBUGGING_INFO
#undef DBX_DEBUGGING_INFO
#define DWARF2_DEBUGGING_INFO
+#define VMS_DEBUGGING_INFO
+
+#define DWARF2_UNWIND_INFO 1
+
+#undef EH_RETURN_HANDLER_RTX
+#define EH_RETURN_HANDLER_RTX \
+ gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, 8))
+
+#define LINK_EH_SPEC "vms-dwarf2eh.o%s "
+
+#ifdef IN_LIBGCC2
+#include <libicb.h>
+#include <pdscdef.h>
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
+ do { \
+ unsigned long handle; \
+ PDSCDEF *pv; \
+ INVO_CONTEXT_BLK invo; \
+ \
+ memset (&invo, 0, sizeof (INVO_CONTEXT_BLK)); \
+ \
+ invo.libicb$q_ireg [29] = *((long long *) (CONTEXT)->reg [29]); \
+ invo.libicb$q_ireg [30] = (long long) (CONTEXT)->cfa; \
+ handle = LIB$GET_INVO_HANDLE (&invo); \
+ LIB$GET_INVO_CONTEXT (handle, &invo); \
+ pv = (PDSCDEF *) invo.libicb$ph_procedure_descriptor; \
+ \
+ if (pv && ((pv->pdsc$w_flags & 0xf) == PDSC$K_KIND_FP_STACK)) \
+ { \
+ int i, j; \
+ \
+ (FS)->cfa_offset = pv->pdsc$l_size; \
+ (FS)->cfa_reg = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30; \
+ (FS)->retaddr_column = 26; \
+ (FS)->cfa_how = CFA_REG_OFFSET; \
+ (FS)->regs.reg[27].loc.offset = -pv->pdsc$l_size; \
+ (FS)->regs.reg[27].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[26].loc.offset \
+ = -(pv->pdsc$l_size - pv->pdsc$w_rsa_offset); \
+ (FS)->regs.reg[26].how = REG_SAVED_OFFSET; \
+ \
+ for (i = 0, j = 0; i < 32; i++) \
+ if (1<<i & pv->pdsc$l_ireg_mask) \
+ { \
+ (FS)->regs.reg[i].loc.offset \
+ = -(pv->pdsc$l_size - pv->pdsc$w_rsa_offset - 8 * ++j); \
+ (FS)->regs.reg[i].how = REG_SAVED_OFFSET; \
+ } \
+ \
+ goto SUCCESS; \
+ } \
+} while (0)
+#endif
/* This is how to output an assembler line
that says to advance the location counter
@@ -439,30 +437,8 @@ extern int vms_valid_decl_attribute_p ();
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
fprintf (FILE, "\t.align %d\n", LOG);
-#define ASM_OUTPUT_SECTION(FILE,SECTION) \
- (strcmp (SECTION, ".text") == 0) \
- ? text_section () \
- : named_section (NULL_TREE, SECTION, 0), \
- ASM_OUTPUT_ALIGN (FILE, 0) \
-
-#define ASM_OUTPUT_SECTION_NAME(FILE,DECL,NAME,RELOC) \
- do \
- { \
- char *flags; \
- int ovr = 0; \
- if (DECL && DECL_MACHINE_ATTRIBUTES (DECL) \
- && lookup_attribute \
- ("overlaid", DECL_MACHINE_ATTRIBUTES (DECL))) \
- flags = ",OVR", ovr = 1; \
- else if (strncmp (NAME,".debug", 6) == 0) \
- flags = ",NOWRT"; \
- else \
- flags = ""; \
- fputc ('\n', (FILE)); \
- fprintf (FILE, ".section\t%s%s\n", NAME, flags); \
- if (ovr) \
- (NAME) = ""; \
- } while (0)
+/* Switch into a generic section. */
+#define TARGET_ASM_NAMED_SECTION vms_asm_named_section
#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \
do { literals_section(); \
@@ -474,7 +450,7 @@ extern int vms_valid_decl_attribute_p ();
} while (0)
#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+#define PREFERRED_DEBUGGING_TYPE VMS_AND_DWARF2_DEBUG
#undef ASM_FORMAT_PRIVATE_NAME
#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
@@ -486,10 +462,38 @@ extern int vms_valid_decl_attribute_p ();
#undef ASM_SPEC
#undef ASM_FINAL_SPEC
+
+/* The VMS convention is to always provide minimal debug info
+ for a traceback unless specifically overridden. Defaulting this here
+ is a kludge. */
+
+#define OPTIMIZATION_OPTIONS(OPTIMIZE, OPTIMIZE_SIZE) \
+{ \
+ write_symbols = VMS_DEBUG; \
+ debug_info_level = (enum debug_info_level) 1; \
+}
+
+/* Override traceback debug info on -g0. */
+#undef OVERRIDE_OPTIONS
+#define OVERRIDE_OPTIONS \
+{ \
+ if (write_symbols == NO_DEBUG) \
+ debug_info_level = (enum debug_info_level) 0; \
+ override_options (); \
+}
+
+/* Link with vms-dwarf2.o if -g (except -g0). This causes the
+ VMS link to pull all the dwarf2 debug sections together. */
#undef LINK_SPEC
+#define LINK_SPEC "%{g:-g vms-dwarf2.o%s} %{g0} %{g1:-g1 vms-dwarf2.o%s} \
+%{g2:-g2 vms-dwarf2.o%s} %{g3:-g3 vms-dwarf2.o%s} %{shared} %{v} %{map}"
+
#undef STARTFILE_SPEC
-#define ASM_SPEC "-nocpp %{pg}"
-#define LINK_SPEC "%{g3:-g3} %{g0:-g0} %{shared:-shared} %{v:-v}"
+#define STARTFILE_SPEC "%{!shared:%{mvms-return-codes:vcrt0.o%s} \
+%{!mvms-return-codes:pcrt0.o%s}}"
+
+#undef LIB_SPEC
+#define LIB_SPEC "-lc"
/* Define the names of the division and modulus functions. */
#define DIVSI3_LIBCALL "OTS$DIV_I"
@@ -501,6 +505,14 @@ extern int vms_valid_decl_attribute_p ();
#define UMODSI3_LIBCALL "OTS$REM_UI"
#define UMODDI3_LIBCALL "OTS$REM_UL"
-#define DIR_SEPARATOR ']'
+#define NAME__MAIN "__gccmain"
+#define SYMBOL__MAIN __gccmain
-#define PREFIX "GNU_ROOT:"
+/* Specify the list of include file directories. */
+#define INCLUDE_DEFAULTS \
+{ \
+ { "/gnu_gxx_include", 0, 1, 1 }, \
+ { "/gnu_cc_include", 0, 0, 0 }, \
+ { "/gnu/include", 0, 0, 0 }, \
+ { 0, 0, 0, 0 } \
+}
diff --git a/contrib/gcc/config/alpha/vms64.h b/contrib/gcc/config/alpha/vms64.h
new file mode 100644
index 0000000..3b4f587
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms64.h
@@ -0,0 +1,32 @@
+/* Output variables, constants and external declarations, for GNU compiler.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas Rupp (rupp@gnat.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. */
+
+/* Defaults to BITS_PER_WORD, e.g. 64 which is what is wanted.
+ This is incompatible with DEC C, but matches DEC Ada */
+#undef LONG_TYPE_SIZE
+
+/* Defaults to "long int" */
+#undef SIZE_TYPE
+#undef PTRDIFF_TYPE
+
+#undef POINTERS_EXTEND_UNSIGNED
+#undef POINTER_SIZE
+#define POINTER_SIZE 64
diff --git a/contrib/gcc/config/alpha/vms_tramp.asm b/contrib/gcc/config/alpha/vms_tramp.asm
new file mode 100644
index 0000000..9a6a1c8
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms_tramp.asm
@@ -0,0 +1,52 @@
+/* VMS trampoline for nested functions
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas B. Rupp (rupp@gnat.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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+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. */
+
+;# Alpha OpenVMS trampoline
+;#
+ .set noreorder
+ .set volatile
+ .set noat
+ .file 1 "vms_tramp.asm"
+.text
+ .align 3
+ .globl __tramp
+ .ent __tramp
+__tramp..en:
+
+.link
+ .align 3
+__tramp:
+ .pdesc __tramp..en,null
+.text
+ ldq $1,24($27)
+ ldq $27,16($27)
+ ldq $28,8($27)
+ jmp $31,($28),0
+ .end __tramp
diff --git a/contrib/gcc/config/alpha/vxworks.h b/contrib/gcc/config/alpha/vxworks.h
index 7ef1fee..2f711ce 100644
--- a/contrib/gcc/config/alpha/vxworks.h
+++ b/contrib/gcc/config/alpha/vxworks.h
@@ -28,8 +28,8 @@ Boston, MA 02111-1307, USA. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "\
--D__vxworks -D__alpha_vxworks -Asystem(vxworks) \
--Asystem(embedded) -D_LONGLONG"
+-D__vxworks -D__alpha_vxworks -Asystem=vxworks \
+-Asystem=embedded -D_LONGLONG"
/* VxWorks does all the library stuff itself. */
diff --git a/contrib/gcc/config/alpha/x-vms b/contrib/gcc/config/alpha/x-vms
new file mode 100644
index 0000000..f53f1c7
--- /dev/null
+++ b/contrib/gcc/config/alpha/x-vms
@@ -0,0 +1,22 @@
+# Under VMS, directory names cannot contain dots.
+version:=$(shell echo $(gcc_version) | sed -e 's/\./_/g')
+
+# Rules for linker and compiler wrappers. These are only useful on
+# a VMS host.
+EXTRA_PROGRAMS=ld.exe decc.exe
+vms-ld.o : $(srcdir)/config/alpha/vms-ld.c
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+ld.exe : vms-ld.o
+ $(CC) -o $@ vms-ld.o ../libiberty/libiberty.a
+
+vms-cc.o : $(srcdir)/config/alpha/vms-cc.c
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+decc.exe : vms-cc.o
+ $(CC) -o $@ vms-cc.o ../libiberty/libiberty.a
+
+# These extra parts can only be compiled on a VMS host and are only needed
+# on a VMS target. The rules are in t-vms.
+VMS_EXTRA_PARTS=vcrt0.o pcrt0.o
+
+# Doesn't work on VMS
+USE_COLLECT2=
diff --git a/contrib/gcc/config/alpha/xm-alpha-interix.h b/contrib/gcc/config/alpha/xm-alpha-interix.h
index 02c53b8..dd71a1d 100644
--- a/contrib/gcc/config/alpha/xm-alpha-interix.h
+++ b/contrib/gcc/config/alpha/xm-alpha-interix.h
@@ -1,6 +1,6 @@
/* Configuration for GNU compiler
for an DEC/Compaq Alpha
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
Donn Terry, Softway Systems, Inc.
derived from code by Douglas B. Rupp (drupp@cs.washington.edu)
@@ -21,11 +21,6 @@ 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. */
-#include <alpha/xm-alpha.h>
-
-#undef HOST_BITS_PER_LONG
-#define HOST_BITS_PER_LONG 32
-
#define HOST_BITS_PER_WIDE_INT 64
#ifdef __GNUC__
# define HOST_WIDE_INT long long
@@ -33,7 +28,6 @@ Boston, MA 02111-1307, USA. */
# define HOST_WIDE_INT __int64
#endif
-
#define HOST_BITS_PER_WIDEST_INT HOST_BITS_PER_LONGLONG
#ifdef __GNUC__
# define HOST_WIDEST_INT long long
diff --git a/contrib/gcc/config/alpha/xm-vms.h b/contrib/gcc/config/alpha/xm-vms.h
index 472a225..d728ec1 100644
--- a/contrib/gcc/config/alpha/xm-vms.h
+++ b/contrib/gcc/config/alpha/xm-vms.h
@@ -1,5 +1,5 @@
/* Configuration for GNU C-compiler for openVMS/Alpha.
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2001 Free Software Foundation, Inc.
Contributed by Klaus Kaempf (kkaempf@progis.de).
This file is part of GNU CC.
@@ -19,75 +19,27 @@ 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. */
-/* If compiling with DECC, need to fix problem with <stdio.h>
- which defines a macro called FILE_TYPE that breaks "tree.h".
- Fortunately it uses #ifndef to suppress multiple inclusions.
- Three possible cases:
- 1) <stdio.h> has already been included -- ours will be no-op;
- 2) <stdio.h> will be included after us -- "theirs" will be no-op;
- 3) <stdio.h> isn't needed -- including it here shouldn't hurt.
- In all three cases, the problem macro will be removed here. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef __DECC
-#undef FILE_TYPE
-#endif
-
-#undef HOST_BITS_PER_LONG
-#define HOST_BITS_PER_LONG 32
-
#define HOST_WIDE_INT long long
#define HOST_BITS_PER_WIDE_INT 64
-#undef SUCCESS_EXIT_CODE
-#define SUCCESS_EXIT_CODE 1
-#undef FATAL_EXIT_CODE
-#define FATAL_EXIT_CODE (44 | 0x10000000) /* Abort, and no DCL message. */
-
/* A couple of conditionals for execution machine are controlled here. */
#ifndef VMS
#define VMS
#endif
-#define GCC_INCLUDE_DIR ""
-/* Specify the list of include file directories. */
-#define INCLUDE_DEFAULTS \
-{ \
- { "GNU_GXX_INCLUDE:", "G++", 1, 1 }, \
- { "GNU_CC_INCLUDE:", "GCC", 0, 0 }, \
- { ".", 0, 0, 1 }, \
- { 0, 0, 0, 0 } \
-}
-
/* Define a local equivalent (sort of) for unlink */
#define unlink remove
-#define NEED_ATEXIT
-#define HAVE_VPRINTF
-#define HAVE_PUTENV
-#define HAVE_STRERROR
-#define HAVE_ATOLL
+/* Causes exit() to be redefined to __posix_exit() and
+ Posix compatible failure and success codes to be used */
+#define _POSIX_EXIT 1
-#define NO_SYS_PARAMS_H /* Don't have <sys/params.h> */
-#define USE_C_ALLOCA /* Using alloca.c */
+/* Open files in stream mode if not otherwise explicitly specified */
+#define __UNIX_FOPEN 1
-#define HAVE_FCNTL_H 1
-#define HAVE_STDLIB_H 1
-#define HAVE_UNISTD_H 1
-#define HAVE_STRING_H 1
-#define HAVE_LIMITS_H 1
-#define HAVE_STDDEF_H 1
-#define HAVE_TIME_H 1
#define STDC_HEADERS 1
-#define HAVE_CPP_STRINGIFY 1
-#if __STDC__
-extern void *alloca (size_t);
-#else
-extern char *alloca (unsigned int);
-#endif
+#define HOST_EXECUTABLE_SUFFIX ".exe"
+#define HOST_OBJECT_SUFFIX ".obj"
-#define OBJECT_SUFFIX ".obj"
-#define EXECUTABLE_SUFFIX ".exe"
+#define DUMPFILE_FORMAT "_%02d_"
diff --git a/contrib/gcc/config/alpha/xm-vms64.h b/contrib/gcc/config/alpha/xm-vms64.h
new file mode 100644
index 0000000..26fd829
--- /dev/null
+++ b/contrib/gcc/config/alpha/xm-vms64.h
@@ -0,0 +1,29 @@
+/* Configuration for GNU C-compiler for openVMS/Alpha.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Douglas Rupp (rupp@gnat.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. */
+
+#undef HOST_WIDE_INT
+
+/* Since DEC C long != Gnu C long */
+#define HOST_PTR_PRINTF "%llx"
+#define HOST_WIDE_INT_PRINT_DEC "%lld"
+#define HOST_WIDE_INT_PRINT_UNSIGNED "%llu"
+#define HOST_WIDE_INT_PRINT_HEX "0x%llx"
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%016llx"
OpenPOWER on IntegriCloud