📄 mn10300.c
字号:
/* Subroutines for insn-output.c for Matsushita MN10300 series Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Jeff Law (law@cygnus.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, 51 Franklin Street, Fifth Floor,Boston, MA 02110-1301, USA. */#include "config.h"#include "system.h"#include "coretypes.h"#include "tm.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 "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "expr.h"#include "optabs.h"#include "function.h"#include "obstack.h"#include "toplev.h"#include "tm_p.h"#include "target.h"#include "target-def.h"/* This is used by GOTaddr2picreg to uniquely identify UNSPEC_INT_LABELs. */int mn10300_unspec_int_label_counter;/* This is used in the am33_2.0-linux-gnu port, in which global symbol names are not prefixed by underscores, to tell whether to prefix a label with a plus sign or not, so that the assembler can tell symbol names from register names. */int mn10300_protect_label;/* The selected processor. */enum processor_type mn10300_processor = PROCESSOR_DEFAULT;/* The size of the callee register save area. Right now we save everything on entry since it costs us nothing in code size. It does cost us from a speed standpoint, so we want to optimize this sooner or later. */#define REG_SAVE_BYTES (4 * regs_ever_live[2] \ + 4 * regs_ever_live[3] \ + 4 * regs_ever_live[6] \ + 4 * regs_ever_live[7] \ + 16 * (regs_ever_live[14] || regs_ever_live[15] \ || regs_ever_live[16] || regs_ever_live[17]))static bool mn10300_handle_option (size_t, const char *, int);static int mn10300_address_cost_1 (rtx, int *);static int mn10300_address_cost (rtx);static bool mn10300_rtx_costs (rtx, int, int, int *);static void mn10300_file_start (void);static bool mn10300_return_in_memory (tree, tree);static rtx mn10300_builtin_saveregs (void);static bool mn10300_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);static int mn10300_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);/* Initialize the GCC target structure. */#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS mn10300_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST mn10300_address_cost#undef TARGET_ASM_FILE_START#define TARGET_ASM_FILE_START mn10300_file_start#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true#undef TARGET_DEFAULT_TARGET_FLAGS#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0#undef TARGET_HANDLE_OPTION#define TARGET_HANDLE_OPTION mn10300_handle_option#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info#undef TARGET_PROMOTE_PROTOTYPES#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true#undef TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY mn10300_return_in_memory#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE mn10300_pass_by_reference#undef TARGET_CALLEE_COPIES#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES mn10300_arg_partial_bytes#undef TARGET_EXPAND_BUILTIN_SAVEREGS#define TARGET_EXPAND_BUILTIN_SAVEREGS mn10300_builtin_saveregsstatic void mn10300_encode_section_info (tree, rtx, int);struct gcc_target targetm = TARGET_INITIALIZER;/* Implement TARGET_HANDLE_OPTION. */static boolmn10300_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value){ switch (code) { case OPT_mam33: mn10300_processor = value ? PROCESSOR_AM33 : PROCESSOR_MN10300; return true; case OPT_mam33_2: mn10300_processor = (value ? PROCESSOR_AM33_2 : MIN (PROCESSOR_AM33, PROCESSOR_DEFAULT)); return true; default: return true; }}/* Implement OVERRIDE_OPTIONS. */voidmn10300_override_options (void){ if (TARGET_AM33) target_flags &= ~MASK_MULT_BUG;}static voidmn10300_file_start (void){ default_file_start (); if (TARGET_AM33_2) fprintf (asm_out_file, "\t.am33_2\n"); else if (TARGET_AM33) fprintf (asm_out_file, "\t.am33\n");}/* Print operand X using operand code CODE to assembly language output file FILE. */voidprint_operand (FILE *file, rtx x, int code){ switch (code) { case 'b': case 'B': if (cc_status.mdep.fpCC) { switch (code == 'b' ? GET_CODE (x) : reverse_condition_maybe_unordered (GET_CODE (x))) { case NE: fprintf (file, "ne"); break; case EQ: fprintf (file, "eq"); break; case GE: fprintf (file, "ge"); break; case GT: fprintf (file, "gt"); break; case LE: fprintf (file, "le"); break; case LT: fprintf (file, "lt"); break; case ORDERED: fprintf (file, "lge"); break; case UNORDERED: fprintf (file, "uo"); break; case LTGT: fprintf (file, "lg"); break; case UNEQ: fprintf (file, "ue"); break; case UNGE: fprintf (file, "uge"); break; case UNGT: fprintf (file, "ug"); break; case UNLE: fprintf (file, "ule"); break; case UNLT: fprintf (file, "ul"); break; default: gcc_unreachable (); } break; } /* These are normal and reversed branches. */ switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) { case NE: fprintf (file, "ne"); break; case EQ: fprintf (file, "eq"); break; case GE: fprintf (file, "ge"); break; case GT: fprintf (file, "gt"); break; case LE: fprintf (file, "le"); break; case LT: fprintf (file, "lt"); break; case GEU: fprintf (file, "cc"); break; case GTU: fprintf (file, "hi"); break; case LEU: fprintf (file, "ls"); break; case LTU: fprintf (file, "cs"); break; default: gcc_unreachable (); } break; case 'C': /* This is used for the operand to a call instruction; if it's a REG, enclose it in parens, else output the operand normally. */ if (GET_CODE (x) == REG) { fputc ('(', file); print_operand (file, x, 0); fputc (')', file); } else print_operand (file, x, 0); break; case 'D': switch (GET_CODE (x)) { case MEM: fputc ('(', file); output_address (XEXP (x, 0)); fputc (')', file); break; case REG: fprintf (file, "fd%d", REGNO (x) - 18); break; default: gcc_unreachable (); } break; /* These are the least significant word in a 64bit value. */ case 'L': switch (GET_CODE (x)) { case MEM: fputc ('(', file); output_address (XEXP (x, 0)); fputc (')', file); break; case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case SUBREG: fprintf (file, "%s", reg_names[subreg_regno (x)]); break; case CONST_DOUBLE: { long val[2]; REAL_VALUE_TYPE rv; switch (GET_MODE (x)) { case DFmode: REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_DOUBLE (rv, val); fprintf (file, "0x%lx", val[0]); break;; case SFmode: REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]); fprintf (file, "0x%lx", val[0]); break;; case VOIDmode: case DImode: print_operand_address (file, GEN_INT (CONST_DOUBLE_LOW (x))); break; default: break; } break; } case CONST_INT: { rtx low, high; split_double (x, &low, &high); fprintf (file, "%ld", (long)INTVAL (low)); break; } default: gcc_unreachable (); } break; /* Similarly, but for the most significant word. */ case 'H': switch (GET_CODE (x)) { case MEM: fputc ('(', file); x = adjust_address (x, SImode, 4); output_address (XEXP (x, 0)); fputc (')', file); break; case REG: fprintf (file, "%s", reg_names[REGNO (x) + 1]); break; case SUBREG: fprintf (file, "%s", reg_names[subreg_regno (x) + 1]); break; case CONST_DOUBLE: { long val[2]; REAL_VALUE_TYPE rv; switch (GET_MODE (x)) { case DFmode: REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_DOUBLE (rv, val); fprintf (file, "0x%lx", val[1]); break;; case SFmode: gcc_unreachable (); case VOIDmode: case DImode: print_operand_address (file, GEN_INT (CONST_DOUBLE_HIGH (x))); break; default: break; } break; } case CONST_INT: { rtx low, high; split_double (x, &low, &high); fprintf (file, "%ld", (long)INTVAL (high)); break; } default: gcc_unreachable (); } break; case 'A': fputc ('(', file); if (GET_CODE (XEXP (x, 0)) == REG) output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx)); else output_address (XEXP (x, 0)); fputc (')', file); break; case 'N': gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255); fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff)); break; case 'U': gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255); fprintf (file, "%d", (int)(INTVAL (x) & 0xff)); break; /* For shift counts. The hardware ignores the upper bits of any immediate, but the assembler will flag an out of range shift count as an error. So we mask off the high bits of the immediate here. */ case 'S': if (GET_CODE (x) == CONST_INT) { fprintf (file, "%d", (int)(INTVAL (x) & 0x1f)); break; } /* FALL THROUGH */ default: switch (GET_CODE (x)) { case MEM: fputc ('(', file); output_address (XEXP (x, 0)); fputc (')', file); break; case PLUS: output_address (x); break; case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case SUBREG: fprintf (file, "%s", reg_names[subreg_regno (x)]); break; /* This will only be single precision.... */ case CONST_DOUBLE: { unsigned long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); fprintf (file, "0x%lx", val); break; } case CONST_INT: case SYMBOL_REF: case CONST: case LABEL_REF: case CODE_LABEL: case UNSPEC: print_operand_address (file, x); break; default: gcc_unreachable (); } break; }}/* Output assembly language output for the address ADDR to FILE. */voidprint_operand_address (FILE *file, rtx addr){ switch (GET_CODE (addr)) { case POST_INC: print_operand_address (file, XEXP (addr, 0)); fputc ('+', file); break; case REG: print_operand (file, addr, 0); break; case PLUS: { rtx base, index; if (REG_P (XEXP (addr, 0)) && REG_OK_FOR_BASE_P (XEXP (addr, 0))) base = XEXP (addr, 0), index = XEXP (addr, 1); else if (REG_P (XEXP (addr, 1)) && REG_OK_FOR_BASE_P (XEXP (addr, 1))) base = XEXP (addr, 1), index = XEXP (addr, 0); else gcc_unreachable (); print_operand (file, index, 0); fputc (',', file); print_operand (file, base, 0);; break; } case SYMBOL_REF: output_addr_const (file, addr); break; default: output_addr_const (file, addr); break; }}/* Count the number of FP registers that have to be saved. */static intfp_regs_to_save (void){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -