📄 xtensa.c
字号:
/* Subroutines for insn-output.c for Tensilica's Xtensa architecture. Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.This file is part of GCC.GCC is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.GCC is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public Licensealong with GCC; see the file COPYING. If not, write to the FreeSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA02110-1301, 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 "basic-block.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "insn-attr.h"#include "insn-codes.h"#include "recog.h"#include "output.h"#include "tree.h"#include "expr.h"#include "flags.h"#include "reload.h"#include "tm_p.h"#include "function.h"#include "toplev.h"#include "optabs.h"#include "libfuncs.h"#include "ggc.h"#include "target.h"#include "target-def.h"#include "langhooks.h"#include "tree-gimple.h"/* Enumeration for all of the relational tests, so that we can build arrays indexed by the test type, and not worry about the order of EQ, NE, etc. */enum internal_test{ ITEST_EQ, ITEST_NE, ITEST_GT, ITEST_GE, ITEST_LT, ITEST_LE, ITEST_GTU, ITEST_GEU, ITEST_LTU, ITEST_LEU, ITEST_MAX};/* Cached operands, and operator to compare for use in set/branch on condition codes. */rtx branch_cmp[2];/* what type of branch to use */enum cmp_type branch_type;/* Array giving truth value on whether or not a given hard register can support a given mode. */char xtensa_hard_regno_mode_ok[(int) MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];/* Current frame size calculated by compute_frame_size. */unsigned xtensa_current_frame_size;/* Largest block move to handle in-line. */#define LARGEST_MOVE_RATIO 15/* Define the structure for the machine field in struct function. */struct machine_function GTY(()){ int accesses_prev_frame; bool need_a7_copy; bool vararg_a7; rtx set_frame_ptr_insn;};/* Vector, indexed by hard register number, which contains 1 for a register that is allowable in a candidate for leaf function treatment. */const char xtensa_leaf_regs[FIRST_PSEUDO_REGISTER] ={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};/* Map hard register number to register class */const enum reg_class xtensa_regno_to_class[FIRST_PSEUDO_REGISTER] ={ RL_REGS, SP_REG, RL_REGS, RL_REGS, RL_REGS, RL_REGS, RL_REGS, GR_REGS, RL_REGS, RL_REGS, RL_REGS, RL_REGS, RL_REGS, RL_REGS, RL_REGS, RL_REGS, AR_REGS, AR_REGS, BR_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, ACC_REG,};/* Map register constraint character to register class. */enum reg_class xtensa_char_to_class[256] ={ NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS, NO_REGS,};static enum internal_test map_test_to_internal_test (enum rtx_code);static rtx gen_int_relational (enum rtx_code, rtx, rtx, int *);static rtx gen_float_relational (enum rtx_code, rtx, rtx);static rtx gen_conditional_move (rtx);static rtx fixup_subreg_mem (rtx);static struct machine_function * xtensa_init_machine_status (void);static bool xtensa_return_in_msb (tree);static void printx (FILE *, signed int);static void xtensa_function_epilogue (FILE *, HOST_WIDE_INT);static rtx xtensa_builtin_saveregs (void);static unsigned int xtensa_multibss_section_type_flags (tree, const char *, int) ATTRIBUTE_UNUSED;static void xtensa_select_rtx_section (enum machine_mode, rtx, unsigned HOST_WIDE_INT);static bool xtensa_rtx_costs (rtx, int, int, int *);static tree xtensa_build_builtin_va_list (void);static bool xtensa_return_in_memory (tree, tree);static tree xtensa_gimplify_va_arg_expr (tree, tree, tree *, tree *);static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;/* This macro generates the assembly code for function exit, on machines that need it. If FUNCTION_EPILOGUE is not defined then individual return instructions are generated for each return statement. Args are same as for FUNCTION_PROLOGUE. */#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE xtensa_function_epilogue/* These hooks specify assembly directives for creating certain kinds of integer object. */#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"#undef TARGET_ASM_SELECT_RTX_SECTION#define TARGET_ASM_SELECT_RTX_SECTION xtensa_select_rtx_section#undef TARGET_DEFAULT_TARGET_FLAGS#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_FUSED_MADD)#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS xtensa_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST hook_int_rtx_0#undef TARGET_BUILD_BUILTIN_VA_LIST#define TARGET_BUILD_BUILTIN_VA_LIST xtensa_build_builtin_va_list#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 xtensa_return_in_memory#undef TARGET_SPLIT_COMPLEX_ARG#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true#undef TARGET_MUST_PASS_IN_STACK#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size#undef TARGET_EXPAND_BUILTIN_SAVEREGS#define TARGET_EXPAND_BUILTIN_SAVEREGS xtensa_builtin_saveregs#undef TARGET_GIMPLIFY_VA_ARG_EXPR#define TARGET_GIMPLIFY_VA_ARG_EXPR xtensa_gimplify_va_arg_expr#undef TARGET_RETURN_IN_MSB#define TARGET_RETURN_IN_MSB xtensa_return_in_msbstruct gcc_target targetm = TARGET_INITIALIZER;/* * Functions to test Xtensa immediate operand validity. */boolxtensa_simm8 (HOST_WIDE_INT v){ return v >= -128 && v <= 127;}boolxtensa_simm8x256 (HOST_WIDE_INT v){ return (v & 255) == 0 && (v >= -32768 && v <= 32512);}boolxtensa_simm12b (HOST_WIDE_INT v){ return v >= -2048 && v <= 2047;}static boolxtensa_uimm8 (HOST_WIDE_INT v){ return v >= 0 && v <= 255;}static boolxtensa_uimm8x2 (HOST_WIDE_INT v){ return (v & 1) == 0 && (v >= 0 && v <= 510);}static boolxtensa_uimm8x4 (HOST_WIDE_INT v){ return (v & 3) == 0 && (v >= 0 && v <= 1020);}static boolxtensa_b4const (HOST_WIDE_INT v){ switch (v) { case -1: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 10: case 12: case 16: case 32: case 64: case 128: case 256: return true; } return false;}boolxtensa_b4const_or_zero (HOST_WIDE_INT v){ if (v == 0) return true; return xtensa_b4const (v);}boolxtensa_b4constu (HOST_WIDE_INT v){ switch (v) { case 32768: case 65536: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 10: case 12: case 16: case 32: case 64: case 128: case 256: return true; } return false;}boolxtensa_mask_immediate (HOST_WIDE_INT v){#define MAX_MASK_SIZE 16 int mask_size; for (mask_size = 1; mask_size <= MAX_MASK_SIZE; mask_size++) { if ((v & 1) == 0) return false; v = v >> 1; if (v == 0) return true; } return false;}boolxtensa_const_ok_for_letter_p (HOST_WIDE_INT v, int c){ switch (c) { case 'I': return xtensa_simm12b (v); case 'J': return xtensa_simm8 (v); case 'K': return (v == 0 || xtensa_b4const (v)); case 'L': return xtensa_b4constu (v); case 'M': return (v >= -32 && v <= 95); case 'N': return xtensa_simm8x256 (v); case 'O': return (v == -1 || (v >= 1 && v <= 15)); case 'P': return xtensa_mask_immediate (v); default: break; } return false;}/* This is just like the standard true_regnum() function except that it works even when reg_renumber is not initialized. */intxt_true_regnum (rtx x){ if (GET_CODE (x) == REG) { if (reg_renumber && REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (x)] >= 0) return reg_renumber[REGNO (x)]; return REGNO (x); } if (GET_CODE (x) == SUBREG) { int base = xt_true_regnum (SUBREG_REG (x)); if (base >= 0 && base < FIRST_PSEUDO_REGISTER) return base + subreg_regno_offset (REGNO (SUBREG_REG (x)), GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x), GET_MODE (x)); } return -1;}intxtensa_valid_move (enum machine_mode mode, rtx *operands){ /* Either the destination or source must be a register, and the MAC16 accumulator doesn't count. */ if (register_operand (operands[0], mode)) { int dst_regnum = xt_true_regnum (operands[0]); /* The stack pointer can only be assigned with a MOVSP opcode. */ if (dst_regnum == STACK_POINTER_REGNUM) return (mode == SImode && register_operand (operands[1], mode) && !ACC_REG_P (xt_true_regnum (operands[1]))); if (!ACC_REG_P (dst_regnum)) return true; } if (register_operand (operands[1], mode)) { int src_regnum = xt_true_regnum (operands[1]); if (!ACC_REG_P (src_regnum)) return true; } return FALSE;}intsmalloffset_mem_p (rtx op){ if (GET_CODE (op) == MEM) { rtx addr = XEXP (op, 0); if (GET_CODE (addr) == REG) return REG_OK_FOR_BASE_P (addr); if (GET_CODE (addr) == PLUS) { rtx offset = XEXP (addr, 0); HOST_WIDE_INT val; if (GET_CODE (offset) != CONST_INT) offset = XEXP (addr, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -