📄 pa.c
字号:
/* Subroutines for insn-output.c for HPPA. Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc. Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.cThis 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 "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 "tree.h"#include "reload.h"#include "c-tree.h"#include "expr.h"#include "obstack.h"#include "toplev.h"static void restore_unscaled_index_insn_codes PROTO((rtx));static void record_unscaled_index_insn_codes PROTO((rtx));static void pa_combine_instructions PROTO((rtx));static int pa_can_combine_p PROTO((rtx, rtx, rtx, int, rtx, rtx, rtx));static int forward_branch_p PROTO((rtx));static int shadd_constant_p PROTO((int));/* Save the operands last given to a compare for use when we generate a scc or bcc insn. */rtx hppa_compare_op0, hppa_compare_op1;enum cmp_type hppa_branch_type;/* Which cpu we are scheduling for. */enum processor_type pa_cpu;/* String to hold which cpu we are scheduling for. */char *pa_cpu_string;/* Which architecture we are generating code for. */enum architecture_type pa_arch;/* String to hold which architecture we are generating code for. */char *pa_arch_string;/* Set by the FUNCTION_PROFILER macro. */int hp_profile_labelno;/* Counts for the number of callee-saved general and floating point registers which were saved by the current function's prologue. */static int gr_saved, fr_saved;/* Whether or not the current function uses an out-of-line prologue and epilogue. */static int out_of_line_prologue_epilogue;static rtx find_addr_reg ();/* Keep track of the number of bytes we have output in the CODE subspaces during this compilation so we'll know when to emit inline long-calls. */unsigned int total_code_bytes;/* Variables to handle plabels that we discover are necessary at assembly output time. They are output after the current function. */struct deferred_plabel{ rtx internal_label; char *name;} *deferred_plabels = 0;int n_deferred_plabels = 0;/* Array indexed by INSN_UIDs holding the INSN_CODE of an insn which uses an unscaled indexed address before delay slot scheduling. */static int *unscaled_index_insn_codes;/* Upper bound for the array. */static int max_unscaled_index_insn_codes_uid;voidoverride_options (){ /* Default to 7100LC scheduling. */ if (pa_cpu_string && ! strcmp (pa_cpu_string, "7100")) { pa_cpu_string = "7100"; pa_cpu = PROCESSOR_7100; } else if (pa_cpu_string && ! strcmp (pa_cpu_string, "700")) { pa_cpu_string = "700"; pa_cpu = PROCESSOR_700; } else if (pa_cpu_string == NULL || ! strcmp (pa_cpu_string, "7100LC")) { pa_cpu_string = "7100LC"; pa_cpu = PROCESSOR_7100LC; } else if (pa_cpu_string && ! strcmp (pa_cpu_string, "7200")) { pa_cpu_string = "7200"; pa_cpu = PROCESSOR_7200; } else if (pa_cpu_string && ! strcmp (pa_cpu_string, "8000")) { pa_cpu_string = "8000"; pa_cpu = PROCESSOR_8000; } else { warning ("Unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, and 8000\n", pa_cpu_string); } /* Set the instruction set architecture. */ if (pa_arch_string && ! strcmp (pa_arch_string, "1.0")) { pa_arch_string = "1.0"; pa_arch = ARCHITECTURE_10; target_flags &= ~(MASK_PA_11 | MASK_PA_20); } else if (pa_arch_string && ! strcmp (pa_arch_string, "1.1")) { pa_arch_string = "1.1"; pa_arch = ARCHITECTURE_11; target_flags &= ~MASK_PA_20; target_flags |= MASK_PA_11; } else if (pa_arch_string && ! strcmp (pa_arch_string, "2.0")) { pa_arch_string = "2.0"; pa_arch = ARCHITECTURE_20; target_flags |= MASK_PA_11 | MASK_PA_20; } else if (pa_arch_string) { warning ("Unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string); } if (flag_pic && TARGET_PORTABLE_RUNTIME) { warning ("PIC code generation is not supported in the portable runtime model\n"); } if (flag_pic && (TARGET_NO_SPACE_REGS || TARGET_FAST_INDIRECT_CALLS)) { warning ("PIC code generation is not compatible with fast indirect calls\n"); } if (flag_pic && profile_flag) { warning ("PIC code generation is not compatible with profiling\n"); } if (TARGET_SPACE && (flag_pic || profile_flag)) { warning ("Out of line entry/exit sequences are not compatible\n"); warning ("with PIC or profiling\n"); } if (! TARGET_GAS && write_symbols != NO_DEBUG) { warning ("-g is only supported when using GAS on this processor,"); warning ("-g option disabled."); write_symbols = NO_DEBUG; }}/* Return non-zero only if OP is a register of mode MODE, or CONST0_RTX. */intreg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ return (op == CONST0_RTX (mode) || register_operand (op, mode));}/* Return non-zero if OP is suitable for use in a call to a named function. (???) For 2.5 try to eliminate either call_operand_address or function_label_operand, they perform very similar functions. */intcall_operand_address (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);}/* Return 1 if X contains a symbolic expression. We know these expressions will have one of a few well defined forms, so we need only check those forms. */intsymbolic_expression_p (x) register rtx x;{ /* Strip off any HIGH. */ if (GET_CODE (x) == HIGH) x = XEXP (x, 0); return (symbolic_operand (x, VOIDmode));}intsymbolic_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ switch (GET_CODE (op)) { case SYMBOL_REF: case LABEL_REF: return 1; case CONST: op = XEXP (op, 0); return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF || GET_CODE (XEXP (op, 0)) == LABEL_REF) && GET_CODE (XEXP (op, 1)) == CONST_INT); default: return 0; }}/* Return truth value of statement that OP is a symbolic memory operand of mode MODE. */intsymbolic_memory_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);}/* Return 1 if the operand is either a register or a memory operand that is not symbolic. */intreg_or_nonsymb_mem_operand (op, mode) register rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) return 1; return 0;}/* Return 1 if the operand is either a register, zero, or a memory operand that is not symbolic. */intreg_or_0_or_nonsymb_mem_operand (op, mode) register rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (op == CONST0_RTX (mode)) return 1; if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) return 1; return 0;}/* Accept any constant that can be moved in one instructions into a general register. */intcint_ok_for_move (intval) HOST_WIDE_INT intval;{ /* OK if ldo, ldil, or zdepi, can be used. */ return (VAL_14_BITS_P (intval) || (intval & 0x7ff) == 0 || zdepi_cint_p (intval));}/* Accept anything that can be moved in one instruction into a general register. */intmove_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == CONSTANT_P_RTX) return 1; if (GET_CODE (op) == CONST_INT) return cint_ok_for_move (INTVAL (op)); if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); if (GET_CODE (op) == LO_SUM) return (register_operand (XEXP (op, 0), Pmode) && CONSTANT_P (XEXP (op, 1))); /* Since move_operand is only used for source operands, we can always allow scaled indexing! */ if (! TARGET_DISABLE_INDEXING && GET_CODE (op) == PLUS && ((GET_CODE (XEXP (op, 0)) == MULT && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT && INTVAL (XEXP (XEXP (op, 0), 1)) == GET_MODE_SIZE (mode) && GET_CODE (XEXP (op, 1)) == REG) || (GET_CODE (XEXP (op, 1)) == MULT &&GET_CODE (XEXP (XEXP (op, 1), 0)) == REG && GET_CODE (XEXP (XEXP (op, 1), 1)) == CONST_INT && INTVAL (XEXP (XEXP (op, 1), 1)) == GET_MODE_SIZE (mode) && GET_CODE (XEXP (op, 0)) == REG))) return 1; return memory_address_p (mode, op);}/* Accept REG and any CONST_INT that can be moved in one instruction into a general register. */intreg_or_cint_move_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_INT) return cint_ok_for_move (INTVAL (op)); return 0;}intpic_label_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (!flag_pic) return 0; switch (GET_CODE (op)) { case LABEL_REF: return 1; case CONST: op = XEXP (op, 0); return (GET_CODE (XEXP (op, 0)) == LABEL_REF && GET_CODE (XEXP (op, 1)) == CONST_INT); default: return 0; }}intfp_reg_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return reg_renumber && FP_REG_P (op);}/* Return truth value of whether OP can be used as an operand in a three operand arithmetic insn that accepts registers of mode MODE or 14-bit signed integers. */intarith_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));}/* Return truth value of whether OP can be used as an operand in a three operand arithmetic insn that accepts registers of mode MODE or 11-bit signed integers. */intarith11_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));}/* A constant integer suitable for use in a PRE_MODIFY memory reference. */intpre_cint_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT && INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10);}/* A constant integer suitable for use in a POST_MODIFY memory reference. */intpost_cint_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT && INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10);}intarith_double_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_DOUBLE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -