Index: gcc/gimple-pretty-print.c
===================================================================
--- gcc/gimple-pretty-print.c	(revision 198895)
+++ gcc/gimple-pretty-print.c	(working copy)
@@ -1859,7 +1859,9 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple g
 
   if ((flags & TDF_LINENO) && gimple_has_location (gs))
     {
-      expanded_location xloc = expand_location (gimple_location (gs));
+      location_t loc = gimple_location (gs);
+      expanded_location xloc = expand_location (loc);
+      int discriminator = get_discriminator_from_locus (loc);
       pp_character (buffer, '[');
       if (xloc.file)
 	{
@@ -1869,6 +1871,11 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple g
       pp_decimal_int (buffer, xloc.line);
       pp_string (buffer, ":");
       pp_decimal_int (buffer, xloc.column);
+      if (discriminator)
+	{
+	  pp_string (buffer, " discrim ");
+	  pp_decimal_int (buffer, discriminator);
+	}
       pp_string (buffer, "] ");
     }
 
@@ -2079,8 +2086,6 @@ dump_gimple_bb_header (FILE *outf, basic_block bb,
 			 indent, "", get_lineno (gsi_stmt (gsi)));
 		break;
 	      }
-	  if (bb->discriminator)
-	    fprintf (outf, ", discriminator %i", bb->discriminator);
 	  fputc ('\n', outf);
 	}
     }
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	(revision 198895)
+++ gcc/tree-cfg.c	(working copy)
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "basic-block.h"
 #include "flags.h"
+#include "input.h"
 #include "function.h"
 #include "ggc.h"
 #include "gimple-pretty-print.h"
@@ -746,22 +747,63 @@ same_line_p (location_t locus1, location_t locus2)
           && filename_cmp (from.file, to.file) == 0);
 }
 
-/* Assign a unique discriminator value to block BB if it begins at the same
-   LOCUS as its predecessor block.  */
+/* Assign a unique discriminator value to instructions in block BB that
+   have the same LOCUS as its predecessor block.  */
 
 static void
 assign_discriminator (location_t locus, basic_block bb)
 {
   gimple first_in_to_bb, last_in_to_bb;
+  int discriminator = 0;
+  tree block = LOCATION_BLOCK (locus);
+  locus = LOCATION_LOCUS (locus);
 
-  if (locus == 0 || bb->discriminator != 0)
+  if (locus == UNKNOWN_LOCATION)
     return;
 
+  if (has_discriminator (locus))
+    locus = map_discriminator_location (locus);
+
+  /* Check the locus of the first (non-label) instruction in the block.  */
   first_in_to_bb = first_non_label_stmt (bb);
-  last_in_to_bb = last_stmt (bb);
-  if ((first_in_to_bb && same_line_p (locus, gimple_location (first_in_to_bb)))
-      || (last_in_to_bb && same_line_p (locus, gimple_location (last_in_to_bb))))
-    bb->discriminator = next_discriminator_for_locus (locus);
+  if (first_in_to_bb)
+    {
+      location_t first_locus = gimple_location (first_in_to_bb);
+      if (! has_discriminator (first_locus)
+          && (same_line_p (locus, first_locus)))
+	discriminator = next_discriminator_for_locus (locus);
+    }
+
+  /* If the first instruction doesn't trigger a discriminator, check the
+     last instruction of the block.  This catches the case where the
+     increment portion of a for loop is placed at the end of the loop
+     body.  */
+  if (discriminator == 0)
+    {
+      last_in_to_bb = last_stmt (bb);
+      if (last_in_to_bb)
+	{
+	   location_t last_locus = gimple_location (last_in_to_bb);
+	   if (! has_discriminator (last_locus)
+	       && same_line_p (locus, last_locus))
+	     discriminator = next_discriminator_for_locus (locus);
+	}
+    }
+
+  if (discriminator != 0)
+    {
+      location_t new_locus = location_with_discriminator (locus, discriminator);
+      gimple_stmt_iterator gsi;
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+	{
+	  gimple stmt = gsi_stmt (gsi);
+	  if (same_line_p (locus, gimple_location (stmt)))
+	    gimple_set_location (stmt, block ?
+		COMBINE_LOCATION_DATA (line_table, new_locus, block) :
+		LOCATION_LOCUS (new_locus));
+	}
+    }
 }
 
 /* Create the edges for a GIMPLE_COND starting at block BB.  */
Index: gcc/diagnostic.c
===================================================================
--- gcc/diagnostic.c	(revision 198895)
+++ gcc/diagnostic.c	(working copy)
@@ -185,6 +185,7 @@ diagnostic_set_info_translated (diagnostic_info *d
 				va_list *args, location_t location,
 				diagnostic_t kind)
 {
+  location = map_discriminator_location (location);
   diagnostic->message.err_no = errno;
   diagnostic->message.args_ptr = args;
   diagnostic->message.format_spec = msg;
@@ -477,6 +478,9 @@ diagnostic_report_current_module (diagnostic_conte
   if (where <= BUILTINS_LOCATION)
     return;
 
+  if (has_discriminator (where))
+    where = map_discriminator_location (where);
+
   linemap_resolve_location (line_table, where,
 			    LRK_MACRO_DEFINITION_LOCATION,
 			    &map);
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	(revision 198895)
+++ gcc/rtl.h	(working copy)
@@ -1916,6 +1916,7 @@ extern rtx prev_cc0_setter (rtx);
 extern int insn_line (const_rtx);
 extern const char * insn_file (const_rtx);
 extern tree insn_scope (const_rtx);
+extern int insn_discriminator (const_rtx);
 extern location_t prologue_location, epilogue_location;
 
 /* In jump.c */
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 198895)
+++ gcc/builtins.c	(working copy)
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "diagnostic-core.h"
 #include "builtins.h"
+#include "input.h"
 
 
 #ifndef PAD_VARARGS_DOWN
@@ -12107,13 +12108,16 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
   tree fntype = TREE_TYPE (current_function_decl);
   int nargs = call_expr_nargs (exp);
   tree arg;
+  location_t loc = LOCATION_LOCUS (input_location);
+  if (has_discriminator (loc))
+    loc = map_discriminator_location (loc);
+
   /* There is good chance the current input_location points inside the
      definition of the va_start macro (perhaps on the token for
      builtin) in a system header, so warnings will not be emitted.
      Use the location in real source code.  */
   source_location current_location =
-    linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
-					      NULL);
+    linemap_unwind_to_first_non_reserved_loc (line_table, loc, NULL);
 
   if (!stdarg_p (fntype))
     {
Index: gcc/cfghooks.c
===================================================================
--- gcc/cfghooks.c	(revision 198895)
+++ gcc/cfghooks.c	(working copy)
@@ -483,7 +483,6 @@ split_block (basic_block bb, void *i)
 
   new_bb->count = bb->count;
   new_bb->frequency = bb->frequency;
-  new_bb->discriminator = bb->discriminator;
 
   if (dom_info_available_p (CDI_DOMINATORS))
     {
Index: gcc/final.c
===================================================================
--- gcc/final.c	(revision 198895)
+++ gcc/final.c	(working copy)
@@ -124,9 +124,6 @@ static int last_linenum;
 /* Last discriminator written to assembly.  */
 static int last_discriminator;
 
-/* Discriminator of current block.  */
-static int discriminator;
-
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
@@ -136,9 +133,10 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
-/* Override filename and line number.  */
+/* Override filename, line number, and discriminator.  */
 static const char *override_filename;
 static int override_linenum;
+static int override_discriminator;
 
 /* Whether to force emission of a line note before the next insn.  */
 static bool force_source_line = false;
@@ -1682,7 +1680,7 @@ final_start_function (rtx first, FILE *file,
 
   last_filename = LOCATION_FILE (prologue_location);
   last_linenum = LOCATION_LINE (prologue_location);
-  last_discriminator = discriminator = 0;
+  last_discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
@@ -2135,8 +2133,6 @@ final_scan_insn (rtx insn, FILE *file, int optimiz
 	  else
 	    *seen |= SEEN_BB;
 
-          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
-
 	  break;
 
 	case NOTE_INSN_EH_REGION_BEG:
@@ -2229,6 +2225,8 @@ final_scan_insn (rtx insn, FILE *file, int optimiz
 		{
 		  override_filename = LOCATION_FILE (*locus_ptr);
 		  override_linenum = LOCATION_LINE (*locus_ptr);
+		  override_discriminator =
+		      get_discriminator_from_locus (*locus_ptr);
 		}
 	    }
 	  break;
@@ -2262,11 +2260,14 @@ final_scan_insn (rtx insn, FILE *file, int optimiz
 		{
 		  override_filename = LOCATION_FILE (*locus_ptr);
 		  override_linenum = LOCATION_LINE (*locus_ptr);
+		  override_discriminator =
+		      get_discriminator_from_locus (*locus_ptr);
 		}
 	      else
 		{
 		  override_filename = NULL;
 		  override_linenum = 0;
+		  override_discriminator = 0;
 		}
 	    }
 	  break;
@@ -2949,6 +2950,17 @@ final_scan_insn (rtx insn, FILE *file, int optimiz
     }
   return NEXT_INSN (insn);
 }
+
+/* Return discriminator of the statement that produced this insn.  */
+int
+insn_discriminator (const_rtx insn)
+{
+  location_t loc = INSN_LOCATION (insn);
+  if (!loc)
+    return 0;
+  return get_discriminator_from_locus (loc);
+}
+
 
 /* Return whether a source line note needs to be emitted before INSN.
    Sets IS_STMT to TRUE if the line should be marked as a possible
@@ -2959,16 +2971,19 @@ notice_source_line (rtx insn, bool *is_stmt)
 {
   const char *filename;
   int linenum;
+  int discriminator;
 
   if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
+      discriminator = override_discriminator;
     }
   else
     {
       filename = insn_file (insn);
       linenum = insn_line (insn);
+      discriminator = insn_discriminator (insn);
     }
 
   if (filename == NULL)
Index: gcc/input.c
===================================================================
--- gcc/input.c	(revision 198895)
+++ gcc/input.c	(working copy)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "intl.h"
 #include "input.h"
+#include "vec.h"
 
 /* Current position in real source file.  */
 
@@ -29,8 +30,18 @@ location_t input_location;
 
 struct line_maps *line_table;
 
+static vec<location_t> discriminator_location_locations;
+static vec<location_t> discriminator_location_discriminators;
+static location_t next_discriminator_location = UNKNOWN_LOCATION;
+static location_t min_discriminator_location = UNKNOWN_LOCATION;
+
 /* Expand the source location LOC into a human readable location.  If
    LOC resolves to a builtin location, the file name of the readable
+   location is set to the string "<built-in>".  */
+
+
+/* Expand the source location LOC into a human readable location.  If
+   LOC resolves to a builtin location, the file name of the readable
    location is set to the string "<built-in>". If EXPANSION_POINT_P is
    TRUE and LOC is virtual, then it is resolved to the expansion
    point of the involved macro.  Otherwise, it is resolved to the
@@ -58,6 +69,13 @@ expand_location_1 (source_location loc,
       loc = LOCATION_LOCUS (loc);
     }
 
+  /* If LOC describes a location with a discriminator, extract the
+     discriminator and map it to the real location.  */
+  if (min_discriminator_location != UNKNOWN_LOCATION
+      && loc >= min_discriminator_location
+      && loc < min_discriminator_location + next_discriminator_location)
+    loc = map_discriminator_location (loc);
+
   memset (&xloc, 0, sizeof (xloc));
 
   if (loc >= RESERVED_LOCATION_COUNT)
@@ -278,3 +296,69 @@ dump_line_table_statistics (void)
            STAT_LABEL (total_used_map_size));
   fprintf (stderr, "\n");
 }
+
+/* Associate the DISCRIMINATOR with LOCUS, and return a new locus.
+   We associate discriminators with a locus by allocating location_t
+   values beyond those assigned by libcpp.  Each new value is mapped
+   directly to a real location_t value, and separately to the
+   discriminator.  */
+
+location_t
+location_with_discriminator (location_t locus, int discriminator)
+{
+  tree block = LOCATION_BLOCK (locus);
+  location_t ret;
+  locus = LOCATION_LOCUS (locus);
+
+  if (locus == UNKNOWN_LOCATION)
+    return block ? COMBINE_LOCATION_DATA (line_table, locus, block)
+		 : locus;
+
+  if (min_discriminator_location == UNKNOWN_LOCATION)
+    {
+      min_discriminator_location = line_table->highest_location + 1;
+      next_discriminator_location = min_discriminator_location;
+    }
+
+  discriminator_location_locations.safe_push(locus);
+  discriminator_location_discriminators.safe_push(discriminator);
+
+  ret = block ?
+      COMBINE_LOCATION_DATA (line_table, next_discriminator_location, block)
+      : LOCATION_LOCUS (next_discriminator_location);
+  next_discriminator_location++;
+  return ret;
+}
+
+/* Return TRUE if LOCUS represents a location with a discriminator.  */
+
+bool
+has_discriminator (location_t locus)
+{
+  locus = LOCATION_LOCUS (locus);
+  return (min_discriminator_location != UNKNOWN_LOCATION
+	  && locus >= min_discriminator_location
+	  && locus < min_discriminator_location + next_discriminator_location);
+}
+
+/* Return the real location_t value for LOCUS.  */
+
+location_t
+map_discriminator_location (location_t locus)
+{
+  locus = LOCATION_LOCUS (locus);
+  if (! has_discriminator (locus))
+    return locus;
+  return (location_t) discriminator_location_locations[locus - min_discriminator_location];
+}
+
+/* Return the discriminator for LOCUS.  */
+
+int
+get_discriminator_from_locus (location_t locus)
+{
+  locus = LOCATION_LOCUS (locus);
+  if (! has_discriminator (locus))
+    return 0;
+  return (location_t) discriminator_location_discriminators[locus - min_discriminator_location];
+}
Index: gcc/input.h
===================================================================
--- gcc/input.h	(revision 198895)
+++ gcc/input.h	(working copy)
@@ -47,6 +47,11 @@ typedef source_location location_t;
 
 extern location_t input_location;
 
+extern location_t location_with_discriminator (location_t, int);
+extern bool has_discriminator (location_t);
+extern location_t map_discriminator_location (location_t);
+extern int get_discriminator_from_locus (location_t);
+
 #define LOCATION_FILE(LOC) ((expand_location (LOC)).file)
 #define LOCATION_LINE(LOC) ((expand_location (LOC)).line)
 #define LOCATION_COLUMN(LOC)((expand_location (LOC)).column)
@@ -59,7 +64,8 @@ extern location_t input_location;
 #define input_line LOCATION_LINE (input_location)
 #define input_filename LOCATION_FILE (input_location)
 #define in_system_header_at(LOC) \
-  ((linemap_location_in_system_header_p (line_table, LOC)))
+  ((linemap_location_in_system_header_p (line_table, \
+                                         map_discriminator_location (LOC))))
 #define in_system_header (in_system_header_at (input_location))
 
 void dump_line_table_statistics (void);
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	(revision 198895)
+++ gcc/print-rtl.c	(working copy)
@@ -398,7 +398,13 @@ print_rtx (const_rtx in_rtx)
 		redundant with line number information and do not print anything
 		when there is no location information available.  */
 	    if (INSN_LOCATION (in_rtx) && insn_file (in_rtx))
-	      fprintf(outfile, " %s:%i", insn_file (in_rtx), insn_line (in_rtx));
+	      {
+		int discriminator = insn_discriminator (in_rtx);
+		fprintf (outfile, " %s:%i", insn_file (in_rtx),
+			 insn_line (in_rtx));
+		if (discriminator)
+		  fprintf (outfile, " discrim %d", discriminator);
+	      }
 #endif
 	  }
 	else if (i == 6 && GET_CODE (in_rtx) == ASM_OPERANDS)
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c	(revision 198895)
+++ gcc/tree-pretty-print.c	(working copy)
@@ -467,6 +467,7 @@ static void
 dump_location (pretty_printer *buffer, location_t loc)
 {
   expanded_location xloc = expand_location (loc);
+  int discriminator = get_discriminator_from_locus (loc);
 
   pp_character (buffer, '[');
   if (xloc.file)
@@ -475,6 +476,11 @@ dump_location (pretty_printer *buffer, location_t
       pp_string (buffer, " : ");
     }
   pp_decimal_int (buffer, xloc.line);
+  if (discriminator)
+    {
+      pp_string (buffer, " discrim ");
+      pp_decimal_int (buffer, discriminator);
+    }
   pp_string (buffer, "] ");
 }
 
Index: gcc/basic-block.h
===================================================================
--- gcc/basic-block.h	(revision 198895)
+++ gcc/basic-block.h	(working copy)
@@ -213,11 +213,6 @@ struct GTY((chain_next ("%h.next_bb"), chain_prev
 
   /* Expected frequency.  Normalized to be in range 0 to BB_FREQ_MAX.  */
   int frequency;
-
-  /* The discriminator for this block.  The discriminator distinguishes
-     among several basic blocks that share a common locus, allowing for
-     more accurate sample-based profiling.  */
-  int discriminator;
 };
 
 /* This ensures that struct gimple_bb_info is smaller than
Index: gcc/tree-diagnostic.c
===================================================================
--- gcc/tree-diagnostic.c	(revision 198895)
+++ gcc/tree-diagnostic.c	(working copy)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "input.h"
 #include "tree.h"
 #include "diagnostic.h"
 #include "tree-pretty-print.h"
@@ -107,6 +108,8 @@ maybe_unwind_expanded_macro_loc (diagnostic_contex
   unsigned ix;
   loc_map_pair loc, *iter;
 
+  if (has_discriminator (where))
+    where = map_discriminator_location (where);
   map = linemap_lookup (line_table, where);
   if (!linemap_macro_expansion_map_p (map))
     return;
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c	(revision 198895)
+++ gcc/tree-ssa.c	(working copy)
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "langhooks.h"
 #include "basic-block.h"
+#include "input.h"
 #include "function.h"
 #include "gimple-pretty-print.h"
 #include "bitmap.h"
@@ -1610,6 +1611,8 @@ warn_uninit (enum opt_code wc, tree t,
   location = (context != NULL && gimple_has_location (context))
 	     ? gimple_location (context)
 	     : DECL_SOURCE_LOCATION (var);
+  if (has_discriminator (location))
+    location = map_discriminator_location (location);
   location = linemap_resolve_location (line_table, location,
 				       LRK_SPELLING_LOCATION,
 				       NULL);
