📄 arm.c
字号:
/* Output routines for GCC for ARM. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) and Martin Simmons (@harleqn.co.uk). More major hacks by Richard Earnshaw (rearnsha@arm.com).This file is part of GNU CC.GNU CC 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.GNU CC 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 GNU CC; 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 "rtl.h"#include "tree.h"#include "obstack.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 "reload.h"#include "function.h"#include "expr.h"#include "optabs.h"#include "toplev.h"#include "recog.h"#include "ggc.h"#include "except.h"#include "c-pragma.h"#include "integrate.h"#include "tm_p.h"#include "target.h"#include "target-def.h"/* Forward definitions of types. */typedef struct minipool_node Mnode;typedef struct minipool_fixup Mfix;/* In order to improve the layout of the prototypes below some short type abbreviations are defined here. */#define Hint HOST_WIDE_INT#define Mmode enum machine_mode#define Ulong unsigned long#define Ccstar const char *const struct attribute_spec arm_attribute_table[];/* Forward function declarations. */static void arm_add_gc_roots PARAMS ((void));static int arm_gen_constant PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));static unsigned bit_count PARAMS ((Ulong));static int const_ok_for_op PARAMS ((Hint, enum rtx_code));static rtx emit_multi_reg_push PARAMS ((int));static rtx emit_sfm PARAMS ((int, int));#ifndef AOF_ASSEMBLERstatic bool arm_assemble_integer PARAMS ((rtx, unsigned int, int));#endifstatic Ccstar fp_const_from_val PARAMS ((REAL_VALUE_TYPE *));static arm_cc get_arm_condition_code PARAMS ((rtx));static void init_fpa_table PARAMS ((void));static Hint int_log2 PARAMS ((Hint));static rtx is_jump_table PARAMS ((rtx));static Ccstar output_multi_immediate PARAMS ((rtx *, Ccstar, Ccstar, int, Hint));static void print_multi_reg PARAMS ((FILE *, Ccstar, int, int));static Mmode select_dominance_cc_mode PARAMS ((rtx, rtx, Hint));static Ccstar shift_op PARAMS ((rtx, Hint *));static struct machine_function * arm_init_machine_status PARAMS ((void));static int number_of_first_bit_set PARAMS ((int));static void replace_symbols_in_block PARAMS ((tree, rtx, rtx));static void thumb_exit PARAMS ((FILE *, int, rtx));static void thumb_pushpop PARAMS ((FILE *, int, int));static Ccstar thumb_condition_code PARAMS ((rtx, int));static rtx is_jump_table PARAMS ((rtx));static Hint get_jump_table_size PARAMS ((rtx));static Mnode * move_minipool_fix_forward_ref PARAMS ((Mnode *, Mnode *, Hint));static Mnode * add_minipool_forward_ref PARAMS ((Mfix *));static Mnode * move_minipool_fix_backward_ref PARAMS ((Mnode *, Mnode *, Hint));static Mnode * add_minipool_backward_ref PARAMS ((Mfix *));static void assign_minipool_offsets PARAMS ((Mfix *));static void arm_print_value PARAMS ((FILE *, rtx));static void dump_minipool PARAMS ((rtx));static int arm_barrier_cost PARAMS ((rtx));static Mfix * create_fix_barrier PARAMS ((Mfix *, Hint));static void push_minipool_barrier PARAMS ((rtx, Hint));static void push_minipool_fix PARAMS ((rtx, Hint, rtx *, Mmode, rtx));static void note_invalid_constants PARAMS ((rtx, Hint));static int current_file_function_operand PARAMS ((rtx));static Ulong arm_compute_save_reg0_reg12_mask PARAMS ((void));static Ulong arm_compute_save_reg_mask PARAMS ((void));static Ulong arm_isr_value PARAMS ((tree));static Ulong arm_compute_func_type PARAMS ((void));static tree arm_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree arm_handle_isr_attribute PARAMS ((tree *, tree, tree, int, bool *));static void arm_output_function_epilogue PARAMS ((FILE *, Hint));static void arm_output_function_prologue PARAMS ((FILE *, Hint));static void thumb_output_function_prologue PARAMS ((FILE *, Hint));static int arm_comp_type_attributes PARAMS ((tree, tree));static void arm_set_default_type_attributes PARAMS ((tree));static int arm_adjust_cost PARAMS ((rtx, rtx, rtx, int));static int count_insns_for_constant PARAMS ((HOST_WIDE_INT, int));static int arm_get_strip_length PARAMS ((int));#ifdef OBJECT_FORMAT_ELFstatic void arm_elf_asm_named_section PARAMS ((const char *, unsigned int));#endif#ifndef ARM_PEstatic void arm_encode_section_info PARAMS ((tree, int));#endif#ifdef AOF_ASSEMBLERstatic void aof_globalize_label PARAMS ((FILE *, const char *));#endifstatic void arm_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree));#undef Hint#undef Mmode#undef Ulong#undef Ccstar/* Initialize the GCC target structure. */#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES#undef TARGET_MERGE_DECL_ATTRIBUTES#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes#endif#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE arm_attribute_table#ifdef AOF_ASSEMBLER#undef TARGET_ASM_BYTE_OP#define TARGET_ASM_BYTE_OP "\tDCB\t"#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"#undef TARGET_ASM_GLOBALIZE_LABEL#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label#else#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP NULL#undef TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER arm_assemble_integer#endif#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue#undef TARGET_COMP_TYPE_ATTRIBUTES#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes#undef TARGET_INIT_BUILTINS#define TARGET_INIT_BUILTINS arm_init_builtins#undef TARGET_EXPAND_BUILTIN#define TARGET_EXPAND_BUILTIN arm_expand_builtin#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST arm_adjust_cost#undef TARGET_ENCODE_SECTION_INFO#ifdef ARM_PE#define TARGET_ENCODE_SECTION_INFO arm_pe_encode_section_info#else#define TARGET_ENCODE_SECTION_INFO arm_encode_section_info#endif#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding#undef TARGET_ASM_OUTPUT_MI_THUNK#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcallstruct gcc_target targetm = TARGET_INITIALIZER;/* Obstack for minipool constant handling. */static struct obstack minipool_obstack;static char * minipool_startobj;/* The maximum number of insns skipped which will be conditionalised if possible. */static int max_insns_skipped = 5;extern FILE * asm_out_file;/* True if we are currently building a constant table. */int making_const_table;/* Define the information needed to generate branch insns. This is stored from the compare operation. */rtx arm_compare_op0, arm_compare_op1;/* What type of floating point are we tuning for? */enum floating_point_type arm_fpu;/* What type of floating point instructions are available? */enum floating_point_type arm_fpu_arch;/* What program mode is the cpu running in? 26-bit mode or 32-bit mode. */enum prog_mode_type arm_prgmode;/* Set by the -mfp=... option. */const char * target_fp_name = NULL;/* Used to parse -mstructure_size_boundary command line option. */const char * structure_size_string = NULL;int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;/* Bit values used to identify processor capabilities. */#define FL_CO_PROC (1 << 0) /* Has external co-processor bus */#define FL_FAST_MULT (1 << 1) /* Fast multiply */#define FL_MODE26 (1 << 2) /* 26-bit mode support */#define FL_MODE32 (1 << 3) /* 32-bit mode support */#define FL_ARCH4 (1 << 4) /* Architecture rel 4 */#define FL_ARCH5 (1 << 5) /* Architecture rel 5 */#define FL_THUMB (1 << 6) /* Thumb aware */#define FL_LDSCHED (1 << 7) /* Load scheduling necessary */#define FL_STRONG (1 << 8) /* StrongARM */#define FL_ARCH5E (1 << 9) /* DSP extenstions to v5 */#define FL_XSCALE (1 << 10) /* XScale *//* The bits in this mask specify which instructions we are allowed to generate. */static unsigned long insn_flags = 0;/* The bits in this mask specify which instruction scheduling options should be used. Note - there is an overlap with the FL_FAST_MULT. For some hardware we want to be able to generate the multiply instructions, but to tune as if they were not present in the architecture. */static unsigned long tune_flags = 0;/* The following are used in the arm.md file as equivalents to bits in the above two flag variables. *//* Nonzero if this is an "M" variant of the processor. */int arm_fast_multiply = 0;/* Nonzero if this chip supports the ARM Architecture 4 extensions. */int arm_arch4 = 0;/* Nonzero if this chip supports the ARM Architecture 5 extensions. */int arm_arch5 = 0;/* Nonzero if this chip supports the ARM Architecture 5E extensions. */int arm_arch5e = 0;/* Nonzero if this chip can benefit from load scheduling. */int arm_ld_sched = 0;/* Nonzero if this chip is a StrongARM. */int arm_is_strong = 0;/* Nonzero if this chip is an XScale. */int arm_arch_xscale = 0;/* Nonzero if tuning for XScale */int arm_tune_xscale = 0;/* Nonzero if this chip is an ARM6 or an ARM7. */int arm_is_6_or_7 = 0;/* Nonzero if generating Thumb instructions. */int thumb_code = 0;/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we must report the mode of the memory reference from PRINT_OPERAND to PRINT_OPERAND_ADDRESS. */enum machine_mode output_memory_reference_mode;/* The register number to be used for the PIC offset register. */const char * arm_pic_register_string = NULL;int arm_pic_register = INVALID_REGNUM;/* Set to 1 when a return insn is output, this means that the epilogue is not needed. */int return_used_this_function;/* Set to 1 after arm_reorg has started. Reset to start at the start of the next function. */static int after_arm_reorg = 0;/* The maximum number of insns to be used when loading a constant. */static int arm_constant_limit = 3;/* For an explanation of these variables, see final_prescan_insn below. */int arm_ccfsm_state;enum arm_cond_code arm_current_cc;rtx arm_target_insn;int arm_target_label;/* The condition codes of the ARM, and the inverse function. */static const char * const arm_condition_codes[] ={ "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};#define streq(string1, string2) (strcmp (string1, string2) == 0)/* Initialization code. */struct processors{ const char *const name; const unsigned long flags;};/* Not all of these give usefully different compilation alternatives, but there is no simple way of generalizing them. */static const struct processors all_cores[] ={ /* ARM Cores */ {"arm2", FL_CO_PROC | FL_MODE26 }, {"arm250", FL_CO_PROC | FL_MODE26 }, {"arm3", FL_CO_PROC | FL_MODE26 }, {"arm6", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm60", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm600", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm610", FL_MODE26 | FL_MODE32 }, {"arm620", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm7", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* arm7m doesn't exist on its own, but only with D, (and I), but those don't alter the code, so arm7m is sometimes used. */ {"arm7m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, {"arm7di", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm7dmi", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, {"arm70", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm700", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm700i", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm710", FL_MODE26 | FL_MODE32 }, {"arm710t", FL_MODE26 | FL_MODE32 | FL_THUMB }, {"arm720", FL_MODE26 | FL_MODE32 }, {"arm720t", FL_MODE26 | FL_MODE32 | FL_THUMB }, {"arm740t", FL_MODE26 | FL_MODE32 | FL_THUMB }, {"arm710c", FL_MODE26 | FL_MODE32 }, {"arm7100", FL_MODE26 | FL_MODE32 }, {"arm7500", FL_MODE26 | FL_MODE32 }, /* Doesn't have an external co-proc, but does have embedded fpu. */ {"arm7500fe", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, {"arm7tdmi", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB }, {"arm8", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, {"arm810", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, {"arm9", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, {"arm920", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, {"arm920t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, {"arm940t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, {"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED }, {"arm9e", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED }, {"strongarm", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, {"strongarm110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, {"strongarm1100", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, {"strongarm1110", FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_STRONG }, {"arm10tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_ARCH5 }, {"arm1020t", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_ARCH5 }, {"xscale", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE }, {NULL, 0}};static const struct processors all_architectures[] ={ /* ARM Architectures */ { "armv2", FL_CO_PROC | FL_MODE26 }, { "armv2a", FL_CO_PROC | FL_MODE26 }, { "armv3", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, { "armv3m", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, { "armv4", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 }, /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no implementations that support it, so we will leave it out for now. */ { "armv4t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB }, { "armv5", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 }, { "armv5t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 }, { "armv5te", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E }, { NULL, 0 }};/* This is a magic stucture. The 'string' field is magically filled in with a pointer to the value specified by the user on the command line assuming that the user has specified such a value. */struct arm_cpu_select arm_select[] ={ /* string name processors */ { NULL, "-mcpu=", all_cores }, { NULL, "-march=", all_architectures }, { NULL, "-mtune=", all_cores }};/* Return the number of bits set in VALUE. */static unsignedbit_count (value) unsigned long value;{ unsigned long count = 0; while (value) { count++; value &= value - 1; /* Clear the least-significant set bit. */ } return count;}/* Fix up any incompatible options that the user has specified.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -