📄 alpha.c
字号:
/* Subroutines used for code generation on the DEC Alpha. Copyright (C) 1992, 93, 94, 95, 96, 1997 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 modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include <stdio.h>#include "rtl.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 "expr.h"#include "obstack.h"#include "tree.h"/* Specify which cpu to schedule for. */enum processor_type alpha_cpu;/* Specify how accurate floating-point traps need to be. */enum alpha_trap_precision alpha_tp;/* Specify the floating-point rounding mode. */enum alpha_fp_rounding_mode alpha_fprm;/* Specify which things cause traps. */enum alpha_fp_trap_mode alpha_fptm;/* Strings decoded into the above options. */char *alpha_cpu_string; /* -mcpu=ev[4|5] */char *alpha_tp_string; /* -mtrap-precision=[p|s|i] */char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] *//* 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;/* Save the name of the current function as used by the assembler. This is used by the epilogue. */char *alpha_function_name;/* Non-zero if inside of a function, because the Alpha asm can't handle .files inside of functions. */static int inside_function = FALSE;/* Non-zero if an instruction that may cause a trap is pending. */static int trap_pending = 0;/* Nonzero if the current function needs gp. */int alpha_function_needs_gp;extern char *version_string;extern int rtx_equal_function_value_matters;/* Declarations of static functions. */static void alpha_set_memflags_1 PROTO((rtx, int, int, int));static rtx alpha_emit_set_const_1 PROTO((rtx, enum machine_mode, HOST_WIDE_INT, int));static void add_long_const PROTO((FILE *, HOST_WIDE_INT, int, int, int));/* Compute the size of the save area in the stack. */static void alpha_sa_mask PROTO((unsigned long *imaskP, unsigned long *fmaskP));/* Get the number of args of a function in one of two ways. */#ifdef OPEN_VMS#define NUM_ARGS current_function_args_info.num_args#else#define NUM_ARGS current_function_args_info#endif/* Parse target option strings. */voidoverride_options (){ alpha_cpu = TARGET_CPU_DEFAULT & MASK_CPU_EV6 ? PROCESSOR_EV6 : (TARGET_CPU_DEFAULT & MASK_CPU_EV5 ? PROCESSOR_EV5 : PROCESSOR_EV4); if (alpha_cpu_string) { if (! strcmp (alpha_cpu_string, "ev4") || ! strcmp (alpha_cpu_string, "21064")) { alpha_cpu = PROCESSOR_EV4; target_flags &= ~ (MASK_BWX | MASK_CIX | MASK_MAX); } else if (! strcmp (alpha_cpu_string, "ev5") || ! strcmp (alpha_cpu_string, "21164")) { alpha_cpu = PROCESSOR_EV5; target_flags &= ~ (MASK_BWX | MASK_CIX | MASK_MAX); } else if (! strcmp (alpha_cpu_string, "ev56") || ! strcmp (alpha_cpu_string, "21164a")) { alpha_cpu = PROCESSOR_EV5; target_flags |= MASK_BWX; target_flags &= ~ (MASK_CIX | MASK_MAX); } else if (! strcmp (alpha_cpu_string, "pca56") || ! strcmp (alpha_cpu_string, "21164PC")) { alpha_cpu = PROCESSOR_EV5; target_flags |= MASK_BWX | MASK_MAX; target_flags &= ~ MASK_CIX; } else if (! strcmp (alpha_cpu_string, "ev6") || ! strcmp (alpha_cpu_string, "21264")) { alpha_cpu = PROCESSOR_EV6; target_flags |= MASK_BWX | MASK_CIX | MASK_MAX; } else error ("bad value `%s' for -mcpu switch", alpha_cpu_string); } alpha_tp = ALPHA_TP_PROG; alpha_fprm = ALPHA_FPRM_NORM; alpha_fptm = ALPHA_FPTM_N; if (TARGET_IEEE) { 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 (alpha_tp_string) { if (! strcmp (alpha_tp_string, "p")) alpha_tp = ALPHA_TP_PROG; else if (! strcmp (alpha_tp_string, "f")) alpha_tp = ALPHA_TP_FUNC; else if (! strcmp (alpha_tp_string, "i")) alpha_tp = ALPHA_TP_INSN; else error ("bad value `%s' for -mtrap-precision switch", alpha_tp_string); } if (alpha_fprm_string) { if (! strcmp (alpha_fprm_string, "n")) alpha_fprm = ALPHA_FPRM_NORM; else if (! strcmp (alpha_fprm_string, "m")) alpha_fprm = ALPHA_FPRM_MINF; else if (! strcmp (alpha_fprm_string, "c")) alpha_fprm = ALPHA_FPRM_CHOP; else if (! strcmp (alpha_fprm_string,"d")) alpha_fprm = ALPHA_FPRM_DYN; else error ("bad value `%s' for -mfp-rounding-mode switch", alpha_fprm_string); } if (alpha_fptm_string) { if (strcmp (alpha_fptm_string, "n") == 0) alpha_fptm = ALPHA_FPTM_N; else if (strcmp (alpha_fptm_string, "u") == 0) alpha_fptm = ALPHA_FPTM_U; else if (strcmp (alpha_fptm_string, "su") == 0) alpha_fptm = ALPHA_FPTM_SU; else if (strcmp (alpha_fptm_string, "sui") == 0) alpha_fptm = ALPHA_FPTM_SUI; else error ("bad value `%s' for -mfp-trap-mode switch", alpha_fptm_string); } /* Do some sanity checks on the above option. */ if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI) && alpha_tp != ALPHA_TP_INSN) { warning ("fp software completion requires -mtrap-precision=i"); alpha_tp = ALPHA_TP_INSN; } if (TARGET_FLOAT_VAX) { if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN) { warning ("rounding mode not supported for VAX floats"); alpha_fprm = ALPHA_FPRM_NORM; } if (alpha_fptm == ALPHA_FPTM_SUI) { warning ("trap mode not supported for VAX floats"); alpha_fptm = ALPHA_FPTM_SU; } }}/* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */intzap_mask (value) HOST_WIDE_INT value;{ int i; for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++, value >>= 8) if ((value & 0xff) != 0 && (value & 0xff) != 0xff) return 0; return 1;}/* Returns 1 if OP is either the constant zero or a register. If a register, it must be in the proper mode unless MODE is VOIDmode. */intreg_or_0_operand (op, mode) register rtx op; enum machine_mode mode;{ return op == const0_rtx || register_operand (op, mode);}/* Return 1 if OP is a constant in the range of 0-63 (for a shift) or any register. */intreg_or_6bit_operand (op, mode) register rtx op; enum machine_mode mode;{ return ((GET_CODE (op) == CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (op) < 64) || register_operand (op, mode));}/* Return 1 if OP is an 8-bit constant or any register. */intreg_or_8bit_operand (op, mode) register rtx op; enum machine_mode mode;{ return ((GET_CODE (op) == CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100) || register_operand (op, mode));}/* Return 1 if OP is an 8-bit constant. */intcint8_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100);}/* Return 1 if the operand is a valid second operand to an add insn. */intadd_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K') || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L') || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')); return register_operand (op, mode);}/* Return 1 if the operand is a valid second operand to a sign-extending add insn. */intsext_add_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255 || (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255); return register_operand (op, mode);}/* Return 1 if OP is the constant 4 or 8. */intconst48_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && (INTVAL (op) == 4 || INTVAL (op) == 8));}/* Return 1 if OP is a valid first operand to an AND insn. */intand_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode) return (zap_mask (CONST_DOUBLE_LOW (op)) && zap_mask (CONST_DOUBLE_HIGH (op))); if (GET_CODE (op) == CONST_INT) return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100 || zap_mask (INTVAL (op))); return register_operand (op, mode);}/* Return 1 if OP is a valid first operand to an IOR or XOR insn. */intor_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100); return register_operand (op, mode);}/* Return 1 if OP is a constant that is the width, in bits, of an integral mode smaller than DImode. */intmode_width_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32));}/* Return 1 if OP is a constant that is the width of an integral machine mode smaller than an integer. */intmode_mask_operand (op, mode) register rtx op; enum machine_mode mode;{#if HOST_BITS_PER_WIDE_INT == 32 if (GET_CODE (op) == CONST_DOUBLE) return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1;#endif return (GET_CODE (op) == CONST_INT && (INTVAL (op) == 0xff || INTVAL (op) == 0xffff#if HOST_BITS_PER_WIDE_INT == 64 || INTVAL (op) == 0xffffffff#endif ));}/* Return 1 if OP is a multiple of 8 less than 64. */intmul8_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (op) < 64 && (INTVAL (op) & 7) == 0);}/* Return 1 if OP is the constant zero in floating-point. */intfp0_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_MODE (op) == mode && GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode));}/* Return 1 if OP is the floating-point constant zero or a register. */intreg_or_fp0_operand (op, mode) register rtx op; enum machine_mode mode;{ return fp0_operand (op, mode) || register_operand (op, mode);}/* Return 1 if OP is a register or a constant integer. */intreg_or_cint_operand (op, mode) register rtx op; enum machine_mode mode;{ return GET_CODE (op) == CONST_INT || register_operand (op, mode);}/* Return 1 if OP is something that can be reloaded into a register; if it is a MEM, it need not be valid. */intsome_operand (op, mode) register rtx op; enum machine_mode mode;{ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) return 0; switch (GET_CODE (op)) { case REG: case MEM: case CONST_DOUBLE: case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST: return 1; case SUBREG: return some_operand (SUBREG_REG (op), VOIDmode); } return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -