diff mbox

[UPC,03/22] options processing, driver

Message ID 20151201060232.GA31043@intrepid.com
State New
Headers show

Commit Message

Gary Funck Dec. 1, 2015, 6:02 a.m. UTC
Background
----------

An overview email, describing the UPC-related changes is here:
  https://gcc.gnu.org/ml/gcc-patches/2015-12/msg00005.html

The GUPC branch is described here:
  http://gcc.gnu.org/projects/gupc.html

The UPC-related source code differences are summarized here:
  http://gccupc.org/gupc-changes

All languages (c, c++, fortran, go, lto, objc, obj-c++) have been
bootstrapped; no test suite regressions were introduced,
relative to the GCC trunk.

If you are on the cc-list, your name was chosen either
because you are listed as a maintainer for the area that
applies to the patches described in this email, or you
were a frequent contributor of patches made to files listed
in this email.

In the change log entries included in each patch, the directory
containing the affected files is listed, followed by the files.
When the patches are applied, the change log entries will be
distributed to the appropriate ChangeLog file.

Overview
--------

UPC language support requires some extensions to the GCC driver.
Most of the new UPC-specific spec's will be triggered by the presence
of -fupc on the gcc command line.  Further, -fupc, will be asserted
when source files ending in .upc are compiled.
The linker spec, LINK_COMMAND_SPEC, is extended to bring in
UPC start/end files and to link with libgupc when -fupc is asserted.

Some new UPC-specific command line options are defined in c.opt.
These new UPC-specific options will only have an effect when -fupc
is asserted, and will be detected as an error otherwise.

c_common_parse_file() will call the UPC-specific language hook,
lang_hooks.upc.write_global_declarations() just after
parsing the source file via c_parse_file().  It is called
there to generate an initialization routine
within the scope of the current compilation unit.
This initialization routine will initialize file scope
UPC shared variables, and initialize pointers-to-shared
as needed.  The address of this initialization routine 
is placed in a special linker section named by
targetm.upc.init_array_section_name().

A new UPC-specific driver program called 'gupc' is implemented by
gcc/c/gupcspec.c.  It will be installed as both a 'gupc' and 'upc'
executable ('upc' is a symlink to 'gupc').  This is a convenience
driver similar to gfortran.  It asserts -fupc and
will cause .c source files to be compiled as UPC source files.
This implicit handling of .c files as .upc files provides compatibility
with other UPC compilers.

2015-11-30  Gary Funck  <gary@intrepid.com>

	gcc/
	* gcc.c (upc_crtbegin_spec, link_upc_spec, upc_crtend_spec,
	upc_options): New.  Define UPC-related spec's.
	(default_compilers): Add support for .upc files.
	(static_specs): Initialize UPC-specific spec's.
	(LINK_COMMAND_SPEC): Add UPC-specific linker spec's.
	* timevar.def (TV_TREE_UPC_GENERICIZE): New.  Define a new
	time variable for the 'UPC genericize' pass.
	gcc/c-family/
	* c-opts.c: #include "c-upc-pts.h" to bring in UPC_MAX_THREADS.
	(upc_init_options, upc_handle_option): New.
	(c_common_init_options):
	Call upc_init_options() if -fupc is asserted.
	(c_common_handle_option): Call upc_handle_option
	to handle UPC-specific options.
	(c_common_parse_file):
	Call lang_hooks.upc.write_global_declarations() if -fupc is asserted.
	* c.opt (dwarf-2-upc, fupc, fupc-debug, fupc-inline-lib,
	fupc-pre-include, fupc-pthreads-model-tls, fupc-threads,
	fupc-instrument, fupc-instrument-functions): New.
	Define UPS-specific command line options.
	gcc/c/
	* gupcspec.c: New.  Implement the 'gupc' driver program.
diff mbox

Patch

Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(.../trunk)	(revision 231059)
+++ gcc/gcc.c	(.../branches/gupc)	(revision 231080)
@@ -1016,16 +1016,20 @@  proper position among the other output f
     %{flto} %{fno-lto} %{flto=*} %l " LINK_PIE_SPEC \
    "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \
    "%X %{o*} %{e*} %{N} %{n} %{r}\
-    %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} \
+    %{s} %{t} %{u*} %{z} %{Z}\
+    %{!nostdlib:%{!nostartfiles:%{fupc:%:include(upc-crtbegin.spec)%(upc_crtbegin)}}}\
+    %{!nostdlib:%{!nostartfiles:%S}} \
     %{static:} %{L*} %(mfwrap) %(link_libgcc) " \
     VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o " CHKP_SPEC " \
     %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*} 1):\
 	%:include(libgomp.spec)%(link_gomp)}\
     %{fcilkplus:%:include(libcilkrts.spec)%(link_cilkrts)}\
     %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
+    %{fupc:%:include(libgupc.spec)%(link_upc)}\
     %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} " SANITIZER_SPEC " \
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
+    %{!nostdlib:%{!nostartfiles:%{fupc:%:include(upc-crtend.spec)%(upc_crtend)}}}\
     %{!nostdlib:%{!nostartfiles:%E}} %{T*}  \n%(post_link) }}}}}}"
 #endif
 
@@ -1061,6 +1065,9 @@  static const char *asm_final_spec = ASM_
 static const char *link_spec = LINK_SPEC;
 static const char *lib_spec = LIB_SPEC;
 static const char *link_gomp_spec = "";
+static const char *upc_crtbegin_spec = "";
+static const char *link_upc_spec = "";
+static const char *upc_crtend_spec = "";
 static const char *libgcc_spec = LIBGCC_SPEC;
 static const char *endfile_spec = ENDFILE_SPEC;
 static const char *startfile_spec = STARTFILE_SPEC;
@@ -1134,6 +1141,9 @@  static const char *cc1_options =
  %{fsyntax-only:-o %j} %{-param*}\
  %{coverage:-fprofile-arcs -ftest-coverage}";
 
+static const char *upc_options =
+ "-fupc %{!fno-upc-pre-include:-include gcc-upc.h}";
+
 static const char *asm_options =
 "%{-target-help:%:print-asm-header()} "
 #if HAVE_GNU_AS
@@ -1345,6 +1355,21 @@  static const struct compiler default_com
        as %(asm_debug) %(asm_options) %m.s %A }}}}"
 #endif
    , 0, 0, 0},
+  {".upc", "@upc", 0, 0, 0},
+  {"@upc",
+     /* Same as "@c" above, with the addition of %(upc_options).  */
+     "%{E|M|MM:cc1 -E %(upc_options) %(cpp_options) %(cpp_debug_options)}\
+      %{!E:%{!M:%{!MM:\
+	%{traditional|ftraditional|traditional-cpp:\
+              %e UPC does not support traditional compilation}\
+	%{save-temps|no-integrated-cpp:\
+	      cc1 -E %(upc_options) %(cpp_options)\
+	  %{save-temps:%b.mi} %{!save-temps:%g.mi} \n\
+	      cc1 -fpreprocessed %{save-temps:%b.mi} %{!save-temps:%g.mi}\
+	             %(upc_options) %(cc1_options)}\
+	%{!save-temps:%{!no-integrated-cpp:\
+	    cc1 %(cpp_unique_options) %(upc_options) %(cc1_options)}}\
+        %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
 
 #include "specs.h"
   /* Mark end of table.  */
@@ -1555,6 +1580,7 @@  static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("trad_capable_cpp",		&trad_capable_cpp),
   INIT_STATIC_SPEC ("cc1",			&cc1_spec),
   INIT_STATIC_SPEC ("cc1_options",		&cc1_options),
+  INIT_STATIC_SPEC ("upc_options",		&upc_options),
   INIT_STATIC_SPEC ("cc1plus",			&cc1plus_spec),
   INIT_STATIC_SPEC ("link_gcc_c_sequence",	&link_gcc_c_sequence_spec),
   INIT_STATIC_SPEC ("link_ssp",			&link_ssp_spec),
@@ -1562,6 +1588,9 @@  static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("link",			&link_spec),
   INIT_STATIC_SPEC ("lib",			&lib_spec),
   INIT_STATIC_SPEC ("link_gomp",		&link_gomp_spec),
+  INIT_STATIC_SPEC ("upc_crtbegin",		&upc_crtbegin_spec),
+  INIT_STATIC_SPEC ("link_upc",			&link_upc_spec),
+  INIT_STATIC_SPEC ("upc_crtend",		&upc_crtend_spec),
   INIT_STATIC_SPEC ("libgcc",			&libgcc_spec),
   INIT_STATIC_SPEC ("startfile",		&startfile_spec),
   INIT_STATIC_SPEC ("cross_compile",		&cross_compile),
Index: gcc/timevar.def
===================================================================
--- gcc/timevar.def	(.../trunk)	(revision 231059)
+++ gcc/timevar.def	(.../branches/gupc)	(revision 231080)
@@ -143,6 +143,7 @@  DEFTIMEVAR (TV_EARLY_INLINING        , "
 DEFTIMEVAR (TV_INLINE_PARAMETERS     , "inline parameters")
 DEFTIMEVAR (TV_INTEGRATION           , "integration")
 DEFTIMEVAR (TV_TREE_GIMPLIFY	     , "tree gimplify")
+DEFTIMEVAR (TV_TREE_UPC_GENERICIZE   , "tree UPC genericize")
 DEFTIMEVAR (TV_TREE_EH		     , "tree eh")
 DEFTIMEVAR (TV_TREE_CFG		     , "tree CFG construction")
 DEFTIMEVAR (TV_TREE_CLEANUP_CFG	     , "tree CFG cleanup")
Index: gcc/c-family/c-opts.c
===================================================================
--- gcc/c-family/c-opts.c	(.../trunk)	(revision 231059)
+++ gcc/c-family/c-opts.c	(.../branches/gupc)	(revision 231080)
@@ -27,6 +27,7 @@  along with GCC; see the file COPYING3.
 #include "tm_p.h"		/* For C_COMMON_OVERRIDE_OPTIONS.  */
 #include "diagnostic.h"
 #include "c-pragma.h"
+#include "c-upc-pts.h"
 #include "flags.h"
 #include "toplev.h"
 #include "langhooks.h"
@@ -208,6 +209,46 @@  c_common_init_options_struct (struct gcc
   opts->x_flag_complex_method = 2;
 }
 
+/* Initialize UPC-specific options.  */
+static void
+upc_init_options ()
+{
+  struct cl_option_handlers handlers;
+
+  /* UPC is based upon the C99 dialect.  Assert it here.
+   * We'll let the user override these options as he/she
+   * sees fit.  For example, -traditional will disable
+   * prototype checking.  */
+  set_std_c99 ( 0 /* iso=0 */ );
+
+  /* The consensus of the UPC community seems to be that
+     arithmetic on (void *) pointers and sizeof (void)
+     are compilation errors.  Enable this warning-as-error
+     mode by default.  */
+  warn_pointer_arith = 1;
+  set_default_handlers (&handlers);
+  control_warning_option (OPT_Wpointer_arith, (int) DK_ERROR, true,
+			  UNKNOWN_LOCATION, CL_C,
+			  &handlers, &global_options, &global_options_set,
+			  global_dc);
+
+  /* By default, don't generate UPC's DWARF2 extensions.  */
+  use_upc_dwarf2_extensions = 0;
+  flag_upc = 1;
+  flag_upc_threads = 0;
+  flag_upc_pthreads = 0;
+  /* By default, don't map UPC threads to POSIX threads.  */
+  flag_upc_pthreads = 0;
+  upc_pthreads_model = upc_pthreads_no_model;
+  /* By default, GASP profiling is off.  */
+  flag_upc_instrument = 0;
+  flag_upc_instrument_functions = 0;
+  /* By default, optimization level > 0 defines shared access routines
+     inlining, otherwise use the user specified flag to unconditionally
+     enable/disable inlining of the UPC shared memory access routines.  */
+  flag_upc_inline_lib = -1;
+}
+
 /* Common initialization before calling option handlers.  */
 void
 c_common_init_options (unsigned int decoded_options_count,
@@ -235,20 +276,94 @@  c_common_init_options (unsigned int deco
     {
       /* The default for C is gnu11.  */
       set_std_c11 (false /* ISO */);
-
-      /* If preprocessing assembly language, accept any of the C-family
-	 front end options since the driver may pass them through.  */
       for (i = 1; i < decoded_options_count; i++)
-	if (decoded_options[i].opt_index == OPT_lang_asm)
-	  {
-	    accept_all_c_family_options = true;
-	    break;
-	  }
+        {
+          /* If preprocessing assembly language, accept any of the C-family
+	     front end options since the driver may pass them through.  */
+	  if (decoded_options[i].opt_index == OPT_lang_asm)
+	    {
+	      accept_all_c_family_options = true;
+	      break;
+	    }
+	  /* If compiling UPC, initialize appropriate default options.  */
+	  if (decoded_options[i].opt_index == OPT_fupc)
+	    {
+	      upc_init_options ();
+	      break;
+	    }
+        }
     }
 
   global_dc->colorize_source_p = true;
 }
 
+/* Process UPC specific command line switches */
+
+static bool
+upc_handle_option (const enum opt_code code, const char *arg, const int value)
+{
+  int result = 1;
+  if (!flag_upc)
+    {
+      error ("%s is supported only when -fupc is also present", arg);
+      return false;
+    }
+  switch (code)
+    {
+    default:
+      gcc_unreachable ();
+      break;
+    case OPT_fupc:
+      flag_upc = value;
+      break;
+    case OPT_dwarf_2_upc:
+      use_upc_dwarf2_extensions = value;
+      break;
+    case OPT_fupc_debug:
+      if ((value == 1) && (flag_upc_inline_lib == 1))
+	error ("-fupc-debug is incompatible with -fupc-inline-lib");
+      flag_upc_debug = value;
+      break;
+    case OPT_fupc_inline_lib:
+      if ((value == 1) && (flag_upc_instrument == 1))
+	error ("-fupc-inline-lib is incompatible with -fupc-instrument");
+      if ((value == 1) && (flag_upc_debug == 1))
+	error ("-fupc-inline-lib is incompatible with -fupc-debug");
+      flag_upc_inline_lib = value;
+      break;
+    case OPT_fupc_instrument:
+      if ((value == 1) && (flag_upc_inline_lib == 1))
+	error ("-fupc-instrument is incompatible with -fupc-inline-lib");
+      flag_upc_instrument = value;
+      break;
+    case OPT_fupc_instrument_functions:
+      if ((value == 1) && (flag_upc_inline_lib == 1))
+	error
+	  ("-fupc-instrument-functions is incompatible "
+	   "with -fupc-inline-lib");
+      flag_upc_instrument = value;
+      flag_upc_instrument_functions = value;
+      break;
+    case OPT_fupc_pthreads_model_tls:
+      flag_upc_pthreads = 1;
+      upc_pthreads_model = upc_pthreads_tls_model;
+      break;
+    case OPT_fupc_threads_:
+      {
+        int num_threads = value;
+	if (num_threads > UPC_MAX_THREADS)
+	  {
+	    error ("THREADS value exceeds UPC implementation limit of %d",
+		   UPC_MAX_THREADS);
+	    num_threads = 1;
+	  }
+        flag_upc_threads = num_threads;
+      }
+      break;
+    }
+  return result;
+}
+
 /* Handle switch SCODE with argument ARG.  VALUE is true, unless no-
    form of an -f or -W option was given.  Returns false if the switch was
    invalid, true if valid.  Use HANDLERS in recursive handle_option calls.  */
@@ -532,6 +647,17 @@  c_common_handle_option (size_t scode, co
       cpp_opts->ext_numeric_literals = value;
       break;
 
+    case OPT_fupc:
+    case OPT_dwarf_2_upc:
+    case OPT_fupc_debug:
+    case OPT_fupc_inline_lib:
+    case OPT_fupc_instrument:
+    case OPT_fupc_instrument_functions:
+    case OPT_fupc_pthreads_model_tls:
+    case OPT_fupc_threads_:
+      result = upc_handle_option (code, arg, value);
+      break;
+
     case OPT_idirafter:
       add_path (xstrdup (arg), AFTER, 0, true);
       break;
@@ -1062,6 +1188,9 @@  c_common_parse_file (void)
       pch_init ();
       push_file_scope ();
       c_parse_file ();
+      /* Generate UPC global initialization code, if required.  */
+      if (flag_upc)
+        (*lang_hooks.upc.write_global_declarations) ();
       pop_file_scope ();
       /* And end the main input file, if the debug writer wants it  */
       if (debug_hooks->start_end_main_source_file)
Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(.../trunk)	(revision 231059)
+++ gcc/c-family/c.opt	(.../branches/gupc)	(revision 231080)
@@ -992,6 +992,10 @@  d
 C ObjC C++ ObjC++ Joined
 ; Documented in common.opt.  FIXME - what about -dI, -dD, -dN and -dD?
 
+dwarf-2-upc
+C Report Var(use_upc_dwarf2_extensions) Init(0)
+Generate DWARF-2 debug info with UPC extensions.
+
 fabi-compat-version=
 C++ ObjC++ Joined RejectNegative UInteger Var(flag_abi_compat_version) Init(-1)
 The version of the C++ ABI used for -Wabi warnings and link compatibility aliases.
@@ -1512,6 +1516,46 @@  funsigned-char
 C ObjC C++ ObjC++ LTO Var(flag_signed_char, 0)
 Make \"char\" unsigned by default.
 
+fupc
+C Report Var(flag_upc) Init(0)
+Enable UPC.
+
+fupc-debug
+C Var(flag_upc_debug)
+Generate code that provides the UPC runtime with
+the file and line number where the runtime was called.
+
+fupc-inline-lib
+C Var(flag_upc_inline_lib)
+Generate code for inlined UPC runtime library routines.
+Default, at optimization levels greater than 0.
+
+fupc-pre-include
+C Init(1)
+Pre-include UPC runtime header file.
+
+fupc-pthreads-model-tls
+C
+Generate code for a POSIX threads based UPC runtime environment
+with TLS (Thread Local Storage) support.
+
+fupc-threads=
+C Joined RejectNegative UInteger
+Specify the compile-time value of THREADS.
+
+fupc-threads-
+C Joined RejectNegative UInteger Alias(fupc-threads=)
+Deprecated in favor of -fupc-threads=.
+
+fupc-instrument
+C Var(flag_upc_instrument)
+Instrument UPC shared accesses and library calls, using GASP tool support.
+
+fupc-instrument-functions
+C Var(flag_upc_instrument_functions)
+Instrument functions calls, using GASP tool support
+(implies -fupc-instrument).
+
 fuse-cxa-atexit
 C++ ObjC++ Var(flag_use_cxa_atexit) Init(DEFAULT_USE_CXA_ATEXIT)
 Use __cxa_atexit to register destructors.
Index: gcc/c/gupcspec.c
===================================================================
--- gcc/c/gupcspec.c	(.../trunk)	(revision 0)
+++ gcc/c/gupcspec.c	(.../branches/gupc)	(revision 231080)
@@ -0,0 +1,303 @@ 
+/* gupcspec.c: the UPC compiler driver program
+   Copyright (C) 2001-2015 Free Software Foundation, Inc.
+   Contributed by Gary Funck <gary@intrepid.com>
+     and Nenad Vukicevic <nenad@intrepid.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "gcc.h"
+#include "opts.h"
+
+#include "tm.h"
+
+
+/* GUPC driver - derived from fortran/gfortranspec.c.  */
+
+/* The original argument list and related info is copied here.  */
+static unsigned int gupc_xargc;
+static const struct cl_decoded_option *gupc_x_decoded_options;
+static void append_arg (const struct cl_decoded_option *);
+
+/* The new argument list will be built here.  */
+static unsigned int gupc_newargc;
+static struct cl_decoded_option *gupc_new_decoded_options;
+
+static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX;
+static const char *const standard_exec_prefix = STANDARD_EXEC_PREFIX;
+
+/* By default the linker is always invoked.  */
+static int invoke_linker = 1;
+
+static int match_suffix (const char *s, const char *suffix);
+
+#define END_ARGS ((char *) 0)
+
+/* Return true if the strings S1 and S2 are either both NULL
+ * or both the same string.  */
+
+static bool
+strings_same (const char *s1, const char *s2)
+{
+  return s1 == s2 || (s1 != NULL && s2 != NULL && strcmp (s1, s2) == 0);
+}
+
+/* Return whether decoded option structures OPT1 and OPT2 are the
+   same.  */
+
+static bool
+options_same (const struct cl_decoded_option *opt1,
+	      const struct cl_decoded_option *opt2)
+{
+  return (opt1->opt_index == opt2->opt_index
+	  && strings_same (opt1->arg, opt2->arg)
+	  && strings_same (opt1->orig_option_with_args_text,
+			   opt2->orig_option_with_args_text)
+	  && strings_same (opt1->canonical_option[0],
+			   opt2->canonical_option[0])
+	  && strings_same (opt1->canonical_option[1],
+			   opt2->canonical_option[1])
+	  && strings_same (opt1->canonical_option[2],
+			   opt2->canonical_option[2])
+	  && strings_same (opt1->canonical_option[3],
+			   opt2->canonical_option[3])
+	  && (opt1->canonical_option_num_elements
+	      == opt2->canonical_option_num_elements)
+	  && opt1->value == opt2->value && opt1->errors == opt2->errors);
+}
+
+/* Append another argument to the list being built.  As long as it is
+   identical to the corresponding arg in the original list, just increment
+   the new arg count.  Otherwise allocate a new list, etc.  */
+
+static void
+append_arg (const struct cl_decoded_option *arg)
+{
+  static unsigned int newargsize;
+
+  if (gupc_new_decoded_options == gupc_x_decoded_options
+      && gupc_newargc < gupc_xargc
+      && options_same (arg, &gupc_x_decoded_options[gupc_newargc]))
+    {
+      ++gupc_newargc;
+      return;			/* Nothing new here.  */
+    }
+
+  if (gupc_new_decoded_options == gupc_x_decoded_options)
+    {				/* Make new arglist.  */
+      unsigned int i;
+
+      newargsize = (gupc_xargc << 2) + 20;	/* This should handle all.  */
+      gupc_new_decoded_options =
+	XNEWVEC (struct cl_decoded_option, newargsize);
+
+      /* Copy what has been done so far.  */
+      for (i = 0; i < gupc_newargc; ++i)
+	gupc_new_decoded_options[i] = gupc_x_decoded_options[i];
+    }
+
+  if (gupc_newargc == newargsize)
+    fatal_error (input_location, "overflowed output arg list for %qs",
+		 arg->orig_option_with_args_text);
+
+  gupc_new_decoded_options[gupc_newargc++] = *arg;
+}
+
+/* Append an option described by OPT_INDEX, ARG and VALUE to the list
+   being built.  */
+static void
+append_option (size_t opt_index, const char *arg, int value)
+{
+  struct cl_decoded_option decoded;
+
+  generate_option (opt_index, arg, value, CL_DRIVER, &decoded);
+  append_arg (&decoded);
+}
+
+static int
+match_suffix (const char *s, const char *suffix)
+{
+  int slen = strlen (s);
+  int xlen = strlen (suffix);
+  const char *start = (xlen <= slen) ? s + slen - xlen : 0;
+  return start && !strncmp (start, suffix, xlen);
+}
+
+void
+lang_specific_driver (struct cl_decoded_option **in_decoded_options,
+		      unsigned int *in_decoded_options_count,
+		      int *in_added_libraries ATTRIBUTE_UNUSED)
+{
+  struct cl_decoded_option *decoded_options = *in_decoded_options;
+  unsigned int i;
+  int is_x_in_effect = 0;
+  int is_x_upc_in_effect = 0;
+  int verbose = 0;
+  int n_infiles = 0;
+  int n_outfiles = 0;
+  int pre_processed = 0;
+
+  gupc_xargc = *in_decoded_options_count;
+  gupc_x_decoded_options = decoded_options;
+  gupc_newargc = 0;
+  gupc_new_decoded_options = decoded_options;
+
+  /* First pass through the argument list.  */
+
+  /* Check to see if any switches are asserted that inhibit linking
+     and record the presence of other switches that may require
+     special handling.  */
+  for (i = 1; i < gupc_xargc; ++i)
+    {
+      if (decoded_options[i].errors & CL_ERR_MISSING_ARG)
+	continue;
+
+      switch (decoded_options[i].opt_index)
+	{
+
+	case OPT_SPECIAL_input_file:
+	  ++n_infiles;
+	  continue;
+
+	case OPT_nostdlib:
+	case OPT_nodefaultlibs:
+	case OPT_c:
+	case OPT_S:
+	case OPT_fsyntax_only:
+	case OPT_E:
+	  /* These options disable linking entirely or linking of the
+	     standard libraries.  */
+	  invoke_linker = 0;
+	  break;
+
+	case OPT_fpreprocessed:
+	  pre_processed = 1;
+	  break;
+
+	case OPT_l:
+	  ++n_infiles;
+	  break;
+
+	case OPT_o:
+	  ++n_outfiles;
+	  break;
+
+	case OPT_v:
+	  verbose = 1;
+	  break;
+
+	case OPT__version:
+	  /* Optional GUPC version string. Let GCC handle it for now.  */
+	  break;
+
+	case OPT__help:
+	  /* Let gcc.c handle this, as it has a really
+	     cool facility for handling --help and --verbose --help.  */
+	  return;
+
+	default:
+	  break;
+	}
+    }
+
+  /* Create the new argument list.  */
+
+  /* Start with the compiler itself.  */
+  append_arg (&decoded_options[0]);
+
+  /* Always assert -fupc.  */
+  append_option (OPT_fupc, NULL, 1);
+
+  /* If there are no input files, no need for the library.  */
+  if (n_infiles == 0)
+    invoke_linker = 0;
+
+  /* Copy in the arguments as passed to 'upc' */
+  is_x_in_effect = 0;
+  is_x_upc_in_effect = 0;
+  for (i = 1; i < gupc_xargc; ++i)
+    {
+      /* Skip -fupc, we asserted it above.  */
+      if (decoded_options[i].opt_index == OPT_fupc)
+        continue;
+
+      /* Check for "-x [c,upc,..]".  */
+      if (decoded_options[i].opt_index == OPT_x)
+	{
+	  /* Go to default if "none" found.  */
+	  if (!strcmp (decoded_options[i].arg, "none"))
+	    {
+	      is_x_in_effect = 0;
+	      is_x_upc_in_effect = 0;
+	    }
+	  else
+	    is_x_in_effect = 1;
+	}
+
+      /* By default, driver accepts C files as UPC files.  Unless there
+         is "-x" option in affect.  */
+      if (decoded_options[i].opt_index == OPT_SPECIAL_input_file)
+	{
+	  const int is_c_file = match_suffix (decoded_options[i].arg, ".c")
+	    || match_suffix (decoded_options[i].arg, ".h")
+	    || (pre_processed && match_suffix (decoded_options[i].arg, ".i"));
+	  if (is_c_file)
+	    {
+              if ( !(is_x_in_effect || is_x_upc_in_effect))
+		{
+		  append_option (OPT_x, "upc", 1);
+	   	  is_x_upc_in_effect = 1;
+		}
+	      append_arg (&decoded_options[i]);
+	      continue;
+	    }
+	  else
+	    {
+	      if (is_x_upc_in_effect)
+	        {
+	          is_x_upc_in_effect = 0;
+		  append_option (OPT_x, "none", 1);
+	        }
+	    }
+	}
+      append_arg (&decoded_options[i]);
+    }
+
+  if (verbose)
+    {
+      fprintf (stderr, "Driving:");
+      for (i = 0; i < gupc_newargc; i++)
+	fprintf (stderr, " %s",
+		 gupc_new_decoded_options[i].orig_option_with_args_text);
+      fprintf (stderr, "\n");
+    }
+
+  *in_decoded_options_count = gupc_newargc;
+  *in_decoded_options = gupc_new_decoded_options;
+}
+
+/* Called before linking.  Returns 0 on success and -1 on failure.  */
+int
+lang_specific_pre_link (void)
+{
+  return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate.  */
+int lang_specific_extra_outfiles = 0;	/* Not used for GUPC.  */