📄 vax.c
字号:
/* Subroutines for insn-output.c for VAX. Copyright (C) 1987, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.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 "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "function.h"#include "output.h"#include "insn-attr.h"#include "recog.h"#include "expr.h"#include "flags.h"#include "debug.h"#include "tm_p.h"#include "target.h"#include "target-def.h"static int follows_p PARAMS ((rtx, rtx));static void vax_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));#if VMS_TARGETstatic void vms_asm_out_constructor PARAMS ((rtx, int));static void vms_asm_out_destructor PARAMS ((rtx, int));static void vms_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));static void vms_encode_section_info PARAMS ((tree, int));static void vms_globalize_label PARAMS ((FILE *, const char *));#endifstatic void vax_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree));/* Initialize the GCC target structure. */#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE vax_output_function_prologue#if VMS_TARGET#undef TARGET_ASM_SELECT_SECTION#define TARGET_ASM_SELECT_SECTION vms_select_section#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO vms_encode_section_info#undef TARGET_ASM_GLOBALIZE_LABEL#define TARGET_ASM_GLOBALIZE_LABEL vms_globalize_label#endif#undef TARGET_ASM_OUTPUT_MI_THUNK#define TARGET_ASM_OUTPUT_MI_THUNK vax_output_mi_thunk#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcallstruct gcc_target targetm = TARGET_INITIALIZER;/* Set global variables as needed for the options enabled. */voidoverride_options (){ /* We're VAX floating point, not IEEE floating point. */ memset (real_format_for_mode, 0, sizeof real_format_for_mode); real_format_for_mode[SFmode - QFmode] = &vax_f_format; real_format_for_mode[DFmode - QFmode] = (TARGET_G_FLOAT ? &vax_g_format : &vax_d_format);}/* Generate the assembly code for function entry. FILE is a stdio stream to output the code to. SIZE is an int: how many units of temporary storage to allocate. Refer to the array `regs_ever_live' to determine which registers to save; `regs_ever_live[I]' is nonzero if register number I is ever used in the function. This function is responsible for knowing which registers should not be saved even if used. */static voidvax_output_function_prologue (file, size) FILE * file; HOST_WIDE_INT size;{ register int regno; register int mask = 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (regs_ever_live[regno] && !call_used_regs[regno]) mask |= 1 << regno; fprintf (file, "\t.word 0x%x\n", mask); if (dwarf2out_do_frame ()) { const char *label = dwarf2out_cfi_label (); int offset = 0; for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno) if (regs_ever_live[regno] && !call_used_regs[regno]) dwarf2out_reg_save (label, regno, offset -= 4); dwarf2out_reg_save (label, PC_REGNUM, offset -= 4); dwarf2out_reg_save (label, FRAME_POINTER_REGNUM, offset -= 4); dwarf2out_reg_save (label, ARG_POINTER_REGNUM, offset -= 4); dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4)); } if (VMS_TARGET) { /* Adjusting the stack pointer by 4 before calling C$MAIN_ARGS is required when linking with the VMS POSIX version of the C run-time library; using `subl2 $4,r0' is adequate but we use `clrl -(sp)' instead. The extra 4 bytes could be removed after the call because STARTING_FRAME_OFFSET's setting of -4 will end up adding them right back again, but don't bother. */ if (MAIN_NAME_P (DECL_NAME (current_function_decl))) asm_fprintf (file, "\tclrl -(%Rsp)\n\tjsb _C$MAIN_ARGS\n"); } size -= STARTING_FRAME_OFFSET; if (size >= 64) asm_fprintf (file, "\tmovab %d(%Rsp),%Rsp\n", -size); else if (size) asm_fprintf (file, "\tsubl2 $%d,%Rsp\n", size);}/* This is like nonimmediate_operand with a restriction on the type of MEM. */voidsplit_quadword_operands (operands, low, n) rtx *operands, *low; int n ATTRIBUTE_UNUSED;{ int i; /* Split operands. */ low[0] = low[1] = low[2] = 0; for (i = 0; i < 3; i++) { if (low[i]) /* it's already been figured out */; else if (GET_CODE (operands[i]) == MEM && (GET_CODE (XEXP (operands[i], 0)) == POST_INC)) { rtx addr = XEXP (operands[i], 0); operands[i] = low[i] = gen_rtx_MEM (SImode, addr); if (which_alternative == 0 && i == 0) { addr = XEXP (operands[i], 0); operands[i+1] = low[i+1] = gen_rtx_MEM (SImode, addr); } } else { low[i] = operand_subword (operands[i], 0, 0, DImode); operands[i] = operand_subword (operands[i], 1, 0, DImode); } }}voidprint_operand_address (file, addr) FILE *file; register rtx addr;{ register rtx reg1, breg, ireg; rtx offset; retry: switch (GET_CODE (addr)) { case MEM: fprintf (file, "*"); addr = XEXP (addr, 0); goto retry; case REG: fprintf (file, "(%s)", reg_names[REGNO (addr)]); break; case PRE_DEC: fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); break; case POST_INC: fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); break; case PLUS: /* There can be either two or three things added here. One must be a REG. One can be either a REG or a MULT of a REG and an appropriate constant, and the third can only be a constant or a MEM. We get these two or three things and put the constant or MEM in OFFSET, the MULT or REG in IREG, and the REG in BREG. If we have a register and can't tell yet if it is a base or index register, put it into REG1. */ reg1 = 0; ireg = 0; breg = 0; offset = 0; if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) || GET_CODE (XEXP (addr, 0)) == MEM) { offset = XEXP (addr, 0); addr = XEXP (addr, 1); } else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) || GET_CODE (XEXP (addr, 1)) == MEM) { offset = XEXP (addr, 1); addr = XEXP (addr, 0); } else if (GET_CODE (XEXP (addr, 1)) == MULT) { ireg = XEXP (addr, 1); addr = XEXP (addr, 0); } else if (GET_CODE (XEXP (addr, 0)) == MULT) { ireg = XEXP (addr, 0); addr = XEXP (addr, 1); } else if (GET_CODE (XEXP (addr, 1)) == REG) { reg1 = XEXP (addr, 1); addr = XEXP (addr, 0); } else if (GET_CODE (XEXP (addr, 0)) == REG) { reg1 = XEXP (addr, 0); addr = XEXP (addr, 1); } else abort (); if (GET_CODE (addr) == REG) { if (reg1) ireg = addr; else reg1 = addr; } else if (GET_CODE (addr) == MULT) ireg = addr; else if (GET_CODE (addr) == PLUS) { if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) || GET_CODE (XEXP (addr, 0)) == MEM) { if (offset) { if (GET_CODE (offset) == CONST_INT) offset = plus_constant (XEXP (addr, 0), INTVAL (offset)); else if (GET_CODE (XEXP (addr, 0)) == CONST_INT) offset = plus_constant (offset, INTVAL (XEXP (addr, 0))); else abort (); } offset = XEXP (addr, 0); } else if (GET_CODE (XEXP (addr, 0)) == REG) { if (reg1) ireg = reg1, breg = XEXP (addr, 0), reg1 = 0; else reg1 = XEXP (addr, 0); } else if (GET_CODE (XEXP (addr, 0)) == MULT) { if (ireg) abort (); ireg = XEXP (addr, 0); } else abort (); if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) || GET_CODE (XEXP (addr, 1)) == MEM) { if (offset) { if (GET_CODE (offset) == CONST_INT) offset = plus_constant (XEXP (addr, 1), INTVAL (offset)); else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) offset = plus_constant (offset, INTVAL (XEXP (addr, 1))); else abort (); } offset = XEXP (addr, 1); } else if (GET_CODE (XEXP (addr, 1)) == REG) { if (reg1) ireg = reg1, breg = XEXP (addr, 1), reg1 = 0; else reg1 = XEXP (addr, 1); } else if (GET_CODE (XEXP (addr, 1)) == MULT) { if (ireg) abort (); ireg = XEXP (addr, 1); } else abort (); } else abort (); /* If REG1 is nonzero, figure out if it is a base or index register. */ if (reg1) { if (breg != 0 || (offset && GET_CODE (offset) == MEM)) { if (ireg) abort (); ireg = reg1; } else breg = reg1; } if (offset != 0) output_address (offset); if (breg != 0) fprintf (file, "(%s)", reg_names[REGNO (breg)]); if (ireg != 0) { if (GET_CODE (ireg) == MULT) ireg = XEXP (ireg, 0); if (GET_CODE (ireg) != REG) abort (); fprintf (file, "[%s]", reg_names[REGNO (ireg)]); } break; default: output_addr_const (file, addr); }}const char *rev_cond_name (op) rtx op;{ switch (GET_CODE (op)) { case EQ: return "neq"; case NE: return "eql"; case LT: return "geq"; case LE: return "gtr"; case GT: return "leq"; case GE: return "lss"; case LTU: return "gequ"; case LEU: return "gtru"; case GTU: return "lequ"; case GEU: return "lssu"; default: abort (); }}intvax_float_literal(c) register rtx c;{ register enum machine_mode mode; REAL_VALUE_TYPE r, s; int i; if (GET_CODE (c) != CONST_DOUBLE) return 0; mode = GET_MODE (c); if (c == const_tiny_rtx[(int) mode][0] || c == const_tiny_rtx[(int) mode][1] || c == const_tiny_rtx[(int) mode][2]) return 1; REAL_VALUE_FROM_CONST_DOUBLE (r, c); for (i = 0; i < 7; i++) { int x = 1 << i; REAL_VALUE_FROM_INT (s, x, 0, mode); if (REAL_VALUES_EQUAL (r, s)) return 1; if (!exact_real_inverse (mode, &s)) abort (); if (REAL_VALUES_EQUAL (r, s)) return 1; } return 0;}/* Return the cost in cycles of a memory address, relative to register indirect. Each of the following adds the indicated number of cycles: 1 - symbolic address 1 - pre-decrement 1 - indexing and/or offset(register) 2 - indirect */intvax_address_cost (addr) register rtx addr;{ int reg = 0, indexed = 0, indir = 0, offset = 0, predec = 0; rtx plus_op0 = 0, plus_op1 = 0; restart: switch (GET_CODE (addr)) { case PRE_DEC: predec = 1; case REG: case SUBREG: case POST_INC: reg = 1; break; case MULT: indexed = 1; /* 2 on VAX 2 */ break; case CONST_INT: /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */ if (offset == 0) offset = (unsigned HOST_WIDE_INT)(INTVAL(addr)+128) > 256; break; case CONST: case SYMBOL_REF: offset = 1; /* 2 on VAX 2 */ break; case LABEL_REF: /* this is probably a byte offset from the pc */ if (offset == 0) offset = 1; break; case PLUS: if (plus_op0) plus_op1 = XEXP (addr, 0); else plus_op0 = XEXP (addr, 0); addr = XEXP (addr, 1); goto restart; case MEM: indir = 2; /* 3 on VAX 2 */ addr = XEXP (addr, 0); goto restart; default: break; } /* Up to 3 things can be added in an address. They are stored in plus_op0, plus_op1, and addr. */ if (plus_op0) { addr = plus_op0; plus_op0 = 0; goto restart; } if (plus_op1) { addr = plus_op1; plus_op1 = 0; goto restart; } /* Indexing and register+offset can both be used (except on a VAX 2) without increasing execution time over either one alone. */ if (reg && indexed && offset) return reg + indir + offset + predec; return reg + indexed + indir + offset + predec;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -