📄 sparc.c
字号:
/* Subroutines for insn-output.c for Sun SPARC. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) 64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans, at Cygnus Support.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 "system.h"#include "tree.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 "expr.h"#include "recog.h"#include "toplev.h"/* 1 if the caller has placed an "unimp" insn immediately after the call. This is used in v8 code when calling a function that returns a structure. v9 doesn't have this. Be careful to have this test be the same as that used on the call. */#define SKIP_CALLERS_UNIMP_P \(!TARGET_ARCH64 && current_function_returns_struct \ && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))) \ && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) \ == INTEGER_CST))/* Global variables for machine-dependent things. *//* Size of frame. Need to know this to emit return insns from leaf procedures. ACTUAL_FSIZE is set by compute_frame_size() which is called during the reload pass. This is important as the value is later used in insn scheduling (to see what can go in a delay slot). APPARENT_FSIZE is the size of the stack less the register save area and less the outgoing argument area. It is used when saving call preserved regs. */static int apparent_fsize;static int actual_fsize;/* Save the operands last given to a compare for use when we generate a scc or bcc insn. */rtx sparc_compare_op0, sparc_compare_op1;/* We may need an epilogue if we spill too many registers. If this is non-zero, then we branch here for the epilogue. */static rtx leaf_label;#ifdef LEAF_REGISTERS/* Vector to say how input registers are mapped to output registers. FRAME_POINTER_REGNUM cannot be remapped by this function to eliminate it. You must use -fomit-frame-pointer to get that. */char leaf_reg_remap[] ={ 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, -1, 15, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100};#endif/* Name of where we pretend to think the frame pointer points. Normally, this is "%fp", but if we are in a leaf procedure, this is "%sp+something". We record "something" separately as it may be too big for reg+constant addressing. */static const char *frame_base_name;static int frame_base_offset;static rtx pic_setup_code PROTO((void));static void sparc_init_modes PROTO((void));static int save_regs PROTO((FILE *, int, int, const char *, int, int, int));static int restore_regs PROTO((FILE *, int, int, const char *, int, int));static void build_big_number PROTO((FILE *, int, const char *));static int function_arg_slotno PROTO((const CUMULATIVE_ARGS *, enum machine_mode, tree, int, int, int *, int *));static int supersparc_adjust_cost PROTO((rtx, rtx, rtx, int));static int hypersparc_adjust_cost PROTO((rtx, rtx, rtx, int));static int ultrasparc_adjust_cost PROTO((rtx, rtx, rtx, int));static void sparc_output_addr_vec PROTO((rtx));static void sparc_output_addr_diff_vec PROTO((rtx));static void sparc_output_deferred_case_vectors PROTO((void));#ifdef DWARF2_DEBUGGING_INFOextern char *dwarf2out_cfi_label ();#endif/* Option handling. *//* Code model option as passed by user. */const char *sparc_cmodel_string;/* Parsed value. */enum cmodel sparc_cmodel;/* Record alignment options as passed by user. */const char *sparc_align_loops_string;const char *sparc_align_jumps_string;const char *sparc_align_funcs_string;/* Parsed values, as a power of two. */int sparc_align_loops;int sparc_align_jumps;int sparc_align_funcs;struct sparc_cpu_select sparc_select[] ={ /* switch name, tune arch */ { (char *)0, "default", 1, 1 }, { (char *)0, "-mcpu=", 1, 1 }, { (char *)0, "-mtune=", 1, 0 }, { 0, 0, 0, 0 }};/* CPU type. This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx. */enum processor_type sparc_cpu;/* Validate and override various options, and do some machine dependent initialization. */voidsparc_override_options (){ static struct code_model { const char *name; int value; } cmodels[] = { { "32", CM_32 }, { "medlow", CM_MEDLOW }, { "medmid", CM_MEDMID }, { "medany", CM_MEDANY }, { "embmedany", CM_EMBMEDANY }, { 0, 0 } }; struct code_model *cmodel; /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=. */ static struct cpu_default { int cpu; const char *name; } cpu_default[] = { /* There must be one entry here for each TARGET_CPU value. */ { TARGET_CPU_sparc, "cypress" }, { TARGET_CPU_sparclet, "tsc701" }, { TARGET_CPU_sparclite, "f930" }, { TARGET_CPU_v8, "v8" }, { TARGET_CPU_hypersparc, "hypersparc" }, { TARGET_CPU_sparclite86x, "sparclite86x" }, { TARGET_CPU_supersparc, "supersparc" }, { TARGET_CPU_v9, "v9" }, { TARGET_CPU_ultrasparc, "ultrasparc" }, { 0, 0 } }; struct cpu_default *def; /* Table of values for -m{cpu,tune}=. */ static struct cpu_table { const char *name; enum processor_type processor; int disable; int enable; } cpu_table[] = { { "v7", PROCESSOR_V7, MASK_ISA, 0 }, { "cypress", PROCESSOR_CYPRESS, MASK_ISA, 0 }, { "v8", PROCESSOR_V8, MASK_ISA, MASK_V8 }, /* TI TMS390Z55 supersparc */ { "supersparc", PROCESSOR_SUPERSPARC, MASK_ISA, MASK_V8 }, { "sparclite", PROCESSOR_SPARCLITE, MASK_ISA, MASK_SPARCLITE }, /* The Fujitsu MB86930 is the original sparclite chip, with no fpu. The Fujitsu MB86934 is the recent sparclite chip, with an fpu. */ { "f930", PROCESSOR_F930, MASK_ISA|MASK_FPU, MASK_SPARCLITE }, { "f934", PROCESSOR_F934, MASK_ISA, MASK_SPARCLITE|MASK_FPU }, { "hypersparc", PROCESSOR_HYPERSPARC, MASK_ISA, MASK_V8|MASK_FPU }, { "sparclite86x", PROCESSOR_SPARCLITE86X, MASK_ISA|MASK_FPU, MASK_V8 }, { "sparclet", PROCESSOR_SPARCLET, MASK_ISA, MASK_SPARCLET }, /* TEMIC sparclet */ { "tsc701", PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET }, { "v9", PROCESSOR_V9, MASK_ISA, MASK_V9 }, /* TI ultrasparc */ { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9 }, { 0, 0, 0, 0 } }; struct cpu_table *cpu; struct sparc_cpu_select *sel; int fpu; #ifndef SPARC_BI_ARCH /* Check for unsupported architecture size. */ if (! TARGET_64BIT != DEFAULT_ARCH32_P) { error ("%s is not supported by this configuration", DEFAULT_ARCH32_P ? "-m64" : "-m32"); }#endif /* At the moment we don't allow different pointer size and architecture */ if (! TARGET_64BIT != ! TARGET_PTR64) { error ("-mptr%d not allowed on -m%d", TARGET_PTR64 ? 64 : 32, TARGET_64BIT ? 64 : 32); if (TARGET_64BIT) target_flags |= MASK_PTR64; else target_flags &= ~MASK_PTR64; } /* Code model selection. */ sparc_cmodel = SPARC_DEFAULT_CMODEL; #ifdef SPARC_BI_ARCH if (TARGET_ARCH32) sparc_cmodel = CM_32;#endif if (sparc_cmodel_string != NULL) { if (TARGET_ARCH64) { for (cmodel = &cmodels[0]; cmodel->name; cmodel++) if (strcmp (sparc_cmodel_string, cmodel->name) == 0) break; if (cmodel->name == NULL) error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string); else sparc_cmodel = cmodel->value; } else error ("-mcmodel= is not supported on 32 bit systems"); } fpu = TARGET_FPU; /* save current -mfpu status */ /* Set the default CPU. */ for (def = &cpu_default[0]; def->name; ++def) if (def->cpu == TARGET_CPU_DEFAULT) break; if (! def->name) abort (); sparc_select[0].string = def->name; for (sel = &sparc_select[0]; sel->name; ++sel) { if (sel->string) { for (cpu = &cpu_table[0]; cpu->name; ++cpu) if (! strcmp (sel->string, cpu->name)) { if (sel->set_tune_p) sparc_cpu = cpu->processor; if (sel->set_arch_p) { target_flags &= ~cpu->disable; target_flags |= cpu->enable; } break; } if (! cpu->name) error ("bad value (%s) for %s switch", sel->string, sel->name); } } /* If -mfpu or -mno-fpu was explicitly used, don't override with the processor default. */ if (TARGET_FPU_SET) target_flags = (target_flags & ~MASK_FPU) | fpu; /* Use the deprecated v8 insns for sparc64 in 32 bit mode. */ if (TARGET_V9 && TARGET_ARCH32) target_flags |= MASK_DEPRECATED_V8_INSNS; /* V8PLUS requires V9, makes no sense in 64 bit mode. */ if (! TARGET_V9 || TARGET_ARCH64) target_flags &= ~MASK_V8PLUS; /* Don't use stack biasing in 32 bit mode. */ if (TARGET_ARCH32) target_flags &= ~MASK_STACK_BIAS; /* Don't allow -mvis if FPU is disabled. */ if (! TARGET_FPU) target_flags &= ~MASK_VIS; /* Validate -malign-loops= value, or provide default. */ if (sparc_align_loops_string) { sparc_align_loops = exact_log2 (atoi (sparc_align_loops_string)); if (sparc_align_loops < 2 || sparc_align_loops > 7) fatal ("-malign-loops=%s is not between 4 and 128 or is not a power of two", sparc_align_loops_string); } else { /* ??? This relies on ASM_OUTPUT_ALIGN to not emit the alignment if its 0. This sounds a bit kludgey. */ sparc_align_loops = 0; } /* Validate -malign-jumps= value, or provide default. */ if (sparc_align_jumps_string) { sparc_align_jumps = exact_log2 (atoi (sparc_align_jumps_string)); if (sparc_align_jumps < 2 || sparc_align_loops > 7) fatal ("-malign-jumps=%s is not between 4 and 128 or is not a power of two", sparc_align_jumps_string); } else { /* ??? This relies on ASM_OUTPUT_ALIGN to not emit the alignment if its 0. This sounds a bit kludgey. */ sparc_align_jumps = 0; } /* Validate -malign-functions= value, or provide default. */ if (sparc_align_funcs_string) { sparc_align_funcs = exact_log2 (atoi (sparc_align_funcs_string)); if (sparc_align_funcs < 2 || sparc_align_loops > 7) fatal ("-malign-functions=%s is not between 4 and 128 or is not a power of two", sparc_align_funcs_string); } else sparc_align_funcs = DEFAULT_SPARC_ALIGN_FUNCS; /* Validate PCC_STRUCT_RETURN. */ if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN) flag_pcc_struct_return = (TARGET_ARCH64 ? 0 : 1); /* Do various machine dependent initializations. */ sparc_init_modes (); if ((profile_flag || profile_block_flag) && sparc_cmodel != CM_MEDLOW) { error ("profiling does not support code models other than medlow"); }}/* Miscellaneous utilities. *//* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move or branch on register contents instructions. */intv9_regcmp_p (code) enum rtx_code code;{ return (code == EQ || code == NE || code == GE || code == LT || code == LE || code == GT);}/* Operand constraints. *//* Return non-zero only if OP is a register of mode MODE, or const0_rtx. Don't allow const0_rtx if TARGET_LIVE_G0 because %g0 may contain anything. */intreg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (TARGET_LIVE_G0) return 0; if (op == const0_rtx) return 1; if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0) return 1; if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT && GET_CODE (op) == CONST_DOUBLE && fp_zero_operand (op)) return 1; return 0;}/* Nonzero if OP is a floating point value with value 0.0. */intfp_zero_operand (op) rtx op;{ REAL_VALUE_TYPE r; REAL_VALUE_FROM_CONST_DOUBLE (r, op); return (REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r));}/* Nonzero if OP is an integer register. */intintreg_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (register_operand (op, SImode) || (TARGET_ARCH64 && register_operand (op, DImode)));}/* Nonzero if OP is a floating point condition code register. */intfcc_reg_operand (op, mode) rtx op; enum machine_mode mode;{ /* This can happen when recog is called from combine. Op may be a MEM. Fail instead of calling abort in this case. */ if (GET_CODE (op) != REG) return 0; if (mode != VOIDmode && mode != GET_MODE (op)) return 0; if (mode == VOIDmode && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode)) return 0;#if 0 /* ??? ==> 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */ if (reg_renumber == 0) return REGNO (op) >= FIRST_PSEUDO_REGISTER; return REGNO_OK_FOR_CCFP_P (REGNO (op));#else return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;#endif}/* Nonzero if OP is an integer or floating point condition code register. */inticc_or_fcc_reg_operand (op, mode) rtx op; enum machine_mode mode;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -