diff options
Diffstat (limited to 'gcc/config/arm')
-rw-r--r-- | gcc/config/arm/arm-c.c | 2 | ||||
-rw-r--r-- | gcc/config/arm/arm-cores.def | 1 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/arm/arm-tune.md | 2 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 435 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 147 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 48 | ||||
-rw-r--r-- | gcc/config/arm/constraints.md | 12 | ||||
-rw-r--r-- | gcc/config/arm/thumb2.md | 164 |
9 files changed, 398 insertions, 415 deletions
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c index 4e2a9cbe51a..786a7a3587f 100644 --- a/gcc/config/arm/arm-c.c +++ b/gcc/config/arm/arm-c.c @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "tm_p.h" #include "tree.h" #include "output.h" -#include "c-common.h" +#include "c-family/c-common.h" /* Output C specific EABI object attributes. These can not be done in diff --git a/gcc/config/arm/arm-cores.def b/gcc/config/arm/arm-cores.def index a1a6960f5fd..9e949a2c334 100644 --- a/gcc/config/arm/arm-cores.def +++ b/gcc/config/arm/arm-cores.def @@ -123,6 +123,7 @@ ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, 9e) ARM_CORE("cortex-a9", cortexa9, 7A, FL_LDSCHED, 9e) ARM_CORE("cortex-r4", cortexr4, 7R, FL_LDSCHED, 9e) ARM_CORE("cortex-r4f", cortexr4f, 7R, FL_LDSCHED, 9e) +ARM_CORE("cortex-m4", cortexm4, 7EM, FL_LDSCHED, 9e) ARM_CORE("cortex-m3", cortexm3, 7M, FL_LDSCHED, 9e) ARM_CORE("cortex-m1", cortexm1, 6M, FL_LDSCHED, 9e) ARM_CORE("cortex-m0", cortexm0, 6M, FL_LDSCHED, 9e) diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 2933201a1eb..61dcf07d8ef 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -136,8 +136,6 @@ extern const char *arithmetic_instr (rtx, int); extern void output_ascii_pseudo_op (FILE *, const unsigned char *, int); extern const char *output_return_instruction (rtx, int, int); extern void arm_poke_function_name (FILE *, const char *); -extern void arm_print_operand (FILE *, rtx, int); -extern void arm_print_operand_address (FILE *, rtx); extern void arm_final_prescan_insn (rtx); extern int arm_debugger_arg_offset (int, rtx); extern bool arm_is_long_call_p (tree); diff --git a/gcc/config/arm/arm-tune.md b/gcc/config/arm/arm-tune.md index 7aef5f5fb78..4123043058b 100644 --- a/gcc/config/arm/arm-tune.md +++ b/gcc/config/arm/arm-tune.md @@ -1,5 +1,5 @@ ;; -*- buffer-read-only: t -*- ;; Generated automatically by gentune.sh from arm-cores.def (define_attr "tune" - "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,cortexa5,cortexa8,cortexa9,cortexr4,cortexr4f,cortexm3,cortexm1,cortexm0" + "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,cortexa5,cortexa8,cortexa9,cortexr4,cortexr4f,cortexm4,cortexm3,cortexm1,cortexm0" (const (symbol_ref "((enum attr_tune) arm_tune)"))) diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 6c886dccaef..9cb272c323e 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -45,7 +45,7 @@ #include "cgraph.h" #include "ggc.h" #include "except.h" -#include "c-pragma.h" +#include "c-family/c-pragma.h" /* ??? */ #include "integrate.h" #include "tm_p.h" #include "target.h" @@ -83,6 +83,9 @@ static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code); static rtx emit_sfm (int, int); static unsigned arm_size_return_regs (void); static bool arm_assemble_integer (rtx, unsigned int, int); +static void arm_print_operand (FILE *, rtx, int); +static void arm_print_operand_address (FILE *, rtx); +static bool arm_print_operand_punct_valid_p (unsigned char code); static const char *fp_const_from_val (REAL_VALUE_TYPE *); static arm_cc get_arm_condition_code (rtx); static HOST_WIDE_INT int_log2 (HOST_WIDE_INT); @@ -285,6 +288,13 @@ static const struct attribute_spec arm_attribute_table[] = #undef TARGET_ASM_INTEGER #define TARGET_ASM_INTEGER arm_assemble_integer +#undef TARGET_PRINT_OPERAND +#define TARGET_PRINT_OPERAND arm_print_operand +#undef TARGET_PRINT_OPERAND_ADDRESS +#define TARGET_PRINT_OPERAND_ADDRESS arm_print_operand_address +#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P +#define TARGET_PRINT_OPERAND_PUNCT_VALID_P arm_print_operand_punct_valid_p + #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue @@ -424,8 +434,8 @@ static const struct attribute_spec arm_attribute_table[] = #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack #ifdef TARGET_UNWIND_INFO -#undef TARGET_UNWIND_EMIT -#define TARGET_UNWIND_EMIT arm_unwind_emit +#undef TARGET_ASM_UNWIND_EMIT +#define TARGET_ASM_UNWIND_EMIT arm_unwind_emit /* EABI unwinding tables use a different format for the typeinfo tables. */ #undef TARGET_ASM_TTYPE @@ -527,9 +537,6 @@ enum processor_type arm_tune = arm_none; /* The current tuning set. */ const struct tune_params *current_tune; -/* The default processor used if not overridden by commandline. */ -static enum processor_type arm_default_cpu = arm_none; - /* Which floating point hardware to schedule for. */ int arm_fpu_attr; @@ -585,6 +592,10 @@ static int thumb_call_reg_needed; #define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */ +/* Flags that only effect tuning, not available instructions. */ +#define FL_TUNE (FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \ + | FL_CO_PROC) + #define FL_FOR_ARCH2 FL_NOTM #define FL_FOR_ARCH3 (FL_FOR_ARCH2 | FL_MODE32) #define FL_FOR_ARCH3M (FL_FOR_ARCH3 | FL_ARCH3M) @@ -687,9 +698,9 @@ int arm_arch_thumb2; /* Nonzero if chip supports integer division instruction. */ int arm_arch_hwdiv; -/* 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. */ +/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, + we must report the mode of the memory reference from + TARGET_PRINT_OPERAND to TARGET_PRINT_OPERAND_ADDRESS. */ enum machine_mode output_memory_reference_mode; /* The register number to be used for the PIC offset register. */ @@ -770,7 +781,7 @@ 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##_tune}, + {NAME, IDENT, #ARCH, FLAGS | FL_FOR_ARCH##ARCH, &arm_##COSTS##_tune}, #include "arm-cores.def" #undef ARM_CORE {NULL, arm_none, NULL, 0, NULL} @@ -805,36 +816,19 @@ static const struct processors all_architectures[] = {"armv7-a", cortexa8, "7A", FL_CO_PROC | FL_FOR_ARCH7A, NULL}, {"armv7-r", cortexr4, "7R", FL_CO_PROC | FL_FOR_ARCH7R, NULL}, {"armv7-m", cortexm3, "7M", FL_CO_PROC | FL_FOR_ARCH7M, NULL}, - {"armv7e-m", cortexm3, "7EM", FL_CO_PROC | FL_FOR_ARCH7EM, NULL}, + {"armv7e-m", cortexm4, "7EM", FL_CO_PROC | FL_FOR_ARCH7EM, 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}, {"iwmmxt2", iwmmxt2, "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 +/* These are populated as commandline arguments are processed, or NULL + if not specified. */ +static const struct processors *arm_selected_arch; +static const struct processors *arm_selected_cpu; +static const struct processors *arm_selected_tune; /* The name of the preprocessor macro to define for this architecture. */ @@ -1196,6 +1190,24 @@ arm_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); } +/* Lookup NAME in SEL. */ + +static const struct processors * +arm_find_cpu (const char *name, const struct processors *sel, const char *desc) +{ + if (!(name && *name)) + return NULL; + + for (; sel->name != NULL; sel++) + { + if (streq (name, sel->name)) + return sel; + } + + error ("bad value (%s) for %s switch", name, desc); + return NULL; +} + /* Implement TARGET_HANDLE_OPTION. */ static bool @@ -1204,11 +1216,11 @@ arm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) switch (code) { case OPT_march_: - arm_select[1].string = arg; + arm_selected_arch = arm_find_cpu(arg, all_architectures, "-march"); return true; case OPT_mcpu_: - arm_select[0].string = arg; + arm_selected_cpu = arm_find_cpu(arg, all_cores, "-mcpu"); return true; case OPT_mhard_float: @@ -1220,7 +1232,7 @@ arm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) return true; case OPT_mtune_: - arm_select[2].string = arg; + arm_selected_tune = arm_find_cpu(arg, all_cores, "-mtune"); return true; default: @@ -1320,88 +1332,52 @@ void arm_override_options (void) { unsigned i; - enum processor_type target_arch_cpu = arm_none; - enum processor_type selected_cpu = arm_none; - /* Set up the flags based on the cpu/architecture selected by the user. */ - for (i = ARRAY_SIZE (arm_select); i--;) + if (arm_selected_arch) { - 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_CPU) - selected_cpu = (enum processor_type) (sel - ptr->processors); - - 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 (0, "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); - } + if (arm_selected_cpu) + { + /* Check for conflict between mcpu and march. */ + if ((arm_selected_cpu->flags ^ arm_selected_arch->flags) & ~FL_TUNE) + { + warning (0, "switch -mcpu=%s conflicts with -march=%s switch", + arm_selected_cpu->name, arm_selected_arch->name); + /* -march wins for code generation. + -mcpu wins for default tuning. */ + if (!arm_selected_tune) + arm_selected_tune = arm_selected_cpu; + + arm_selected_cpu = arm_selected_arch; + } + else + /* -mcpu wins. */ + arm_selected_arch = NULL; + } + else + /* Pick a CPU based on the architecture. */ + arm_selected_cpu = arm_selected_arch; } - /* 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) + if (!arm_selected_cpu) { const struct processors * sel; unsigned int sought; - selected_cpu = (enum processor_type) TARGET_CPU_DEFAULT; - if (selected_cpu == arm_none) + arm_selected_cpu = &all_cores[TARGET_CPU_DEFAULT]; + if (!arm_selected_cpu->name) { #ifdef SUBTARGET_CPU_DEFAULT /* Use the subtarget default CPU if none was specified by configure. */ - selected_cpu = (enum processor_type) SUBTARGET_CPU_DEFAULT; + arm_selected_cpu = &all_cores[SUBTARGET_CPU_DEFAULT]; #endif /* Default to ARM6. */ - if (selected_cpu == arm_none) - selected_cpu = arm6; + if (arm_selected_cpu->name) + arm_selected_cpu = &all_cores[arm6]; } - sel = &all_cores[selected_cpu]; + sel = arm_selected_cpu; insn_flags = sel->flags; /* Now check to see if the user has specified some command line @@ -1462,20 +1438,21 @@ arm_override_options (void) sel = best_fit; } - insn_flags = sel->flags; + arm_selected_cpu = sel; } - sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch); - arm_default_cpu = (enum processor_type) (sel - all_cores); - if (arm_tune == arm_none) - arm_tune = arm_default_cpu; } - /* The processor for which we should tune should now have been - chosen. */ - gcc_assert (arm_tune != arm_none); + gcc_assert (arm_selected_cpu); + /* The selected cpu may be an architecture, so lookup tuning by core ID. */ + if (!arm_selected_tune) + arm_selected_tune = &all_cores[arm_selected_cpu->core]; - tune_flags = all_cores[(int)arm_tune].flags; - current_tune = all_cores[(int)arm_tune].tune; + sprintf (arm_arch_name, "__ARM_ARCH_%s__", arm_selected_cpu->arch); + insn_flags = arm_selected_cpu->flags; + + arm_tune = arm_selected_tune->core; + tune_flags = arm_selected_tune->flags; + current_tune = arm_selected_tune->tune; if (target_fp16_format_name) { @@ -1858,7 +1835,7 @@ arm_override_options (void) /* Enable -mfix-cortex-m3-ldrd by default for Cortex-M3 cores. */ if (fix_cm3_ldrd == 2) { - if (selected_cpu == cortexm3) + if (arm_selected_cpu->core == cortexm3) fix_cm3_ldrd = 1; else fix_cm3_ldrd = 0; @@ -3854,7 +3831,18 @@ static bool use_vfp_abi (enum arm_pcs pcs_variant, bool is_double) { if (pcs_variant == ARM_PCS_AAPCS_VFP) - return true; + { + static bool seen_thumb1_vfp = false; + + if (TARGET_THUMB1 && !seen_thumb1_vfp) + { + sorry ("Thumb-1 hard-float VFP ABI"); + /* sorry() is not immediately fatal, so only display this once. */ + seen_thumb1_vfp = true; + } + + return true; + } if (pcs_variant != ARM_PCS_AAPCS_LOCAL) return false; @@ -6410,23 +6398,6 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed) return true; case MINUS: - if (TARGET_THUMB2) - { - if (GET_MODE_CLASS (mode) == MODE_FLOAT) - { - if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode)) - *total = COSTS_N_INSNS (1); - else - *total = COSTS_N_INSNS (20); - } - else - *total = COSTS_N_INSNS (ARM_NUM_REGS (mode)); - /* Thumb2 does not have RSB, so all arguments must be - registers (subtracting a constant is canonicalized as - addition of the negated constant). */ - return false; - } - if (mode == DImode) { *total = COSTS_N_INSNS (ARM_NUM_REGS (mode)); @@ -11471,6 +11442,60 @@ note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes) return result; } +/* Convert instructions to their cc-clobbering variant if possible, since + that allows us to use smaller encodings. */ + +static void +thumb2_reorg (void) +{ + basic_block bb; + regset_head live; + + INIT_REG_SET (&live); + + /* We are freeing block_for_insn in the toplev to keep compatibility + with old MDEP_REORGS that are not CFG based. Recompute it now. */ + compute_bb_for_insn (); + df_analyze (); + + FOR_EACH_BB (bb) + { + rtx insn; + COPY_REG_SET (&live, DF_LR_OUT (bb)); + df_simulate_initialize_backwards (bb, &live); + FOR_BB_INSNS_REVERSE (bb, insn) + { + if (NONJUMP_INSN_P (insn) + && !REGNO_REG_SET_P (&live, CC_REGNUM)) + { + rtx pat = PATTERN (insn); + if (GET_CODE (pat) == SET + && low_register_operand (XEXP (pat, 0), SImode) + && thumb_16bit_operator (XEXP (pat, 1), SImode) + && low_register_operand (XEXP (XEXP (pat, 1), 0), SImode) + && low_register_operand (XEXP (XEXP (pat, 1), 1), SImode)) + { + rtx dst = XEXP (pat, 0); + rtx src = XEXP (pat, 1); + rtx op0 = XEXP (src, 0); + if (rtx_equal_p (dst, op0) + || GET_CODE (src) == PLUS || GET_CODE (src) == MINUS) + { + rtx ccreg = gen_rtx_REG (CCmode, CC_REGNUM); + rtx clobber = gen_rtx_CLOBBER (VOIDmode, ccreg); + rtvec vec = gen_rtvec (2, pat, clobber); + PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec); + INSN_CODE (insn) = -1; + } + } + } + if (NONDEBUG_INSN_P (insn)) + df_simulate_one_insn_backwards (bb, insn, &live); + } + } + CLEAR_REG_SET (&live); +} + /* Gcc puts the pool in the wrong place for ARM, since we can only load addresses a limited distance around the pc. We do some special munging to move the constant pool values to the correct @@ -11482,6 +11507,9 @@ arm_reorg (void) HOST_WIDE_INT address = 0; Mfix * fix; + if (TARGET_THUMB2) + thumb2_reorg (); + minipool_fix_head = minipool_fix_tail = NULL; /* The first insn must always be a note, or the code below won't @@ -15064,7 +15092,7 @@ arm_print_condition (FILE *stream) before output. If CODE is 'B' then output a bitwise inverted value of X (a const int). If X is a REG and CODE is `M', output a ldm/stm style multi-reg. */ -void +static void arm_print_operand (FILE *stream, rtx x, int code) { switch (code) @@ -15683,6 +15711,140 @@ arm_print_operand (FILE *stream, rtx x, int code) } } +/* Target hook for printing a memory address. */ +static void +arm_print_operand_address (FILE *stream, rtx x) +{ + if (TARGET_32BIT) + { + int is_minus = GET_CODE (x) == MINUS; + + if (GET_CODE (x) == REG) + asm_fprintf (stream, "[%r, #0]", REGNO (x)); + else if (GET_CODE (x) == PLUS || is_minus) + { + rtx base = XEXP (x, 0); + rtx index = XEXP (x, 1); + HOST_WIDE_INT offset = 0; + if (GET_CODE (base) != REG + || (GET_CODE (index) == REG && REGNO (index) == SP_REGNUM)) + { + /* Ensure that BASE is a register. */ + /* (one of them must be). */ + /* Also ensure the SP is not used as in index register. */ + rtx temp = base; + base = index; + index = temp; + } + switch (GET_CODE (index)) + { + case CONST_INT: + offset = INTVAL (index); + if (is_minus) + offset = -offset; + asm_fprintf (stream, "[%r, #%wd]", + REGNO (base), offset); + break; + + case REG: + asm_fprintf (stream, "[%r, %s%r]", + REGNO (base), is_minus ? "-" : "", + REGNO (index)); + break; + + case MULT: + case ASHIFTRT: + case LSHIFTRT: + case ASHIFT: + case ROTATERT: + { + asm_fprintf (stream, "[%r, %s%r", + REGNO (base), is_minus ? "-" : "", + REGNO (XEXP (index, 0))); + arm_print_operand (stream, index, 'S'); + fputs ("]", stream); + break; + } + + default: + gcc_unreachable (); + } + } + else if (GET_CODE (x) == PRE_INC || GET_CODE (x) == POST_INC + || GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_DEC) + { + extern enum machine_mode output_memory_reference_mode; + + gcc_assert (GET_CODE (XEXP (x, 0)) == REG); + + if (GET_CODE (x) == PRE_DEC || GET_CODE (x) == PRE_INC) + asm_fprintf (stream, "[%r, #%s%d]!", + REGNO (XEXP (x, 0)), + GET_CODE (x) == PRE_DEC ? "-" : "", + GET_MODE_SIZE (output_memory_reference_mode)); + else + asm_fprintf (stream, "[%r], #%s%d", + REGNO (XEXP (x, 0)), + GET_CODE (x) == POST_DEC ? "-" : "", + GET_MODE_SIZE (output_memory_reference_mode)); + } + else if (GET_CODE (x) == PRE_MODIFY) + { + asm_fprintf (stream, "[%r, ", REGNO (XEXP (x, 0))); + if (GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT) + asm_fprintf (stream, "#%wd]!", + INTVAL (XEXP (XEXP (x, 1), 1))); + else + asm_fprintf (stream, "%r]!", + REGNO (XEXP (XEXP (x, 1), 1))); + } + else if (GET_CODE (x) == POST_MODIFY) + { + asm_fprintf (stream, "[%r], ", REGNO (XEXP (x, 0))); + if (GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT) + asm_fprintf (stream, "#%wd", + INTVAL (XEXP (XEXP (x, 1), 1))); + else + asm_fprintf (stream, "%r", + REGNO (XEXP (XEXP (x, 1), 1))); + } + else output_addr_const (stream, x); + } + else + { + if (GET_CODE (x) == REG) + asm_fprintf (stream, "[%r]", REGNO (x)); + else if (GET_CODE (x) == POST_INC) + asm_fprintf (stream, "%r!", REGNO (XEXP (x, 0))); + else if (GET_CODE (x) == PLUS) + { + gcc_assert (GET_CODE (XEXP (x, 0)) == REG); + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + asm_fprintf (stream, "[%r, #%wd]", + REGNO (XEXP (x, 0)), + INTVAL (XEXP (x, 1))); + else + asm_fprintf (stream, "[%r, %r]", + REGNO (XEXP (x, 0)), + REGNO (XEXP (x, 1))); + } + else + output_addr_const (stream, x); + } +} + +/* Target hook for indicating whether a punctuation character for + TARGET_PRINT_OPERAND is valid. */ +static bool +arm_print_operand_punct_valid_p (unsigned char code) +{ + return (code == '@' || code == '|' || code == '.' + || code == '(' || code == ')' || code == '#' + || (TARGET_32BIT && (code == '?')) + || (TARGET_THUMB2 && (code == '!')) + || (TARGET_THUMB && (code == '_'))); +} + /* Target hook for assembling integer objects. The ARM version needs to handle word-sized values specially. */ static bool @@ -19313,7 +19475,7 @@ static struct machine_function * arm_init_machine_status (void) { struct machine_function *machine; - machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function)); + machine = ggc_alloc_cleared_machine_function (); #if ARM_FT_UNKNOWN != 0 machine->func_type = ARM_FT_UNKNOWN; @@ -20167,13 +20329,10 @@ arm_file_start (void) if (TARGET_BPABI) { const char *fpu_name; - if (arm_select[0].string) - asm_fprintf (asm_out_file, "\t.cpu %s\n", arm_select[0].string); - else if (arm_select[1].string) - asm_fprintf (asm_out_file, "\t.arch %s\n", arm_select[1].string); + if (arm_selected_arch) + asm_fprintf (asm_out_file, "\t.arch %s\n", arm_selected_arch->name); else - asm_fprintf (asm_out_file, "\t.cpu %s\n", - all_cores[arm_default_cpu].name); + asm_fprintf (asm_out_file, "\t.cpu %s\n", arm_selected_cpu->name); if (TARGET_SOFT_FLOAT) { diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index cf7089b7bc4..8a2d394725f 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -1498,17 +1498,6 @@ do { \ /* Offset of first parameter from the argument pointer register value. */ #define FIRST_PARM_OFFSET(FNDECL) (TARGET_ARM ? 4 : 0) -/* Value is the number of byte of arguments automatically - popped when returning from a subroutine call. - FUNDECL is the declaration node of the function (as a tree), - FUNTYPE is the data type of the function (as a tree), - or for a library call it is an identifier node for the subroutine name. - SIZE is the number of bytes of arguments passed on the stack. - - On the ARM, the caller does not pop any of its arguments that were passed - on the stack. */ -#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0 - /* Define how to find the value returned by a library function assuming the value has mode MODE. */ #define LIBCALL_VALUE(MODE) \ @@ -2414,17 +2403,6 @@ extern int making_const_table; else if (TARGET_THUMB1) \ thumb1_final_prescan_insn (INSN) -#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ - (CODE == '@' || CODE == '|' || CODE == '.' \ - || CODE == '(' || CODE == ')' || CODE == '#' \ - || (TARGET_32BIT && (CODE == '?')) \ - || (TARGET_THUMB2 && (CODE == '!')) \ - || (TARGET_THUMB && (CODE == '_'))) - -/* Output an operand of an instruction. */ -#define PRINT_OPERAND(STREAM, X, CODE) \ - arm_print_operand (STREAM, X, CODE) - #define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ (HOST_BITS_PER_WIDE_INT <= 32 ? (unsigned HOST_WIDE_INT) (x) \ : ((((unsigned HOST_WIDE_INT)(x)) & (unsigned HOST_WIDE_INT) 0xffffffff) |\ @@ -2433,131 +2411,6 @@ extern int making_const_table; & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ : 0)))) -/* Output the address of an operand. */ -#define ARM_PRINT_OPERAND_ADDRESS(STREAM, X) \ -{ \ - int is_minus = GET_CODE (X) == MINUS; \ - \ - if (GET_CODE (X) == REG) \ - asm_fprintf (STREAM, "[%r, #0]", REGNO (X)); \ - else if (GET_CODE (X) == PLUS || is_minus) \ - { \ - rtx base = XEXP (X, 0); \ - rtx index = XEXP (X, 1); \ - HOST_WIDE_INT offset = 0; \ - if (GET_CODE (base) != REG \ - || (GET_CODE (index) == REG && REGNO (index) == SP_REGNUM)) \ - { \ - /* Ensure that BASE is a register. */ \ - /* (one of them must be). */ \ - /* Also ensure the SP is not used as in index register. */ \ - rtx temp = base; \ - base = index; \ - index = temp; \ - } \ - switch (GET_CODE (index)) \ - { \ - case CONST_INT: \ - offset = INTVAL (index); \ - if (is_minus) \ - offset = -offset; \ - asm_fprintf (STREAM, "[%r, #%wd]", \ - REGNO (base), offset); \ - break; \ - \ - case REG: \ - asm_fprintf (STREAM, "[%r, %s%r]", \ - REGNO (base), is_minus ? "-" : "", \ - REGNO (index)); \ - break; \ - \ - case MULT: \ - case ASHIFTRT: \ - case LSHIFTRT: \ - case ASHIFT: \ - case ROTATERT: \ - { \ - asm_fprintf (STREAM, "[%r, %s%r", \ - REGNO (base), is_minus ? "-" : "", \ - REGNO (XEXP (index, 0))); \ - arm_print_operand (STREAM, index, 'S'); \ - fputs ("]", STREAM); \ - break; \ - } \ - \ - default: \ - gcc_unreachable (); \ - } \ - } \ - else if (GET_CODE (X) == PRE_INC || GET_CODE (X) == POST_INC \ - || GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_DEC) \ - { \ - extern enum machine_mode output_memory_reference_mode; \ - \ - gcc_assert (GET_CODE (XEXP (X, 0)) == REG); \ - \ - if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ - asm_fprintf (STREAM, "[%r, #%s%d]!", \ - REGNO (XEXP (X, 0)), \ - GET_CODE (X) == PRE_DEC ? "-" : "", \ - GET_MODE_SIZE (output_memory_reference_mode)); \ - else \ - asm_fprintf (STREAM, "[%r], #%s%d", \ - REGNO (XEXP (X, 0)), \ - GET_CODE (X) == POST_DEC ? "-" : "", \ - GET_MODE_SIZE (output_memory_reference_mode)); \ - } \ - else if (GET_CODE (X) == PRE_MODIFY) \ - { \ - asm_fprintf (STREAM, "[%r, ", REGNO (XEXP (X, 0))); \ - if (GET_CODE (XEXP (XEXP (X, 1), 1)) == CONST_INT) \ - asm_fprintf (STREAM, "#%wd]!", \ - INTVAL (XEXP (XEXP (X, 1), 1))); \ - else \ - asm_fprintf (STREAM, "%r]!", \ - REGNO (XEXP (XEXP (X, 1), 1))); \ - } \ - else if (GET_CODE (X) == POST_MODIFY) \ - { \ - asm_fprintf (STREAM, "[%r], ", REGNO (XEXP (X, 0))); \ - if (GET_CODE (XEXP (XEXP (X, 1), 1)) == CONST_INT) \ - asm_fprintf (STREAM, "#%wd", \ - INTVAL (XEXP (XEXP (X, 1), 1))); \ - else \ - asm_fprintf (STREAM, "%r", \ - REGNO (XEXP (XEXP (X, 1), 1))); \ - } \ - else output_addr_const (STREAM, X); \ -} - -#define THUMB_PRINT_OPERAND_ADDRESS(STREAM, X) \ -{ \ - if (GET_CODE (X) == REG) \ - asm_fprintf (STREAM, "[%r]", REGNO (X)); \ - else if (GET_CODE (X) == POST_INC) \ - asm_fprintf (STREAM, "%r!", REGNO (XEXP (X, 0))); \ - else if (GET_CODE (X) == PLUS) \ - { \ - gcc_assert (GET_CODE (XEXP (X, 0)) == REG); \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - asm_fprintf (STREAM, "[%r, #%wd]", \ - REGNO (XEXP (X, 0)), \ - INTVAL (XEXP (X, 1))); \ - else \ - asm_fprintf (STREAM, "[%r, %r]", \ - REGNO (XEXP (X, 0)), \ - REGNO (XEXP (X, 1))); \ - } \ - else \ - output_addr_const (STREAM, X); \ -} - -#define PRINT_OPERAND_ADDRESS(STREAM, X) \ - if (TARGET_32BIT) \ - ARM_PRINT_OPERAND_ADDRESS (STREAM, X) \ - else \ - THUMB_PRINT_OPERAND_ADDRESS (STREAM, X) - #define OUTPUT_ADDR_CONST_EXTRA(file, x, fail) \ if (arm_output_addr_const_extra (file, x) == FALSE) \ goto fail diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 628bd62ae62..725d505ab5c 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -737,14 +737,14 @@ [(set (reg:CC CC_REGNUM) (compare:CC (match_operand:SI 1 "s_register_operand" "r,r") - (match_operand:SI 2 "arm_addimm_operand" "I,L"))) + (match_operand:SI 2 "arm_addimm_operand" "L,I"))) (set (match_operand:SI 0 "s_register_operand" "=r,r") (plus:SI (match_dup 1) - (match_operand:SI 3 "arm_addimm_operand" "L,I")))] + (match_operand:SI 3 "arm_addimm_operand" "I,L")))] "TARGET_32BIT && INTVAL (operands[2]) == -INTVAL (operands[3])" "@ - sub%.\\t%0, %1, %2 - add%.\\t%0, %1, #%n2" + add%.\\t%0, %1, %3 + sub%.\\t%0, %1, #%n3" [(set_attr "conds" "set")] ) @@ -1422,7 +1422,15 @@ (set_attr "predicable" "yes")] ) -;; Unnamed template to match long long multiply-accumulate (smlal) +(define_expand "maddsidi4" + [(set (match_operand:DI 0 "s_register_operand" "") + (plus:DI + (mult:DI + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "")) + (sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))) + (match_operand:DI 3 "s_register_operand" "")))] + "TARGET_32BIT && arm_arch3m" + "") (define_insn "*mulsidi3adddi" [(set (match_operand:DI 0 "s_register_operand" "=&r") @@ -1518,7 +1526,15 @@ (set_attr "predicable" "yes")] ) -;; Unnamed template to match long long unsigned multiply-accumulate (umlal) +(define_expand "umaddsidi4" + [(set (match_operand:DI 0 "s_register_operand" "") + (plus:DI + (mult:DI + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "")) + (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))) + (match_operand:DI 3 "s_register_operand" "")))] + "TARGET_32BIT && arm_arch3m" + "") (define_insn "*umulsidi3adddi" [(set (match_operand:DI 0 "s_register_operand" "=&r") @@ -1686,29 +1702,29 @@ (set_attr "predicable" "yes")] ) -(define_insn "*mulhisi3addsi" +(define_insn "maddhisi4" [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI (match_operand:SI 1 "s_register_operand" "r") + (plus:SI (match_operand:SI 3 "s_register_operand" "r") (mult:SI (sign_extend:SI - (match_operand:HI 2 "s_register_operand" "%r")) + (match_operand:HI 1 "s_register_operand" "%r")) (sign_extend:SI - (match_operand:HI 3 "s_register_operand" "r")))))] + (match_operand:HI 2 "s_register_operand" "r")))))] "TARGET_DSP_MULTIPLY" - "smlabb%?\\t%0, %2, %3, %1" + "smlabb%?\\t%0, %1, %2, %3" [(set_attr "insn" "smlaxy") (set_attr "predicable" "yes")] ) -(define_insn "*mulhidi3adddi" +(define_insn "*maddhidi4" [(set (match_operand:DI 0 "s_register_operand" "=r") (plus:DI - (match_operand:DI 1 "s_register_operand" "0") + (match_operand:DI 3 "s_register_operand" "0") (mult:DI (sign_extend:DI - (match_operand:HI 2 "s_register_operand" "%r")) + (match_operand:HI 1 "s_register_operand" "%r")) (sign_extend:DI - (match_operand:HI 3 "s_register_operand" "r")))))] + (match_operand:HI 2 "s_register_operand" "r")))))] "TARGET_DSP_MULTIPLY" - "smlalbb%?\\t%Q0, %R0, %2, %3" + "smlalbb%?\\t%Q0, %R0, %1, %2" [(set_attr "insn" "smlalxy") (set_attr "predicable" "yes")]) diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md index 575d0ac4e9a..6d6c77d4b66 100644 --- a/gcc/config/arm/constraints.md +++ b/gcc/config/arm/constraints.md @@ -31,7 +31,7 @@ ;; The following multi-letter normal constraints have been used: ;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy ;; in Thumb-1 state: Pa, Pb -;; in Thumb-2 state: Ps, Pt, Pu, Pv +;; in Thumb-2 state: Ps, Pt, Pu, Pv, Pw, Px ;; The following memory constraints have been used: ;; in ARM/Thumb-2 state: Q, Ut, Uv, Uy, Un, Um, Us @@ -168,6 +168,16 @@ (and (match_code "const_int") (match_test "TARGET_THUMB2 && ival >= -255 && ival <= 0"))) +(define_constraint "Pw" + "@internal In Thumb-2 state a constant in the range -255 to -1" + (and (match_code "const_int") + (match_test "TARGET_THUMB2 && ival >= -255 && ival <= -1"))) + +(define_constraint "Px" + "@internal In Thumb-2 state a constant in the range -7 to -1" + (and (match_code "const_int") + (match_test "TARGET_THUMB2 && ival >= -7 && ival <= -1"))) + (define_constraint "G" "In ARM/Thumb-2 state a valid FPA immediate constant." (and (match_code "const_double") diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md index fa325b171e3..398518329e2 100644 --- a/gcc/config/arm/thumb2.md +++ b/gcc/config/arm/thumb2.md @@ -319,8 +319,8 @@ " [(set_attr "length" "8,12,16,8,8") (set_attr "type" "*,*,*,load2,store2") - (set_attr "pool_range" "1020") - (set_attr "neg_pool_range" "0")] + (set_attr "pool_range" "*,*,*,1020,*") + (set_attr "neg_pool_range" "*,*,*,0,*")] ) (define_insn "*thumb2_cmpsi_shiftsi" @@ -1082,29 +1082,6 @@ }" ) -;; Peepholes and insns for 16-bit flag clobbering instructions. -;; The conditional forms of these instructions do not clobber CC. -;; However by the time peepholes are run it is probably too late to do -;; anything useful with this information. -(define_peephole2 - [(set (match_operand:SI 0 "low_register_operand" "") - (match_operator:SI 3 "thumb_16bit_operator" - [(match_operand:SI 1 "low_register_operand" "") - (match_operand:SI 2 "low_register_operand" "")]))] - "TARGET_THUMB2 - && (rtx_equal_p(operands[0], operands[1]) - || GET_CODE(operands[3]) == PLUS - || GET_CODE(operands[3]) == MINUS) - && peep2_regno_dead_p(0, CC_REGNUM)" - [(parallel - [(set (match_dup 0) - (match_op_dup 3 - [(match_dup 1) - (match_dup 2)])) - (clobber (reg:CC CC_REGNUM))])] - "" -) - (define_insn "*thumb2_alusi3_short" [(set (match_operand:SI 0 "s_register_operand" "=l") (match_operator:SI 3 "thumb_16bit_operator" @@ -1254,6 +1231,32 @@ (set_attr "length" "2")] ) +(define_peephole2 + [(set (match_operand:CC 0 "cc_register" "") + (compare:CC (match_operand:SI 1 "low_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "TARGET_THUMB2 + && peep2_reg_dead_p (1, operands[1]) + && satisfies_constraint_Pw (operands[2])" + [(parallel + [(set (match_dup 0) (compare:CC (match_dup 1) (match_dup 2))) + (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 3)))])] + "operands[3] = GEN_INT (- INTVAL (operands[2]));" +) + +(define_peephole2 + [(match_scratch:SI 3 "l") + (set (match_operand:CC 0 "cc_register" "") + (compare:CC (match_operand:SI 1 "low_register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "TARGET_THUMB2 + && satisfies_constraint_Px (operands[2])" + [(parallel + [(set (match_dup 0) (compare:CC (match_dup 1) (match_dup 2))) + (set (match_dup 3) (plus:SI (match_dup 1) (match_dup 4)))])] + "operands[4] = GEN_INT (- INTVAL (operands[2]));" +) + (define_insn "*thumb2_addsi3_compare0" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV @@ -1506,88 +1509,31 @@ (set_attr "predicable" "yes")] ) -(define_insn "*thumb2_tlobits_cbranch" - [(set (pc) - (if_then_else - (match_operator 0 "equality_operator" - [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l,h,h") - (match_operand:SI 2 "const_int_operand" "i,Pu,i") - (const_int 0)) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (match_scratch:SI 4 "=l,X,r")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_THUMB2" - "* - { - if (which_alternative == 0) - { - rtx op[3]; - op[0] = operands[4]; - op[1] = operands[1]; - op[2] = GEN_INT (32 - INTVAL (operands[2])); - - output_asm_insn (\"lsls\\t%0, %1, %2\", op); - switch (get_attr_length (insn)) - { - case 4: return \"b%d0\\t%l3\"; - case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; - } - } - else - { - rtx op[3]; - - if (which_alternative == 1) - { - op[0] = operands[1]; - op[1] = GEN_INT ((1 << INTVAL (operands[2])) - 1); - output_asm_insn (\"tst\\t%0, %1\", op); - } - else - { - op[0] = operands[4]; - op[1] = operands[1]; - op[2] = GEN_INT (32 - INTVAL (operands[2])); - output_asm_insn (\"lsls\\t%0, %1, %2\", op); - } +(define_peephole2 + [(set (match_operand:CC_NOOV 0 "cc_register" "") + (compare:CC_NOOV (zero_extract:SI + (match_operand:SI 1 "low_register_operand" "") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "")) + (const_int 0))) + (match_scratch:SI 3 "l") + (set (pc) + (if_then_else (match_operator:CC_NOOV 4 "equality_operator" + [(match_dup 0) (const_int 0)]) + (match_operand 5 "" "") + (match_operand 6 "" "")))] + "TARGET_THUMB2 + && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32)" + [(parallel [(set (match_dup 0) + (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (clobber (match_dup 3))]) + (set (pc) + (if_then_else (match_op_dup 4 [(match_dup 0) (const_int 0)]) + (match_dup 5) (match_dup 6)))] + " + operands[2] = GEN_INT (31 - INTVAL (operands[2])); + operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]) == NE ? LT : GE, + VOIDmode, operands[0], const0_rtx); + ") - switch (get_attr_length (insn)) - { - case 6: return \"b%d0\\t%l3\"; - case 8: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; - } - } - }" - [(set (attr "far_jump") - (if_then_else - (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) - (le (minus (match_dup 3) (pc)) (const_int 2048))) - (const_string "no") - (const_string "yes"))) - (set (attr "length") - (if_then_else - (eq (symbol_ref ("which_alternative")) - (const_int 0)) - (if_then_else - (and (ge (minus (match_dup 3) (pc)) (const_int -250)) - (le (minus (match_dup 3) (pc)) (const_int 256))) - (const_int 4) - (if_then_else - (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) - (le (minus (match_dup 3) (pc)) (const_int 2048))) - (const_int 6) - (const_int 8))) - (if_then_else - (and (ge (minus (match_dup 3) (pc)) (const_int -250)) - (le (minus (match_dup 3) (pc)) (const_int 256))) - (const_int 6) - (if_then_else - (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) - (le (minus (match_dup 3) (pc)) (const_int 2048))) - (const_int 8) - (const_int 10)))))] -) |