📄 arm.c
字号:
/* 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 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 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 this chip is an ARM6 or an ARM7. */int arm_is_6_or_7 = 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. */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; 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}};/* 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. */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}};/* 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"); set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idivmod"); set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidivmod");}/* Fix up any incompatible options that the user has specified. This has now turned into a maze. */voidarm_override_options (void){ unsigned i; enum processor_type target_arch_cpu = arm_none; /* Set up the flags based on the cpu/architecture selected by the user. */ for (i = ARRAY_SIZE (arm_select); i--;) { struct arm_cpu_select * ptr = arm_select + i; if (ptr->string != NULL && ptr->string[0] != '\0') { const struct processors * sel; for (sel = ptr->processors; sel->name != NULL; sel++) if (streq (ptr->string, sel->name)) { /* Set the architecture define. */ if (i != ARM_OPT_SET_TUNE) sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch); /* Determine the processor core for which we should tune code-generation. */ if (/* -mcpu= is a sensible default. */ i == ARM_OPT_SET_CPU /* -mtune= overrides -mcpu= and -march=. */ || i == ARM_OPT_SET_TUNE) arm_tune = (enum processor_type) (sel - ptr->processors); /* Remember the CPU associated with this architecture. If no other option is used to set the CPU type, we'll use this to guess the most suitable tuning options. */ if (i == ARM_OPT_SET_ARCH) target_arch_cpu = sel->core; if (i != ARM_OPT_SET_TUNE) { /* If we have been given an architecture and a processor make sure that they are compatible. We only generate a warning though, and we prefer the CPU over the architecture. */ if (insn_flags != 0 && (insn_flags ^ sel->flags)) warning ("switch -mcpu=%s conflicts with -march= switch", ptr->string); insn_flags = sel->flags; } break; } if (sel->name == NULL) error ("bad value (%s) for %s switch", ptr->string, ptr->name); } } /* Guess the tuning options from the architecture if necessary. */ if (arm_tune == arm_none) arm_tune = target_arch_cpu; /* If the user did not specify a processor, choose one for them. */ if (insn_flags == 0) { const struct processors * sel; unsigned int sought; enum processor_type cpu; cpu = TARGET_CPU_DEFAULT; if (cpu == arm_none) {#ifdef SUBTARGET_CPU_DEFAULT /* Use the subtarget default CPU if none was specified by configure. */ cpu = SUBTARGET_CPU_DEFAULT;#endif /* Default to ARM6. */ if (cpu == arm_none)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -