possible. */
static int max_insns_skipped = 5;
+extern FILE * asm_out_file;
/* Some function declarations. */
-extern FILE *asm_out_file;
static HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT));
static char *output_multi_immediate PROTO ((rtx *, char *, char *, int,
rtx arm_compare_op0, arm_compare_op1;
int arm_compare_fp;
-/* What type of cpu are we compiling for? */
-enum processor_type arm_cpu;
-
/* What type of floating point are we tuning for? */
enum floating_point_type arm_fpu;
enum prog_mode_type arm_prgmode;
/* Set by the -mfp=... option */
-char *target_fp_name = NULL;
+char * target_fp_name = NULL;
/* Used to parse -mstructure_size_boundary command line option. */
char * structure_size_string = NULL;
/* Nonzero if this chip supports the ARM Architecture 4 extensions */
int arm_arch4 = 0;
-/* Set to the features we should tune the code for (multiply speed etc). */
-int tune_flags = 0;
+/* Nonzero if this chip can benefit from laod scheduling. */
+int arm_ld_sched = 0;
+
+/* Nonzero if this chip is a StrongARM. */
+int arm_is_strong = 0;
+
+/* Nonzero if this chip is a an ARM6 or an ARM7. */
+int arm_is_6_or_7 = 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
int arm_target_label;
/* The condition codes of the ARM, and the inverse function. */
-char *arm_condition_codes[] =
+char * arm_condition_codes[] =
{
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
static enum arm_cond_code get_arm_condition_code ();
+#define streq(string1, string2) (strcmp (string1, string2) == 0)
\f
/* Initialization code */
-struct arm_cpu_select arm_select[4] =
-{
- /* switch name, tune arch */
- { (char *)0, "--with-cpu=", 1, 1 },
- { (char *)0, "-mcpu=", 1, 1 },
- { (char *)0, "-march=", 0, 1 },
- { (char *)0, "-mtune=", 1, 0 },
-};
-
#define FL_CO_PROC 0x01 /* Has external co-processor bus */
#define FL_FAST_MULT 0x02 /* Fast multiply */
#define FL_MODE26 0x04 /* 26-bit mode support */
#define FL_MODE32 0x08 /* 32-bit mode support */
#define FL_ARCH4 0x10 /* Architecture rel 4 */
#define FL_THUMB 0x20 /* Thumb aware */
+#define FL_LDSCHED 0x40 /* Load scheduling necessary */
+#define FL_STRONG 0x80 /* StrongARM */
struct processors
{
- char *name;
- enum processor_type type;
+ char * name;
unsigned int flags;
};
/* Not all of these give usefully different compilation alternatives,
but there is no simple way of generalizing them. */
-static struct processors all_procs[] =
+static struct processors all_cores[] =
{
- {"arm2", PROCESSOR_ARM2, FL_CO_PROC | FL_MODE26},
- {"arm250", PROCESSOR_ARM2, FL_CO_PROC | FL_MODE26},
- {"arm3", PROCESSOR_ARM2, FL_CO_PROC | FL_MODE26},
- {"arm6", PROCESSOR_ARM6, FL_CO_PROC | FL_MODE32 | FL_MODE26},
- {"arm600", PROCESSOR_ARM6, FL_CO_PROC | FL_MODE32 | FL_MODE26},
- {"arm610", PROCESSOR_ARM6, FL_MODE32 | FL_MODE26},
- {"arm7", PROCESSOR_ARM7, FL_CO_PROC | FL_MODE32 | FL_MODE26},
- /* arm7m doesn't exist on its own, only in conjunction with D, (and I), but
- those don't alter the code, so it is sometimes known as the arm7m */
- {"arm7m", PROCESSOR_ARM7, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_MODE26)},
- {"arm7dm", PROCESSOR_ARM7, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_MODE26)},
- {"arm7dmi", PROCESSOR_ARM7, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_MODE26)},
- {"arm700", PROCESSOR_ARM7, FL_CO_PROC | FL_MODE32 | FL_MODE26},
- {"arm710", PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
- {"arm7100", PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
- {"arm7500", PROCESSOR_ARM7, FL_MODE32 | FL_MODE26},
- /* Doesn't really have an external co-proc, but does have embedded fpu */
- {"arm7500fe", PROCESSOR_ARM7, FL_CO_PROC | FL_MODE32 | FL_MODE26},
- {"arm7tdmi", PROCESSOR_ARM7, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_ARCH4 | FL_THUMB)},
- {"arm8", PROCESSOR_ARM8, (FL_FAST_MULT | FL_MODE32 | FL_MODE26
- | FL_ARCH4)},
- {"arm810", PROCESSOR_ARM8, (FL_FAST_MULT | FL_MODE32 | FL_MODE26
- | FL_ARCH4)},
- /* The next two are the same, but arm9 only exists in the thumb variant */
- {"arm9", PROCESSOR_ARM9, (FL_FAST_MULT | FL_MODE32 | FL_ARCH4
- | FL_THUMB)},
- {"arm9tdmi", PROCESSOR_ARM9, (FL_FAST_MULT | FL_MODE32 | FL_ARCH4
- | FL_THUMB)},
- {"strongarm", PROCESSOR_STARM, (FL_FAST_MULT | FL_MODE32 | FL_MODE26
- | FL_ARCH4)},
- {"strongarm110", PROCESSOR_STARM, (FL_FAST_MULT | FL_MODE32 | FL_MODE26
- | FL_ARCH4)},
- {"armv2", PROCESSOR_NONE, FL_CO_PROC | FL_MODE26},
- {"armv2a", PROCESSOR_NONE, FL_CO_PROC | FL_MODE26},
- {"armv3", PROCESSOR_NONE, FL_CO_PROC | FL_MODE32 | FL_MODE26},
- {"armv3m", PROCESSOR_NONE, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_MODE26)},
- {"armv4", PROCESSOR_NONE, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_MODE26 | FL_ARCH4)},
+ /* 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", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* arm7m doesn't exist on its own, */
+ {"arm7d", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* but only with D, (and I), */
+ {"arm7dm", FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT }, /* but those don't alter the code, */
+ {"arm7di", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* so arm7m is sometimes used. */
+ {"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 },
+ {"arm710c", FL_MODE26 | FL_MODE32 },
+ {"arm7100", FL_MODE26 | FL_MODE32 },
+ {"arm7500", FL_MODE26 | FL_MODE32 },
+ {"arm7500fe", FL_CO_PROC | FL_MODE26 | FL_MODE32 }, /* Doesn't really have an external co-proc, but does have embedded fpu. */
+ {"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 },
+ {"arm9tdmi", FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | 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 },
+
+ {NULL, 0}
+};
+
+static 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", PROCESSOR_NONE, (FL_CO_PROC | FL_FAST_MULT | FL_MODE32
- | FL_ARCH4)},
- {NULL, 0, 0}
+ {"armv4t", FL_CO_PROC | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
+ {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 }
};
/* Fix up any incompatible options that the user has specified.
void
arm_override_options ()
{
- int arm_thumb_aware = 0;
- int flags = 0;
+ unsigned int flags = 0;
unsigned i;
struct arm_cpu_select * ptr;
- static struct cpu_default
- {
- int cpu;
- char * name;
- }
- cpu_defaults[] =
- {
- { TARGET_CPU_arm2, "arm2" },
- { TARGET_CPU_arm6, "arm6" },
- { TARGET_CPU_arm610, "arm610" },
- { TARGET_CPU_arm7dm, "arm7dm" },
- { TARGET_CPU_arm7500fe, "arm7500fe" },
- { TARGET_CPU_arm7tdmi, "arm7tdmi" },
- { TARGET_CPU_arm8, "arm8" },
- { TARGET_CPU_arm810, "arm810" },
- { TARGET_CPU_strongarm, "strongarm" },
- { 0, 0 }
- };
- struct cpu_default *def;
-
- /* Set the default. */
- for (def = &cpu_defaults[0]; def->name; ++def)
- if (def->cpu == TARGET_CPU_DEFAULT)
- break;
- if (! def->name)
- abort ();
-
- arm_select[0].string = def->name;
-
- for (i = 0; i < sizeof (arm_select) / sizeof (arm_select[0]); i++)
+
+ /* Set up the flags based on the cpu/architecture selected by the user. */
+ for (i = sizeof (arm_select) / sizeof (arm_select[0]); i--;)
{
- ptr = &arm_select[i];
- if (ptr->string != (char *)0 && ptr->string[0] != '\0')
+ struct arm_cpu_select * ptr = arm_select + i;
+
+ if (ptr->string != NULL && ptr->string[0] != '\0')
{
- struct processors *sel;
+ struct processors * sel;
- for (sel = all_procs; sel->name != NULL; sel++)
- if (! strcmp (ptr->string, sel->name))
+ for (sel = ptr->processors; sel->name != NULL; sel ++)
+ if (streq (ptr->string, sel->name))
{
- /* -march= is the only flag that can take an architecture
- type, so if we match when the tune bit is set, the
- option was invalid. */
- if (ptr->set_tune_p)
+ if (flags != 0)
{
- if (sel->type == PROCESSOR_NONE)
- continue; /* Its an architecture, not a cpu */
-
- arm_cpu = sel->type;
- tune_flags = sel->flags;
+ /* We scan the arm_select array in the order:
+ tune -> arch -> cpu
+ So if we have been asked to tune for, say, an ARM8,
+ but we are told that the cpu is only an ARM6, then
+ we have problems. We detect this by seeing if the
+ flags bits accumulated so far can be supported by the
+ cpu/architecture type now being parsed. If they can,
+ then OR in any new bits. If they cannot then report
+ an error. */
+ if ((flags & sel->flags) != flags)
+ error ("switch %s%s overridden by another switch",
+ ptr->string, sel->name );
}
- if (ptr->set_arch_p)
- flags = sel->flags;
-
+ flags = sel->flags;
+
break;
}
}
}
+ /* If the user did not specify a processor, choose one for them. */
+ if (flags == 0)
+ {
+ struct processors * sel;
+ int sought = 0;
+
+ if (TARGET_THUMB_INTERWORK)
+ {
+ sought |= FL_THUMB;
+
+ /* Force apcs-32 to be used for Thumb targets. */
+ target_flags |= ARM_FLAG_APCS_32;
+ }
+
+ if (TARGET_APCS_32)
+ sought |= FL_MODE32;
+ else
+ sought |= FL_MODE26;
+
+ if (sought != 0)
+ {
+ for (sel = all_cores; sel->name != NULL; sel++)
+ if ((sel->flags & sought) == sought)
+ {
+ flags = sel->flags;
+ break;
+ }
+
+ if (sel->name == NULL)
+ fatal ("Unable to select a cpu that matches command line specification");
+ }
+ else
+ {
+ /* The user did not specify any command line switches that require
+ a certain kind of CPU. Use TARGET_CPU_DEFAULT instead. */
+
+ static struct cpu_default
+ {
+ int cpu;
+ char * name;
+ }
+ cpu_defaults[] =
+ {
+ { TARGET_CPU_arm2, "arm2" },
+ { TARGET_CPU_arm6, "arm6" },
+ { TARGET_CPU_arm610, "arm610" },
+ { TARGET_CPU_arm7m, "arm7m" },
+ { TARGET_CPU_arm7500fe, "arm7500fe" },
+ { TARGET_CPU_arm7tdmi, "arm7tdmi" },
+ { TARGET_CPU_arm8, "arm8" },
+ { TARGET_CPU_arm810, "arm810" },
+ { TARGET_CPU_arm9, "arm9" },
+ { TARGET_CPU_strongarm, "strongarm" },
+ { TARGET_CPU_generic, "arm" },
+ { 0, 0 }
+ };
+ struct cpu_default * def;
+
+ /* Find the default. */
+ for (def = cpu_defaults; def->name; def ++)
+ if (def->cpu == TARGET_CPU_DEFAULT)
+ break;
+
+ if (def->name == NULL)
+ abort ();
+
+ /* Find the default CPU's flags. */
+ for (sel = all_cores; sel->name != NULL; sel ++)
+ if (streq (def->name, sel->name))
+ break;
+
+ if (sel->name == NULL)
+ abort ();
+
+ flags = sel->flags;
+ }
+ }
+
+ /* Cope with some redundant flags. */
+ if (TARGET_6)
+ {
+ warning ("Option '-m6' deprecated. Use: '-mapcs-32' or -mcpu=<proc>");
+ target_flags |= ARM_FLAG_APCS_32;
+ }
+
+ if (TARGET_3)
+ {
+ warning ("Option '-m3' deprecated. Use: '-mapcs-26' or -mcpu=<proc>");
+ target_flags &= ~ARM_FLAG_APCS_32;
+ }
+
+ /* Make sure that the processor choice does not conflict with any of the
+ other command line choices. */
+ if (TARGET_APCS_32 && !(flags & FL_MODE32))
+ {
+ warning ("target CPU does not support APCS-32" );
+ target_flags &= ~ ARM_FLAG_APCS_32;
+ }
+ else if (! TARGET_APCS_32 && !(flags & FL_MODE26))
+ {
+ warning ("target CPU does not support APCS-26" );
+ target_flags |= ARM_FLAG_APCS_32;
+ }
+
+ if (TARGET_THUMB_INTERWORK && !(flags & FL_THUMB))
+ {
+ warning ("target CPU does not support interworking" );
+ target_flags &= ~ARM_FLAG_THUMB;
+ }
+
+ /* If interworking is enabled then APCS-32 must be selected as well. */
+ if (TARGET_THUMB_INTERWORK)
+ {
+ if (! TARGET_APCS_32)
+ warning ("interworking forces APCS-32 to be used" );
+ target_flags |= ARM_FLAG_APCS_32;
+ }
+
+ if (TARGET_APCS_STACK && ! TARGET_APCS)
+ {
+ warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
+ target_flags |= ARM_FLAG_APCS_FRAME;
+ }
+
if (write_symbols != NO_DEBUG && flag_omit_frame_pointer)
warning ("-g with -fomit-frame-pointer may not give sensible debugging");
if (TARGET_POKE_FUNCTION_NAME)
target_flags |= ARM_FLAG_APCS_FRAME;
- if (TARGET_6)
- warning ("Option '-m6' deprecated. Use: '-mapcs-32' or -mcpu=<proc>");
-
- if (TARGET_3)
- warning ("Option '-m3' deprecated. Use: '-mapcs-26' or -mcpu=<proc>");
-
if (TARGET_APCS_REENT && flag_pic)
fatal ("-fpic and -mapcs-reent are incompatible");
if (TARGET_APCS_REENT)
- warning ("APCS reentrant code not supported.");
+ warning ("APCS reentrant code not supported. Ignored");
/* If stack checking is disabled, we can use r10 as the PIC register,
which keeps r9 available. */
if (TARGET_APCS_FLOAT)
warning ("Passing floating point arguments in fp regs not yet supported");
- if (TARGET_APCS_STACK && ! TARGET_APCS)
- {
- warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
- target_flags |= ARM_FLAG_APCS_FRAME;
- }
-
- /* Default is to tune for an FPA */
- arm_fpu = FP_HARD;
-
+ /* Initialise booleans used elsewhere in this file, and in arm.md */
+ arm_fast_multiply = (flags & FL_FAST_MULT) != 0;
+ arm_arch4 = (flags & FL_ARCH4) != 0;
+ arm_ld_sched = (flags & FL_LDSCHED) != 0;
+ arm_is_strong = (flags & FL_STRONG);
+
+ /* The arm.md file needs to know if theprocessor is an ARM6 or an ARM7 */
+ arm_is_6_or_7 = ((flags & (FL_MODE26 | FL_MODE32)) && !(flags & FL_ARCH4));
+
/* Default value for floating point code... if no co-processor
bus, then schedule for emulated floating point. Otherwise,
assume the user has an FPA.
Note: this does not prevent use of floating point instructions,
-msoft-float does that. */
- if ((tune_flags & FL_CO_PROC) == 0)
+ if ((flags & FL_CO_PROC) == 0)
arm_fpu = FP_SOFT3;
-
- arm_fast_multiply = (flags & FL_FAST_MULT) != 0;
- arm_arch4 = (flags & FL_ARCH4) != 0;
- arm_thumb_aware = (flags & FL_THUMB) != 0;
-
+ else
+ arm_fpu = FP_HARD;
+
if (target_fp_name)
{
- if (strcmp (target_fp_name, "2") == 0)
+ if (streq (target_fp_name, "2"))
arm_fpu_arch = FP_SOFT2;
- else if (strcmp (target_fp_name, "3") == 0)
- arm_fpu_arch = FP_HARD;
+ else if (streq (target_fp_name, "3"))
+ arm_fpu_arch = FP_SOFT3;
else
- fatal ("Invalid floating point emulation option: -mfpe=%s",
+ fatal ("Invalid floating point emulation option: -mfpe-%s",
target_fp_name);
}
else
arm_fpu_arch = FP_DEFAULT;
+
+ if (TARGET_FPE && arm_fpu != FP_HARD)
+ arm_fpu = FP_SOFT2;
- if (TARGET_THUMB_INTERWORK && ! arm_thumb_aware)
- {
- warning ("This processor variant does not support Thumb interworking");
- target_flags &= ~ARM_FLAG_THUMB;
- }
-
- if (TARGET_FPE && arm_fpu == FP_HARD)
- arm_fpu = FP_SOFT3;
-
- /* If optimizing for space, don't synthesize constants */
- if (optimize_size)
- arm_constant_limit = 1;
-
- /* Override a few things based on the tuning pararmeters. */
- switch (arm_cpu)
- {
- case PROCESSOR_ARM2:
- case PROCESSOR_ARM3:
- /* For arm2/3 there is no need to do any scheduling if there is
- only a floating point emulator, or we are doing software
- floating-point. */
- if (TARGET_SOFT_FLOAT || arm_fpu != FP_HARD)
- flag_schedule_insns = flag_schedule_insns_after_reload = 0;
- break;
-
- case PROCESSOR_ARM6:
- case PROCESSOR_ARM7:
- break;
-
- case PROCESSOR_ARM8:
- case PROCESSOR_ARM9:
- /* For these processors, it never costs more than 2 cycles to load a
- constant, and the load scheduler may well reduce that to 1. */
- arm_constant_limit = 1;
- break;
-
- case PROCESSOR_STARM:
- /* Same as above */
- arm_constant_limit = 1;
- /* StrongARM has early execution of branches, a sequence that is worth
- skipping is shorter. */
- max_insns_skipped = 3;
- break;
-
- default:
- fatal ("Unknown cpu type selected");
- break;
- }
-
- /* If optimizing for size, bump the number of instructions that we
- are prepared to conditionally execute (even on a StrongARM). */
- if (optimize_size)
- max_insns_skipped = 6;
+ /* For arm2/3 there is no need to do any scheduling if there is only
+ a floating point emulator, or we are doing software floating-point. */
+ if ((TARGET_SOFT_FLOAT || arm_fpu != FP_HARD) && (flags & FL_MODE32) == 0)
+ flag_schedule_insns = flag_schedule_insns_after_reload = 0;
arm_prog_mode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
else
warning ("Structure size boundary can only be set to 8 or 32");
}
+
+ /* If optimizing for space, don't synthesize constants.
+ For processors with load scheduling, it never costs more than 2 cycles
+ to load a constant, and the load scheduler may well reduce that to 1. */
+ if (optimize_size || (flags & FL_LDSCHED))
+ arm_constant_limit = 1;
+
+ /* If optimizing for size, bump the number of instructions that we
+ are prepared to conditionally execute (even on a StrongARM).
+ Otherwise for the StrongARM, which has early execution of branches,
+ a sequence that is worth skipping is shorter. */
+ if (optimize_size)
+ max_insns_skipped = 6;
+ else if (arm_is_strong)
+ max_insns_skipped = 3;
}
\f
/* Return 1 if it is possible to return using a single instruction */
{
int regno;
- if (!reload_completed ||current_function_pretend_args_size
+ if (!reload_completed
+ || current_function_pretend_args_size
|| current_function_anonymous_args
|| ((get_frame_size () + current_function_outgoing_args_size != 0)
- && !(TARGET_APCS || frame_pointer_needed)))
+ && !(TARGET_APCS && frame_pointer_needed)))
return 0;
/* Can't be done if interworking with Thumb, and any registers have been
stacked. Similarly, on StrongARM, conditional returns are expensive
if they aren't taken and registers have been stacked. */
- if (iscond && arm_cpu == PROCESSOR_STARM && frame_pointer_needed)
+ if (iscond && arm_is_strong && frame_pointer_needed)
return 0;
- else if ((iscond && arm_cpu == PROCESSOR_STARM)
- || TARGET_THUMB_INTERWORK)
+ if ((iscond && arm_is_strong)
+ || TARGET_THUMB_INTERWORK)
for (regno = 0; regno < 16; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
return 0;
gen_rtx_NOT (mode,
gen_rtx_ASHIFT (mode,
source,
- shift))));
+ shift))));
emit_insn (gen_rtx_SET (VOIDmode, target,
gen_rtx_NOT (mode,
gen_rtx_LSHIFTRT (mode, sub,
gen_rtx_NOT (mode,
gen_rtx_LSHIFTRT (mode,
source,
- shift))));
+ shift))));
emit_insn (gen_rtx_SET (VOIDmode, target,
gen_rtx_NOT (mode,
gen_rtx_ASHIFT (mode, sub,
- shift))));
+ shift))));
}
return 2;
}
return code;
}
-
-/* Handle aggregates that are not laid out in a BLKmode element.
- This is a sub-element of RETURN_IN_MEMORY. */
+/* Decide whether a type should be returned in memory (true)
+ or in a register (false). This is called by the macro
+ RETURN_IN_MEMORY. */
int
arm_return_in_memory (type)
tree type;
{
- if (TREE_CODE (type) == RECORD_TYPE)
+ if (! AGGREGATE_TYPE_P (type))
+ {
+ /* All simple types are returned in registers. */
+ return 0;
+ }
+ else if (int_size_in_bytes (type) > 4)
+ {
+ /* All structures/unions bigger than one word are returned in memory. */
+ return 1;
+ }
+ else if (TREE_CODE (type) == RECORD_TYPE)
{
tree field;
- /* For a struct, we can return in a register if every element was a
- bit-field. */
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- if (TREE_CODE (field) != FIELD_DECL
- || ! DECL_BIT_FIELD_TYPE (field))
- return 1;
+ /* For a struct the APCS says that we must return in a register if
+ every addressable element has an offset of zero. For practical
+ purposes this means that the structure can have at most one non
+ bit-field element and that this element must be the first one in
+ the structure. */
+
+ /* Find the first field, ignoring non FIELD_DECL things which will
+ have been created by C++. */
+ for (field = TYPE_FIELDS (type);
+ field && TREE_CODE (field) != FIELD_DECL;
+ field = TREE_CHAIN (field))
+ continue;
+
+ if (field == NULL)
+ return 0; /* An empty structure. Allowed by an extension to ANSI C. */
+
+ /* Now check the remaining fields, if any. */
+ for (field = TREE_CHAIN (field);
+ field;
+ field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ if (! DECL_BIT_FIELD_TYPE (field))
+ return 1;
+ }
return 0;
}
/* Unions can be returned in registers if every element is
integral, or can be returned in an integer register. */
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type);
+ field;
+ field = TREE_CHAIN (field))
{
- if (TREE_CODE (field) != FIELD_DECL
- || (AGGREGATE_TYPE_P (TREE_TYPE (field))
- && RETURN_IN_MEMORY (TREE_TYPE (field)))
- || FLOAT_TYPE_P (TREE_TYPE (field)))
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ if (RETURN_IN_MEMORY (TREE_TYPE (field)))
return 1;
}
+
return 0;
}
+
/* XXX Not sure what should be done for other aggregates, so put them in
memory. */
return 1;
gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
-
+
emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx));
emit_jump_insn (gen_pic_add_dot_plus_eight(l1, pic_offset_table_rtx));
emit_label (l1);
int add_cost = const_ok_for_arm (i) ? 4 : 8;
int j;
/* Tune as appropriate */
- int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
+ int booth_unit_size = (arm_fast_multiply ? 8 : 2);
for (j = 0; i && j < 32; j += booth_unit_size)
{
return add_cost;
}
- return (((tune_flags & FL_FAST_MULT) ? 8 : 30)
+ return ((arm_fast_multiply ? 8 : 30)
+ (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
+ (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4));
/* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm if
the offset isn't small enough */
- if (nops == 2
- && (arm_cpu == PROCESSOR_ARM8 || arm_cpu == PROCESSOR_ARM9
- || arm_cpu == PROCESSOR_STARM))
+ if (nops == 2 && arm_ld_sched)
return 0;
/* Can't do it without setting up the offset, only do this if it takes
if (use_return_insn (FALSE) && return_used_this_function)
{
if ((frame_size + current_function_outgoing_args_size) != 0
- && !(frame_pointer_needed || TARGET_APCS))
+ && !(frame_pointer_needed && TARGET_APCS))
abort ();
goto epilogue_done;
}
if (TARGET_THUMB_INTERWORK)
{
if (! lr_save_eliminated)
- print_multi_reg(f, "ldmfd\t%ssp!", live_regs_mask | 0x4000,
- FALSE);
+ live_regs_mask |= 0x4000;
+
+ if (live_regs_mask != 0)
+ print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE);
fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX);
}
gen_rtvec (1, gen_rtx_REG (XFmode,
base_reg++)),
2));
-
for (i = 1; i < count; i++)
XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode,
gen_rtx_REG (XFmode, base_reg++));
}
/* If we are profiling, make sure no instructions are scheduled before
- the call to mcount. */
- if (profile_flag || profile_block_flag)
+ the call to mcount. Similarly if the user has requested no
+ scheduling in the prolog. */
+ if (profile_flag || profile_block_flag || TARGET_NO_SCHED_PRO)
emit_insn (gen_blockage ());
}
if (arm_ccfsm_state == 4)
{
if (insn == arm_target_insn)
- {
- arm_target_insn = NULL;
- arm_ccfsm_state = 0;
- }
+ {
+ arm_target_insn = NULL;
+ arm_ccfsm_state = 0;
+ }
return;
}
-/* Definitions of target machine for GNU compiler, for Acorn RISC Machine.
+/* Definitions of target machine for GNU compiler, for ARM.
Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
and Martin Simmons (@harleqn.co.uk).
#define TARGET_CPU_arm810 0x0020
#define TARGET_CPU_strongarm 0x0040
#define TARGET_CPU_strongarm110 0x0040
+#define TARGET_CPU_strongarm1100 0x0040
#define TARGET_CPU_arm9 0x0080
#define TARGET_CPU_arm9tdmi 0x0080
/* Configure didn't specify */
%{march=arm9tdmi:-D__ARM_ARCH_4T__} \
%{march=strongarm:-D__ARM_ARCH_4__} \
%{march=strongarm110:-D__ARM_ARCH_4__} \
+%{march=strongarm1100:-D__ARM_ARCH_4__} \
%{march=armv2:-D__ARM_ARCH_2__} \
%{march=armv2a:-D__ARM_ARCH_2__} \
%{march=armv3:-D__ARM_ARCH_3__} \
%{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} \
%{mcpu=strongarm:-D__ARM_ARCH_4__} \
%{mcpu=strongarm110:-D__ARM_ARCH_4__} \
+ %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \
%{!mcpu*:%{!m6:%{!m2:%{!m3:%(cpp_cpu_arch_default)}}}}} \
"
extern int target_flags;
/* The floating point instruction architecture, can be 2 or 3 */
-extern char *target_fp_name;
+extern char * target_fp_name;
/* Nonzero if the function prologue (and epilogue) should obey
the ARM Procedure Call Standard. */
big-endian (for backwards compatibility with older versions of GCC). */
#define ARM_FLAG_LITTLE_WORDS (0x2000)
+/* Nonzero if we need to protect the prolog from scheduling */
+#define ARM_FLAG_NO_SCHED_PRO (0x4000)
+
/* Nonzero if a call to abort should be generated if a noreturn
function tries to return. */
#define ARM_FLAG_ABORT_NORETURN (0x8000)
#define TARGET_BIG_END (target_flags & ARM_FLAG_BIG_END)
#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB)
#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS)
+#define TARGET_NO_SCHED_PRO (target_flags & ARM_FLAG_NO_SCHED_PRO)
#define TARGET_ABORT_NORETURN (target_flags & ARM_FLAG_ABORT_NORETURN)
/* SUBTARGET_SWITCHES is used to add flags on a per-config basis.
{"abort-on-noreturn", ARM_FLAG_ABORT_NORETURN, \
"Generate a call to abort if a noreturn function returns"}, \
{"no-abort-on-noreturn", -ARM_FLAG_ABORT_NORETURN, ""}, \
+ {"sched-prolog", -ARM_FLAG_NO_SCHED_PRO, \
+ "Do not move instructions into a function's prologue" }, \
+ {"no-sched-prolog", ARM_FLAG_NO_SCHED_PRO, "" }, \
SUBTARGET_SWITCHES \
{"", TARGET_DEFAULT } \
}
#define TARGET_OPTIONS \
{ \
- {"cpu=", \
- &arm_select[1].string, \
- "Specify the name of the target CPU"}, \
- {"arch=", \
- &arm_select[2].string, \
- "Specify the name of the target architecture"}, \
- {"tune=", \
- &arm_select[3].string, \
- "Order instructions for best performance on this CPU"}, \
- {"fp=", \
- &target_fp_name, \
- "Specify the version of the floating point emulator"}, \
- {"structure-size-boundary=", \
- &structure_size_string, \
- "Specify the minumum bit alignment of structures"} \
+ {"cpu=", & arm_select[0].string, \
+ "Specify the name of the target CPU" }, \
+ {"arch=", & arm_select[1].string, \
+ "Specify the name of the target architecture" }, \
+ {"tune=", & arm_select[2].string, "" }, \
+ {"fpe=", & target_fp_name, "" }, \
+ {"fp=", & target_fp_name, \
+ "Specify the version of the floating point emulator" }, \
+ { "structure-size-boundary=", & structure_size_string, \
+ "Specify the minumum bit alignment of structures" } \
}
-/* arm_select[0] is reserved for the default cpu. */
struct arm_cpu_select
{
- char *string;
- char *name;
- int set_tune_p;
- int set_arch_p;
+ char * string;
+ char * name;
+ struct processors * processors;
};
+/* This is a magic array. If the user specifies a command line switch
+ which matches one of the entries in TARGET_OPTIONS then the corresponding
+ string pointer will be set to the value specified by the user. */
extern struct arm_cpu_select arm_select[];
-#ifndef PROCESSOR_DEFAULT
-#define PROCESSOR_DEFAULT PROCESSOR_ARM2
-#endif
-
-#ifndef TARGET_CPU_DEFAULT
-#define TARGET_CPU_DEFAULT ((char *) 0)
-#endif
-
-/* Which processor we are running on, for instruction scheduling
- purposes. */
-enum processor_type
-{
- PROCESSOR_ARM2,
- PROCESSOR_ARM3,
- PROCESSOR_ARM6,
- PROCESSOR_ARM7,
- PROCESSOR_ARM8,
- PROCESSOR_ARM9,
- PROCESSOR_STARM,
- PROCESSOR_NONE /* NOTE: This must be last, since it doesn't
- appear in the attr_cpu list */
-};
-
-/* Recast the cpu class to be the cpu attribute. */
-#define arm_cpu_attr ((enum attr_cpu)arm_cpu)
-
-extern enum processor_type arm_cpu;
-
enum prog_mode_type
{
prog_mode26,
/* Nonzero if this chip supports the ARM Architecture 4 extensions */
extern int arm_arch4;
+/* Nonzero if this chip can benefit from load scheduling. */
+extern int arm_ld_sched;
+
+/* Nonzero if this chip is a StrongARM. */
+extern int arm_is_strong;
+
+/* Nonzero if this chip is a an ARM6 or an ARM7. */
+extern int arm_is_6_or_7;
+
#ifndef TARGET_DEFAULT
#define TARGET_DEFAULT 0
#endif
r4-r8 S register variable
r9 S (rfp) register variable (real frame pointer)
-
- r10 F S (sl) stack limit (not currently used)
+
+ r10 F S (sl) stack limit (used by -mapcs-stack-check)
r11 F S (fp) argument pointer
r12 (ip) temp workspace
r13 F S (sp) lower end of current stack frame
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0; \
} \
+ else if (! TARGET_APCS_STACK) \
+ { \
+ fixed_regs[10] = 0; \
+ call_used_regs[10] = 0; \
+ } \
}
/* Return number of consecutive hard regs needed starting at reg REGNO
/* How large values are returned */
/* A C expression which can inhibit the returning of certain function values
in registers, based on the type of value. */
-#define RETURN_IN_MEMORY(TYPE) \
- (TYPE_MODE ((TYPE)) == BLKmode || \
- (AGGREGATE_TYPE_P ((TYPE)) && arm_return_in_memory ((TYPE))))
+#define RETURN_IN_MEMORY(TYPE) arm_return_in_memory (TYPE)
/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return
values must be in memory. On the ARM, they need only do so if larger
#define FINALIZE_PIC arm_finalize_pic ()
-/* We can't directly access anything that contains a symbol, nor can
- we indirect via the constant pool */
+/* We can't directly access anything that contains a symbol,
+ nor can we indirect via the constant pool. */
#define LEGITIMATE_PIC_OPERAND_P(X) \
(! symbol_mentioned_p (X) \
&& (! CONSTANT_POOL_ADDRESS_P (X) \
; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option.
(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode")))
-; CPU attribute is used to determine the best instruction mix for performance
-; on the named processor.
-(define_attr "cpu" "arm2,arm3,arm6,arm7,arm8,arm9,st_arm"
- (const (symbol_ref "arm_cpu_attr")))
+(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong")))
; Floating Point Unit. If we only have floating point emulation, then there
; is no point in scheduling the floating point insns. (Well, for best
"normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4"
(const_string "normal"))
-; Load scheduling, set from the cpu characteristic
-(define_attr "ldsched" "no,yes"
- (if_then_else (eq_attr "cpu" "arm8,arm9,st_arm")
- (const_string "yes")
- (const_string "no")))
+; Load scheduling, set from the arm_ld_sched variable
+; initialised by arm_override_options()
+(define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched")))
; condition codes: this one is used by final_prescan_insn to speed up
; conditionalizing instructions. It saves having to scan the rtl to see if
; have one. Later ones, such as StrongARM, have write-back caches, so don't
; suffer blockages enough to warrent modelling this (and it can adversely
; affect the schedule).
-(define_attr "model_wbuf" "no,yes"
- (if_then_else (eq_attr "cpu" "arm6,arm7")
- (const_string "yes")
- (const_string "no")))
+(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7")))
(define_attr "write_conflict" "no,yes"
(if_then_else (eq_attr "type"
(and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7)
(define_function_unit "core" 1 0
- (and (eq_attr "cpu" "!arm8,st_arm") (eq_attr "type" "mult")) 16 16)
+ (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16)
(define_function_unit "core" 1 0
- (and (eq_attr "cpu" "arm8") (eq_attr "type" "mult")) 4 4)
+ (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no"))
+ (eq_attr "type" "mult")) 4 4)
(define_function_unit "core" 1 0
- (and (eq_attr "cpu" "st_arm") (eq_attr "type" "mult")) 3 2)
+ (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes"))
+ (eq_attr "type" "mult")) 3 2)
(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3)
(const_int 0)))
(clobber (match_scratch:QI 3 "=r"))]
"INTVAL (operands[2]) >= 0 && INTVAL (operands[1]) > 0
- && (INTVAL (operands[2]) + INTVAL (operands[1]) <= 8)"
+ && ((INTVAL (operands[2]) + INTVAL (operands[1])) <= 8)"
"*
operands[1] = GEN_INT (((1 << INTVAL (operands[1])) - 1)
<< INTVAL (operands[2]));
emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
emit_insn (gen_iorsi3 (op1, gen_rtx_LSHIFTRT (SImode, operands[0],
- operands[1]),
+ operands[1]),
op0));
emit_insn (gen_rotlsi3 (subtarget, op1, operands[1]));
}
""
"
{
- if (arm_arch4 && GET_CODE (operands[1]) == MEM)
+ if (GET_CODE (operands[1]) == MEM)
{
- emit_insn (gen_rtx_SET (VOIDmode, operands[0],
- gen_rtx_ZERO_EXTEND (SImode, operands[1])));
- DONE;
- }
- if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM)
- {
- emit_insn (gen_movhi_bytes (operands[0], operands[1]));
- DONE;
+ if (TARGET_SHORT_BY_BYTES)
+ {
+ emit_insn (gen_movhi_bytes (operands[0], operands[1]));
+ DONE;
+ }
+ else if (arm_arch4)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operands[0],
+ gen_rtx_ZERO_EXTEND (SImode, operands[1])));
+ DONE;
+ }
}
if (! s_register_operand (operands[1], HImode))
operands[1] = copy_to_mode_reg (HImode, operands[1]);
(const_int 16)))]
""
"
-{
- if (arm_arch4 && GET_CODE (operands[1]) == MEM)
- {
- emit_insn (gen_rtx_SET (VOIDmode, operands[0],
- gen_rtx_SIGN_EXTEND (SImode, operands[1])));
- DONE;
- }
-
- if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM)
+{
+ if (GET_CODE (operands[1]) == MEM)
{
- emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
- DONE;
- }
+ if (TARGET_SHORT_BY_BYTES)
+ {
+ emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
+ DONE;
+ }
+ else if (arm_arch4)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+ DONE;
+ }
+ }
if (! s_register_operand (operands[1], HImode))
operands[1] = copy_to_mode_reg (HImode, operands[1]);
operands[1] = gen_lowpart (SImode, operands[1]);
{
if (arm_arch4 && GET_CODE (operands[1]) == MEM)
{
- emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operands[0],
gen_rtx_SIGN_EXTEND (HImode, operands[1])));
DONE;
}
&& GET_CODE (XEXP (operands[1], 1)) != CONST_INT
&& ! s_register_operand (XEXP (operands[1], 1), VOIDmode))
operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
- XEXP (operands[1], 1),
- XEXP (operands[1], 0));
+ XEXP (operands[1], 1),
+ XEXP (operands[1], 0));
}
")
{
if (arm_arch4 && GET_CODE (operands[1]) == MEM)
{
- emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operands[0],
gen_rtx_SIGN_EXTEND (SImode, operands[1])));
DONE;
}
&& GET_CODE (XEXP (operands[1], 1)) != CONST_INT
&& ! s_register_operand (XEXP (operands[1], 1), VOIDmode))
operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
- XEXP (operands[1], 1),
- XEXP (operands[1], 0));
+ XEXP (operands[1], 1),
+ XEXP (operands[1], 0));
}
")
XEXP (XEXP (operands[0], 0), 1)));
emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (DFmode, operands[2]),
- operands[1]));
+ operands[1]));
if (code == POST_DEC)
emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8)));
extern int arm_ccfsm_state;
if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
- {
- arm_ccfsm_state += 2;
- return \"\";
- }
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
return \"b%?\\t%l0\";
}")
}
")
-
;; The next two patterns occur when an AND operation is followed by a
;; scc insn sequence