mmix.c

来自「gcc3.2.1源代码」· C语言 代码 · 共 2,281 行 · 第 1/5 页

C
2,281
字号
/* Definitions of target machine for GNU compiler, for MMIX.   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.   Contributed by Hans-Peter Nilsson (hp@bitrange.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 "regs.h"#include "hard-reg-set.h"#include "hashtab.h"#include "insn-config.h"#include "output.h"#include "flags.h"#include "tree.h"#include "function.h"#include "expr.h"#include "toplev.h"#include "recog.h"#include "ggc.h"#include "dwarf2.h"#include "debug.h"#include "tm_p.h"#include "integrate.h"#include "target.h"#include "target-def.h"/* First some local helper definitions.  */#define MMIX_FIRST_GLOBAL_REGNUM 32/* We'd need a current_function_has_landing_pad.  It's marked as such when   a nonlocal_goto_receiver is expanded.  Not just a C++ thing, but   mostly.  */#define MMIX_CFUN_HAS_LANDING_PAD (cfun->machine->has_landing_pad != 0)/* We have no means to tell DWARF 2 about the register stack, so we need   to store the return address on the stack if an exception can get into   this function.  FIXME: Narrow condition.  */#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \ (flag_exceptions && ! leaf_function_p ())#define IS_MMIX_EH_RETURN_DATA_REG(REGNO)	\ (current_function_calls_eh_return		\  && (EH_RETURN_DATA_REGNO (0) == REGNO		\      || EH_RETURN_DATA_REGNO (1) == REGNO	\      || EH_RETURN_DATA_REGNO (2) == REGNO	\      || EH_RETURN_DATA_REGNO (3) == REGNO))/* The canonical saved comparison operands for non-cc0 machines, set in   the compare expander.  */rtx mmix_compare_op0;rtx mmix_compare_op1;/* We ignore some options with arguments.  They are passed to the linker,   but also ends up here because they start with "-m".  We tell the driver   to store them in a variable we don't inspect.  */const char *mmix_cc1_ignored_option;/* Declarations of locals.  *//* This is used in the prologue for what number to pass in a PUSHJ or   PUSHGO insn.  */static int mmix_highest_saved_stack_register;/* Intermediate for insn output.  */static int mmix_output_destination_register;static void mmix_output_shiftvalue_op_from_str  PARAMS ((FILE *, const char *, HOST_WIDEST_INT));static void mmix_output_shifted_value PARAMS ((FILE *, HOST_WIDEST_INT));static void mmix_output_condition PARAMS ((FILE *, rtx, int));static HOST_WIDEST_INT mmix_intval PARAMS ((rtx));static void mmix_output_octa PARAMS ((FILE *, HOST_WIDEST_INT, int));static bool mmix_assemble_integer PARAMS ((rtx, unsigned int, int));static void mmix_init_machine_status PARAMS ((struct function *));extern void mmix_target_asm_function_prologue  PARAMS ((FILE *, HOST_WIDE_INT));extern void mmix_target_asm_function_epilogue  PARAMS ((FILE *, HOST_WIDE_INT));/* Target structure macros.  Listed by node.  See `Using and Porting GCC'   for a general description.  *//* Node: Function Entry */#undef TARGET_ASM_BYTE_OP#define TARGET_ASM_BYTE_OP NULL#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP NULL#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP NULL#undef TARGET_ASM_ALIGNED_DI_OP#define TARGET_ASM_ALIGNED_DI_OP NULL#undef TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER mmix_assemble_integer#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epiloguestruct gcc_target targetm = TARGET_INITIALIZER;/* Functions that are expansions for target macros.   See Target Macros in `Using and Porting GCC'.  *//* OVERRIDE_OPTIONS.  */voidmmix_override_options (){  /* Should we err or should we warn?  Hmm.  At least we must neutralize     it.  For example the wrong kind of case-tables will be generated with     PIC; we use absolute address items for mmixal compatibility.  FIXME:     They could be relative if we just elide them to after all pertinent     labels.  */  if (flag_pic)    {      warning ("-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");      flag_pic = 0;    }  /* All other targets add GC roots from their override_options function,     so play along.  */  ggc_add_rtx_root (&mmix_compare_op0, 1);  ggc_add_rtx_root (&mmix_compare_op1, 1);}/* INIT_EXPANDERS.  */voidmmix_init_expanders (){  init_machine_status = mmix_init_machine_status;}/* Set the per-function data.  */static voidmmix_init_machine_status (f)     struct function *f;{  f->machine = xcalloc (1, sizeof (struct machine_function));}/* DATA_ALIGNMENT.   We have trouble getting the address of stuff that is located at other   than 32-bit alignments (GETA requirements), so try to give everything   at least 32-bit alignment. */intmmix_data_alignment (type, basic_align)     tree type ATTRIBUTE_UNUSED;     int basic_align;{  if (basic_align < 32)    return 32;  return basic_align;}/* CONSTANT_ALIGNMENT.  */intmmix_constant_alignment (constant, basic_align)     tree constant ATTRIBUTE_UNUSED;     int basic_align;{  if (basic_align < 32)    return 32;  return basic_align;}/* LOCAL_ALIGNMENT.  */intmmix_local_alignment (type, basic_align)     tree type ATTRIBUTE_UNUSED;     int basic_align;{  if (basic_align < 32)    return 32;  return basic_align;}/* CONDITIONAL_REGISTER_USAGE.  */voidmmix_conditional_register_usage (){  int i;  if (TARGET_ABI_GNU)    {      static const int gnu_abi_reg_alloc_order[]	= MMIX_GNU_ABI_REG_ALLOC_ORDER;      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	reg_alloc_order[i] = gnu_abi_reg_alloc_order[i];      /* Change the default from the mmixware ABI.  For the GNU ABI,	 $15..$30 are call-saved just as $0..$14.  There must be one	 call-clobbered local register for the "hole" describing number of	 saved local registers saved by PUSHJ/PUSHGO during the function	 call, receiving the return value at return.  So best is to use	 the highest, $31.  It's already marked call-clobbered for the	 mmixware ABI.  */      for (i = 15; i <= 30; i++)	call_used_regs[i] = 0;      /* "Unfix" the parameter registers.  */      for (i = MMIX_RESERVED_GNU_ARG_0_REGNUM;	   i < MMIX_RESERVED_GNU_ARG_0_REGNUM + MMIX_MAX_ARGS_IN_REGS;	   i++)	fixed_regs[i] = 0;    }  /* Step over the ":" in special register names.  */  if (! TARGET_TOPLEVEL_SYMBOLS)    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)      if (reg_names[i][0] == ':')	reg_names[i]++;}/* PREFERRED_RELOAD_CLASS.   We need to extend the reload class of REMAINDER_REG and HIMULT_REG.  */enum reg_classmmix_preferred_reload_class (x, class)     rtx x ATTRIBUTE_UNUSED;     enum reg_class class;{  /* FIXME: Revisit.  */  return GET_CODE (x) == MOD && GET_MODE (x) == DImode    ? REMAINDER_REG : class;}/* PREFERRED_OUTPUT_RELOAD_CLASS.   We need to extend the reload class of REMAINDER_REG and HIMULT_REG.  */enum reg_classmmix_preferred_output_reload_class (x, class)     rtx x ATTRIBUTE_UNUSED;     enum reg_class class;{  /* FIXME: Revisit.  */  return GET_CODE (x) == MOD && GET_MODE (x) == DImode    ? REMAINDER_REG : class;}/* SECONDARY_RELOAD_CLASS.   We need to reload regs of REMAINDER_REG and HIMULT_REG elsewhere.  */enum reg_classmmix_secondary_reload_class (class, mode, x, in_p)     enum reg_class class;     enum machine_mode mode ATTRIBUTE_UNUSED;     rtx x ATTRIBUTE_UNUSED;     int in_p ATTRIBUTE_UNUSED;{  if (class == REMAINDER_REG      || class == HIMULT_REG      || class == SYSTEM_REGS)    return GENERAL_REGS;  return NO_REGS;}/* CONST_OK_FOR_LETTER_P.  */intmmix_const_ok_for_letter_p (value, c)     HOST_WIDE_INT value;     int c;{  return    (c == 'I' ? value >= 0 && value <= 255     : c == 'J' ? value >= 0 && value <= 65535     : c == 'K' ? value <= 0 && value >= -255     : c == 'L' ? mmix_shiftable_wyde_value (value)     : c == 'M' ? value == 0     : c == 'N' ? mmix_shiftable_wyde_value (~value)     : c == 'O' ? (value == 3 || value == 5 || value == 9		   || value == 17)     : 0);}/* CONST_DOUBLE_OK_FOR_LETTER_P.  */intmmix_const_double_ok_for_letter_p (value, c)     rtx value;     int c;{  return    (c == 'G' ? value == CONST0_RTX (GET_MODE (value))     : 0);}/* EXTRA_CONSTRAINT.   We need this since our constants are not always expressible as   CONST_INT:s, but rather often as CONST_DOUBLE:s.  */intmmix_extra_constraint (x, c, strict)     rtx x;     int c;     int strict;{  HOST_WIDEST_INT value;  /* When checking for an address, we need to handle strict vs. non-strict     register checks.  Don't use address_operand, but instead its     equivalent (its callee, which it is just a wrapper for),     memory_operand_p and the strict-equivalent strict_memory_address_p.  */  if (c == 'U')    return      strict      ? strict_memory_address_p (Pmode, x)      : memory_address_p (Pmode, x);  /* R asks whether x is to be loaded with GETA or something else.  Right     now, only a SYMBOL_REF and LABEL_REF can fit for     TARGET_BASE_ADDRESSES.     Only constant symbolic addresses apply.  With TARGET_BASE_ADDRESSES,     we just allow straight LABEL_REF or SYMBOL_REFs with SYMBOL_REF_FLAG     set right now; only function addresses and code labels.  If we change     to let SYMBOL_REF_FLAG be set on other symbols, we have to check     inside CONST expressions.  When TARGET_BASE_ADDRESSES is not in     effect, a "raw" constant check together with mmix_constant_address_p     is all that's needed; we want all constant addresses to be loaded     with GETA then.  */  if (c == 'R')    return      GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE      && mmix_constant_address_p (x)      && (! TARGET_BASE_ADDRESSES	  || (GET_CODE (x) == LABEL_REF	      || (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))));  if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode)    return 0;  value = mmix_intval (x);  /* We used to map Q->J, R->K, S->L, T->N, U->O, but we don't have to any     more ('U' taken for address_operand, 'R' similarly).  Some letters map     outside of CONST_INT, though; we still use 'S' and 'T'.  */  if (c == 'S')    return mmix_shiftable_wyde_value (value);  else if (c == 'T')    return mmix_shiftable_wyde_value (~value);  return 0;}/* DYNAMIC_CHAIN_ADDRESS.  */rtxmmix_dynamic_chain_address (frame)     rtx frame;{  /* FIXME: the frame-pointer is stored at offset -8 from the current     frame-pointer.  Unfortunately, the caller assumes that a     frame-pointer is present for *all* previous frames.  There should be     a way to say that that cannot be done, like for RETURN_ADDR_RTX.  */  return plus_constant (frame, -8);}/* STARTING_FRAME_OFFSET.  */intmmix_starting_frame_offset (){  /* The old frame pointer is in the slot below the new one, so     FIRST_PARM_OFFSET does not need to depend on whether the     frame-pointer is needed or not.  We have to adjust for the register     stack pointer being located below the saved frame pointer.     Similarly, we store the return address on the stack too, for     exception handling, and always if we save the register stack pointer.  */  return    (-8     + (MMIX_CFUN_HAS_LANDING_PAD	? -16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? -8 : 0)));}/* RETURN_ADDR_RTX.  */rtxmmix_return_addr_rtx (count, frame)     int count;     rtx frame ATTRIBUTE_UNUSED;{  return count == 0    ? (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS       /* FIXME: Set frame_alias_set on the following.  (Why?)	  See mmix_initial_elimination_offset for the reason we can't use	  get_hard_reg_initial_val for both.  Always using a stack slot	  and not a register would be suboptimal.  */       ? validize_mem (gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, -16)))       : get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM))    : NULL_RTX;}/* SETUP_FRAME_ADDRESSES.  */voidmmix_setup_frame_addresses (){  /* Nothing needed at the moment.  */}/* The difference between the (imaginary) frame pointer and the stack   pointer.  Used to eliminate the frame pointer.  */intmmix_initial_elimination_offset (fromreg, toreg)     int fromreg;     int toreg;{  int regno;  int fp_sp_offset    = (get_frame_size () + current_function_outgoing_args_size + 7) & ~7;  /* There is no actual offset between these two virtual values, but for     the frame-pointer, we have the old one in the stack position below     it, so the offset for the frame-pointer to the stack-pointer is one     octabyte larger.  */  if (fromreg == MMIX_ARG_POINTER_REGNUM      && toreg == MMIX_FRAME_POINTER_REGNUM)    return 0;  /* The difference is the size of local variables plus the size of     outgoing function arguments that would normally be passed as     registers but must be passed on stack because we're out of     function-argument registers.  Only global saved registers are

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?