📄 pa.c
字号:
/* Subroutines for insn-output.c for HPPA. Copyright (C) 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdio.h>#include "config.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 "c-tree.h"#include "expr.h"#include "obstack.h"/* 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;/* Set by the FUNCTION_PROFILER macro. */int hp_profile_labelno;/* Name of where we pretend to think the frame pointer points. Normally, this is "4", but if we are in a leaf procedure, this is "something(30)". Will this work? */char *frame_base_name;static rtx find_addr_reg ();/* 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 || register_operand (op, mode));}intcall_operand_address (op, mode) rtx op; enum machine_mode mode;{ return (REG_P (op) || (CONSTANT_P (op) && ! TARGET_LONG_CALLS));}intsymbolic_operand (op, mode) register rtx op; enum machine_mode mode;{ 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;{ 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;}intmove_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (op == CONST0_RTX (mode)) return 1; if (GET_MODE (op) != mode) return 0; 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))); return memory_address_p (mode, op);}intpic_operand (op, mode) rtx op; enum machine_mode mode;{ return flag_pic && GET_CODE (op) == LABEL_REF;}intshort_memory_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == MEM) { if (GET_CODE (XEXP (op, 0)) == REG) return 1; else if (GET_CODE (XEXP (op, 0)) == PLUS) { rtx op1 = XEXP (XEXP (op, 0), 0); rtx op2 = XEXP (XEXP (op, 0), 1); if (GET_CODE (op1) == REG) return (GET_CODE (op2) == CONST_INT && INT_5_BITS (op2)); else if (GET_CODE (op2) == REG) return (GET_CODE (op1) == CONST_INT && INT_5_BITS (op1)); } } return 0;}intregister_or_short_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); return short_memory_operand (op, mode);}intfp_reg_operand (op, mode) rtx op; enum machine_mode mode;{ return reg_renumber && FP_REG_P (op);}intcheck_fp_mov (operands) rtx *operands;{ enum machine_mode mode = GET_MODE (operands[0]); if (fp_reg_operand (operands[0], mode)) return (register_operand (operands[1], mode) || short_memory_operand (operands[1], mode)); else if (fp_reg_operand (operands[1], mode)) return (register_operand (operands[0], mode) || short_memory_operand (operands[0], mode)); else return 1;}extern int current_function_uses_pic_offset_table;extern rtx force_reg (), validize_mem ();/* The rtx for the global offset table which is a special form that *is* a position independent symbolic constant. */rtx pic_pc_rtx;/* Ensure that we are not using patterns that are not OK with PIC. */intcheck_pic (i) int i;{ extern rtx recog_operand[]; switch (flag_pic) { case 1: if (GET_CODE (recog_operand[i]) == SYMBOL_REF || (GET_CODE (recog_operand[i]) == CONST && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) abort (); case 2: default: return 1; }}/* Return truth value of whether OP is EQ or NE. */inteq_or_neq (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == EQ || GET_CODE (op) == NE);}/* 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)));}intarith_double_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode && VAL_14_BITS_P (CONST_DOUBLE_LOW (op)) && (CONST_DOUBLE_HIGH (op) >= 0 == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));}/* Return truth value of whether OP is a integer which fits the range constraining immediate operands in three-address insns. */intint5_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));}intuint5_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));} intint11_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));}intarith5_operand (op, mode) rtx op; enum machine_mode mode;{ return register_operand (op, mode) || int5_operand (op, mode);}/* True iff zdepi can be used to generate this CONST_INT. */intdepi_cint_operand (op, mode) rtx op; enum machine_mode mode;{ unsigned x; unsigned lbmask, t; if (GET_CODE (op) != CONST_INT) return 0; /* This might not be obvious, but it's at least fast. This function is critcal; we don't have the time loops would take. */ x = INTVAL (op); lbmask = x & -x; t = ((x >> 4) + lbmask) & ~(lbmask - 1); return ((t & (t - 1)) == 0);}/* True iff depi or extru can be used to compute (reg & mask). */intconsec_zeros_p (mask) unsigned mask;{ mask = ~mask; mask += mask & -mask; return (mask & (mask - 1)) == 0;}/* True iff depi or extru can be used to compute (reg & OP). */intand_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && consec_zeros_p (INTVAL (op))));}/* True iff depi can be used to compute (reg | MASK). */intior_mask_p (mask) unsigned mask;{ mask += mask & -mask; return (mask & (mask - 1)) == 0;}/* True iff depi can be used to compute (reg | OP). */intior_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op))));}intarith32_operand (op, mode) rtx op; enum machine_mode mode;{ return register_operand (op, mode) || GET_CODE (op) == CONST_INT;}/* True iff OP can be the source of a move to a general register. */intsrcsi_operand (op, mode) rtx op; enum machine_mode mode;{ /* Not intended for other modes than SImode. */ if (mode != SImode) return 0; /* Accept any register or memory reference. */ if (nonimmediate_operand (op, mode)) return 1; if (depi_cint_operand (op, mode)) return 1; /* OK if ldo or ldil can be used. */ return (GET_CODE (op) == CONST_INT && (INT_14_BITS (op) || (INTVAL (op) & 0x7ff) == 0));}/* Legitimize PIC addresses. If the address is already position-independent, we return ORIG. Newly generated position-independent addresses go to REG. If we need more than one register, we lose. */rtxlegitimize_pic_address (orig, mode, reg) rtx orig, reg; enum machine_mode mode;{ rtx pic_ref = orig; if (GET_CODE (orig) == SYMBOL_REF) { if (reg == 0) abort (); if (flag_pic == 2) { emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (HIGH, Pmode, orig))); emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (LO_SUM, Pmode, reg, orig))); orig = reg; } pic_ref = gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig)); current_function_uses_pic_offset_table = 1; RTX_UNCHANGING_P (pic_ref) = 1; emit_move_insn (reg, pic_ref); return reg; } else if (GET_CODE (orig) == CONST) { rtx base, offset; if (GET_CODE (XEXP (orig, 0)) == PLUS && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) return orig; if (reg == 0) abort (); if (GET_CODE (XEXP (orig, 0)) == PLUS) { base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, base == reg ? 0 : reg); } else abort (); if (GET_CODE (orig) == CONST_INT) { if (SMALL_INT (orig)) return plus_constant_for_output (base, INTVAL (orig)); orig = force_reg (Pmode, orig); } pic_ref = gen_rtx (PLUS, Pmode, base, orig); /* Likewise, should we set special REG_NOTEs here? */ } return pic_ref;}/* Set up PIC-specific rtl. This should not cause any insns to be emitted. */voidinitialize_pic (){}/* Emit special PIC prologues and epilogues. */voidfinalize_pic (){ /* Need to emit this whether or not we obey regdecls, since setjmp/longjmp can cause life info to screw up. */ emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));}/* For the HPPA, REG and REG+CONST is cost 0 and addresses involving symbolic constants are cost 2. PIC addresses are very expensive. It is no coincidence that this has the same structure as GO_IF_LEGITIMATE_ADDRESS. */inthppa_address_cost (X)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -