📄 mn10300.c
字号:
/* Subroutines for insn-output.c for Matsushita MN10300 series Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 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, 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 "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 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 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_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;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: abort (); } 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: abort (); } 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: abort (); } 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: abort (); } 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: abort (); 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: abort (); } 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': if (INTVAL (x) < -128 || INTVAL (x) > 255) abort (); fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff)); break; case 'U': if (INTVAL (x) < -128 || INTVAL (x) > 255) abort (); 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: abort (); } 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 abort (); 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){ int i, n = 0; if (! TARGET_AM33_2) return 0; for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i) if (regs_ever_live[i] && ! call_used_regs[i]) ++n; return n;}/* Print a set of registers in the format required by "movm" and "ret". Register K is saved if bit K of MASK is set. The data and address registers can be stored individually, but the extended registers cannot. We assume that the mask alread takes that into account. For instance, bits 14 to 17 must have the same value. */voidmn10300_print_reg_list (FILE *file, int mask){ int need_comma; int i; need_comma = 0; fputc ('[', file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -