📄 ip2k.c
字号:
/* Subroutines used for code generation on Ubicom IP2022 Communications Controller. Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Red Hat, Inc and Ubicom, 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 "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "insn-addr.h"#include "flags.h"#include "reload.h"#include "tree.h"#include "expr.h"#include "optabs.h"#include "toplev.h"#include "obstack.h"#include "function.h"#include "recog.h"#include "tm_p.h"#include "target.h"#include "target-def.h"#include "basic-block.h"/* There are problems with 'frame_pointer_needed'. If we force it on, we either end up not eliminating uses of FP, which results in SPILL register failures or we may end up with calculation errors in the stack offsets. Isolate the decision process into a simple macro. */#define CHAIN_FRAMES (frame_pointer_needed || FRAME_POINTER_REQUIRED)static int ip2k_naked_function_p (tree);#ifdef IP2K_MD_REORG_PASSstatic void mdr_resequence_xy_yx (rtx);static void mdr_pres_replace_and_recurse (rtx, rtx, rtx);static void mdr_propagate_reg_equivs_sequence (rtx, rtx, rtx);static void mdr_propagate_reg_equivs (rtx);static int track_dp_reload (rtx , rtx *, int , int);static void mdr_try_dp_reload_elim (rtx);static void mdr_try_move_dp_reload (rtx);static void mdr_try_move_pushes (rtx);static void mdr_try_propagate_clr_sequence (rtx, unsigned int);static void mdr_try_propagate_clr (rtx);static void mdr_try_propagate_move_sequence (rtx, rtx, rtx);static void mdr_try_propagate_move (rtx);static void mdr_try_remove_redundant_insns (rtx);static int track_w_reload (rtx, rtx *, int , int);static void mdr_try_wreg_elim (rtx);#endif /* IP2K_MD_REORG_PASS */static void ip2k_reorg (void);static int ip2k_check_can_adjust_stack_ref (rtx, int);static void ip2k_adjust_stack_ref (rtx *, int);static int ip2k_xexp_not_uses_reg_for_mem (rtx, unsigned int);static tree ip2k_handle_progmem_attribute (tree *, tree, tree, int, bool *);static tree ip2k_handle_fndecl_attribute (tree *, tree, tree, int, bool *);static bool ip2k_rtx_costs (rtx, int, int, int *);static int ip2k_address_cost (rtx);static void ip2k_init_libfuncs (void);static bool ip2k_return_in_memory (tree, tree);static void ip2k_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);const struct attribute_spec ip2k_attribute_table[];/* Initialize the GCC target structure. */#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue#undef TARGET_ASM_UNIQUE_SECTION#define TARGET_ASM_UNIQUE_SECTION unique_section#undef TARGET_ASM_FUNCTION_RODATA_SECTION#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE ip2k_attribute_table#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS ip2k_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST ip2k_address_cost#undef TARGET_MACHINE_DEPENDENT_REORG#define TARGET_MACHINE_DEPENDENT_REORG ip2k_reorg#undef TARGET_INIT_LIBFUNCS#define TARGET_INIT_LIBFUNCS ip2k_init_libfuncs#undef TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY ip2k_return_in_memory#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS ip2k_setup_incoming_varargsstruct gcc_target targetm = TARGET_INITIALIZER;/* Prologue/Epilogue size in words. */static int prologue_size;static int epilogue_size;/* compare and test instructions for the IP2K are materialized by the conditional branch that uses them. This is because conditional branches are skips over unconditional branches. */rtx ip2k_compare_operands[3]; /* Additional operands for condition code. */int ip2k_test_flag; /* Indicates Z, WREG contain condition code information. *//* Some ip2k patterns push a byte onto the stack and then access SP-relative addresses. Since reload doesn't know about these pushes, we must track them internally with a %< (push) or %> (pop) indicator. */static int ip2k_stack_delta;/* Track if or how far our ip2k reorganization pass has run. */int ip2k_reorg_in_progress = 0;int ip2k_reorg_completed = 0;int ip2k_reorg_split_dimode = 0;int ip2k_reorg_split_simode = 0;int ip2k_reorg_split_himode = 0;int ip2k_reorg_split_qimode = 0;int ip2k_reorg_merge_qimode = 0;/* Set up local allocation order. */voidip2k_init_local_alloc (int *rao){ static const int alloc_order[] = REG_ALLOC_ORDER; memcpy (rao, alloc_order, sizeof (alloc_order));}/* Returns the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), FUNTYPE is the data type of the function (as a tree), or for a library call it is an identifier node for the subroutine name. SIZE is the number of bytes of arguments passed on the stack. */intip2k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size){ if (TREE_CODE (funtype) == IDENTIFIER_NODE) return size; if (TYPE_ARG_TYPES (funtype) == NULL_TREE || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)) return size; return 0;}/* Return nonzero if FUNC is a naked function. */static intip2k_naked_function_p (tree func){ tree a; if (TREE_CODE (func) != FUNCTION_DECL) abort (); a = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); return a != NULL_TREE;}/* Output function prologue. */voidfunction_prologue (FILE *file, HOST_WIDE_INT size){ int leaf_func_p; int main_p; int reg; rtx operands[2]; prologue_size = epilogue_size = 0; if (ip2k_naked_function_p (current_function_decl)) { fprintf (file, "/* prologue: naked */\n"); return; } leaf_func_p = leaf_function_p (); main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); /* For now, we compute all these facts about the function, but don't take any action based on the information. */ prologue_size = 0; fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", size); /* Unless we're a leaf we need to save the return PC. */ if (! leaf_func_p) { OUT_AS1 (push, calll); OUT_AS1 (push, callh); prologue_size += 4; } /* We need to save the old FP and set the new FP pointing at the stack location where the old one is saved. Note that because of post-decrement addressing, the SP is off-by-one after the push, so we harvest the SP address BEFORE we push the MSBs of the FP. */ if (CHAIN_FRAMES) { OUT_AS1 (push, REG_FP+1); /* Save old LSBs. */ OUT_AS2 (mov, w, spl); OUT_AS2 (mov, REG_FP+1, w); /* SPL -> FPL */ OUT_AS2 (mov, w, sph); /* Freeze SP MSBs */ OUT_AS1 (push, REG_FP); /* Save old MSBs */ OUT_AS2 (mov, REG_FP, w); /* SPH -> FPH */ prologue_size += 12; } for (reg = (CHAIN_FRAMES) ? (REG_FP - 1) : (REG_FP + 1); reg > 0; --reg) { if (regs_ever_live[reg] && ! call_used_regs[reg]) { fprintf (file, "\t" AS1 (push,%s) "\n", reg_names[reg]); prologue_size += 2; } } if (size) { operands[0] = GEN_INT (size); switch (size & 0xff) { case 0: break; case 1: OUT_AS1 (dec, spl); prologue_size += 2; break; default: OUT_AS2 (mov, w, %L0); OUT_AS2 (sub, spl, w); prologue_size += 4; } switch (size & 0xff00) { case 0: break; case 0x100: OUT_AS1 (dec, sph); prologue_size += 2; break; default: if ((size & 0xff) != ((size >> 8) & 0xff)) OUT_AS2 (mov, w, %H0); /* Otherwise W has value we want. */ OUT_AS2 (sub, sph, w); prologue_size += 4; } }/* XXX - change this to use the carry-propagating subtract trick. */ if (flag_stack_check) { OUT_AS2 (mov, w, sph); OUT_AS2 (cmp, w, #%%hi8data(_end)); OUT_AS1 (sc, ); /* C == 0 -> hi8(edata) < sph */ OUT_AS1 (page, 1f); OUT_AS1 (jmp, 1f); OUT_AS1 (sz, ); /* Z == 1 -> look at low byte */ OUT_AS1 (page,0f); OUT_AS1 (jmp,0f); /* sp < edata, so raise stack fault */ OUT_AS2 (mov, w, spl); OUT_AS2 (cmp, w, #%%lo8data(_end)); OUT_AS1 (sc,); /* C==1 -> lo8(edata) >= spl */ OUT_AS1 (page,1f); OUT_AS1 (jmp,1f); OUT_AS1 (0:,); output_asm_insn ("push\t$ff", operands); OUT_AS1 (system,); OUT_AS1 (1:, ); prologue_size += 30; }}/* Output function epilogue. */voidfunction_epilogue (FILE *file, HOST_WIDE_INT size){ int leaf_func_p; int reg,savelimit; rtx operands[2]; /* Dummy used by OUT_ASn */ int args_locals_size = current_function_args_size; int saved_regs_p = 0; int need_ret = 1; /* Use this opportunity to reset the reorg flags! */ ip2k_reorg_in_progress = 0; ip2k_reorg_completed = 0; ip2k_reorg_split_dimode = 0; ip2k_reorg_split_simode = 0; ip2k_reorg_split_himode = 0; ip2k_reorg_split_qimode = 0; ip2k_reorg_merge_qimode = 0; if (ip2k_naked_function_p (current_function_decl)) { fprintf (file, "/* epilogue: naked */\n"); return; } leaf_func_p = leaf_function_p (); epilogue_size = 0; fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", size); savelimit = (CHAIN_FRAMES) ? REG_FP : (REG_FP + 2); for (reg = 0; reg < savelimit; reg++) if (regs_ever_live[reg] && ! call_used_regs[reg]) { saved_regs_p = 1; break; } if (size) { if (leaf_func_p && !CHAIN_FRAMES && !saved_regs_p && current_function_pops_args) args_locals_size = current_function_args_size + size; else { operands[0] = GEN_INT (size); switch (size & 0xff) { default: OUT_AS2 (mov, w, %L0); OUT_AS2 (add, spl, w); epilogue_size += 4; /* fall-through */ case 0: break; case 1: OUT_AS1 (inc, spl); epilogue_size += 2; } switch (size & 0xff00) { default: if ((size & 0xff) != ((size >> 8) & 0xff)) OUT_AS2 (mov, w, %H0); OUT_AS2 (add, sph, w); epilogue_size += 4; /* fall-through */ case 0: break; case 0x100: OUT_AS1 (inc, sph); epilogue_size += 2; } } } for (reg = 0; reg < savelimit; reg++) { if (regs_ever_live[reg] && ! call_used_regs[reg]) { fprintf (file, "\t" AS1 (pop,%s) "\n", reg_names[reg]); prologue_size += 2; } } if (CHAIN_FRAMES && ! (current_function_pops_args && current_function_args_size >= 2 && current_function_args_size < 0x100)) { OUT_AS1 (pop, REG_FP); OUT_AS1 (pop, REG_FP+1); epilogue_size += 4; } if (! leaf_func_p) { if (current_function_pops_args && current_function_args_size >= 2 && current_function_args_size < 0x100) { if (current_function_args_size == 2) { if (CHAIN_FRAMES) { OUT_AS1 (page, __fp_pop2_args_ret); OUT_AS1 (jmp, __fp_pop2_args_ret); } else { OUT_AS1 (page, __pop2_args_ret); OUT_AS1 (jmp, __pop2_args_ret); } epilogue_size += 4; } else { operands[0] = GEN_INT (current_function_args_size); OUT_AS2 (mov, w, %L0); if (CHAIN_FRAMES) { OUT_AS1 (page, __fp_pop_args_ret); OUT_AS1 (jmp, __fp_pop_args_ret); } else { OUT_AS1 (page, __pop_args_ret); OUT_AS1 (jmp, __pop_args_ret); } epilogue_size += 6; } need_ret = 0; } else { OUT_AS1 (pop, callh); OUT_AS1 (pop, calll); epilogue_size += 4; } } else { if (current_function_pops_args && args_locals_size >= 2 && args_locals_size < 0x100) { if (args_locals_size == 2) { if (CHAIN_FRAMES) { OUT_AS1 (page, __leaf_fp_pop2_args_ret); OUT_AS1 (jmp, __leaf_fp_pop2_args_ret); epilogue_size += 4; need_ret = 0; } } else { operands[0] = GEN_INT (args_locals_size); if (CHAIN_FRAMES) { OUT_AS2 (mov, w, %L0); OUT_AS1 (page, __leaf_fp_pop_args_ret); OUT_AS1 (jmp, __leaf_fp_pop_args_ret); epilogue_size += 6; need_ret = 0; } } } } if (current_function_pops_args && args_locals_size && need_ret) { operands[0] = GEN_INT (args_locals_size); switch (args_locals_size & 0xff) { default: OUT_AS2 (mov, w, %L0); OUT_AS2 (add, spl, w); epilogue_size += 4; /* fall-through */ case 0: break; case 1: OUT_AS1 (inc, spl); epilogue_size += 2; } switch (args_locals_size & 0xff00) { default: if ((args_locals_size & 0xff) != ((args_locals_size >> 8) & 0xff)) OUT_AS2 (mov, w, %H0); OUT_AS2 (add, sph, w); epilogue_size += 4; /* fall-through */ case 0: break; case 0x100: OUT_AS1 (inc, sph); epilogue_size += 2; } } if (need_ret) { OUT_AS1 (ret,); epilogue_size += 2; } fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);}/* Return the difference between the registers after the function prologue. Stack Frame grows down: ARGUMENTS <------ AP ($102:$103) RETURN PC (unless leaf function) SAVEDFP (if needed)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -