diff --git a/gcc/coverage.c b/gcc/coverage.c
index 4c06fa4..205bee5 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -1128,6 +1128,75 @@ coverage_obj_finish (vec<constructor_elt, va_gc> *ctor)
   varpool_finalize_decl (gcov_info_var);
 }

+/* Check the profile data file.
+   Return -1 if the file is not available or corrupted,
+       0 if the file is available and all counters are zero,
+       1 otherwise.  */
+
+int
+coverage_check (const char *filename)
+{
+  int ret = 0;
+  int len = strlen (filename);
+  int prefix_len = 0;
+  gcov_unsigned_t tag;
+  char *data_filename;
+
+  if (!profile_data_prefix && !IS_ABSOLUTE_PATH (filename))
+    profile_data_prefix = getpwd ();
+
+  if (profile_data_prefix)
+    prefix_len = strlen (profile_data_prefix);
+
+  data_filename = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX)
+               + prefix_len + 2);
+
+  if (profile_data_prefix)
+    {
+      memcpy (data_filename, profile_data_prefix, prefix_len);
+      data_filename[prefix_len++] = '/';
+    }
+  memcpy (data_filename + prefix_len, filename, len);
+  strcpy (data_filename + prefix_len + len, GCOV_DATA_SUFFIX);
+
+  if (!gcov_open (data_filename, 1))
+    return -1;
+  if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)
+      || gcov_read_unsigned () != GCOV_VERSION)
+    {
+      gcov_close ();
+      return -1;
+    }
+  gcov_read_unsigned ();
+
+  while ((tag = gcov_read_unsigned ()))
+    {
+      gcov_unsigned_t length = gcov_read_unsigned ();
+      gcov_position_t offset = gcov_position ();
+
+      if (GCOV_TAG_IS_COUNTER (tag))
+    {
+      unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
+      unsigned ix;
+
+      for (ix = 0; ix != n_counts; ix++)
+        if (gcov_read_counter ())
+          ret = 1;
+    }
+      gcov_sync (offset, length);
+
+      if (gcov_is_error ())
+    {
+      ret = -1;
+      break;
+    }
+    }
+
+  gcov_close ();
+
+  return ret;
+}
+
 /* Perform file-level initialization. Read in data file, generate name
    of notes file.  */

diff --git a/gcc/coverage.h b/gcc/coverage.h
index 81f87a6..51d1119 100644
--- a/gcc/coverage.h
+++ b/gcc/coverage.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see

 #include "gcov-io.h"

+extern int coverage_check (const char *);
 extern void coverage_init (const char *);
 extern void coverage_finish (void);

diff --git a/gcc/toplev.c b/gcc/toplev.c
index d646faf..b0c3906 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1222,6 +1222,77 @@ init_alignments (void)
   align_functions_log = floor_log2 (align_functions * 2 - 1);
 }

+/* Override options based on profile.  */
+
+static void
+profile_based_option_override (void)
+{
+  int status;
+  const char *name = aux_base_name;
+
+  if (!flag_branch_probabilities)
+    return;
+
+  if (!name)
+    {
+      char *newname;
+      if (!main_input_filename)
+    return;
+      newname = xstrdup (lbasename (main_input_filename));
+      strip_off_ending (newname, strlen (newname));
+      name = newname;
+    }
+
+  status = coverage_check (name);
+  if (status > 0)
+    return;
+
+  /* Profile data file is valid and all profile counters are zero.
+     Prefer optimizing code size.  */
+  if (status == 0)
+    {
+      optimize = 2;
+      optimize_size = 1;
+      maybe_set_param_value (PARAM_MIN_CROSSJUMP_INSNS, 1,
+                 param_values, global_options_set.x_param_values);
+
+      /* Ignore coverage mismatch since all counters are zero.  */
+      diagnostic_classify_diagnostic (global_dc, OPT_Wcoverage_mismatch,
+                      DK_IGNORED, UNKNOWN_LOCATION);
+    }
+
+  if (!flag_profile_use)
+    return;
+
+  /* Disable optimization options for PGO.  */
+  if (!global_options_set.x_flag_profile_values)
+    flag_profile_values = false;
+  if (!global_options_set.x_flag_unroll_loops)
+    flag_unroll_loops = false;
+  if (!global_options_set.x_flag_peel_loops)
+    flag_peel_loops = false;
+  if (!global_options_set.x_flag_tracer)
+    flag_tracer = false;
+  if (!global_options_set.x_flag_value_profile_transformations)
+    flag_value_profile_transformations = false;
+  if (!global_options_set.x_flag_ipa_cp_clone)
+    flag_ipa_cp_clone = false;
+  if (!global_options_set.x_flag_predictive_commoning)
+    flag_predictive_commoning = false;
+  if (!global_options_set.x_flag_unswitch_loops)
+    flag_unswitch_loops = false;
+  if (!global_options_set.x_flag_gcse_after_reload)
+    flag_gcse_after_reload = false;
+  if (!global_options_set.x_flag_tree_loop_vectorize
+      && !global_options_set.x_flag_tree_vectorize)
+    flag_tree_loop_vectorize = false;
+  if (!global_options_set.x_flag_tree_slp_vectorize
+      && !global_options_set.x_flag_tree_vectorize)
+    flag_tree_slp_vectorize = false;
+  if (!global_options_set.x_flag_vect_cost_model)
+    flag_vect_cost_model = VECT_COST_MODEL_CHEAP;
+}
+
 /* Process the options that have been parsed.  */
 static void
 process_options (void)
@@ -1245,6 +1316,8 @@ process_options (void)
      so we can correctly initialize debug output.  */
   no_backend = lang_hooks.post_options (&main_input_filename);

+  profile_based_option_override ();
+
   /* Some machines may reject certain combinations of options.  */
   targetm.target_option.override ();

