📄 ip2k.c
字号:
/* Subroutines used for code generation on Ubicom IP2022 Communications Controller. Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Red Hat, Inc and Ubicom, Inc. This file is part of GNU CC. GNU CC 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. GNU CC 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 GNU CC; 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 "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 "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 PARAMS ((tree));#ifdef IP2K_MD_REORG_PASSstatic void mdr_resequence_xy_yx PARAMS ((rtx));static void mdr_pres_replace_and_recurse PARAMS ((rtx, rtx, rtx));static void mdr_propagate_reg_equivs_sequence PARAMS ((rtx, rtx, rtx));static void mdr_propagate_reg_equivs PARAMS ((rtx));static int track_dp_reload PARAMS ((rtx , rtx *, int , int));static void mdr_try_dp_reload_elim PARAMS ((rtx));static void mdr_try_move_dp_reload PARAMS ((rtx));static void mdr_try_move_pushes PARAMS ((rtx));static void mdr_try_propagate_clr_sequence PARAMS ((rtx, unsigned int));static void mdr_try_propagate_clr PARAMS ((rtx));static void mdr_try_propagate_move_sequence PARAMS ((rtx, rtx, rtx));static void mdr_try_propagate_move PARAMS ((rtx));static void mdr_try_remove_redundant_insns PARAMS ((rtx));static int track_w_reload PARAMS ((rtx, rtx *, int , int));static void mdr_try_wreg_elim PARAMS ((rtx));#endif /* IP2K_MD_REORG_PASS */static int ip2k_check_can_adjust_stack_ref PARAMS ((rtx, int));static void ip2k_adjust_stack_ref PARAMS ((rtx *, int));static int ip2k_xexp_not_uses_reg_for_mem PARAMS ((rtx, unsigned int));static tree ip2k_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree ip2k_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));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_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO encode_section_info#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE ip2k_attribute_tablestruct gcc_target targetm = TARGET_INITIALIZER;/* Commands in the functions prologues in the compiled file. */static int commands_in_prologues;/* Commands in the functions epilogues in the compiled file. */static int commands_in_epilogues;/* 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 (rao) 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 (fundecl, funtype, size) 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 (func) 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, size) 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 = ! strcmp ("main", current_function_name); /* 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=%d */\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, size) 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=%d */\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-thru */ 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-thru */ 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-thru */ 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-thru */ 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); commands_in_prologues += prologue_size; commands_in_epilogues += 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) <------ FP [HARD_FRAME_POINTER] ($FD:$FE) SAVED REGS <------ VFP [$100:$101] STACK ALLOCATION <------ SP ($6:$7) */intip2k_init_elim_offset (from, to) int from; int to;{ int leaf_func_p = leaf_function_p (); int no_saved_pc = leaf_func_p || ip2k_naked_function_p (current_function_decl); int offset; int reg; int reglimit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -