📄 mmix.c
字号:
/* 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 GCC.GCC 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.GCC 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 GCC; 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"#include "real.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. Before any whole-function analysis, regs_ever_live[] isn't initialized. We know it's up-to-date after reload_completed; it may contain incorrect information some time before that. Within a RTL sequence (after a call to start_sequence, such as in RTL expanders), leaf_function_p doesn't see all insns (perhaps any insn). But regs_ever_live is up-to-date when leaf_function_p () isn't, so we "or" them together to get accurate information. FIXME: Some tweak to leaf_function_p might be preferrable. */#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \ (flag_exceptions \ && ((reload_completed && regs_ever_live[MMIX_rJ_REGNUM]) \ || !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))/* For the default ABI, we rename registers at output-time to fill the gap between the (statically partitioned) saved registers and call-clobbered registers. In effect this makes unused call-saved registers to be used as call-clobbered registers. The benefit comes from keeping the number of local registers (value of rL) low, since there's a cost of increasing rL and clearing unused (unset) registers with lower numbers. Don't translate while outputting the prologue. */#define MMIX_OUTPUT_REGNO(N) \ (TARGET_ABI_GNU \ || (int) (N) < MMIX_RETURN_VALUE_REGNUM \ || (int) (N) > MMIX_LAST_STACK_REGISTER_REGNUM \ || cfun == NULL \ || cfun->machine == NULL \ || cfun->machine->in_prologue \ ? (N) : ((N) - MMIX_RETURN_VALUE_REGNUM \ + cfun->machine->highest_saved_stack_register + 1))/* The %d in "POP %d,0". */#define MMIX_POP_ARGUMENT() \ ((! TARGET_ABI_GNU \ && current_function_return_rtx != NULL \ && ! current_function_returns_struct) \ ? (GET_CODE (current_function_return_rtx) == PARALLEL \ ? GET_NUM_ELEM (XVEC (current_function_return_rtx, 0)) : 1) \ : 0)/* 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. *//* 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 struct machine_function * mmix_init_machine_status PARAMS ((void));static void mmix_encode_section_info PARAMS ((tree, int));static const char *mmix_strip_name_encoding PARAMS ((const char *));static void mmix_emit_sp_add PARAMS ((HOST_WIDE_INT offset));static void mmix_target_asm_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void mmix_target_asm_function_end_prologue PARAMS ((FILE *));static void mmix_target_asm_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void mmix_asm_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree));/* 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_END_PROLOGUE#define TARGET_ASM_FUNCTION_END_PROLOGUE mmix_target_asm_function_end_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO mmix_encode_section_info#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING mmix_strip_name_encoding#undef TARGET_ASM_OUTPUT_MI_THUNK#define TARGET_ASM_OUTPUT_MI_THUNK mmix_asm_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;/* 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; }}/* INIT_EXPANDERS. */voidmmix_init_expanders (){ init_machine_status = mmix_init_machine_status;}/* Set the per-function data. */static struct machine_function *mmix_init_machine_status (){ return ggc_alloc_cleared (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" that holds the 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]++;}/* LOCAL_REGNO. All registers that are part of the register stack and that will be saved are local. */intmmix_local_regno (regno) int regno;{ return regno <= MMIX_LAST_STACK_REGISTER_REGNUM && !call_used_regs[regno];}/* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -