📄 mmix.c
字号:
/* Definitions of target machine for GNU compiler, for MMIX. Copyright (C) 2000, 2001, 2002, 2003, 2004 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 "coretypes.h"#include "tm.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 preferable. */#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 (FILE *, const char *, HOST_WIDEST_INT);static void mmix_output_shifted_value (FILE *, HOST_WIDEST_INT);static void mmix_output_condition (FILE *, rtx, int);static HOST_WIDEST_INT mmix_intval (rtx);static void mmix_output_octa (FILE *, HOST_WIDEST_INT, int);static bool mmix_assemble_integer (rtx, unsigned int, int);static struct machine_function *mmix_init_machine_status (void);static void mmix_encode_section_info (tree, rtx, int);static const char *mmix_strip_name_encoding (const char *);static void mmix_emit_sp_add (HOST_WIDE_INT offset);static void mmix_target_asm_function_prologue (FILE *, HOST_WIDE_INT);static void mmix_target_asm_function_end_prologue (FILE *);static void mmix_target_asm_function_epilogue (FILE *, HOST_WIDE_INT);static void mmix_reorg (void);static void mmix_asm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);static void mmix_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);static void mmix_file_start (void);static void mmix_file_end (void);static bool mmix_rtx_costs (rtx, int, int, int *);static rtx mmix_struct_value_rtx (tree, int);static bool mmix_pass_by_reference (const CUMULATIVE_ARGS *, enum machine_mode, tree, bool);/* 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_vcall#undef TARGET_ASM_FILE_START#define TARGET_ASM_FILE_START mmix_file_start#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true#undef TARGET_ASM_FILE_END#define TARGET_ASM_FILE_END mmix_file_end#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS mmix_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST hook_int_rtx_0#undef TARGET_MACHINE_DEPENDENT_REORG#define TARGET_MACHINE_DEPENDENT_REORG mmix_reorg#undef TARGET_PROMOTE_FUNCTION_ARGS#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true#if 0/* Apparently not doing TRT if int < register-size. FIXME: Perhaps FUNCTION_VALUE and LIBCALL_VALUE needs tweaking as some ports say. */#undef TARGET_PROMOTE_FUNCTION_RETURN#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true#endif#undef TARGET_STRUCT_VALUE_RTX#define TARGET_STRUCT_VALUE_RTX mmix_struct_value_rtx#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS mmix_setup_incoming_varargs#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE mmix_pass_by_reference#undef TARGET_CALLEE_COPIES#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_truestruct 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 (void){ /* 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 (void){ init_machine_status = mmix_init_machine_status;}/* Set the per-function data. */static struct machine_function *mmix_init_machine_status (void){ 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 (tree type ATTRIBUTE_UNUSED, int basic_align){ if (basic_align < 32) return 32; return basic_align;}/* CONSTANT_ALIGNMENT. */intmmix_constant_alignment (tree constant ATTRIBUTE_UNUSED, int basic_align){ if (basic_align < 32) return 32; return basic_align;}/* LOCAL_ALIGNMENT. */intmmix_local_alignment (tree type ATTRIBUTE_UNUSED, int basic_align){ if (basic_align < 32) return 32; return basic_align;}/* CONDITIONAL_REGISTER_USAGE. */voidmmix_conditional_register_usage (void){ 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 (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 (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 (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 (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 (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 (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 (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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -