📄 s390.c
字号:
/* Subroutines used for code generation on IBM S/390 and zSeries Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com).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 "rtl.h"#include "tree.h"#include "tm_p.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "except.h"#include "function.h"#include "recog.h"#include "expr.h"#include "reload.h"#include "toplev.h"#include "basic-block.h"#include "integrate.h"#include "ggc.h"#include "target.h"#include "target-def.h"#include "debug.h"static bool s390_assemble_integer PARAMS ((rtx, unsigned int, int));static int s390_adjust_cost PARAMS ((rtx, rtx, rtx, int));static int s390_adjust_priority PARAMS ((rtx, int));#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"#undef TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER s390_assemble_integer#undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE s390_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE s390_function_epilogue#undef TARGET_ASM_OPEN_PAREN#define TARGET_ASM_OPEN_PAREN ""#undef TARGET_ASM_CLOSE_PAREN#define TARGET_ASM_CLOSE_PAREN ""#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST s390_adjust_cost#undef TARGET_SCHED_ADJUST_PRIORITY#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_prioritystruct gcc_target targetm = TARGET_INITIALIZER;extern int reload_completed;/* The alias set for prologue/epilogue register save/restore. */static int s390_sr_alias_set = 0;/* Function count for creating unique internal labels in a compile unit. */int s390_function_count = 0;/* Save information from a "cmpxx" operation until the branch or scc is emitted. */rtx s390_compare_op0, s390_compare_op1;/* Structure used to hold the components of a S/390 memory address. A legitimate address on S/390 is of the general form base + index + displacement where any of the components is optional. base and index are registers of the class ADDR_REGS, displacement is an unsigned 12-bit immediate constant. */struct s390_address{ rtx base; rtx indx; rtx disp; int pointer;};/* Structure containing information for prologue and epilogue. */ struct s390_frame{ int frame_pointer_p; int return_reg_saved_p; int save_fprs_p; int first_save_gpr; int first_restore_gpr; int last_save_gpr; int arg_frame_offset; HOST_WIDE_INT frame_size;};static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));static int s390_branch_condition_mask PARAMS ((rtx));static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));static int check_mode PARAMS ((rtx, enum machine_mode *));static int general_s_operand PARAMS ((rtx, enum machine_mode, int));static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));static int reg_used_in_mem_p PARAMS ((int, rtx));static int addr_generation_dependency_p PARAMS ((rtx, rtx));static void s390_split_branches PARAMS ((void));static void find_constant_pool_ref PARAMS ((rtx, rtx *));static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));static void s390_chunkify_pool PARAMS ((void));static int save_fprs_p PARAMS ((void));static int find_unused_clobbered_reg PARAMS ((void));static void s390_frame_info PARAMS ((struct s390_frame *));static rtx save_fpr PARAMS ((rtx, int, int));static rtx restore_fpr PARAMS ((rtx, int, int));static int s390_function_arg_size PARAMS ((enum machine_mode, tree)); /* Return true if SET either doesn't set the CC register, or else the source and destination have matching CC modes and that CC mode is at least as constrained as REQ_MODE. */ static ints390_match_ccmode_set (set, req_mode) rtx set; enum machine_mode req_mode;{ enum machine_mode set_mode; if (GET_CODE (set) != SET) abort (); if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set)))) return 1; set_mode = GET_MODE (SET_DEST (set)); switch (set_mode) { case CCSmode: if (req_mode != CCSmode) return 0; break; case CCUmode: if (req_mode != CCUmode) return 0; break; case CCLmode: if (req_mode != CCLmode) return 0; break; case CCZmode: if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode) return 0; break; default: abort (); } return (GET_MODE (SET_SRC (set)) == set_mode);}/* Return true if every SET in INSN that sets the CC register has source and destination with matching CC modes and that CC mode is at least as constrained as REQ_MODE. */ ints390_match_ccmode (insn, req_mode) rtx insn; enum machine_mode req_mode;{ int i; if (GET_CODE (PATTERN (insn)) == SET) return s390_match_ccmode_set (PATTERN (insn), req_mode); if (GET_CODE (PATTERN (insn)) == PARALLEL) for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) { rtx set = XVECEXP (PATTERN (insn), 0, i); if (GET_CODE (set) == SET) if (!s390_match_ccmode_set (set, req_mode)) return 0; } return 1;}/* Given a comparison code OP (EQ, NE, etc.) and the operands OP0 and OP1 of a COMPARE, return the mode to be used for the comparison. */enum machine_modes390_select_ccmode (code, op0, op1) enum rtx_code code; rtx op0; rtx op1;{ switch (code) { case EQ: case NE: if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS || GET_CODE (op1) == NEG) return CCLmode; return CCZmode; case LE: case LT: case GE: case GT: case UNORDERED: case ORDERED: case UNEQ: case UNLE: case UNLT: case UNGE: case UNGT: case LTGT: return CCSmode; case LEU: case LTU: case GEU: case GTU: return CCUmode; default: abort (); }}/* Return branch condition mask to implement a branch specified by CODE. */static ints390_branch_condition_mask (code) rtx code;{ const int CC0 = 1 << 3; const int CC1 = 1 << 2; const int CC2 = 1 << 1; const int CC3 = 1 << 0; if (GET_CODE (XEXP (code, 0)) != REG || REGNO (XEXP (code, 0)) != CC_REGNUM || XEXP (code, 1) != const0_rtx) abort (); switch (GET_MODE (XEXP (code, 0))) { case CCZmode: switch (GET_CODE (code)) { case EQ: return CC0; case NE: return CC1 | CC2 | CC3; default: abort (); } break; case CCLmode: switch (GET_CODE (code)) { case EQ: return CC0 | CC2; case NE: return CC1 | CC3; case UNORDERED: return CC2 | CC3; /* carry */ case ORDERED: return CC0 | CC1; /* no carry */ default: abort (); } break; case CCUmode: switch (GET_CODE (code)) { case EQ: return CC0; case NE: return CC1 | CC2 | CC3; case LTU: return CC1; case GTU: return CC2; case LEU: return CC0 | CC1; case GEU: return CC0 | CC2; default: abort (); } break; case CCSmode: switch (GET_CODE (code)) { case EQ: return CC0; case NE: return CC1 | CC2 | CC3; case LT: return CC1; case GT: return CC2; case LE: return CC0 | CC1; case GE: return CC0 | CC2; case UNORDERED: return CC3; case ORDERED: return CC0 | CC1 | CC2; case UNEQ: return CC0 | CC3; case UNLT: return CC1 | CC3; case UNGT: return CC2 | CC3; case UNLE: return CC0 | CC1 | CC3; case UNGE: return CC0 | CC2 | CC3; case LTGT: return CC1 | CC2; default: abort (); } default: abort (); }}/* If INV is false, return assembler mnemonic string to implement a branch specified by CODE. If INV is true, return mnemonic for the corresponding inverted branch. */static const char *s390_branch_condition_mnemonic (code, inv) rtx code; int inv;{ static const char *mnemonic[16] = { NULL, "o", "h", "nle", "l", "nhe", "lh", "ne", "e", "nlh", "he", "nl", "le", "nh", "no", NULL }; int mask = s390_branch_condition_mask (code); if (inv) mask ^= 15; if (mask < 1 || mask > 14) abort (); return mnemonic[mask];}/* If OP is an integer constant of mode MODE with exactly one HImode subpart unequal to DEF, return the number of that subpart. As a special case, all HImode subparts of OP are equal to DEF, return zero. Otherwise, return -1. */ints390_single_hi (op, mode, def) rtx op; enum machine_mode mode; int def;{ if (GET_CODE (op) == CONST_INT) { unsigned HOST_WIDE_INT value; int n_parts = GET_MODE_SIZE (mode) / 2; int i, part = -1; for (i = 0; i < n_parts; i++) { if (i == 0) value = (unsigned HOST_WIDE_INT) INTVAL (op); else value >>= 16; if ((value & 0xffff) != (unsigned)(def & 0xffff)) { if (part != -1) return -1; else part = i; } } return part == -1 ? 0 : (n_parts - 1 - part); } else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode) { unsigned HOST_WIDE_INT value; int n_parts = GET_MODE_SIZE (mode) / 2; int i, part = -1; for (i = 0; i < n_parts; i++) { if (i == 0) value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op); else if (i == HOST_BITS_PER_WIDE_INT / 16) value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op); else value >>= 16; if ((value & 0xffff) != (unsigned)(def & 0xffff)) { if (part != -1) return -1; else part = i; } } return part == -1 ? 0 : (n_parts - 1 - part); } return -1; }/* Extract the HImode part number PART from integer constant OP of mode MODE. */ints390_extract_hi (op, mode, part) rtx op; enum machine_mode mode; int part;{ int n_parts = GET_MODE_SIZE (mode) / 2; if (part < 0 || part >= n_parts) abort(); else part = n_parts - 1 - part; if (GET_CODE (op) == CONST_INT) { unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op); return ((value >> (16 * part)) & 0xffff); } else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode) { unsigned HOST_WIDE_INT value; if (part < HOST_BITS_PER_WIDE_INT / 16) value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op); else value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op), part -= HOST_BITS_PER_WIDE_INT / 16; return ((value >> (16 * part)) & 0xffff); } abort ();}/* If OP is an integer constant of mode MODE with exactly one QImode subpart unequal to DEF, return the number of that subpart. As a special case, all QImode subparts of OP are equal to DEF, return zero. Otherwise, return -1. */ints390_single_qi (op, mode, def) rtx op; enum machine_mode mode; int def;{ if (GET_CODE (op) == CONST_INT) { unsigned HOST_WIDE_INT value; int n_parts = GET_MODE_SIZE (mode); int i, part = -1; for (i = 0; i < n_parts; i++) { if (i == 0) value = (unsigned HOST_WIDE_INT) INTVAL (op); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -