diff mbox series

Introduce instance discriminators

Message ID ory3e9nify.fsf@lxoliva.fsfla.org
State New
Headers show
Series Introduce instance discriminators | expand

Commit Message

Alexandre Oliva July 18, 2018, 6:53 a.m. UTC
This patch is a rewrite of an earlier patch submitted at
https://gcc.gnu.org/ml/gcc-patches/2012-11/msg02340.html

With -gnateS, the Ada compiler sets itself up to output discriminators
for different instantiations of generics, but the middle and back ends
have lacked support for that.  This patch introduces the missing bits,
translating the GNAT-internal representation of the instance map to an
instance_table that maps ordinary line-map indices to instance
discriminators.

Instance discriminators are not compatible with LTO, in that the
instance mapping is not preserved in LTO dumps.  There are no plans to
preserve discriminators in them.

This patch (minus whitespace changes and tests) was regstrapped on
x86_64-linux-gnu.  The final form of the patch was tested with a
non-bootstrap build, and a single-test check-gnat run.  Ok to install?


From: Olivier Hainque <hainque@adacore.com>
for  libcpp/ChangeLog

	* include/line-map.h (ORDINARY_MAP_INDEX): New.

for  gcc/ChangeLog

    	* einput.c: New file.  Allow associating "line context"
    	extension data to instruction location info, for sets of
    	locations covered by an ordinary line_map structure.
	* einput.h: Likewise.
    	* Makefile.in (OBJS): Add einput.o.
    	* input.c (expand_location_1): On request, provide pointer to the
    	line map that was used to resolve the input location.
    	(map_expand_location): New function.  Same as expand_location,
    	also providing the map from which the input location was resolved.
    	(expand_location, expand_location_to_spelling_point): Adjust calls
    	to expand_location_1.
	(linemap_client_expand_location_to_spelling_point): Likewise.
    	* input.h (map_expand_location): Declare.
    	* emit-rtl.c (insn_location): Handle a location_lc* argument.
    	* rtl.h (insn_location): Adjust prototype.
    	* print-rtl.c (print_rtx): Adjust call to insn_location.
    	* modulo-sched.c (dump_insn_location): Likewise.
    	* tree-inline.c (copy_bb): Copy discriminator field as well.
    	* flag-types.h (loc_discriminator_type): New enum, allowing BB
    	or INSTANCE_ID discriminators.
    	* common.opt (loc_discriminator_kind): New variable, conveying the
    	kinf of discriminator we want to see emited with source locations.
    	* final.c (bb_discriminator, last_bb_discriminator): New statics,
    	to track basic block discriminators.
    	(final_start_function_1): Initialize them.
    	(final_scan_insn_1): On NOTE_INSN_BASIC_BLOCK, track
	bb_discriminator.
    	(notice_source_line): If INSN_HAS_LOCATION, update current
    	discriminator from BB or INSTANCE_ID depending on the kind we're
    	requested to convey.  When deciding to emit, account for both
    	possible kinds of discriminators.

for  gcc/ada

	* trans.c (gigi): When requested so, allocate and populate
	the gcc table controlling the emission of per-instance debug
	info.

From: Alexandre Oliva  <oliva@adacore.com>, Olivier Hainque  <hainque@adacore.com>
for  gcc/testsuite/ChangeLog

	* gnat.dg/dinst.adb: New.
	* gnat.dg/dinst_pkg.ads, gnat.dg/dinst_pkg.adb: New.
---
 gcc/Makefile.in                     |    1 +
 gcc/ada/gcc-interface/trans.c       |   10 ++++++
 gcc/common.opt                      |   12 ++++++++
 gcc/einput.c                        |   55 +++++++++++++++++++++++++++++++++++
 gcc/einput.h                        |   50 ++++++++++++++++++++++++++++++++
 gcc/emit-rtl.c                      |   11 +++++--
 gcc/final.c                         |   29 +++++++++++++++---
 gcc/flag-types.h                    |   14 +++++++++
 gcc/input.c                         |   32 +++++++++++++++++---
 gcc/input.h                         |    2 +
 gcc/modulo-sched.c                  |    2 +
 gcc/print-rtl.c                     |    2 +
 gcc/rtl.h                           |    3 +-
 gcc/testsuite/gnat.dg/dinst.adb     |   20 +++++++++++++
 gcc/testsuite/gnat.dg/dinst_pkg.adb |    7 ++++
 gcc/testsuite/gnat.dg/dinst_pkg.ads |    4 +++
 gcc/tree-inline.c                   |    2 +
 libcpp/include/line-map.h           |    8 +++++
 18 files changed, 247 insertions(+), 17 deletions(-)
 create mode 100644 gcc/einput.c
 create mode 100644 gcc/einput.h
 create mode 100644 gcc/testsuite/gnat.dg/dinst.adb
 create mode 100644 gcc/testsuite/gnat.dg/dinst_pkg.adb
 create mode 100644 gcc/testsuite/gnat.dg/dinst_pkg.ads

Comments

Richard Biener July 18, 2018, 9:58 a.m. UTC | #1
On Wed, Jul 18, 2018 at 8:53 AM Alexandre Oliva <oliva@gnu.org> wrote:
>
> This patch is a rewrite of an earlier patch submitted at
> https://gcc.gnu.org/ml/gcc-patches/2012-11/msg02340.html
>
> With -gnateS, the Ada compiler sets itself up to output discriminators
> for different instantiations of generics, but the middle and back ends
> have lacked support for that.  This patch introduces the missing bits,
> translating the GNAT-internal representation of the instance map to an
> instance_table that maps ordinary line-map indices to instance
> discriminators.
>
> Instance discriminators are not compatible with LTO, in that the
> instance mapping is not preserved in LTO dumps.  There are no plans to
> preserve discriminators in them.

Because...?  I think that's a sentence that should cause me to say "no"
to this patch ;)

Is it possible to merge the BB discriminator stuff with the new framework?

> This patch (minus whitespace changes and tests) was regstrapped on
> x86_64-linux-gnu.  The final form of the patch was tested with a
> non-bootstrap build, and a single-test check-gnat run.  Ok to install?
>
>
> From: Olivier Hainque <hainque@adacore.com>
> for  libcpp/ChangeLog
>
>         * include/line-map.h (ORDINARY_MAP_INDEX): New.
>
> for  gcc/ChangeLog
>
>         * einput.c: New file.  Allow associating "line context"
>         extension data to instruction location info, for sets of
>         locations covered by an ordinary line_map structure.
>         * einput.h: Likewise.
>         * Makefile.in (OBJS): Add einput.o.
>         * input.c (expand_location_1): On request, provide pointer to the
>         line map that was used to resolve the input location.
>         (map_expand_location): New function.  Same as expand_location,
>         also providing the map from which the input location was resolved.
>         (expand_location, expand_location_to_spelling_point): Adjust calls
>         to expand_location_1.
>         (linemap_client_expand_location_to_spelling_point): Likewise.
>         * input.h (map_expand_location): Declare.
>         * emit-rtl.c (insn_location): Handle a location_lc* argument.
>         * rtl.h (insn_location): Adjust prototype.
>         * print-rtl.c (print_rtx): Adjust call to insn_location.
>         * modulo-sched.c (dump_insn_location): Likewise.
>         * tree-inline.c (copy_bb): Copy discriminator field as well.
>         * flag-types.h (loc_discriminator_type): New enum, allowing BB
>         or INSTANCE_ID discriminators.
>         * common.opt (loc_discriminator_kind): New variable, conveying the
>         kinf of discriminator we want to see emited with source locations.
>         * final.c (bb_discriminator, last_bb_discriminator): New statics,
>         to track basic block discriminators.
>         (final_start_function_1): Initialize them.
>         (final_scan_insn_1): On NOTE_INSN_BASIC_BLOCK, track
>         bb_discriminator.
>         (notice_source_line): If INSN_HAS_LOCATION, update current
>         discriminator from BB or INSTANCE_ID depending on the kind we're
>         requested to convey.  When deciding to emit, account for both
>         possible kinds of discriminators.
>
> for  gcc/ada
>
>         * trans.c (gigi): When requested so, allocate and populate
>         the gcc table controlling the emission of per-instance debug
>         info.
>
> From: Alexandre Oliva  <oliva@adacore.com>, Olivier Hainque  <hainque@adacore.com>
> for  gcc/testsuite/ChangeLog
>
>         * gnat.dg/dinst.adb: New.
>         * gnat.dg/dinst_pkg.ads, gnat.dg/dinst_pkg.adb: New.
> ---
>  gcc/Makefile.in                     |    1 +
>  gcc/ada/gcc-interface/trans.c       |   10 ++++++
>  gcc/common.opt                      |   12 ++++++++
>  gcc/einput.c                        |   55 +++++++++++++++++++++++++++++++++++
>  gcc/einput.h                        |   50 ++++++++++++++++++++++++++++++++
>  gcc/emit-rtl.c                      |   11 +++++--
>  gcc/final.c                         |   29 +++++++++++++++---
>  gcc/flag-types.h                    |   14 +++++++++
>  gcc/input.c                         |   32 +++++++++++++++++---
>  gcc/input.h                         |    2 +
>  gcc/modulo-sched.c                  |    2 +
>  gcc/print-rtl.c                     |    2 +
>  gcc/rtl.h                           |    3 +-
>  gcc/testsuite/gnat.dg/dinst.adb     |   20 +++++++++++++
>  gcc/testsuite/gnat.dg/dinst_pkg.adb |    7 ++++
>  gcc/testsuite/gnat.dg/dinst_pkg.ads |    4 +++
>  gcc/tree-inline.c                   |    2 +
>  libcpp/include/line-map.h           |    8 +++++
>  18 files changed, 247 insertions(+), 17 deletions(-)
>  create mode 100644 gcc/einput.c
>  create mode 100644 gcc/einput.h
>  create mode 100644 gcc/testsuite/gnat.dg/dinst.adb
>  create mode 100644 gcc/testsuite/gnat.dg/dinst_pkg.adb
>  create mode 100644 gcc/testsuite/gnat.dg/dinst_pkg.ads
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 2a05a66ea9b87..f9a9fe8726b18 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1285,6 +1285,7 @@ OBJS = \
>         dwarf2cfi.o \
>         dwarf2out.o \
>         early-remat.o \
> +       einput.o \
>         emit-rtl.o \
>         et-forest.o \
>         except.o \
> diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
> index 31e098a0c707a..3ad3f83fd60f5 100644
> --- a/gcc/ada/gcc-interface/trans.c
> +++ b/gcc/ada/gcc-interface/trans.c
> @@ -45,6 +45,7 @@
>  #include "tree-iterator.h"
>  #include "gimplify.h"
>  #include "opts.h"
> +#include "einput.h"
>  #include "common/common-target.h"
>  #include "stringpool.h"
>  #include "attribs.h"
> @@ -300,6 +301,12 @@ gigi (Node_Id gnat_root,
>
>    type_annotate_only = (gigi_operating_mode == 1);
>
> +  if (Generate_SCO_Instance_Table != 0)
> +    {
> +      loc_discriminator_kind = LOC_DISCRIMINATOR_INSTANCE_ID;
> +      instance_table = (int *) xcalloc (number_file, sizeof (int));
> +    }
> +
>    for (i = 0; i < number_file; i++)
>      {
>        /* Use the identifier table to make a permanent copy of the filename as
> @@ -322,6 +329,9 @@ gigi (Node_Id gnat_root,
>        linemap_line_start (line_table, file_info_ptr[i].Num_Source_Lines, 252);
>        linemap_position_for_column (line_table, 252 - 1);
>        linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
> +
> +      if (instance_table)
> +       instance_table[i] = file_info_ptr[i].Instance;
>      }
>
>    gcc_assert (Nkind (gnat_root) == N_Compilation_Unit);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 4d031e81b09a2..b72ff1fd673e6 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -176,6 +176,18 @@ HOST_WIDE_INT function_entry_patch_area_start
>  Variable
>  enum dwarf_gnat_encodings gnat_encodings = DWARF_GNAT_ENCODINGS_DEFAULT
>
> +; Kind of discriminator information we associate with object code
> +; locations in debug information. By default this is set to the basic
> +; block discriminator, an arbitrary values that is guaranteed to be
> +; distinct for each basic block associated with a given source
> +; location. Language front-ends that support multiple instantiations
> +; of a given source template (such as Ada with generics) may instead
> +; provide instance identifiers, allowing external tools to
> +; identify which instance a given object instruction comes from.
> +
> +Variable
> +enum loc_discriminator_type loc_discriminator_kind = LOC_DISCRIMINATOR_BB
> +
>  ; -dP causes the rtl to be emitted as a comment in assembly.
>  Variable
>  int flag_dump_rtl_in_asm
> diff --git a/gcc/einput.c b/gcc/einput.c
> new file mode 100644
> index 0000000000000..32768282a34ac
> --- /dev/null
> +++ b/gcc/einput.c
> @@ -0,0 +1,55 @@
> +/* Data and functions implementing the input expansion extension services.
> +   Copyright (C) 2004-2014 Free Software Foundation, Inc.
> +
> +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 "intl.h"
> +#include "input.h"
> +#include "einput.h"
> +
> +/* Map from ordinary map index to instance id.
> +   See gcc/ada/trans.c for an example of how to fill it in.  */
> +
> +int *instance_table;
> +
> +/* Same as expand_location, filling line context information in addition.  */
> +
> +expanded_location
> +context_expand_location (source_location loc, location_lc *lcp)
> +{
> +  const struct line_map *map;
> +  expanded_location xloc = map_expand_location (loc, /*pmap=*/&map);
> +
> +  /* If an invalid LOC reaches here somehow or we don't have an instance
> +     table to query, assign a constant instance id.  Otherwise, fetch the
> +     instance id associated with the map corresponding to the input LOC.  */
> +
> +  if (map == NULL || instance_table == NULL)
> +    lcp->instance = 0;
> +  else
> +    {
> +      int map_index = ORDINARY_MAP_INDEX (linemap_check_ordinary (map),
> +                                         line_table);
> +
> +      lcp->instance = instance_table [map_index];
> +    }
> +
> +  return xloc;
> +}
> diff --git a/gcc/einput.h b/gcc/einput.h
> new file mode 100644
> index 0000000000000..099aead637492
> --- /dev/null
> +++ b/gcc/einput.h
> @@ -0,0 +1,50 @@
> +/* Extensions to the basic input location expansion services, using
> +   extra datastructures optionally filled by language front-ends.
> +   Copyright (C) 2017 Free Software Foundation, Inc.
> +
> +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/>.  */
> +
> +#ifndef GCC_EINPUT_H
> +#define GCC_EINPUT_H
> +
> +#include "input.h"
> +
> +/* For languages that have the notion of instantiating a given
> +   template multiple times, different linemaps can be allocated for
> +   each instance, which are distinguished by an instance id.  This
> +   table, which has the same indices as the ordinary linemaps in
> +   line_table, stores these instance ids.  */
> +
> +extern int *instance_table;
> +
> +/* Line context information: extra data associated with source *lines* (not
> +   individual source locations), filled by context_expand_location from extra
> +   tables that front-ends may provide by the time we reach the "final"
> +   pass.  */
> +
> +/* The line context information per se, filled by context_expand_location
> +   below from data found in the tables declared above.  */
> +
> +typedef struct location_lc {
> +  /* The instance id associated with the source line, if any.  */
> +  int instance;
> +} location_lc;
> +
> +extern expanded_location context_expand_location (source_location loc,
> +                                                 location_lc *lcp);
> +
> +#endif
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index e4b070486e87e..64af8082c5ddc 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -6567,11 +6567,16 @@ insn_file (const rtx_insn *insn)
>    return LOCATION_FILE (INSN_LOCATION (insn));
>  }
>
> -/* Return expanded location of the statement that produced this insn.  */
> +/* Return expanded location of the statement that produced INSN, and
> +   fill the associated line context information we have into LC if not
> +   NULL.  */
>  expanded_location
> -insn_location (const rtx_insn *insn)
> +insn_location (const rtx_insn *insn, location_lc *lcp)
>  {
> -  return expand_location (INSN_LOCATION (insn));
> +  if (lcp == NULL)
> +    return expand_location (INSN_LOCATION (insn));
> +  else
> +    return context_expand_location (INSN_LOCATION (insn), lcp);
>  }
>
>  /* Return true if memory model MODEL requires a pre-operation (release-style)
> diff --git a/gcc/final.c b/gcc/final.c
> index 445a3fe938a67..b1266affbc108 100644
> --- a/gcc/final.c
> +++ b/gcc/final.c
> @@ -122,12 +122,20 @@ static int last_linenum;
>  /* Column number of last NOTE.  */
>  static int last_columnnum;
>
> -/* Last discriminator written to assembly.  */
> +/* Discriminator written to assembly.  */
>  static int last_discriminator;
>
> -/* Discriminator of current block.  */
> +/* Discriminator to be written to assembly for current instruction.
> +   Note: actual usage depends on loc_discriminator_kind setting.  */
>  static int discriminator;
>
> +/* Discriminator identifying current basic block among others sharing
> +   the same locus.  */
> +static int bb_discriminator;
> +
> +/* Basic block discriminator for previous instruction.  */
> +static int last_bb_discriminator;
> +
>  /* Highest line number in current block.  */
>  static int high_block_linenum;
>
> @@ -1701,6 +1709,7 @@ final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
>    last_linenum = LOCATION_LINE (prologue_location);
>    last_columnnum = LOCATION_COLUMN (prologue_location);
>    last_discriminator = discriminator = 0;
> +  last_bb_discriminator = bb_discriminator = 0;
>
>    high_block_linenum = high_function_linenum = last_linenum;
>
> @@ -2236,8 +2245,7 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>           if (targetm.asm_out.unwind_emit)
>             targetm.asm_out.unwind_emit (asm_out_file, insn);
>
> -          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
> -
> +         bb_discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
>           break;
>
>         case NOTE_INSN_EH_REGION_BEG:
> @@ -3188,10 +3196,21 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
>      }
>    else if (INSN_HAS_LOCATION (insn))
>      {
> -      expanded_location xloc = insn_location (insn);
> +      location_lc llc;
> +      expanded_location xloc = insn_location (insn, &llc);
>        filename = xloc.file;
>        linenum = xloc.line;
>        columnnum = xloc.column;
> +
> +      switch (loc_discriminator_kind)
> +       {
> +       case LOC_DISCRIMINATOR_BB:
> +         discriminator = bb_discriminator;
> +         break;
> +       case LOC_DISCRIMINATOR_INSTANCE_ID:
> +         discriminator = llc.instance;
> +         break;
> +       }
>      }
>    else
>      {
> diff --git a/gcc/flag-types.h b/gcc/flag-types.h
> index 500f6638f36ac..15e80188ef040 100644
> --- a/gcc/flag-types.h
> +++ b/gcc/flag-types.h
> @@ -90,6 +90,20 @@ enum debug_struct_file
>    DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
>  };
>
> +/* Information stored in source location discriminators.  */
> +
> +enum loc_discriminator_type
> +{
> +  LOC_DISCRIMINATOR_BB,                /* Basic block discriminator.
> +                                  Arbitrary, distinct values are set
> +                                  for each of the basic blocks that
> +                                  share a given source location.  */
> +  LOC_DISCRIMINATOR_INSTANCE_ID        /* Instance identifier provided by a
> +                                  language front-end to differentiate
> +                                  instances of a given generic
> +                                  template.  */
> +};
> +
>  /* Balance between GNAT encodings and standard DWARF to emit.  */
>
>  enum dwarf_gnat_encodings
> diff --git a/gcc/input.c b/gcc/input.c
> index d65a82dc26eac..f5a17ebbdf239 100644
> --- a/gcc/input.c
> +++ b/gcc/input.c
> @@ -149,15 +149,19 @@ static const size_t fcache_line_record_size = 100;
>     location towards its expansion point) that is in real source
>     code.
>
> +   If PMAP is non-null, *PMAP is set to designate the line map
> +   from which the location was resolved.
> +
>     ASPECT controls which part of the location to use.  */
>
>  static expanded_location
>  expand_location_1 (source_location loc,
>                    bool expansion_point_p,
> +                  const struct line_map **pmap,
>                    enum location_aspect aspect)
>  {
>    expanded_location xloc;
> -  const line_map_ordinary *map;
> +  const line_map_ordinary *map = NULL;
>    enum location_resolution_kind lrk = LRK_MACRO_EXPANSION_POINT;
>    tree block = NULL;
>
> @@ -203,14 +207,16 @@ expand_location_1 (source_location loc,
>           {
>             source_location start = get_start (loc);
>             if (start != loc)
> -             return expand_location_1 (start, expansion_point_p, aspect);
> +             return expand_location_1 (start, expansion_point_p, NULL,
> +                                       aspect);
>           }
>           break;
>         case LOCATION_ASPECT_FINISH:
>           {
>             source_location finish = get_finish (loc);
>             if (finish != loc)
> -             return expand_location_1 (finish, expansion_point_p, aspect);
> +             return expand_location_1 (finish, expansion_point_p, NULL,
> +                                       aspect);
>           }
>           break;
>         }
> @@ -221,6 +227,9 @@ expand_location_1 (source_location loc,
>    if (loc <= BUILTINS_LOCATION)
>      xloc.file = loc == UNKNOWN_LOCATION ? NULL : _("<built-in>");
>
> +  if (pmap)
> +    *pmap = map;
> +
>    return xloc;
>  }
>
> @@ -802,7 +811,17 @@ is_location_from_builtin_token (source_location loc)
>  expanded_location
>  expand_location (source_location loc)
>  {
> -  return expand_location_1 (loc, /*expansion_point_p=*/true,
> +  return expand_location_1 (loc, /*expansion_point_p=*/true, /*pmap=*/NULL,
> +                           LOCATION_ASPECT_CARET);
> +}
> +
> +/* Same as expand_location, filling PMAP with the map that
> +   was used to resolve, if PMAP is not null.  */
> +
> +expanded_location
> +map_expand_location (source_location loc, const struct line_map **pmap)
> +{
> +  return expand_location_1 (loc, /*expansion_point_p=*/true, /*pmap=*/pmap,
>                             LOCATION_ASPECT_CARET);
>  }
>
> @@ -815,7 +834,7 @@ expand_location (source_location loc)
>  expanded_location
>  expand_location_to_spelling_point (source_location loc)
>  {
> -  return expand_location_1 (loc, /*expansion_point_p=*/false,
> +  return expand_location_1 (loc, /*expansion_point_p=*/false, /*pmap=*/NULL,
>                             LOCATION_ASPECT_CARET);
>  }
>
> @@ -832,7 +851,8 @@ expanded_location
>  linemap_client_expand_location_to_spelling_point (source_location loc,
>                                                   enum location_aspect aspect)
>  {
> -  return expand_location_1 (loc, /*expansion_point_p=*/false, aspect);
> +  return expand_location_1 (loc, /*expansion_point_p=*/false, /*pmap=*/NULL,
> +                           aspect);
>  }
>
>
> diff --git a/gcc/input.h b/gcc/input.h
> index 4619663519a46..25cb8a94147cb 100644
> --- a/gcc/input.h
> +++ b/gcc/input.h
> @@ -37,6 +37,8 @@ extern GTY(()) struct line_maps *saved_line_table;
>  STATIC_ASSERT (BUILTINS_LOCATION < RESERVED_LOCATION_COUNT);
>
>  extern bool is_location_from_builtin_token (source_location);
> +extern expanded_location map_expand_location (source_location loc,
> +                                             const struct line_map **pmap);
>  extern expanded_location expand_location (source_location);
>
>  /* A class capturing the bounds of a buffer, to allow for run-time
> diff --git a/gcc/modulo-sched.c b/gcc/modulo-sched.c
> index 9a27365bfbc4e..1eb9362d31065 100644
> --- a/gcc/modulo-sched.c
> +++ b/gcc/modulo-sched.c
> @@ -1237,7 +1237,7 @@ dump_insn_location (rtx_insn *insn)
>  {
>    if (dump_file && INSN_HAS_LOCATION (insn))
>      {
> -      expanded_location xloc = insn_location (insn);
> +      expanded_location xloc = insn_location (insn, NULL);
>        fprintf (dump_file, " %s:%i", xloc.file, xloc.line);
>      }
>  }
> diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
> index 37c0d53fae276..0632bf0ec1a99 100644
> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
> @@ -397,7 +397,7 @@ rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx)
>           when there is no location information available.  */
>        if (INSN_HAS_LOCATION (in_insn))
>         {
> -         expanded_location xloc = insn_location (in_insn);
> +         expanded_location xloc = insn_location (in_insn, NULL);
>           fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
>         }
>  #endif
> diff --git a/gcc/rtl.h b/gcc/rtl.h
> index 565ce3abbe4e1..05c42fe515c39 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>  #endif  /* GENERATOR_FILE */
>
>  #include "hard-reg-set.h"
> +#include "einput.h"
>
>  /* Value used by some passes to "recognize" noop moves as valid
>   instructions.  */
> @@ -3285,7 +3286,7 @@ extern rtx_insn *prev_cc0_setter (rtx_insn *);
>  extern int insn_line (const rtx_insn *);
>  extern const char * insn_file (const rtx_insn *);
>  extern tree insn_scope (const rtx_insn *);
> -extern expanded_location insn_location (const rtx_insn *);
> +extern expanded_location insn_location (const rtx_insn *, location_lc *);
>  extern location_t prologue_location, epilogue_location;
>
>  /* In jump.c */
> diff --git a/gcc/testsuite/gnat.dg/dinst.adb b/gcc/testsuite/gnat.dg/dinst.adb
> new file mode 100644
> index 0000000000000..460e6c5f914f4
> --- /dev/null
> +++ b/gcc/testsuite/gnat.dg/dinst.adb
> @@ -0,0 +1,20 @@
> +-- { dg-do compile { target *-*-gnu* } }
> +-- { dg-options "-gnateS -gdwarf -g -O -gno-column-info" }
> +-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 1\n" } } */
> +-- { dg-final { scan-assembler-not "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 2\n" } } */
> +-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 3\n" } } */
> +-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 4\n" } } */
> +
> +
> +with DInst_Pkg;
> +procedure DInst is
> +   package I1 is new DInst_Pkg; -- instance 1
> +   package I2 is new DInst_Pkg; -- instance 2
> +   package I3 is new DInst_Pkg; -- instance 3
> +   package I4 is new DInst_Pkg; -- instance 4
> +begin
> +   I1.Foo;
> +   -- I2.Foo;
> +   I3.Foo;
> +   I4.Foo;
> +end;
> diff --git a/gcc/testsuite/gnat.dg/dinst_pkg.adb b/gcc/testsuite/gnat.dg/dinst_pkg.adb
> new file mode 100644
> index 0000000000000..09a9baea1e4e2
> --- /dev/null
> +++ b/gcc/testsuite/gnat.dg/dinst_pkg.adb
> @@ -0,0 +1,7 @@
> +with Ada.Text_IO; use Ada.Text_IO;
> +package body DInst_Pkg is
> +   procedure Foo is
> +   begin
> +      Put_Line ("hello there");
> +   end;
> +end;
> diff --git a/gcc/testsuite/gnat.dg/dinst_pkg.ads b/gcc/testsuite/gnat.dg/dinst_pkg.ads
> new file mode 100644
> index 0000000000000..d22afdbcd6af5
> --- /dev/null
> +++ b/gcc/testsuite/gnat.dg/dinst_pkg.ads
> @@ -0,0 +1,4 @@
> +generic
> +package DInst_Pkg is
> +   procedure Foo;
> +end;
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index 6a16ce546cb04..1c75d805566cd 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -1813,6 +1813,8 @@ copy_bb (copy_body_data *id, basic_block bb,
>    copy_basic_block = create_basic_block (NULL, (basic_block) prev->aux);
>    copy_basic_block->count = bb->count.apply_scale (num, den);
>
> +  copy_basic_block->discriminator = bb->discriminator;
> +
>    copy_gsi = gsi_start_bb (copy_basic_block);
>
>    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
> index ba1750d3cf1bb..0c6fcdbe5ff8c 100644
> --- a/libcpp/include/line-map.h
> +++ b/libcpp/include/line-map.h
> @@ -926,6 +926,14 @@ LINEMAPS_ORDINARY_MAP_AT (const line_maps *set, int index)
>    return &set->info_ordinary.maps[index];
>  }
>
> +/* Return the index of ORD_MAP, which is an ordinary map in SET.  */
> +
> +inline int
> +ORDINARY_MAP_INDEX (const line_map_ordinary *ord_map, const line_maps *set)
> +{
> +  return ord_map - LINEMAPS_ORDINARY_MAP_AT (set, 0);
> +}
> +
>  /* Return the number of ordinary maps allocated in the line table
>     SET.  */
>  inline unsigned int
>
>
> --
> Alexandre Oliva, freedom fighter   https://FSFLA.org/blogs/lxo
> Be the change, be Free!         FSF Latin America board member
> GNU Toolchain Engineer                Free Software Evangelist
Alexandre Oliva July 19, 2018, 7:21 a.m. UTC | #2
On Jul 18, 2018, Richard Biener <richard.guenther@gmail.com> wrote:

> On Wed, Jul 18, 2018 at 8:53 AM Alexandre Oliva <oliva@gnu.org> wrote:
>> Instance discriminators are not compatible with LTO, in that the
>> instance mapping is not preserved in LTO dumps.  There are no plans to
>> preserve discriminators in them.

> Because...

... it follows existing practice.  BB discriminators are not saved for
LTO either.  They could be saved along with the CFG, but AFAICT they
aren't.  As for instance discriminators, we might be able to save them
along with LOC information, but that would be quite wasteful, and
because of the way ordinary maps are reconstructed when reading in the
LTO data, we'd end up with yet another internal representation for
line_maps.  I was told there was no interest from our customers in using
the converage and monitoring aspects of instance discriminators when
performing link-time optimizations, and thus that it made sense to
follow existing practice.


I suspect there might be a way to assign instance discriminator numbers
to individual function DECLs, and then walk up the lexical block tree to
identify the DECL containing the block so as to obtain the discriminator
number.  This would be a lot less efficient, algorithmically speaking,
but, provided that LTO dumps discriminator numbers as part of the decls,
and enough info to reconstruct the lexical block trees, including the
inlined-function enclosing blocks, that should work even for LTO, at
least as long as different decls are maintained for each instance.

Indeed, if this is the case, code ranges of lexical blocks in inlined
subroutines would suffice to identify each instantiation, without the
need for discriminators.  It would be a lot more expensive to gather the
information from that debug info than from discriminators, though.

All this said, there doesn't seem to be much interest in that from Ada
users to justify by itself the pursuit of yet another internal
representation.  I wonder if this sort of discriminator might be of
interest for users of C++ templates as well.
Richard Biener July 19, 2018, 9:02 a.m. UTC | #3
On Thu, Jul 19, 2018 at 9:21 AM Alexandre Oliva <oliva@gnu.org> wrote:
>
> On Jul 18, 2018, Richard Biener <richard.guenther@gmail.com> wrote:
>
> > On Wed, Jul 18, 2018 at 8:53 AM Alexandre Oliva <oliva@gnu.org> wrote:
> >> Instance discriminators are not compatible with LTO, in that the
> >> instance mapping is not preserved in LTO dumps.  There are no plans to
> >> preserve discriminators in them.
>
> > Because...
>
> ... it follows existing practice.  BB discriminators are not saved for
> LTO either.

Oh, that probably wasn't omitted on purpose.  Cary said it was used
for profiling but I can't see any such use.

Is the instance discriminator stuff also used for profiling?  I agree
that coverage probably isn't depending on LTO.

>  They could be saved along with the CFG, but AFAICT they
> aren't.  As for instance discriminators, we might be able to save them
> along with LOC information, but that would be quite wasteful, and
> because of the way ordinary maps are reconstructed when reading in the
> LTO data, we'd end up with yet another internal representation for
> line_maps.  I was told there was no interest from our customers in using
> the converage and monitoring aspects of instance discriminators when
> performing link-time optimizations, and thus that it made sense to
> follow existing practice.
>
>
> I suspect there might be a way to assign instance discriminator numbers
> to individual function DECLs, and then walk up the lexical block tree to
> identify the DECL containing the block so as to obtain the discriminator
> number.  This would be a lot less efficient, algorithmically speaking,
> but, provided that LTO dumps discriminator numbers as part of the decls,
> and enough info to reconstruct the lexical block trees, including the
> inlined-function enclosing blocks, that should work even for LTO, at
> least as long as different decls are maintained for each instance.
>
> Indeed, if this is the case, code ranges of lexical blocks in inlined
> subroutines would suffice to identify each instantiation, without the
> need for discriminators.  It would be a lot more expensive to gather the
> information from that debug info than from discriminators, though.
>
> All this said, there doesn't seem to be much interest in that from Ada
> users to justify by itself the pursuit of yet another internal
> representation.  I wonder if this sort of discriminator might be of
> interest for users of C++ templates as well.
>
> --
> Alexandre Oliva, freedom fighter   https://FSFLA.org/blogs/lxo
> Be the change, be Free!         FSF Latin America board member
> GNU Toolchain Engineer                Free Software Evangelist
Alexandre Oliva July 24, 2018, 6:50 p.m. UTC | #4
On Jul 19, 2018, Richard Biener <richard.guenther@gmail.com> wrote:

> Oh, that probably wasn't omitted on purpose.  Cary said it was used
> for profiling but I can't see any such use.

> Is the instance discriminator stuff also used for profiling?

Not that I know, but...  I probably wouldn't know yet ;-)

Anyway, it was easy enough to implement this:

>> I suspect there might be a way to assign instance discriminator numbers
>> to individual function DECLs, and then walk up the lexical block tree to
>> identify the DECL containing the block so as to obtain the discriminator
>> number.

and then, in a subsequent patch, I went ahead and added support for LTO,
saving and recovering discriminator info for instances and, while at
that, for basic blocks too.

Besides sucessfully regstrapping the first two patches on
x86_64-linux-gnu, I have tested this patchset with an additional
bootstrap with the third (throw-away) patch, that adds -gnateS to Ada
compilations in gcc/ada, libada and gnattools.  I also tested the saving
and restoring of discriminators for LTO by manually inspecting the line
number tables in LTO-recompiled executables, to check that they retained
the instance or BB discriminator numbers that went into the non-LTO
object files.

Ok to install the first two patches?  (the third is just for reference)


Introduce instance discriminators

From: Alexandre Oliva <oliva@adacore.com>

With -gnateS, the Ada compiler sets itself up to output discriminators
for different instantiations of generics, but the middle and back ends
have lacked support for that.  This patch introduces the missing bits,
translating the GNAT-internal representation of the per-file instance
map to an instance_table that maps decls to instance discriminators.


From: Alexandre Oliva  <oliva@adacore.com>, Olivier Hainque  <hainque@adacore.com>
for  gcc/ChangeLog

	* debug.h (decl_to_instance_map_t): New type.
	(decl_to_instance_map): Declare.
	(maybe_create_decl_to_instance_map): New inline function.
    	* final.c (bb_discriminator, last_bb_discriminator): New statics,
    	to track basic block discriminators.
    	(final_start_function_1): Initialize them.
    	(final_scan_insn_1): On NOTE_INSN_BASIC_BLOCK, track
	bb_discriminator.
	(decl_to_instance_map): New variable.
	(map_decl_to_instance, maybe_set_discriminator): New functions.
    	(notice_source_line): Set discriminator.

for  gcc/ada

	* trans.c: Include debug.h.
	(file_map): New static variable.
	(gigi): Set it.  Create decl_to_instance_map when needed.
	(Subprogram_Body_to_gnu): Pass gnu_subprog_decl to...
	(Sloc_to_locus): ... this.  Add decl parm, map it to instance.
	* gigi.h (Sloc_to_locus): Adjust declaration.

for  gcc/testsuite/ChangeLog

	* gnat.dg/dinst.adb: New.
	* gnat.dg/dinst_pkg.ads, gnat.dg/dinst_pkg.adb: New.
---
 gcc/ada/gcc-interface/gigi.h        |    2 +
 gcc/ada/gcc-interface/trans.c       |   29 ++++++++++++---
 gcc/debug.h                         |   15 ++++++++
 gcc/final.c                         |   70 +++++++++++++++++++++++++++++++++--
 gcc/testsuite/gnat.dg/dinst.adb     |   20 ++++++++++
 gcc/testsuite/gnat.dg/dinst_pkg.adb |    7 ++++
 gcc/testsuite/gnat.dg/dinst_pkg.ads |    4 ++
 7 files changed, 137 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gnat.dg/dinst.adb
 create mode 100644 gcc/testsuite/gnat.dg/dinst_pkg.adb
 create mode 100644 gcc/testsuite/gnat.dg/dinst_pkg.ads

diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index a75cb9094491..b890195cefc3 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -285,7 +285,7 @@ extern void process_type (Entity_Id gnat_entity);
    location and false if it doesn't.  If CLEAR_COLUMN is true, set the column
    information to 0.  */
 extern bool Sloc_to_locus (Source_Ptr Sloc, location_t *locus,
-			   bool clear_column = false);
+			   bool clear_column = false, const_tree decl = 0);
 
 /* Post an error message.  MSG is the error message, properly annotated.
    NODE is the node at which to post the error and the node to use for the
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 31e098a0c707..0371d00fce18 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -41,6 +41,7 @@
 #include "stmt.h"
 #include "varasm.h"
 #include "output.h"
+#include "debug.h"
 #include "libfuncs.h"	/* For set_stack_check_libfunc.  */
 #include "tree-iterator.h"
 #include "gimplify.h"
@@ -255,6 +256,12 @@ static tree create_init_temporary (const char *, tree, tree *, Node_Id);
 static const char *extract_encoding (const char *) ATTRIBUTE_UNUSED;
 static const char *decode_name (const char *) ATTRIBUTE_UNUSED;
 
+/* This makes gigi's file_info_ptr visible in this translation unit,
+   so that Sloc_to_locus can look it up when deciding whether to map
+   decls to instances.  */
+
+static struct File_Info_Type *file_map;
+
 /* This is the main program of the back-end.  It sets up all the table
    structures and then generates code.  */
 
@@ -300,6 +307,12 @@ gigi (Node_Id gnat_root,
 
   type_annotate_only = (gigi_operating_mode == 1);
 
+  if (Generate_SCO_Instance_Table != 0)
+    {
+      file_map = file_info_ptr;
+      maybe_create_decl_to_instance_map (number_file);
+    }
+
   for (i = 0; i < number_file; i++)
     {
       /* Use the identifier table to make a permanent copy of the filename as
@@ -701,6 +714,7 @@ gigi (Node_Id gnat_root,
     }
 
   /* Destroy ourselves.  */
+  file_map = NULL;
   destroy_gnat_decl ();
   destroy_gnat_utils ();
 
@@ -3771,7 +3785,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
     }
 
   /* Set the line number in the decl to correspond to that of the body.  */
-  if (!Sloc_to_locus (Sloc (gnat_node), &locus))
+  if (!Sloc_to_locus (Sloc (gnat_node), &locus, false, gnu_subprog_decl))
     locus = input_location;
   DECL_SOURCE_LOCATION (gnu_subprog_decl) = locus;
 
@@ -9970,12 +9984,14 @@ maybe_implicit_deref (tree exp)
   return exp;
 }
 
-/* Convert SLOC into LOCUS.  Return true if SLOC corresponds to a source code
-   location and false if it doesn't.  If CLEAR_COLUMN is true, set the column
-   information to 0.  */
+/* Convert SLOC into LOCUS.  Return true if SLOC corresponds to a
+   source code location and false if it doesn't.  If CLEAR_COLUMN is
+   true, set the column information to 0.  If DECL is given and SLOC
+   refers to a File with an instance, map DECL to that instance.  */
 
 bool
-Sloc_to_locus (Source_Ptr Sloc, location_t *locus, bool clear_column)
+Sloc_to_locus (Source_Ptr Sloc, location_t *locus, bool clear_column,
+	       const_tree decl)
 {
   if (Sloc == No_Location)
     return false;
@@ -9999,6 +10015,9 @@ Sloc_to_locus (Source_Ptr Sloc, location_t *locus, bool clear_column)
   *locus
     = linemap_position_for_line_and_column (line_table, map, line, column);
 
+  if (file_map && file_map[file - 1].Instance)
+    decl_to_instance_map->put (decl, file_map[file - 1].Instance);
+
   return true;
 }
 
diff --git a/gcc/debug.h b/gcc/debug.h
index 126e56e8c8d7..3f78d0602252 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -256,4 +256,19 @@ extern bool dwarf2out_default_as_locview_support (void);
 extern const struct gcc_debug_hooks *
 dump_go_spec_init (const char *, const struct gcc_debug_hooks *);
 
+/* Instance discriminator mapping table.  See final.c.  */
+typedef hash_map<const_tree, int> decl_to_instance_map_t;
+extern decl_to_instance_map_t *decl_to_instance_map;
+
+/* Allocate decl_to_instance_map with COUNT slots to begin wtih, if it
+ * hasn't been allocated yet.  */
+
+static inline decl_to_instance_map_t *
+maybe_create_decl_to_instance_map (int count = 13)
+{
+  if (!decl_to_instance_map)
+    decl_to_instance_map = new decl_to_instance_map_t (count);
+  return decl_to_instance_map;
+}
+
 #endif /* !GCC_DEBUG_H  */
diff --git a/gcc/final.c b/gcc/final.c
index 6fa4acdaa2e9..a8338e0394c1 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -122,12 +122,20 @@ static int last_linenum;
 /* Column number of last NOTE.  */
 static int last_columnnum;
 
-/* Last discriminator written to assembly.  */
+/* Discriminator written to assembly.  */
 static int last_discriminator;
 
-/* Discriminator of current block.  */
+/* Discriminator to be written to assembly for current instruction.
+   Note: actual usage depends on loc_discriminator_kind setting.  */
 static int discriminator;
 
+/* Discriminator identifying current basic block among others sharing
+   the same locus.  */
+static int bb_discriminator;
+
+/* Basic block discriminator for previous instruction.  */
+static int last_bb_discriminator;
+
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
@@ -1701,6 +1709,7 @@ final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
   last_linenum = LOCATION_LINE (prologue_location);
   last_columnnum = LOCATION_COLUMN (prologue_location);
   last_discriminator = discriminator = 0;
+  last_bb_discriminator = bb_discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
@@ -2236,8 +2245,7 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  if (targetm.asm_out.unwind_emit)
 	    targetm.asm_out.unwind_emit (asm_out_file, insn);
 
-          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
-
+	  bb_discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
 	  break;
 
 	case NOTE_INSN_EH_REGION_BEG:
@@ -3144,6 +3152,58 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
 }
 
 
+
+/* Map DECLs to instance discriminators.  This is allocated and
+   defined in ada/gcc-interfaces/trans.c, when compiling with -gnateS.  */
+
+decl_to_instance_map_t *decl_to_instance_map;
+
+/* Return the instance number assigned to DECL.  */
+
+static inline int
+map_decl_to_instance (const_tree decl)
+{
+  int *inst;
+
+  if (!decl_to_instance_map || !decl || !DECL_P (decl))
+    return 0;
+
+  inst = decl_to_instance_map->get (decl);
+
+  if (!inst)
+    return 0;
+
+  return *inst;
+}
+
+/* Set DISCRIMINATOR to the appropriate value, possibly derived from LOC.  */
+
+static inline void
+maybe_set_discriminator (location_t loc)
+{
+  if (!decl_to_instance_map)
+    discriminator = bb_discriminator;
+  else
+    {
+      tree block = LOCATION_BLOCK (loc);
+
+      while (block && TREE_CODE (block) == BLOCK
+	     && !inlined_function_outer_scope_p (block))
+	block = BLOCK_SUPERCONTEXT (block);
+
+      tree decl;
+
+      if (!block)
+	decl = current_function_decl;
+      else if (DECL_P (block))
+	decl = block;
+      else
+	decl = block_ultimate_origin (block);
+
+      discriminator = map_decl_to_instance (decl);
+    }
+}
+
 /* 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
    breakpoint location.  */
@@ -3178,6 +3238,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
+      maybe_set_discriminator (loc);
       force_source_line = true;
     }
   else if (override_filename)
@@ -3192,6 +3253,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
+      maybe_set_discriminator (INSN_LOCATION (insn));
     }
   else
     {
diff --git a/gcc/testsuite/gnat.dg/dinst.adb b/gcc/testsuite/gnat.dg/dinst.adb
new file mode 100644
index 000000000000..460e6c5f914f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dinst.adb
@@ -0,0 +1,20 @@
+-- { dg-do compile { target *-*-gnu* } }
+-- { dg-options "-gnateS -gdwarf -g -O -gno-column-info" }
+-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 1\n" } } */
+-- { dg-final { scan-assembler-not "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 2\n" } } */
+-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 3\n" } } */
+-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 4\n" } } */
+
+
+with DInst_Pkg;
+procedure DInst is
+   package I1 is new DInst_Pkg; -- instance 1 
+   package I2 is new DInst_Pkg; -- instance 2
+   package I3 is new DInst_Pkg; -- instance 3
+   package I4 is new DInst_Pkg; -- instance 4
+begin
+   I1.Foo;
+   -- I2.Foo;
+   I3.Foo;
+   I4.Foo;
+end;
diff --git a/gcc/testsuite/gnat.dg/dinst_pkg.adb b/gcc/testsuite/gnat.dg/dinst_pkg.adb
new file mode 100644
index 000000000000..09a9baea1e4e
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dinst_pkg.adb
@@ -0,0 +1,7 @@
+with Ada.Text_IO; use Ada.Text_IO;
+package body DInst_Pkg is
+   procedure Foo is
+   begin
+      Put_Line ("hello there");
+   end;
+end;
diff --git a/gcc/testsuite/gnat.dg/dinst_pkg.ads b/gcc/testsuite/gnat.dg/dinst_pkg.ads
new file mode 100644
index 000000000000..d22afdbcd6af
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dinst_pkg.ads
@@ -0,0 +1,4 @@
+generic
+package DInst_Pkg is
+   procedure Foo;
+end;


Save discriminator info for LTO

From: Alexandre Oliva <oliva@adacore.com>

for  gcc/ChangeLog

	* gimple-streamer-in.c (input_bb): Restore BB discriminator.
	* gimple-streamer-out.c (output_bb): Save it.
	* lto-streamer-in.c (input_struct_function_base): Restore
	instance discriminator if available.  Create map on demand.
	* lto-streamer-out.c (output_struct_function_base): Save it if
	available.
	* final.c (decl_to_instance_map): Document LTO strategy.
---
 gcc/final.c               |    6 +++++-
 gcc/gimple-streamer-in.c  |    1 +
 gcc/gimple-streamer-out.c |    1 +
 gcc/lto-streamer-in.c     |    8 ++++++++
 gcc/lto-streamer-out.c    |    8 ++++++++
 5 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/gcc/final.c b/gcc/final.c
index a8338e0394c1..842e5e067db7 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3154,7 +3154,11 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
 
 
 /* Map DECLs to instance discriminators.  This is allocated and
-   defined in ada/gcc-interfaces/trans.c, when compiling with -gnateS.  */
+   defined in ada/gcc-interfaces/trans.c, when compiling with -gnateS.
+   Mappings from this table are saved and restored for LTO, so
+   link-time compilation will have this map set, at least in
+   partitions containing at least one DECL with an associated instance
+   discriminator.  */
 
 decl_to_instance_map_t *decl_to_instance_map;
 
diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c
index 6ffef29bf1f8..31ba4cc4e00e 100644
--- a/gcc/gimple-streamer-in.c
+++ b/gcc/gimple-streamer-in.c
@@ -270,6 +270,7 @@ input_bb (struct lto_input_block *ib, enum LTO_tags tag,
     bb->count
       = bb->count.apply_scale (count_materialization_scale, REG_BR_PROB_BASE);
   bb->flags = streamer_read_hwi (ib);
+  bb->discriminator = streamer_read_hwi (ib);
 
   /* LTO_bb1 has statements.  LTO_bb0 does not.  */
   if (tag == LTO_bb0)
diff --git a/gcc/gimple-streamer-out.c b/gcc/gimple-streamer-out.c
index d120aa902952..3a2368047cc6 100644
--- a/gcc/gimple-streamer-out.c
+++ b/gcc/gimple-streamer-out.c
@@ -212,6 +212,7 @@ output_bb (struct output_block *ob, basic_block bb, struct function *fn)
   streamer_write_uhwi (ob, bb->index);
   bb->count.stream_out (ob);
   streamer_write_hwi (ob, bb->flags);
+  streamer_write_hwi (ob, bb->discriminator);
 
   if (!gsi_end_p (bsi) || phi_nodes (bb))
     {
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 8529c82376b8..4ddcc8f7ddd9 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1013,6 +1013,14 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
   /* Input the function start and end loci.  */
   fn->function_start_locus = stream_input_location_now (&bp, data_in);
   fn->function_end_locus = stream_input_location_now (&bp, data_in);
+
+  /* Restore the instance discriminators if present.  */
+  int instance_number = bp_unpack_value (&bp, 1);
+  if (instance_number)
+    {
+      instance_number = bp_unpack_value (&bp, sizeof (int) * CHAR_BIT);
+      maybe_create_decl_to_instance_map ()->put (fn->decl, instance_number);
+    }
 }
 
 
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 78b90e7f5962..9e28d678342c 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -2038,6 +2038,14 @@ output_struct_function_base (struct output_block *ob, struct function *fn)
   stream_output_location (ob, &bp, fn->function_start_locus);
   stream_output_location (ob, &bp, fn->function_end_locus);
 
+  /* Save the instance discriminator if present.  */
+  int *instance_number_p = NULL;
+  if (decl_to_instance_map)
+    instance_number_p = decl_to_instance_map->get (fn->decl);
+  bp_pack_value (&bp, !!instance_number_p, 1);
+  if (instance_number_p)
+    bp_pack_value (&bp, *instance_number_p, sizeof (int) * CHAR_BIT);
+
   streamer_write_bitpack (&bp);
 }
 

This patch is just for reference.  It's what I used in a bootstrap to
get more coverage in testing the function discovery logic to extract
instance numbers.  It caught a number of problems in my initial
attempts.

diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in
index d51d3973b4d1..1625989ae585 100644
--- a/gcc/ada/gcc-interface/Make-lang.in
+++ b/gcc/ada/gcc-interface/Make-lang.in
@@ -45,7 +45,7 @@ RMDIR = rm -rf
 
 
 # Extra flags to pass to recursive makes.
-COMMON_ADAFLAGS= -gnatpg
+COMMON_ADAFLAGS= -gnatpg -gnateS
 ifeq ($(TREECHECKING),)
 CHECKING_ADAFLAGS=
 else
diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in
index 601f23afc1c6..c710a5e37fdf 100644
--- a/gcc/ada/gcc-interface/Makefile.in
+++ b/gcc/ada/gcc-interface/Makefile.in
@@ -104,13 +104,13 @@ TEXI2DVI = texi2dvi
 TEXI2PDF = texi2pdf
 GNATBIND_FLAGS = -static -x
 ADA_CFLAGS =
-ADAFLAGS = -W -Wall -gnatpg -gnata
+ADAFLAGS = -W -Wall -gnatpg -gnata -gnateS
 FORCE_DEBUG_ADAFLAGS = -g
 NO_INLINE_ADAFLAGS = -fno-inline
 NO_OMIT_ADAFLAGS = -fno-omit-frame-pointer
 NO_SIBLING_ADAFLAGS = -fno-optimize-sibling-calls
 NO_REORDER_ADAFLAGS = -fno-toplevel-reorder
-GNATLIBFLAGS = -W -Wall -gnatpg -nostdinc
+GNATLIBFLAGS = -W -Wall -gnatpg -gnateS -nostdinc
 GNATLIBCFLAGS = -g -O2
 # Pretend that _Unwind_GetIPInfo is available for the target by default.  This
 # should be autodetected during the configuration of libada and passed down to
diff --git a/gnattools/Makefile.in b/gnattools/Makefile.in
index d19147fe5d74..6ecae0297b74 100644
--- a/gnattools/Makefile.in
+++ b/gnattools/Makefile.in
@@ -52,7 +52,7 @@ WARN_CFLAGS = @warn_cflags@
 ADA_CFLAGS=@ADA_CFLAGS@
 
 # Variables for gnattools.
-ADAFLAGS= -gnatpg -gnata
+ADAFLAGS= -gnatpg -gnata -gnateS
 
 # For finding the GCC build dir, which is used far too much
 GCC_DIR=../gcc
diff --git a/libada/Makefile.in b/libada/Makefile.in
index a2f6afef838d..ecda73ae1bbd 100644
--- a/libada/Makefile.in
+++ b/libada/Makefile.in
@@ -58,7 +58,7 @@ LDFLAGS=
 # The tedious process of getting CFLAGS right.
 CFLAGS=-g
 PICFLAG = @PICFLAG@
-GNATLIBFLAGS= -W -Wall -gnatpg -nostdinc
+GNATLIBFLAGS= -W -Wall -gnatpg -gnateS -nostdinc
 GNATLIBCFLAGS= -g -O2
 GNATLIBCFLAGS_FOR_C = -W -Wall $(GNATLIBCFLAGS) $(CFLAGS_FOR_TARGET) \
 	-fexceptions -DIN_RTS @have_getipinfo@ @have_capability@
Alexandre Oliva July 30, 2018, 10:35 p.m. UTC | #5
On Jul 24, 2018, Alexandre Oliva <oliva@gnu.org> wrote:

> Ok to install the first two patches?  (the third is just for reference)

Ping?

https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01419.html


> Introduce instance discriminators

> From: Alexandre Oliva <oliva@adacore.com>

> With -gnateS, the Ada compiler sets itself up to output discriminators
> for different instantiations of generics, but the middle and back ends
> have lacked support for that.  This patch introduces the missing bits,
> translating the GNAT-internal representation of the per-file instance
> map to an instance_table that maps decls to instance discriminators.


> From: Alexandre Oliva  <oliva@adacore.com>, Olivier Hainque  <hainque@adacore.com>
> for  gcc/ChangeLog

> 	* debug.h (decl_to_instance_map_t): New type.
> 	(decl_to_instance_map): Declare.
> 	(maybe_create_decl_to_instance_map): New inline function.
>     	* final.c (bb_discriminator, last_bb_discriminator): New statics,
>     	to track basic block discriminators.
>     	(final_start_function_1): Initialize them.
>     	(final_scan_insn_1): On NOTE_INSN_BASIC_BLOCK, track
> 	bb_discriminator.
> 	(decl_to_instance_map): New variable.
> 	(map_decl_to_instance, maybe_set_discriminator): New functions.
>     	(notice_source_line): Set discriminator.

> for  gcc/ada

> 	* trans.c: Include debug.h.
> 	(file_map): New static variable.
> 	(gigi): Set it.  Create decl_to_instance_map when needed.
> 	(Subprogram_Body_to_gnu): Pass gnu_subprog_decl to...
> 	(Sloc_to_locus): ... this.  Add decl parm, map it to instance.
> 	* gigi.h (Sloc_to_locus): Adjust declaration.

> for  gcc/testsuite/ChangeLog

> 	* gnat.dg/dinst.adb: New.
> 	* gnat.dg/dinst_pkg.ads, gnat.dg/dinst_pkg.adb: New.

[...]

> Save discriminator info for LTO

> From: Alexandre Oliva <oliva@adacore.com>

> for  gcc/ChangeLog

> 	* gimple-streamer-in.c (input_bb): Restore BB discriminator.
> 	* gimple-streamer-out.c (output_bb): Save it.
> 	* lto-streamer-in.c (input_struct_function_base): Restore
> 	instance discriminator if available.  Create map on demand.
> 	* lto-streamer-out.c (output_struct_function_base): Save it if
> 	available.
> 	* final.c (decl_to_instance_map): Document LTO strategy.
Richard Biener July 31, 2018, 10:38 a.m. UTC | #6
On Tue, Jul 31, 2018 at 12:35 AM Alexandre Oliva <oliva@gnu.org> wrote:
>
> On Jul 24, 2018, Alexandre Oliva <oliva@gnu.org> wrote:
>
> > Ok to install the first two patches?  (the third is just for reference)
>
> Ping?
>
> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01419.html

OK for the middle-end parts, the Ada parts need separate approval
(maybe CC a maintainer).

Thanks,
Richard.

>
> > Introduce instance discriminators
>
> > From: Alexandre Oliva <oliva@adacore.com>
>
> > With -gnateS, the Ada compiler sets itself up to output discriminators
> > for different instantiations of generics, but the middle and back ends
> > have lacked support for that.  This patch introduces the missing bits,
> > translating the GNAT-internal representation of the per-file instance
> > map to an instance_table that maps decls to instance discriminators.
>
>
> > From: Alexandre Oliva  <oliva@adacore.com>, Olivier Hainque  <hainque@adacore.com>
> > for  gcc/ChangeLog
>
> >       * debug.h (decl_to_instance_map_t): New type.
> >       (decl_to_instance_map): Declare.
> >       (maybe_create_decl_to_instance_map): New inline function.
> >       * final.c (bb_discriminator, last_bb_discriminator): New statics,
> >       to track basic block discriminators.
> >       (final_start_function_1): Initialize them.
> >       (final_scan_insn_1): On NOTE_INSN_BASIC_BLOCK, track
> >       bb_discriminator.
> >       (decl_to_instance_map): New variable.
> >       (map_decl_to_instance, maybe_set_discriminator): New functions.
> >       (notice_source_line): Set discriminator.
>
> > for  gcc/ada
>
> >       * trans.c: Include debug.h.
> >       (file_map): New static variable.
> >       (gigi): Set it.  Create decl_to_instance_map when needed.
> >       (Subprogram_Body_to_gnu): Pass gnu_subprog_decl to...
> >       (Sloc_to_locus): ... this.  Add decl parm, map it to instance.
> >       * gigi.h (Sloc_to_locus): Adjust declaration.
>
> > for  gcc/testsuite/ChangeLog
>
> >       * gnat.dg/dinst.adb: New.
> >       * gnat.dg/dinst_pkg.ads, gnat.dg/dinst_pkg.adb: New.
>
> [...]
>
> > Save discriminator info for LTO
>
> > From: Alexandre Oliva <oliva@adacore.com>
>
> > for  gcc/ChangeLog
>
> >       * gimple-streamer-in.c (input_bb): Restore BB discriminator.
> >       * gimple-streamer-out.c (output_bb): Save it.
> >       * lto-streamer-in.c (input_struct_function_base): Restore
> >       instance discriminator if available.  Create map on demand.
> >       * lto-streamer-out.c (output_struct_function_base): Save it if
> >       available.
> >       * final.c (decl_to_instance_map): Document LTO strategy.
>
>
> --
> Alexandre Oliva, freedom fighter   https://FSFLA.org/blogs/lxo
> Be the change, be Free!         FSF Latin America board member
> GNU Toolchain Engineer                Free Software Evangelist
Arnaud Charlet July 31, 2018, 11:41 a.m. UTC | #7
>>> Ok to install the first two patches?  (the third is just for reference)
>> 
>> Ping?
>> 
>> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01419.html
> 
> OK for the middle-end parts, the Ada parts need separate approval
> (maybe CC a maintainer).

Ok for the Ada part.

Arno
Alexandre Oliva Aug. 7, 2018, 5:53 a.m. UTC | #8
On Jul 30, 2018, Alexandre Oliva <oliva@gnu.org> wrote:

>> for  gcc/ada

>> * trans.c: Include debug.h.
>> (file_map): New static variable.
>> (gigi): Set it.  Create decl_to_instance_map when needed.
>> (Subprogram_Body_to_gnu): Pass gnu_subprog_decl to...
>> (Sloc_to_locus): ... this.  Add decl parm, map it to instance.
>> * gigi.h (Sloc_to_locus): Adjust declaration.

I noticed I missed the gcc-interface dir in these entries.  I'm
installing this patch to gcc/ada/ChangeLog to fix it.

diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 1095165f99fb..792811fb989c 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -10,12 +10,12 @@
 2018-07-31  Alexandre Oliva  <oliva@adacore.com>
             Olivier Hainque  <hainque@adacore.com>
 
-	* trans.c: Include debug.h.
+	* gcc-interface/trans.c: Include debug.h.
 	(file_map): New static variable.
 	(gigi): Set it.  Create decl_to_instance_map when needed.
 	(Subprogram_Body_to_gnu): Pass gnu_subprog_decl to...
 	(Sloc_to_locus): ... this.  Add decl parm, map it to instance.
-	* gigi.h (Sloc_to_locus): Adjust declaration.
+	* gcc-interface/gigi.h (Sloc_to_locus): Adjust declaration.
 
 2018-07-31  Arnaud Charlet  <charlet@adacore.com>
diff mbox series

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2a05a66ea9b87..f9a9fe8726b18 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1285,6 +1285,7 @@  OBJS = \
 	dwarf2cfi.o \
 	dwarf2out.o \
 	early-remat.o \
+	einput.o \
 	emit-rtl.o \
 	et-forest.o \
 	except.o \
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 31e098a0c707a..3ad3f83fd60f5 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -45,6 +45,7 @@ 
 #include "tree-iterator.h"
 #include "gimplify.h"
 #include "opts.h"
+#include "einput.h"
 #include "common/common-target.h"
 #include "stringpool.h"
 #include "attribs.h"
@@ -300,6 +301,12 @@  gigi (Node_Id gnat_root,
 
   type_annotate_only = (gigi_operating_mode == 1);
 
+  if (Generate_SCO_Instance_Table != 0)
+    {
+      loc_discriminator_kind = LOC_DISCRIMINATOR_INSTANCE_ID;
+      instance_table = (int *) xcalloc (number_file, sizeof (int));
+    }
+
   for (i = 0; i < number_file; i++)
     {
       /* Use the identifier table to make a permanent copy of the filename as
@@ -322,6 +329,9 @@  gigi (Node_Id gnat_root,
       linemap_line_start (line_table, file_info_ptr[i].Num_Source_Lines, 252);
       linemap_position_for_column (line_table, 252 - 1);
       linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
+
+      if (instance_table)
+	instance_table[i] = file_info_ptr[i].Instance;
     }
 
   gcc_assert (Nkind (gnat_root) == N_Compilation_Unit);
diff --git a/gcc/common.opt b/gcc/common.opt
index 4d031e81b09a2..b72ff1fd673e6 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -176,6 +176,18 @@  HOST_WIDE_INT function_entry_patch_area_start
 Variable
 enum dwarf_gnat_encodings gnat_encodings = DWARF_GNAT_ENCODINGS_DEFAULT
 
+; Kind of discriminator information we associate with object code
+; locations in debug information. By default this is set to the basic
+; block discriminator, an arbitrary values that is guaranteed to be
+; distinct for each basic block associated with a given source
+; location. Language front-ends that support multiple instantiations
+; of a given source template (such as Ada with generics) may instead
+; provide instance identifiers, allowing external tools to
+; identify which instance a given object instruction comes from.
+
+Variable
+enum loc_discriminator_type loc_discriminator_kind = LOC_DISCRIMINATOR_BB
+
 ; -dP causes the rtl to be emitted as a comment in assembly.
 Variable
 int flag_dump_rtl_in_asm
diff --git a/gcc/einput.c b/gcc/einput.c
new file mode 100644
index 0000000000000..32768282a34ac
--- /dev/null
+++ b/gcc/einput.c
@@ -0,0 +1,55 @@ 
+/* Data and functions implementing the input expansion extension services.
+   Copyright (C) 2004-2014 Free Software Foundation, Inc.
+
+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 "intl.h"
+#include "input.h"
+#include "einput.h"
+
+/* Map from ordinary map index to instance id.
+   See gcc/ada/trans.c for an example of how to fill it in.  */
+
+int *instance_table;
+
+/* Same as expand_location, filling line context information in addition.  */
+
+expanded_location
+context_expand_location (source_location loc, location_lc *lcp)
+{
+  const struct line_map *map;
+  expanded_location xloc = map_expand_location (loc, /*pmap=*/&map);
+
+  /* If an invalid LOC reaches here somehow or we don't have an instance
+     table to query, assign a constant instance id.  Otherwise, fetch the
+     instance id associated with the map corresponding to the input LOC.  */
+
+  if (map == NULL || instance_table == NULL)
+    lcp->instance = 0;
+  else
+    {
+      int map_index = ORDINARY_MAP_INDEX (linemap_check_ordinary (map),
+					  line_table);
+
+      lcp->instance = instance_table [map_index];
+    }
+
+  return xloc;
+}
diff --git a/gcc/einput.h b/gcc/einput.h
new file mode 100644
index 0000000000000..099aead637492
--- /dev/null
+++ b/gcc/einput.h
@@ -0,0 +1,50 @@ 
+/* Extensions to the basic input location expansion services, using
+   extra datastructures optionally filled by language front-ends.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+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/>.  */
+
+#ifndef GCC_EINPUT_H
+#define GCC_EINPUT_H
+
+#include "input.h"
+
+/* For languages that have the notion of instantiating a given
+   template multiple times, different linemaps can be allocated for
+   each instance, which are distinguished by an instance id.  This
+   table, which has the same indices as the ordinary linemaps in
+   line_table, stores these instance ids.  */
+
+extern int *instance_table;
+
+/* Line context information: extra data associated with source *lines* (not
+   individual source locations), filled by context_expand_location from extra
+   tables that front-ends may provide by the time we reach the "final"
+   pass.  */
+
+/* The line context information per se, filled by context_expand_location
+   below from data found in the tables declared above.  */
+
+typedef struct location_lc {
+  /* The instance id associated with the source line, if any.  */
+  int instance;
+} location_lc;
+
+extern expanded_location context_expand_location (source_location loc,
+						  location_lc *lcp);
+
+#endif
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index e4b070486e87e..64af8082c5ddc 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -6567,11 +6567,16 @@  insn_file (const rtx_insn *insn)
   return LOCATION_FILE (INSN_LOCATION (insn));
 }
 
-/* Return expanded location of the statement that produced this insn.  */
+/* Return expanded location of the statement that produced INSN, and
+   fill the associated line context information we have into LC if not
+   NULL.  */
 expanded_location
-insn_location (const rtx_insn *insn)
+insn_location (const rtx_insn *insn, location_lc *lcp)
 {
-  return expand_location (INSN_LOCATION (insn));
+  if (lcp == NULL)
+    return expand_location (INSN_LOCATION (insn));
+  else
+    return context_expand_location (INSN_LOCATION (insn), lcp);
 }
 
 /* Return true if memory model MODEL requires a pre-operation (release-style)
diff --git a/gcc/final.c b/gcc/final.c
index 445a3fe938a67..b1266affbc108 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -122,12 +122,20 @@  static int last_linenum;
 /* Column number of last NOTE.  */
 static int last_columnnum;
 
-/* Last discriminator written to assembly.  */
+/* Discriminator written to assembly.  */
 static int last_discriminator;
 
-/* Discriminator of current block.  */
+/* Discriminator to be written to assembly for current instruction.
+   Note: actual usage depends on loc_discriminator_kind setting.  */
 static int discriminator;
 
+/* Discriminator identifying current basic block among others sharing
+   the same locus.  */
+static int bb_discriminator;
+
+/* Basic block discriminator for previous instruction.  */
+static int last_bb_discriminator;
+
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
@@ -1701,6 +1709,7 @@  final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
   last_linenum = LOCATION_LINE (prologue_location);
   last_columnnum = LOCATION_COLUMN (prologue_location);
   last_discriminator = discriminator = 0;
+  last_bb_discriminator = bb_discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
@@ -2236,8 +2245,7 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  if (targetm.asm_out.unwind_emit)
 	    targetm.asm_out.unwind_emit (asm_out_file, insn);
 
-          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
-
+	  bb_discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
 	  break;
 
 	case NOTE_INSN_EH_REGION_BEG:
@@ -3188,10 +3196,21 @@  notice_source_line (rtx_insn *insn, bool *is_stmt)
     }
   else if (INSN_HAS_LOCATION (insn))
     {
-      expanded_location xloc = insn_location (insn);
+      location_lc llc;
+      expanded_location xloc = insn_location (insn, &llc);
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
+
+      switch (loc_discriminator_kind)
+	{
+	case LOC_DISCRIMINATOR_BB:
+	  discriminator = bb_discriminator;
+	  break;
+	case LOC_DISCRIMINATOR_INSTANCE_ID:
+	  discriminator = llc.instance;
+	  break;
+	}
     }
   else
     {
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 500f6638f36ac..15e80188ef040 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -90,6 +90,20 @@  enum debug_struct_file
   DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
 };
 
+/* Information stored in source location discriminators.  */
+
+enum loc_discriminator_type
+{
+  LOC_DISCRIMINATOR_BB,		/* Basic block discriminator.
+				   Arbitrary, distinct values are set
+				   for each of the basic blocks that
+				   share a given source location.  */
+  LOC_DISCRIMINATOR_INSTANCE_ID	/* Instance identifier provided by a
+				   language front-end to differentiate
+				   instances of a given generic
+				   template.  */
+};
+
 /* Balance between GNAT encodings and standard DWARF to emit.  */
 
 enum dwarf_gnat_encodings
diff --git a/gcc/input.c b/gcc/input.c
index d65a82dc26eac..f5a17ebbdf239 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -149,15 +149,19 @@  static const size_t fcache_line_record_size = 100;
    location towards its expansion point) that is in real source
    code.
 
+   If PMAP is non-null, *PMAP is set to designate the line map
+   from which the location was resolved.
+
    ASPECT controls which part of the location to use.  */
 
 static expanded_location
 expand_location_1 (source_location loc,
 		   bool expansion_point_p,
+		   const struct line_map **pmap,
 		   enum location_aspect aspect)
 {
   expanded_location xloc;
-  const line_map_ordinary *map;
+  const line_map_ordinary *map = NULL;
   enum location_resolution_kind lrk = LRK_MACRO_EXPANSION_POINT;
   tree block = NULL;
 
@@ -203,14 +207,16 @@  expand_location_1 (source_location loc,
 	  {
 	    source_location start = get_start (loc);
 	    if (start != loc)
-	      return expand_location_1 (start, expansion_point_p, aspect);
+	      return expand_location_1 (start, expansion_point_p, NULL,
+					aspect);
 	  }
 	  break;
 	case LOCATION_ASPECT_FINISH:
 	  {
 	    source_location finish = get_finish (loc);
 	    if (finish != loc)
-	      return expand_location_1 (finish, expansion_point_p, aspect);
+	      return expand_location_1 (finish, expansion_point_p, NULL,
+					aspect);
 	  }
 	  break;
 	}
@@ -221,6 +227,9 @@  expand_location_1 (source_location loc,
   if (loc <= BUILTINS_LOCATION)
     xloc.file = loc == UNKNOWN_LOCATION ? NULL : _("<built-in>");
 
+  if (pmap)
+    *pmap = map;
+
   return xloc;
 }
 
@@ -802,7 +811,17 @@  is_location_from_builtin_token (source_location loc)
 expanded_location
 expand_location (source_location loc)
 {
-  return expand_location_1 (loc, /*expansion_point_p=*/true,
+  return expand_location_1 (loc, /*expansion_point_p=*/true, /*pmap=*/NULL,
+			    LOCATION_ASPECT_CARET);
+}
+
+/* Same as expand_location, filling PMAP with the map that
+   was used to resolve, if PMAP is not null.  */
+
+expanded_location
+map_expand_location (source_location loc, const struct line_map **pmap)
+{
+  return expand_location_1 (loc, /*expansion_point_p=*/true, /*pmap=*/pmap,
 			    LOCATION_ASPECT_CARET);
 }
 
@@ -815,7 +834,7 @@  expand_location (source_location loc)
 expanded_location
 expand_location_to_spelling_point (source_location loc)
 {
-  return expand_location_1 (loc, /*expansion_point_p=*/false,
+  return expand_location_1 (loc, /*expansion_point_p=*/false, /*pmap=*/NULL,
 			    LOCATION_ASPECT_CARET);
 }
 
@@ -832,7 +851,8 @@  expanded_location
 linemap_client_expand_location_to_spelling_point (source_location loc,
 						  enum location_aspect aspect)
 {
-  return expand_location_1 (loc, /*expansion_point_p=*/false, aspect);
+  return expand_location_1 (loc, /*expansion_point_p=*/false, /*pmap=*/NULL,
+			    aspect);
 }
 
 
diff --git a/gcc/input.h b/gcc/input.h
index 4619663519a46..25cb8a94147cb 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -37,6 +37,8 @@  extern GTY(()) struct line_maps *saved_line_table;
 STATIC_ASSERT (BUILTINS_LOCATION < RESERVED_LOCATION_COUNT);
 
 extern bool is_location_from_builtin_token (source_location);
+extern expanded_location map_expand_location (source_location loc,
+					      const struct line_map **pmap);
 extern expanded_location expand_location (source_location);
 
 /* A class capturing the bounds of a buffer, to allow for run-time
diff --git a/gcc/modulo-sched.c b/gcc/modulo-sched.c
index 9a27365bfbc4e..1eb9362d31065 100644
--- a/gcc/modulo-sched.c
+++ b/gcc/modulo-sched.c
@@ -1237,7 +1237,7 @@  dump_insn_location (rtx_insn *insn)
 {
   if (dump_file && INSN_HAS_LOCATION (insn))
     {
-      expanded_location xloc = insn_location (insn);
+      expanded_location xloc = insn_location (insn, NULL);
       fprintf (dump_file, " %s:%i", xloc.file, xloc.line);
     }
 }
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 37c0d53fae276..0632bf0ec1a99 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -397,7 +397,7 @@  rtx_writer::print_rtx_operand_code_i (const_rtx in_rtx, int idx)
 	  when there is no location information available.  */
       if (INSN_HAS_LOCATION (in_insn))
 	{
-	  expanded_location xloc = insn_location (in_insn);
+	  expanded_location xloc = insn_location (in_insn, NULL);
 	  fprintf (m_outfile, " \"%s\":%i", xloc.file, xloc.line);
 	}
 #endif
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 565ce3abbe4e1..05c42fe515c39 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  If not see
 #endif  /* GENERATOR_FILE */
 
 #include "hard-reg-set.h"
+#include "einput.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
  instructions.  */
@@ -3285,7 +3286,7 @@  extern rtx_insn *prev_cc0_setter (rtx_insn *);
 extern int insn_line (const rtx_insn *);
 extern const char * insn_file (const rtx_insn *);
 extern tree insn_scope (const rtx_insn *);
-extern expanded_location insn_location (const rtx_insn *);
+extern expanded_location insn_location (const rtx_insn *, location_lc *);
 extern location_t prologue_location, epilogue_location;
 
 /* In jump.c */
diff --git a/gcc/testsuite/gnat.dg/dinst.adb b/gcc/testsuite/gnat.dg/dinst.adb
new file mode 100644
index 0000000000000..460e6c5f914f4
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dinst.adb
@@ -0,0 +1,20 @@ 
+-- { dg-do compile { target *-*-gnu* } }
+-- { dg-options "-gnateS -gdwarf -g -O -gno-column-info" }
+-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 1\n" } } */
+-- { dg-final { scan-assembler-not "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 2\n" } } */
+-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 3\n" } } */
+-- { dg-final { scan-assembler "loc \[0-9] 5 \[0-9]( is_stmt \[0-9])? discriminator 4\n" } } */
+
+
+with DInst_Pkg;
+procedure DInst is
+   package I1 is new DInst_Pkg; -- instance 1 
+   package I2 is new DInst_Pkg; -- instance 2
+   package I3 is new DInst_Pkg; -- instance 3
+   package I4 is new DInst_Pkg; -- instance 4
+begin
+   I1.Foo;
+   -- I2.Foo;
+   I3.Foo;
+   I4.Foo;
+end;
diff --git a/gcc/testsuite/gnat.dg/dinst_pkg.adb b/gcc/testsuite/gnat.dg/dinst_pkg.adb
new file mode 100644
index 0000000000000..09a9baea1e4e2
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dinst_pkg.adb
@@ -0,0 +1,7 @@ 
+with Ada.Text_IO; use Ada.Text_IO;
+package body DInst_Pkg is
+   procedure Foo is
+   begin
+      Put_Line ("hello there");
+   end;
+end;
diff --git a/gcc/testsuite/gnat.dg/dinst_pkg.ads b/gcc/testsuite/gnat.dg/dinst_pkg.ads
new file mode 100644
index 0000000000000..d22afdbcd6af5
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dinst_pkg.ads
@@ -0,0 +1,4 @@ 
+generic
+package DInst_Pkg is
+   procedure Foo;
+end;
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 6a16ce546cb04..1c75d805566cd 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1813,6 +1813,8 @@  copy_bb (copy_body_data *id, basic_block bb,
   copy_basic_block = create_basic_block (NULL, (basic_block) prev->aux);
   copy_basic_block->count = bb->count.apply_scale (num, den);
 
+  copy_basic_block->discriminator = bb->discriminator;
+
   copy_gsi = gsi_start_bb (copy_basic_block);
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index ba1750d3cf1bb..0c6fcdbe5ff8c 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -926,6 +926,14 @@  LINEMAPS_ORDINARY_MAP_AT (const line_maps *set, int index)
   return &set->info_ordinary.maps[index];
 }
 
+/* Return the index of ORD_MAP, which is an ordinary map in SET.  */
+
+inline int
+ORDINARY_MAP_INDEX (const line_map_ordinary *ord_map, const line_maps *set)
+{
+  return ord_map - LINEMAPS_ORDINARY_MAP_AT (set, 0);
+}
+
 /* Return the number of ordinary maps allocated in the line table
    SET.  */
 inline unsigned int