📄 arm.c
字号:
/* Bit values used to identify processor capabilities. */#define FL_CO_PROC (1 << 0) /* Has external co-processor bus */#define FL_ARCH3M (1 << 1) /* Extended 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 extensions to v5 */#define FL_XSCALE (1 << 10) /* XScale */#define FL_CIRRUS (1 << 11) /* Cirrus/DSP. */#define FL_ARCH6 (1 << 12) /* Architecture rel 6. Adds media instructions. */#define FL_VFPV2 (1 << 13) /* Vector Floating Point V2. */#define FL_WBUF (1 << 14) /* Schedule for write buffer ops. Note: ARM6 & 7 derivatives only. */#define FL_ARCH6K (1 << 15) /* Architecture rel 6 K extensions. */#define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */#define FL_FOR_ARCH2 0#define FL_FOR_ARCH3 FL_MODE32#define FL_FOR_ARCH3M (FL_FOR_ARCH3 | FL_ARCH3M)#define FL_FOR_ARCH4 (FL_FOR_ARCH3M | FL_ARCH4)#define FL_FOR_ARCH4T (FL_FOR_ARCH4 | FL_THUMB)#define FL_FOR_ARCH5 (FL_FOR_ARCH4 | FL_ARCH5)#define FL_FOR_ARCH5T (FL_FOR_ARCH5 | FL_THUMB)#define FL_FOR_ARCH5E (FL_FOR_ARCH5 | FL_ARCH5E)#define FL_FOR_ARCH5TE (FL_FOR_ARCH5E | FL_THUMB)#define FL_FOR_ARCH5TEJ FL_FOR_ARCH5TE#define FL_FOR_ARCH6 (FL_FOR_ARCH5TE | FL_ARCH6)#define FL_FOR_ARCH6J FL_FOR_ARCH6#define FL_FOR_ARCH6K (FL_FOR_ARCH6 | FL_ARCH6K)#define FL_FOR_ARCH6Z FL_FOR_ARCH6#define FL_FOR_ARCH6ZK FL_FOR_ARCH6K/* 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. */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 chip supports the ARM Architecture 3M extensions. */int arm_arch3m = 0;/* Nonzero if this chip supports the ARM Architecture 4 extensions. */int arm_arch4 = 0;/* Nonzero if this chip supports the ARM Architecture 4t extensions. */int arm_arch4t = 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 supports the ARM Architecture 6 extensions. */int arm_arch6 = 0;/* Nonzero if this chip supports the ARM 6K extensions. */int arm_arch6k = 0;/* Nonzero if this chip can benefit from load scheduling. */int arm_ld_sched = 0;/* Nonzero if this chip is a StrongARM. */int arm_tune_strongarm = 0;/* Nonzero if this chip is a Cirrus variant. */int arm_arch_cirrus = 0;/* Nonzero if this chip supports Intel Wireless MMX technology. */int arm_arch_iwmmxt = 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 we want to tune for stores that access the write-buffer. This typically means an ARM6 or ARM7 with MMU or MPU. */int arm_tune_wbuf = 0;/* Nonzero if generating Thumb instructions. */int thumb_code = 0;/* Nonzero if we should define __THUMB_INTERWORK__ in the preprocessor. XXX This is a bit of a hack, it's intended to help work around problems in GLD which doesn't understand that armv5t code is interworking clean. */int arm_cpp_interwork = 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. */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; enum processor_type core; const char *arch; const unsigned long flags; bool (* rtx_costs) (rtx, int, int, int *);};/* 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 */#define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \ {NAME, arm_none, #ARCH, FLAGS | FL_FOR_ARCH##ARCH, arm_##COSTS##_rtx_costs},#include "arm-cores.def"#undef ARM_CORE {NULL, arm_none, NULL, 0, NULL}};static const struct processors all_architectures[] ={ /* ARM Architectures */ /* We don't specify rtx_costs here as it will be figured out from the core. */ {"armv2", arm2, "2", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL}, {"armv2a", arm2, "2", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL}, {"armv3", arm6, "3", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3, NULL}, {"armv3m", arm7m, "3M", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3M, NULL}, {"armv4", arm7tdmi, "4", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH4, NULL}, /* 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", arm7tdmi, "4T", FL_CO_PROC | FL_FOR_ARCH4T, NULL}, {"armv5", arm10tdmi, "5", FL_CO_PROC | FL_FOR_ARCH5, NULL}, {"armv5t", arm10tdmi, "5T", FL_CO_PROC | FL_FOR_ARCH5T, NULL}, {"armv5e", arm1026ejs, "5E", FL_CO_PROC | FL_FOR_ARCH5E, NULL}, {"armv5te", arm1026ejs, "5TE", FL_CO_PROC | FL_FOR_ARCH5TE, NULL}, {"armv6", arm1136js, "6", FL_CO_PROC | FL_FOR_ARCH6, NULL}, {"armv6j", arm1136js, "6J", FL_CO_PROC | FL_FOR_ARCH6J, NULL}, {"armv6k", mpcore, "6K", FL_CO_PROC | FL_FOR_ARCH6K, NULL}, {"armv6z", arm1176jzs, "6Z", FL_CO_PROC | FL_FOR_ARCH6Z, NULL}, {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC | FL_FOR_ARCH6ZK, NULL}, {"ep9312", ep9312, "4T", FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL}, {"iwmmxt", iwmmxt, "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL}, {NULL, arm_none, NULL, 0 , NULL}};struct arm_cpu_select{ const char * string; const char * name; const struct processors * processors;};/* This is a magic structure. 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. */static struct arm_cpu_select arm_select[] ={ /* string name processors */ { NULL, "-mcpu=", all_cores }, { NULL, "-march=", all_architectures }, { NULL, "-mtune=", all_cores }};/* Defines representing the indexes into the above table. */#define ARM_OPT_SET_CPU 0#define ARM_OPT_SET_ARCH 1#define ARM_OPT_SET_TUNE 2/* The name of the proprocessor macro to define for this architecture. */char arm_arch_name[] = "__ARM_ARCH_0UNK__";struct fpu_desc{ const char * name; enum fputype fpu;};/* Available values for for -mfpu=. */static const struct fpu_desc all_fpus[] ={ {"fpa", FPUTYPE_FPA}, {"fpe2", FPUTYPE_FPA_EMU2}, {"fpe3", FPUTYPE_FPA_EMU2}, {"maverick", FPUTYPE_MAVERICK}, {"vfp", FPUTYPE_VFP}};/* Floating point models used by the different hardware. See fputype in arm.h. */static const enum fputype fp_model_for_fpu[] ={ /* No FP hardware. */ ARM_FP_MODEL_UNKNOWN, /* FPUTYPE_NONE */ ARM_FP_MODEL_FPA, /* FPUTYPE_FPA */ ARM_FP_MODEL_FPA, /* FPUTYPE_FPA_EMU2 */ ARM_FP_MODEL_FPA, /* FPUTYPE_FPA_EMU3 */ ARM_FP_MODEL_MAVERICK, /* FPUTYPE_MAVERICK */ ARM_FP_MODEL_VFP /* FPUTYPE_VFP */};struct float_abi{ const char * name; enum float_abi_type abi_type;};/* Available values for -mfloat-abi=. */static const struct float_abi all_float_abis[] ={ {"soft", ARM_FLOAT_ABI_SOFT}, {"softfp", ARM_FLOAT_ABI_SOFTFP}, {"hard", ARM_FLOAT_ABI_HARD}};struct abi_name{ const char *name; enum arm_abi_type abi_type;};/* Available values for -mabi=. */static const struct abi_name arm_all_abis[] ={ {"apcs-gnu", ARM_ABI_APCS}, {"atpcs", ARM_ABI_ATPCS}, {"aapcs", ARM_ABI_AAPCS}, {"iwmmxt", ARM_ABI_IWMMXT}, {"aapcs-linux", ARM_ABI_AAPCS_LINUX}};/* Supported TLS relocations. */enum tls_reloc { TLS_GD32, TLS_LDM32, TLS_LDO32, TLS_IE32, TLS_LE32};/* Return the number of bits set in VALUE. */static unsignedbit_count (unsigned long value){ unsigned long count = 0; while (value) { count++; value &= value - 1; /* Clear the least-significant set bit. */ } return count;}/* Set up library functions unique to ARM. */static voidarm_init_libfuncs (void){ /* There are no special library functions unless we are using the ARM BPABI. */ if (!TARGET_BPABI) return; /* The functions below are described in Section 4 of the "Run-Time ABI for the ARM architecture", Version 1.0. */ /* Double-precision floating-point arithmetic. Table 2. */ set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd"); set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv"); set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul"); set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg"); set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub"); /* Double-precision comparisons. Table 3. */ set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq"); set_optab_libfunc (ne_optab, DFmode, NULL); set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt"); set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple"); set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge"); set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt"); set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun"); /* Single-precision floating-point arithmetic. Table 4. */ set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd"); set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv"); set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul"); set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg"); set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub"); /* Single-precision comparisons. Table 5. */ set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq"); set_optab_libfunc (ne_optab, SFmode, NULL); set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt"); set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple"); set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge"); set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt"); set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun"); /* Floating-point to integer conversions. Table 6. */ set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz"); set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz"); set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz"); set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz"); set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz"); set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz"); set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz"); set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz"); /* Conversions between floating types. Table 7. */ set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f"); set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d"); /* Integer to floating-point conversions. Table 8. */ set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d"); set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d"); set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d"); set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d"); set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f"); set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f"); set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f"); set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f"); /* Long long. Table 9. */ set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul"); set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod"); set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod"); set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl"); set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr"); set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr"); set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp"); set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp"); /* Integer (32/32->32) division. \S 4.3.1. */ set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod"); set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod"); /* The divmod functions are designed so that they can be used for plain division, even though they return both the quotient and the remainder. The quotient is returned in the usual location (i.e., r0 for SImode, {r0, r1} for DImode), just as would be expected for an ordinary division routine. Because the AAPCS calling conventions specify that all of { r0, r1, r2, r3 } are callee-saved registers, there is no need to tell the compiler explicitly that those registers are clobbered by these routines. */ set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod"); set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod"); /* For SImode division the ABI provides div-without-mod routines, which are faster. */ set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv"); set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv"); /* We don't have mod libcalls. Fortunately gcc knows how to use the divmod libcalls instead. */ set_optab_libfunc (smod_optab, DImode, NULL); set_optab_libfunc (umod_optab, DImode, NULL); set_optab_libfunc (smod_optab, SImode, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -