Commit f1a681a1 by Prathamesh Kulkarni

PR47785: Add support for handling Xassembler/Wa options with LTO.

2020-02-24  Prathamesh Kulkarni  <prathamesh.kulkarni@linaro.org>
	    Kugan Vivekandarajah  <kugan.vivekanandarajah@linaro.org>

	PR driver/47785
	* gcc.c (putenv_COLLECT_AS_OPTIONS): New function.
	(driver::main): Call putenv_COLLECT_AS_OPTIONS.
	* opts-common.c (parse_options_from_collect_gcc_options): New function.
	(prepend_xassembler_to_collect_as_options): Likewise.
	* opts.h (parse_options_from_collect_gcc_options): Declare prototype.
	(prepend_xassembler_to_collect_as_options): Likewise.
	* lto-opts.c (lto_write_options): Stream assembler options
	in COLLECT_AS_OPTIONS.
	* lto-wrapper.c (xassembler_options_error): New static variable.
	(get_options_from_collect_gcc_options): Move parsing options code to
	parse_options_from_collect_gcc_options and call it.
	(merge_and_complain): Validate -Xassembler options.
	(append_compiler_options): Handle OPT_Xassembler.
	(run_gcc): Append command line -Xassembler options to
	collect_gcc_options.
	* doc/invoke.texi: Add documentation about using Xassembler
	options with LTO.

testsuite/
	* gcc.target/arm/pr78353-1.c: New test.
	* gcc.target/arm/pr78353-2.c: Likewise.
parent 9069e948
2020-02-24 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
Kugan Vivekandarajah <kugan.vivekanandarajah@linaro.org>
PR driver/47785
* gcc.c (putenv_COLLECT_AS_OPTIONS): New function.
(driver::main): Call putenv_COLLECT_AS_OPTIONS.
* opts-common.c (parse_options_from_collect_gcc_options): New function.
(prepend_xassembler_to_collect_as_options): Likewise.
* opts.h (parse_options_from_collect_gcc_options): Declare prototype.
(prepend_xassembler_to_collect_as_options): Likewise.
* lto-opts.c (lto_write_options): Stream assembler options
in COLLECT_AS_OPTIONS.
* lto-wrapper.c (xassembler_options_error): New static variable.
(get_options_from_collect_gcc_options): Move parsing options code to
parse_options_from_collect_gcc_options and call it.
(merge_and_complain): Validate -Xassembler options.
(append_compiler_options): Handle OPT_Xassembler.
(run_gcc): Append command line -Xassembler options to
collect_gcc_options.
* doc/invoke.texi: Add documentation about using Xassembler
options with LTO.
2020-02-24 Kito Cheng <kito.cheng@sifive.com> 2020-02-24 Kito Cheng <kito.cheng@sifive.com>
* config/riscv/riscv.c (riscv_emit_float_compare): Change the code gen * config/riscv/riscv.c (riscv_emit_float_compare): Change the code gen
......
...@@ -11159,6 +11159,12 @@ conflicting translation units. Specifically ...@@ -11159,6 +11159,12 @@ conflicting translation units. Specifically
precedence; and for example @option{-ffp-contract=off} takes precedence precedence; and for example @option{-ffp-contract=off} takes precedence
over @option{-ffp-contract=fast}. You can override them at link time. over @option{-ffp-contract=fast}. You can override them at link time.
When you need to pass options to the assembler via @option{-Wa} or
@option{-Xassembler} make sure to either compile such translation
units with @option{-fno-lto} or consistently use the same assembler
options on all translation units. You can alternatively also
specify assembler options at LTO link time.
To enable debug info generation you need to supply @option{-g} at To enable debug info generation you need to supply @option{-g} at
compile time. If any of the input files at link time were built compile time. If any of the input files at link time were built
with debug info generation enabled the link will enable debug info with debug info generation enabled the link will enable debug info
...@@ -5242,6 +5242,34 @@ do_specs_vec (vec<char_p> vec) ...@@ -5242,6 +5242,34 @@ do_specs_vec (vec<char_p> vec)
} }
} }
/* Add options passed via -Xassembler or -Wa to COLLECT_AS_OPTIONS. */
static void
putenv_COLLECT_AS_OPTIONS (vec<char_p> vec)
{
if (vec.is_empty ())
return;
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_AS_OPTIONS=",
strlen ("COLLECT_AS_OPTIONS="));
char *opt;
unsigned ix;
FOR_EACH_VEC_ELT (vec, ix, opt)
{
obstack_1grow (&collect_obstack, '\'');
obstack_grow (&collect_obstack, opt, strlen (opt));
obstack_1grow (&collect_obstack, '\'');
if (ix < vec.length () - 1)
obstack_1grow(&collect_obstack, ' ');
}
obstack_1grow (&collect_obstack, '\0');
xputenv (XOBFINISH (&collect_obstack, char *));
}
/* Process the sub-spec SPEC as a portion of a larger spec. /* Process the sub-spec SPEC as a portion of a larger spec.
This is like processing a whole spec except that we do This is like processing a whole spec except that we do
not initialize at the beginning and we do not supply a not initialize at the beginning and we do not supply a
...@@ -7363,6 +7391,7 @@ driver::main (int argc, char **argv) ...@@ -7363,6 +7391,7 @@ driver::main (int argc, char **argv)
global_initializations (); global_initializations ();
build_multilib_strings (); build_multilib_strings ();
set_up_specs (); set_up_specs ();
putenv_COLLECT_AS_OPTIONS (assembler_options);
putenv_COLLECT_GCC (argv[0]); putenv_COLLECT_GCC (argv[0]);
maybe_putenv_COLLECT_LTO_WRAPPER (); maybe_putenv_COLLECT_LTO_WRAPPER ();
maybe_putenv_OFFLOAD_TARGETS (); maybe_putenv_OFFLOAD_TARGETS ();
......
...@@ -163,6 +163,12 @@ lto_write_options (void) ...@@ -163,6 +163,12 @@ lto_write_options (void)
append_to_collect_gcc_options (&temporary_obstack, &first_p, append_to_collect_gcc_options (&temporary_obstack, &first_p,
option->canonical_option[j]); option->canonical_option[j]);
} }
const char *collect_as_options = getenv ("COLLECT_AS_OPTIONS");
if (collect_as_options)
prepend_xassembler_to_collect_as_options (collect_as_options,
&temporary_obstack);
obstack_grow (&temporary_obstack, "\0", 1); obstack_grow (&temporary_obstack, "\0", 1);
args = XOBFINISH (&temporary_obstack, char *); args = XOBFINISH (&temporary_obstack, char *);
lto_write_data (args, strlen (args) + 1); lto_write_data (args, strlen (args) + 1);
......
...@@ -73,6 +73,7 @@ static char *offload_objects_file_name; ...@@ -73,6 +73,7 @@ static char *offload_objects_file_name;
static char *makefile; static char *makefile;
static unsigned int num_deb_objs; static unsigned int num_deb_objs;
static const char **early_debug_object_names; static const char **early_debug_object_names;
static bool xassembler_options_error = false;
const char tool_name[] = "lto-wrapper"; const char tool_name[] = "lto-wrapper";
...@@ -137,42 +138,14 @@ get_options_from_collect_gcc_options (const char *collect_gcc, ...@@ -137,42 +138,14 @@ get_options_from_collect_gcc_options (const char *collect_gcc,
unsigned int *decoded_options_count) unsigned int *decoded_options_count)
{ {
struct obstack argv_obstack; struct obstack argv_obstack;
char *argv_storage;
const char **argv; const char **argv;
int j, k, argc; int argc;
argv_storage = xstrdup (collect_gcc_options);
obstack_init (&argv_obstack); obstack_init (&argv_obstack);
obstack_ptr_grow (&argv_obstack, collect_gcc); obstack_ptr_grow (&argv_obstack, collect_gcc);
for (j = 0, k = 0; argv_storage[j] != '\0'; ++j) parse_options_from_collect_gcc_options (collect_gcc_options,
{ &argv_obstack, &argc);
if (argv_storage[j] == '\'')
{
obstack_ptr_grow (&argv_obstack, &argv_storage[k]);
++j;
do
{
if (argv_storage[j] == '\0')
fatal_error (input_location,
"malformed %<COLLECT_GCC_OPTIONS%>");
else if (strncmp (&argv_storage[j], "'\\''", 4) == 0)
{
argv_storage[k++] = '\'';
j += 4;
}
else if (argv_storage[j] == '\'')
break;
else
argv_storage[k++] = argv_storage[j++];
}
while (1);
argv_storage[k++] = '\0';
}
}
obstack_ptr_grow (&argv_obstack, NULL);
argc = obstack_object_size (&argv_obstack) / sizeof (void *) - 1;
argv = XOBFINISH (&argv_obstack, const char **); argv = XOBFINISH (&argv_obstack, const char **);
decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER, decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
...@@ -512,6 +485,45 @@ merge_and_complain (struct cl_decoded_option **decoded_options, ...@@ -512,6 +485,45 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
} }
else else
j++; j++;
if (!xassembler_options_error)
for (i = j = 0; ; i++, j++)
{
for (; i < *decoded_options_count; i++)
if ((*decoded_options)[i].opt_index == OPT_Xassembler)
break;
for (; j < fdecoded_options_count; j++)
if (fdecoded_options[j].opt_index == OPT_Xassembler)
break;
if (i == *decoded_options_count && j == fdecoded_options_count)
break;
else if (i < *decoded_options_count && j == fdecoded_options_count)
{
warning (0, "Extra option to -Xassembler: %s,"
" dropping all -Xassembler and -Wa options.",
(*decoded_options)[i].arg);
xassembler_options_error = true;
break;
}
else if (i == *decoded_options_count && j < fdecoded_options_count)
{
warning (0, "Extra option to -Xassembler: %s,"
" dropping all -Xassembler and -Wa options.",
fdecoded_options[j].arg);
xassembler_options_error = true;
break;
}
else if (strcmp ((*decoded_options)[i].arg, fdecoded_options[j].arg))
{
warning (0, "Options to Xassembler do not match: %s, %s,"
" dropping all -Xassembler and -Wa options.",
(*decoded_options)[i].arg, fdecoded_options[j].arg);
xassembler_options_error = true;
break;
}
}
} }
/* Auxiliary function that frees elements of PTR and PTR itself. /* Auxiliary function that frees elements of PTR and PTR itself.
...@@ -626,6 +638,13 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts, ...@@ -626,6 +638,13 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
case OPT_Os: case OPT_Os:
break; break;
case OPT_Xassembler:
/* When we detected a mismatch in assembler options between
the input TU's fall back to previous behavior of ignoring them. */
if (xassembler_options_error)
continue;
break;
default: default:
if (!(cl_options[option->opt_index].flags & CL_TARGET)) if (!(cl_options[option->opt_index].flags & CL_TARGET))
continue; continue;
...@@ -1251,7 +1270,8 @@ run_gcc (unsigned argc, char *argv[]) ...@@ -1251,7 +1270,8 @@ run_gcc (unsigned argc, char *argv[])
const char **argv_ptr; const char **argv_ptr;
char *list_option_full = NULL; char *list_option_full = NULL;
const char *linker_output = NULL; const char *linker_output = NULL;
const char *collect_gcc, *collect_gcc_options; const char *collect_gcc;
char *collect_gcc_options;
int parallel = 0; int parallel = 0;
int jobserver = 0; int jobserver = 0;
int auto_parallel = 0; int auto_parallel = 0;
...@@ -1281,6 +1301,25 @@ run_gcc (unsigned argc, char *argv[]) ...@@ -1281,6 +1301,25 @@ run_gcc (unsigned argc, char *argv[])
if (!collect_gcc_options) if (!collect_gcc_options)
fatal_error (input_location, fatal_error (input_location,
"environment variable %<COLLECT_GCC_OPTIONS%> must be set"); "environment variable %<COLLECT_GCC_OPTIONS%> must be set");
char *collect_as_options = getenv ("COLLECT_AS_OPTIONS");
/* Prepend -Xassembler to each option, and append the string
to collect_gcc_options. */
if (collect_as_options)
{
obstack temporary_obstack;
obstack_init (&temporary_obstack);
prepend_xassembler_to_collect_as_options (collect_as_options,
&temporary_obstack);
obstack_1grow (&temporary_obstack, '\0');
char *xassembler_opts_string
= XOBFINISH (&temporary_obstack, char *);
strcat (collect_gcc_options, xassembler_opts_string);
}
get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options, get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options,
&decoded_options, &decoded_options,
&decoded_options_count); &decoded_options_count);
......
...@@ -1739,3 +1739,69 @@ control_warning_option (unsigned int opt_index, int kind, const char *arg, ...@@ -1739,3 +1739,69 @@ control_warning_option (unsigned int opt_index, int kind, const char *arg,
} }
} }
} }
/* Parse options in COLLECT_GCC_OPTIONS and push them on ARGV_OBSTACK.
Store number of arguments into ARGC_P. */
void
parse_options_from_collect_gcc_options (const char *collect_gcc_options,
obstack *argv_obstack,
int *argc_p)
{
char *argv_storage = xstrdup (collect_gcc_options);
int j, k;
for (j = 0, k = 0; argv_storage[j] != '\0'; ++j)
{
if (argv_storage[j] == '\'')
{
obstack_ptr_grow (argv_obstack, &argv_storage[k]);
++j;
do
{
if (argv_storage[j] == '\0')
fatal_error (input_location,
"malformed %<COLLECT_GCC_OPTIONS%>");
else if (strncmp (&argv_storage[j], "'\\''", 4) == 0)
{
argv_storage[k++] = '\'';
j += 4;
}
else if (argv_storage[j] == '\'')
break;
else
argv_storage[k++] = argv_storage[j++];
}
while (1);
argv_storage[k++] = '\0';
}
}
obstack_ptr_grow (argv_obstack, NULL);
*argc_p = obstack_object_size (argv_obstack) / sizeof (void *) - 1;
}
/* Prepend -Xassembler for each option in COLLECT_AS_OPTIONS,
and push on O. */
void prepend_xassembler_to_collect_as_options (const char *collect_as_options,
obstack *o)
{
obstack opts_obstack;
int opts_count;
obstack_init (&opts_obstack);
parse_options_from_collect_gcc_options (collect_as_options,
&opts_obstack, &opts_count);
const char **assembler_opts = XOBFINISH (&opts_obstack, const char **);
for (int i = 0; i < opts_count; i++)
{
obstack_grow (o, " '-Xassembler' ",
strlen (" '-Xassembler' "));
const char *opt = assembler_opts[i];
obstack_1grow (o, '\'');
obstack_grow (o, opt, strlen (opt));
obstack_1grow (o, '\'');
}
}
...@@ -460,6 +460,11 @@ extern bool parse_and_check_align_values (const char *flag, ...@@ -460,6 +460,11 @@ extern bool parse_and_check_align_values (const char *flag,
bool report_error, bool report_error,
location_t loc); location_t loc);
extern void parse_options_from_collect_gcc_options (const char *, obstack *,
int *);
extern void prepend_xassembler_to_collect_as_options (const char *, obstack *);
/* Set OPTION in OPTS to VALUE if the option is not set in OPTS_SET. */ /* Set OPTION in OPTS to VALUE if the option is not set in OPTS_SET. */
#define SET_OPTION_IF_UNSET(OPTS, OPTS_SET, OPTION, VALUE) \ #define SET_OPTION_IF_UNSET(OPTS, OPTS_SET, OPTION, VALUE) \
......
2020-02-24 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
Kugan Vivekandarajah <kugan.vivekanandarajah@linaro.org>
PR driver/47785
PR lto/78353
* gcc.target/arm/pr78353-1.c: New test.
* gcc.target/arm/pr78353-2.c: Likewise.
2020-02-23 Thomas Koenig <tkoenig@gcc.gnu.org> 2020-02-23 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/93890 PR fortran/93890
......
/* { dg-do link } */
/* { dg-options "-march=armv7-a -mthumb -O2 -flto -Wa,-mimplicit-it=always" } */
int main(int x)
{
asm("teq %0, #0; addne %0, %0, #1" : "=r" (x));
return x;
}
/* { dg-do link } */
/* { dg-options "-march=armv7-a -mthumb -O2 -flto -Wa,-mimplicit-it=always,-mthumb" } */
int main(int x)
{
asm("teq %0, #0; addne %0, %0, #1" : "=r" (x));
return x;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment