+2017-06-21 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * config/tc-arm.c (dyn_mcpu_ext_opt): New static variable.
+ (dyn_march_ext_opt): Likewise.
+ (md_begin): Copy extension feature bits alongside architecture ones.
+ Merge extensions feature bits in selected_cpu and cpu_variant if there
+ is some.
+ (arm_parse_extension): Pass architecture and extension feature bits in
+ separate parameters, with architecture bits being read only. Update
+ **opt_p directly rather than *ext_set and initialize it if needed.
+ (arm_parse_cpu): Stop merging architecture and extension feature bits
+ and instead use mcpu_cpu_opt and dyn_mcpu_ext_opt to memorize them
+ respectively. Adapt to change in parameters of arm_parse_extension.
+ (arm_parse_arch): Adapt to change in parameters of arm_parse_extension.
+ (aeabi_set_attribute_string): Make function static.
+ (arm_md_post_relax): New function.
+ (s_arm_cpu): Stop merging architecture and extension feature bits and
+ instead use mcpu_cpu_opt and dyn_mcpu_ext_opt to memorize them
+ respectively. Merge extension feature bits in cpu_variant
+ if there is any.
+ (s_arm_arch): Reset extension feature bit. Set selected_cpu from
+ *mcpu_cpu_opt and cpu_variant from selected_cpu and *mfpu_opt for
+ consistency with s_arm_cpu.
+ (s_arm_arch_extension): Update *dyn_mcpu_ext_opt rather than
+ selected_cpu, allocating it before hand if needed. Set selected_cpu
+ from it and then cpu_variant.
+ (s_arm_fpu): Merge *mcpu_ext_opt feature bits if any in cpu_variant.
+ * config/tc-arm.h (md_post_relax_hook): Set to arm_md_post_relax.
+ (aeabi_set_public_attributes): Delete external declaration.
+ (arm_md_post_relax): Declare externally.
+
2017-06-21 Thomas Preud'homme <thomas.preudhomme@arm.com>
* config/tc-arm.c (struct arm_cpu_option_table): New ext field.
static const arm_feature_set *legacy_fpu = NULL;
static const arm_feature_set *mcpu_cpu_opt = NULL;
+static arm_feature_set *dyn_mcpu_ext_opt = NULL;
static const arm_feature_set *mcpu_fpu_opt = NULL;
static const arm_feature_set *march_cpu_opt = NULL;
+static arm_feature_set *dyn_march_ext_opt = NULL;
static const arm_feature_set *march_fpu_opt = NULL;
static const arm_feature_set *mfpu_opt = NULL;
static const arm_feature_set *object_arch = NULL;
mcpu_cpu_opt = legacy_cpu;
}
else if (!mcpu_cpu_opt)
- mcpu_cpu_opt = march_cpu_opt;
+ {
+ mcpu_cpu_opt = march_cpu_opt;
+ dyn_mcpu_ext_opt = dyn_march_ext_opt;
+ /* Avoid double free in arm_md_end. */
+ dyn_march_ext_opt = NULL;
+ }
if (legacy_fpu)
{
mcpu_cpu_opt = &cpu_default;
selected_cpu = cpu_default;
}
+ else if (dyn_mcpu_ext_opt)
+ ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
else
selected_cpu = *mcpu_cpu_opt;
#else
- if (mcpu_cpu_opt)
+ if (mcpu_cpu_opt && dyn_mcpu_ext_opt)
+ ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
+ else if (mcpu_cpu_opt)
selected_cpu = *mcpu_cpu_opt;
else
mcpu_cpu_opt = &arm_arch_any;
#endif
ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+ if (dyn_mcpu_ext_opt)
+ ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, *dyn_mcpu_ext_opt);
autoselect_thumb_from_cpu_variant ();
};
static bfd_boolean
-arm_parse_extension (const char *str, const arm_feature_set **opt_p)
+arm_parse_extension (const char *str, const arm_feature_set *opt_set,
+ arm_feature_set **ext_set_p)
{
- arm_feature_set *ext_set = XNEW (arm_feature_set);
-
/* We insist on extensions being specified in alphabetical order, and with
extensions being added before being removed. We achieve this by having
the global ARM_EXTENSIONS table in alphabetical order, and using the
const arm_feature_set arm_any = ARM_ANY;
int adding_value = -1;
- /* Copy the feature set, so that we can modify it. */
- *ext_set = **opt_p;
- *opt_p = ext_set;
+ if (!*ext_set_p)
+ {
+ *ext_set_p = XNEW (arm_feature_set);
+ **ext_set_p = arm_arch_none;
+ }
while (str != NULL && *str != 0)
{
/* Empty entry. */
if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_any))
continue;
- if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *ext_set))
+ if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *opt_set))
break;
}
if (i == nb_allowed_archs)
/* Add or remove the extension. */
if (adding_value)
- ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->merge_value);
+ ARM_MERGE_FEATURE_SETS (**ext_set_p, **ext_set_p,
+ opt->merge_value);
else
- ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->clear_value);
+ ARM_CLEAR_FEATURE (**ext_set_p, **ext_set_p, opt->clear_value);
break;
}
for (opt = arm_cpus; opt->name != NULL; opt++)
if (opt->name_len == len && strncmp (opt->name, str, len) == 0)
{
- arm_feature_set *cpu_set = XNEW (arm_feature_set);
- ARM_MERGE_FEATURE_SETS (*cpu_set, opt->value, opt->ext);
- mcpu_cpu_opt = cpu_set;
+ mcpu_cpu_opt = &opt->value;
+ if (!dyn_mcpu_ext_opt)
+ dyn_mcpu_ext_opt = XNEW (arm_feature_set);
+ *dyn_mcpu_ext_opt = opt->ext;
mcpu_fpu_opt = &opt->default_fpu;
if (opt->canonical_name)
{
}
if (ext != NULL)
- return arm_parse_extension (ext, &mcpu_cpu_opt);
+ return arm_parse_extension (ext, mcpu_cpu_opt, &dyn_mcpu_ext_opt);
return TRUE;
}
strcpy (selected_cpu_name, opt->name);
if (ext != NULL)
- return arm_parse_extension (ext, &march_cpu_opt);
+ return arm_parse_extension (ext, march_cpu_opt, &dyn_march_ext_opt);
return TRUE;
}
}
/* Set the public EABI object attributes. */
-void
+static void
aeabi_set_public_attributes (void)
{
int arch;
aeabi_set_attribute_int (Tag_Virtualization_use, virt_sec);
}
+/* Post relaxation hook. Recompute ARM attributes now that relaxation is
+ finished and free extension feature bits which will not be used anymore. */
+void
+arm_md_post_relax (void)
+{
+ aeabi_set_public_attributes ();
+ XDELETE (dyn_mcpu_ext_opt);
+ dyn_mcpu_ext_opt = NULL;
+ XDELETE (dyn_march_ext_opt);
+ dyn_march_ext_opt = NULL;
+}
+
/* Add the default contents for the .ARM.attributes section. */
void
arm_md_end (void)
for (opt = arm_cpus + 1; opt->name != NULL; opt++)
if (streq (opt->name, name))
{
- arm_feature_set *cpu_set = XNEW (arm_feature_set);
- ARM_MERGE_FEATURE_SETS (*cpu_set, opt->value, opt->ext);
- mcpu_cpu_opt = cpu_set;
- selected_cpu = *mcpu_cpu_opt;
+ mcpu_cpu_opt = &opt->value;
+ if (!dyn_mcpu_ext_opt)
+ dyn_mcpu_ext_opt = XNEW (arm_feature_set);
+ *dyn_mcpu_ext_opt = opt->ext;
+ ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
if (opt->canonical_name)
strcpy (selected_cpu_name, opt->canonical_name);
else
selected_cpu_name[i] = 0;
}
ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+ if (dyn_mcpu_ext_opt)
+ ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, *dyn_mcpu_ext_opt);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
if (streq (opt->name, name))
{
mcpu_cpu_opt = &opt->value;
- selected_cpu = opt->value;
+ XDELETE (dyn_mcpu_ext_opt);
+ dyn_mcpu_ext_opt = NULL;
+ selected_cpu = *mcpu_cpu_opt;
strcpy (selected_cpu_name, opt->name);
- ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, *mfpu_opt);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
break;
}
+ if (!dyn_mcpu_ext_opt)
+ {
+ dyn_mcpu_ext_opt = XNEW (arm_feature_set);
+ *dyn_mcpu_ext_opt = arm_arch_none;
+ }
if (adding_value)
- ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu,
+ ARM_MERGE_FEATURE_SETS (*dyn_mcpu_ext_opt, *dyn_mcpu_ext_opt,
opt->merge_value);
else
- ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->clear_value);
+ ARM_CLEAR_FEATURE (*dyn_mcpu_ext_opt, *dyn_mcpu_ext_opt,
+ opt->clear_value);
- mcpu_cpu_opt = &selected_cpu;
- ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+ ARM_MERGE_FEATURE_SETS (selected_cpu, *mcpu_cpu_opt, *dyn_mcpu_ext_opt);
+ ARM_MERGE_FEATURE_SETS (cpu_variant, selected_cpu, *mfpu_opt);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;
{
mfpu_opt = &opt->value;
ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
+ if (dyn_mcpu_ext_opt)
+ ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, *dyn_mcpu_ext_opt);
*input_line_pointer = saved_char;
demand_empty_rest_of_line ();
return;