📄 xtensa.c
字号:
/* Subroutines for insn-output.c for Tensilica's Xtensa architecture. Copyright 2001, 2002, 2003, 2004 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, 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. */#include "config.h"#include "system.h"#include "rtl.h"#include "regs.h"#include "machmode.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 "output.h"#include "libfuncs.h"#include "ggc.h"#include "target.h"#include "target-def.h"#include "langhooks.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;/* Tables of ld/st opcode names for block moves */const char *xtensa_ld_opcodes[(int) MAX_MACHINE_MODE];const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];#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 int b4const_or_zero PARAMS ((int));static enum internal_test map_test_to_internal_test PARAMS ((enum rtx_code));static rtx gen_int_relational PARAMS ((enum rtx_code, rtx, rtx, int *));static rtx gen_float_relational PARAMS ((enum rtx_code, rtx, rtx));static rtx gen_conditional_move PARAMS ((rtx));static rtx fixup_subreg_mem PARAMS ((rtx x));static enum machine_mode xtensa_find_mode_for_size PARAMS ((unsigned));static struct machine_function * xtensa_init_machine_status PARAMS ((void));static void printx PARAMS ((FILE *, signed int));static unsigned int xtensa_multibss_section_type_flags PARAMS ((tree, const char *, int));static void xtensa_select_rtx_section PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));static void xtensa_encode_section_info PARAMS ((tree, int));static rtx frame_size_const;static int current_function_arg_words;static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;/* This macro generates the assembly code for function entry. FILE is a stdio stream to output the code to. SIZE is an int: how many units of temporary storage to allocate. Refer to the array 'regs_ever_live' to determine which registers to save; 'regs_ever_live[I]' is nonzero if register number I is ever used in the function. This macro is responsible for knowing which registers should not be saved even if used. */#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE xtensa_function_prologue/* 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_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO xtensa_encode_section_infostruct gcc_target targetm = TARGET_INITIALIZER;/* * Functions to test Xtensa immediate operand validity. */intxtensa_b4constu (v) 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 1; } return 0;}intxtensa_simm8x256 (v) int v;{ return (v & 255) == 0 && (v >= -32768 && v <= 32512);}intxtensa_ai4const (v) int v;{ return (v == -1 || (v >= 1 && v <= 15));}intxtensa_simm7 (v) int v;{ return v >= -32 && v <= 95;}intxtensa_b4const (v) 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 1; } return 0;}intxtensa_simm8 (v) int v;{ return v >= -128 && v <= 127;}intxtensa_tp7 (v) int v;{ return (v >= 7 && v <= 22);}intxtensa_lsi4x4 (v) int v;{ return (v & 3) == 0 && (v >= 0 && v <= 60);}intxtensa_simm12b (v) int v;{ return v >= -2048 && v <= 2047;}intxtensa_uimm8 (v) int v;{ return v >= 0 && v <= 255;}intxtensa_uimm8x2 (v) int v;{ return (v & 1) == 0 && (v >= 0 && v <= 510);}intxtensa_uimm8x4 (v) int v;{ return (v & 3) == 0 && (v >= 0 && v <= 1020);}/* This is just like the standard true_regnum() function except that it works even when reg_renumber is not initialized. */intxt_true_regnum (x) 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;}intadd_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return (xtensa_simm8 (INTVAL (op)) || xtensa_simm8x256 (INTVAL (op))); return register_operand (op, mode);}intarith_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return xtensa_simm8 (INTVAL (op)); return register_operand (op, mode);}intnonimmed_operand (op, mode) rtx op; enum machine_mode mode;{ /* We cannot use the standard nonimmediate_operand() predicate because it includes constant pool memory operands. */ if (memory_operand (op, mode)) return !constantpool_address_p (XEXP (op, 0)); return register_operand (op, mode);}intmem_operand (op, mode) rtx op; enum machine_mode mode;{ /* We cannot use the standard memory_operand() predicate because it includes constant pool memory operands. */ if (memory_operand (op, mode)) return !constantpool_address_p (XEXP (op, 0)); return FALSE;}intxtensa_valid_move (mode, operands) 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;}intmask_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return xtensa_mask_immediate (INTVAL (op)); return register_operand (op, mode);}intextui_fldsz_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return ((GET_CODE (op) == CONST_INT) && xtensa_mask_immediate ((1 << INTVAL (op)) - 1));}intsext_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_SEXT) return nonimmed_operand (op, mode); return mem_operand (op, mode);}intsext_fldsz_operand (op, mode) rtx op;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -