📄 mcore.c
字号:
/* Output routines for Motorola MCore processor Copyright (C) 1993, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the 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 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the 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 "tree.h"#include "tm_p.h"#include "assert.h"#include "mcore.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 "obstack.h"#include "expr.h"#include "reload.h"#include "recog.h"#include "function.h"#include "ggc.h"#include "toplev.h"#include "target.h"#include "target-def.h"/* Maximum size we are allowed to grow the stack in a single operation. If we want more, we must do it in increments of at most this size. If this value is 0, we don't check at all. */const char * mcore_stack_increment_string = 0;int mcore_stack_increment = STACK_UNITS_MAXSTEP;/* For dumping information about frame sizes. */char * mcore_current_function_name = 0;long mcore_current_compilation_timestamp = 0;/* Global variables for machine-dependent things. *//* Saved operands from the last compare to use when we generate an scc or bcc insn. */rtx arch_compare_op0;rtx arch_compare_op1;/* Provides the class number of the smallest class containing reg number. */const int regno_reg_class[FIRST_PSEUDO_REGISTER] ={ GENERAL_REGS, ONLYR1_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, LRW_REGS, GENERAL_REGS, GENERAL_REGS, C_REGS, NO_REGS, NO_REGS,};/* Provide reg_class from a letter such as appears in the machine description. */const enum reg_class reg_class_from_letter[] ={ /* a */ LRW_REGS, /* b */ ONLYR1_REGS, /* c */ C_REGS, /* d */ NO_REGS, /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS, /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ NO_REGS, /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS, /* q */ NO_REGS, /* r */ GENERAL_REGS, /* s */ NO_REGS, /* t */ NO_REGS, /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ ALL_REGS, /* y */ NO_REGS, /* z */ NO_REGS};struct mcore_frame{ int arg_size; /* Stdarg spills (bytes). */ int reg_size; /* Non-volatile reg saves (bytes). */ int reg_mask; /* Non-volatile reg saves. */ int local_size; /* Locals. */ int outbound_size; /* Arg overflow on calls out. */ int pad_outbound; int pad_local; int pad_reg; /* Describe the steps we'll use to grow it. */#define MAX_STACK_GROWS 4 /* Gives us some spare space. */ int growth[MAX_STACK_GROWS]; int arg_offset; int reg_offset; int reg_growth; int local_growth;};typedef enum{ COND_NO, COND_MOV_INSN, COND_CLR_INSN, COND_INC_INSN, COND_DEC_INSN, COND_BRANCH_INSN}cond_type;static void output_stack_adjust (int, int);static int calc_live_regs (int *);static int const_ok_for_mcore (int);static int try_constant_tricks (long, int *, int *);static const char * output_inline_const (enum machine_mode, rtx *);static void layout_mcore_frame (struct mcore_frame *);static void mcore_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);static cond_type is_cond_candidate (rtx);static rtx emit_new_cond_insn (rtx, int);static rtx conditionalize_block (rtx);static void conditionalize_optimization (void);static void mcore_reorg (void);static rtx handle_structs_in_regs (enum machine_mode, tree, int);static void mcore_mark_dllexport (tree);static void mcore_mark_dllimport (tree);static int mcore_dllexport_p (tree);static int mcore_dllimport_p (tree);const struct attribute_spec mcore_attribute_table[];static tree mcore_handle_naked_attribute (tree *, tree, tree, int, bool *);#ifdef OBJECT_FORMAT_ELFstatic void mcore_asm_named_section (const char *, unsigned int, tree);#endifstatic void mcore_unique_section (tree, int);static void mcore_encode_section_info (tree, rtx, int);static const char *mcore_strip_name_encoding (const char *);static int mcore_const_costs (rtx, RTX_CODE);static int mcore_and_cost (rtx);static int mcore_ior_cost (rtx);static bool mcore_rtx_costs (rtx, int, int, int *);static void mcore_external_libcall (rtx);static bool mcore_return_in_memory (tree, tree);static int mcore_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);/* Initialize the GCC target structure. */#undef TARGET_ASM_EXTERNAL_LIBCALL#define TARGET_ASM_EXTERNAL_LIBCALL mcore_external_libcall#if TARGET_DLLIMPORT_DECL_ATTRIBUTES#undef TARGET_MERGE_DECL_ATTRIBUTES#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes#endif#ifdef OBJECT_FORMAT_ELF#undef TARGET_ASM_UNALIGNED_HI_OP#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"#undef TARGET_ASM_UNALIGNED_SI_OP#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"#endif#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE mcore_attribute_table#undef TARGET_ASM_UNIQUE_SECTION#define TARGET_ASM_UNIQUE_SECTION mcore_unique_section#undef TARGET_ASM_FUNCTION_RODATA_SECTION#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO mcore_encode_section_info#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING mcore_strip_name_encoding#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS mcore_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST hook_int_rtx_0#undef TARGET_MACHINE_DEPENDENT_REORG#define TARGET_MACHINE_DEPENDENT_REORG mcore_reorg#undef TARGET_PROMOTE_FUNCTION_ARGS#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true#undef TARGET_PROMOTE_FUNCTION_RETURN#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true#undef TARGET_PROMOTE_PROTOTYPES#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true#undef TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY mcore_return_in_memory#undef TARGET_MUST_PASS_IN_STACK#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES mcore_arg_partial_bytes#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS mcore_setup_incoming_varargsstruct gcc_target targetm = TARGET_INITIALIZER;/* Adjust the stack and return the number of bytes taken to do it. */static voidoutput_stack_adjust (int direction, int size){ /* If extending stack a lot, we do it incrementally. */ if (direction < 0 && size > mcore_stack_increment && mcore_stack_increment > 0) { rtx tmp = gen_rtx_REG (SImode, 1); rtx memref; emit_insn (gen_movsi (tmp, GEN_INT (mcore_stack_increment))); do { emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); memref = gen_rtx_MEM (SImode, stack_pointer_rtx); MEM_VOLATILE_P (memref) = 1; emit_insn (gen_movsi (memref, stack_pointer_rtx)); size -= mcore_stack_increment; } while (size > mcore_stack_increment); /* SIZE is now the residual for the last adjustment, which doesn't require a probe. */ } if (size) { rtx insn; rtx val = GEN_INT (size); if (size > 32) { rtx nval = gen_rtx_REG (SImode, 1); emit_insn (gen_movsi (nval, val)); val = nval; } if (direction > 0) insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val); else insn = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, val); emit_insn (insn); }}/* Work out the registers which need to be saved, both as a mask and a count. */static intcalc_live_regs (int * count){ int reg; int live_regs_mask = 0; * count = 0; for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++) { if (regs_ever_live[reg] && !call_used_regs[reg]) { (*count)++; live_regs_mask |= (1 << reg); } } return live_regs_mask;}/* Print the operand address in x to the stream. */voidmcore_print_operand_address (FILE * stream, rtx x){ switch (GET_CODE (x)) { case REG: fprintf (stream, "(%s)", reg_names[REGNO (x)]); break; case PLUS: { rtx base = XEXP (x, 0); rtx index = XEXP (x, 1); if (GET_CODE (base) != REG) { /* Ensure that BASE is a register (one of them must be). */ rtx temp = base; base = index; index = temp; } switch (GET_CODE (index)) { case CONST_INT: fprintf (stream, "(%s," HOST_WIDE_INT_PRINT_DEC ")", reg_names[REGNO(base)], INTVAL (index)); break; default: debug_rtx (x); abort (); } } break; default: output_addr_const (stream, x); break; }}/* Print operand x (an rtx) in assembler syntax to file stream according to modifier code. 'R' print the next register or memory location along, i.e. the lsw in a double word value 'O' print a constant without the # 'M' print a constant as its negative 'P' print log2 of a power of two 'Q' print log2 of an inverse of a power of two 'U' print register for ldm/stm instruction 'X' print byte number for xtrbN instruction. */voidmcore_print_operand (FILE * stream, rtx x, int code){ switch (code) { case 'N': if (INTVAL(x) == -1) fprintf (asm_out_file, "32"); else fprintf (asm_out_file, "%d", exact_log2 (INTVAL (x) + 1)); break; case 'P': fprintf (asm_out_file, "%d", exact_log2 (INTVAL (x))); break; case 'Q': fprintf (asm_out_file, "%d", exact_log2 (~INTVAL (x))); break; case 'O': fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); break; case 'M': fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, - INTVAL (x)); break; case 'R': /* Next location along in memory or register. */ switch (GET_CODE (x)) { case REG: fputs (reg_names[REGNO (x) + 1], (stream)); break; case MEM: mcore_print_operand_address (stream, XEXP (adjust_address (x, SImode, 4), 0)); break; default: abort (); } break; case 'U': fprintf (asm_out_file, "%s-%s", reg_names[REGNO (x)], reg_names[REGNO (x) + 3]); break; case 'x': fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x)); break; case 'X': fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 3 - INTVAL (x) / 8); break; default: switch (GET_CODE (x)) { case REG: fputs (reg_names[REGNO (x)], (stream)); break; case MEM: output_address (XEXP (x, 0)); break; default: output_addr_const (stream, x); break; } break; }}/* What does a constant cost ? */static intmcore_const_costs (rtx exp, enum rtx_code code){ int val = INTVAL (exp); /* Easy constants. */ if ( CONST_OK_FOR_I (val) || CONST_OK_FOR_M (val) || CONST_OK_FOR_N (val) || (code == PLUS && CONST_OK_FOR_L (val))) return 1; else if (code == AND && ( CONST_OK_FOR_M (~val) || CONST_OK_FOR_N (~val))) return 2; else if (code == PLUS && ( CONST_OK_FOR_I (-val) || CONST_OK_FOR_M (-val) || CONST_OK_FOR_N (-val))) return 2; return 5; }/* What does an and instruction cost - we do this b/c immediates may have been relaxed. We want to ensure that cse will cse relaxed immeds out. Otherwise we'll get bad code (multiple reloads of the same const). */static intmcore_and_cost (rtx x){ int val; if (GET_CODE (XEXP (x, 1)) != CONST_INT) return 2; val = INTVAL (XEXP (x, 1)); /* Do it directly. */ if (CONST_OK_FOR_K (val) || CONST_OK_FOR_M (~val)) return 2; /* Takes one instruction to load. */ else if (const_ok_for_mcore (val)) return 3; /* Takes two instructions to load. */ else if (TARGET_HARDLIT && mcore_const_ok_for_inline (val)) return 4; /* Takes a lrw to load. */ return 5;}/* What does an or cost - see and_cost(). */static intmcore_ior_cost (rtx x){ int val; if (GET_CODE (XEXP (x, 1)) != CONST_INT) return 2; val = INTVAL (XEXP (x, 1)); /* Do it directly with bclri. */ if (CONST_OK_FOR_M (val)) return 2; /* Takes one instruction to load. */ else if (const_ok_for_mcore (val)) return 3; /* Takes two instructions to load. */ else if (TARGET_HARDLIT && mcore_const_ok_for_inline (val)) return 4; /* Takes a lrw to load. */ return 5;}static boolmcore_rtx_costs (rtx x, int code, int outer_code, int * total){ switch (code) { case CONST_INT: *total = mcore_const_costs (x, outer_code); return true; case CONST: case LABEL_REF: case SYMBOL_REF: *total = 5; return true; case CONST_DOUBLE: *total = 10; return true; case AND: *total = COSTS_N_INSNS (mcore_and_cost (x)); return true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -