PR47785: Add support for handling Xassembler/Wa options with LTO.
authorPrathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
Mon, 24 Feb 2020 06:25:45 +0000 (11:55 +0530)
committerPrathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
Mon, 24 Feb 2020 06:25:45 +0000 (11:55 +0530)
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.

gcc/ChangeLog
gcc/doc/invoke.texi
gcc/gcc.c
gcc/lto-opts.c
gcc/lto-wrapper.c
gcc/opts-common.c
gcc/opts.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/pr78353-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/pr78353-2.c [new file with mode: 0644]

index 49986c0e10d5bb83c6598bb1c386981c587f6eba..b5fc309ce8402fd378255614d8c35bb4b4a4b65e 100644 (file)
@@ -1,3 +1,25 @@
+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>
 
        * config/riscv/riscv.c (riscv_emit_float_compare): Change the code gen
index 54017dfce8fda996ce5dbcd1ece66131ffffec24..d4fe9a4d9d4ea3382cc186ea7d3c5aa84cf4a01a 100644 (file)
@@ -11159,6 +11159,12 @@ conflicting translation units.  Specifically
 precedence; and for example @option{-ffp-contract=off} takes precedence
 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
 compile time.  If any of the input files at link time were built
 with debug info generation enabled the link will enable debug info
index effc384f3ef11a7e0e5a1e0469034b7d3ce1de7b..9f790db0daf407f3b095cbb8ade31e762b87ef3c 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -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.
    This is like processing a whole spec except that we do
    not initialize at the beginning and we do not supply a
@@ -7363,6 +7391,7 @@ driver::main (int argc, char **argv)
   global_initializations ();
   build_multilib_strings ();
   set_up_specs ();
+  putenv_COLLECT_AS_OPTIONS (assembler_options);
   putenv_COLLECT_GCC (argv[0]);
   maybe_putenv_COLLECT_LTO_WRAPPER ();
   maybe_putenv_OFFLOAD_TARGETS ();
index 90bfde5a8fd3eb5f1be4641cb24b7a040e52a591..87e916a274174abc3c00ae7eaa9e7548a1b15e9a 100644 (file)
@@ -163,6 +163,12 @@ lto_write_options (void)
        append_to_collect_gcc_options (&temporary_obstack, &first_p,
                                       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);
   args = XOBFINISH (&temporary_obstack, char *);
   lto_write_data (args, strlen (args) + 1);
index fe8f292f8778caf76473c4e8740794c924da56b3..6e3f294257e673cbd0eeb441f8df1f697d697aea 100644 (file)
@@ -73,6 +73,7 @@ static char *offload_objects_file_name;
 static char *makefile;
 static unsigned int num_deb_objs;
 static const char **early_debug_object_names;
+static bool xassembler_options_error = false;
 
 const char tool_name[] = "lto-wrapper";
 
@@ -137,42 +138,14 @@ get_options_from_collect_gcc_options (const char *collect_gcc,
                                      unsigned int *decoded_options_count)
 {
   struct obstack argv_obstack;
-  char *argv_storage;
   const char **argv;
-  int j, k, argc;
+  int argc;
 
-  argv_storage = xstrdup (collect_gcc_options);
   obstack_init (&argv_obstack);
   obstack_ptr_grow (&argv_obstack, collect_gcc);
 
-  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 = obstack_object_size (&argv_obstack) / sizeof (void *) - 1;
+  parse_options_from_collect_gcc_options (collect_gcc_options,
+                                         &argv_obstack, &argc);
   argv = XOBFINISH (&argv_obstack, const char **);
 
   decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER,
@@ -512,6 +485,45 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
       }
    else
      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.
@@ -626,6 +638,13 @@ append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
        case OPT_Os:
          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:
          if (!(cl_options[option->opt_index].flags & CL_TARGET))
            continue;
@@ -1251,7 +1270,8 @@ run_gcc (unsigned argc, char *argv[])
   const char **argv_ptr;
   char *list_option_full = 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 jobserver = 0;
   int auto_parallel = 0;
@@ -1281,6 +1301,25 @@ run_gcc (unsigned argc, char *argv[])
   if (!collect_gcc_options)
     fatal_error (input_location,
                 "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,
                                        &decoded_options,
                                        &decoded_options_count);
index 112de159cce1d1c0bde7d1022d0a74827abe52e2..de9510abd64faa84f220fb29e526b87375364652 100644 (file)
@@ -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, '\'');
+    }
+}
index c6ad6c704649c7d746f14f6ac506b636588a1fdd..8f594b46e330b9ac5497035b93f19a39e2d4928c 100644 (file)
@@ -460,6 +460,11 @@ extern bool parse_and_check_align_values (const char *flag,
                                          bool report_error,
                                          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.  */
 
 #define SET_OPTION_IF_UNSET(OPTS, OPTS_SET, OPTION, VALUE) \
index 06d61c7e2ee0c512bf697fcb99556c98b34b98ac..13c1a132cc1f0c679f83b201bd2be4d29b2b26de 100644 (file)
@@ -1,3 +1,11 @@
+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>
 
        PR fortran/93890
diff --git a/gcc/testsuite/gcc.target/arm/pr78353-1.c b/gcc/testsuite/gcc.target/arm/pr78353-1.c
new file mode 100644 (file)
index 0000000..aec0fb0
--- /dev/null
@@ -0,0 +1,8 @@
+/* { 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;
+}
diff --git a/gcc/testsuite/gcc.target/arm/pr78353-2.c b/gcc/testsuite/gcc.target/arm/pr78353-2.c
new file mode 100644 (file)
index 0000000..18a90e8
--- /dev/null
@@ -0,0 +1,9 @@
+/* { 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;
+}
+