[gcc r15-7323] options: Adjust cl_optimization_compare to avoid checking ICE [PR115913]

2025-02-02 Thread Lewis Hyatt via Gcc-cvs
https://gcc.gnu.org/g:c0008df2118233f1afbed76ce308b4dfb6e6fc1a

commit r15-7323-gc0008df2118233f1afbed76ce308b4dfb6e6fc1a
Author: Lewis Hyatt 
Date:   Sun Jan 26 18:57:00 2025 -0500

options: Adjust cl_optimization_compare to avoid checking ICE [PR115913]

At the end of a sequence like:
 #pragma GCC push_options
 ...
 #pragma GCC pop_options

the handler for pop_options calls cl_optimization_compare() (as generated by
optc-save-gen.awk) to make sure that all global state has been restored to
the value it had prior to the push_options call. The verification is
performed for almost all entries in the global_options struct. This leads to
unexpected checking asserts, as discussed in the PR, in case the state of
warnings-related options has been intentionally modified in between
push_options and pop_options via a call to #pragma GCC diagnostic. Address
that by skipping the verification for CL_WARNING-flagged options.

gcc/ChangeLog:

PR middle-end/115913
* optc-save-gen.awk (cl_optimization_compare): Skip options with
CL_WARNING flag.

gcc/testsuite/ChangeLog:

PR middle-end/115913
* c-c++-common/cpp/pr115913.c: New test.

Diff:
---
 gcc/optc-save-gen.awk | 5 +
 gcc/testsuite/c-c++-common/cpp/pr115913.c | 7 +++
 2 files changed, 12 insertions(+)

diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk
index fa9218472edc..a3d7e5a478e4 100644
--- a/gcc/optc-save-gen.awk
+++ b/gcc/optc-save-gen.awk
@@ -1484,6 +1484,11 @@ for (i = 0; i < n_opts; i++) {
if (name == "")
continue;
 
+   # We do not want to compare warning-related options, since they
+   # might have been modified by a #pragma GCC diagnostic.
+   if (flag_set_p("Warning", flags[i]))
+   continue;
+
if (name in checked_options)
continue;
checked_options[name]++
diff --git a/gcc/testsuite/c-c++-common/cpp/pr115913.c 
b/gcc/testsuite/c-c++-common/cpp/pr115913.c
new file mode 100644
index ..b9d10cda8d24
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr115913.c
@@ -0,0 +1,7 @@
+/* { dg-do preprocess } */
+/* PR middle-end/115913 */
+#pragma GCC push_options
+#pragma GCC diagnostic warning "-Wundef"
+/* The call to cl_optimization_compare performed by pop_options should not
+   lead to a checking failure.  */
+#pragma GCC pop_options


[gcc r15-7324] PR modula2/117411 Request for documentation to include exception example

2025-02-02 Thread Gaius Mulley via Gcc-cvs
https://gcc.gnu.org/g:969c30885558d092ad07c9c71dd54ea14f6096c6

commit r15-7324-g969c30885558d092ad07c9c71dd54ea14f6096c6
Author: Gaius Mulley 
Date:   Sun Feb 2 16:02:27 2025 +

PR modula2/117411 Request for documentation to include exception example

This patch adds a new section to the gm2 documentation and new
corresponding testcode to the regression testsuite.

gcc/ChangeLog:

PR modula2/117411
* doc/gm2.texi (Exception handling): New section.
(The ISO system module): Add description of COFF_T.
(Assembler language): Tidy up last sentance.

gcc/testsuite/ChangeLog:

PR modula2/117411
* gm2/iso/run/pass/except9.mod: New test.
* gm2/iso/run/pass/lazyunique.mod: New test.

Signed-off-by: Gaius Mulley 

Diff:
---
 gcc/doc/gm2.texi  | 162 --
 gcc/testsuite/gm2/iso/run/pass/except9.mod|  78 +
 gcc/testsuite/gm2/iso/run/pass/lazyunique.mod |  87 ++
 3 files changed, 318 insertions(+), 9 deletions(-)

diff --git a/gcc/doc/gm2.texi b/gcc/doc/gm2.texi
index f8ae148b99ba..8baee24f14e0 100644
--- a/gcc/doc/gm2.texi
+++ b/gcc/doc/gm2.texi
@@ -234,6 +234,7 @@ such as the AVR and the ARM).
 * Extensions::GNU Modula-2 language extensions.
 * Type compatibility::Data type compatibility.
 * Unbounded by reference::Explanation of a language optimization.
+* Exception handling::Example of exception handling.
 * Building a shared library:: How to build a shared library.
 * Interface for Python::  How to produce swig interface files.
 * Producing a Python module::  How to produce a Python module.
@@ -1837,7 +1838,7 @@ are all exported from the @code{SYSTEM} module.
 @xref{The PIM system module}.
 @xref{The ISO system module}.
 
-@node Type compatibility, Unbounded by reference, Extensions, Using
+@node Type compatibility, Exception handling, Extensions, Using
 @section Type compatibility
 
 This section discuss the issues surrounding assignment, expression
@@ -1985,7 +1986,148 @@ The types @code{BYTE}, @code{LOC}, @code{WORD} and 
@code{WORD}n
 derivatives are assignment and parameter compatible with any data type
 of the same size.
 
-@node Unbounded by reference, Building a shared library, Type compatibility, 
Using
+@node Exception handling, Unbounded by reference, Type compatibility, Using
+@section Exception handling
+
+This section gives an example of exception handling and briefly
+describes its runtime behavior.  The module below is written in the
+ISO dialect of Modula-2 and can be compiled with the command line:
+
+@example
+$ gm2 -g -fiso -fsoft-check-all lazyunique.mod
+@end example
+
+The option @samp{-fsoft-check-all} generates checks for @code{NIL}
+pointer access violation.  In turn this will call the exception handler.
+
+@example
+@group
+MODULE lazyunique ;  (*!m2iso+gm2*)
+
+FROM Storage IMPORT ALLOCATE ;
+FROM libc IMPORT printf, exit ;
+
+TYPE
+   List = POINTER TO RECORD
+next : List ;
+value: INTEGER ;
+ END ;
+
+   Array = ARRAY [0..3] OF INTEGER ;
+
+CONST
+   Unsorted = Array @{0, 2, 1, 1@} ;
+
+VAR
+   head: List ;
+@end group   
+@end example
+
+@example
+@group
+PROCEDURE Display ;
+VAR
+   p: List ;
+BEGIN
+   p := head^.next ;
+   printf ("\nunique data\n");
+   printf ("===\n");   
+   WHILE p # NIL DO
+  printf ("%d\n", p^.value);
+  p := p^.next
+   END
+END Display ;
+@end group   
+@end example
+
+@example
+@group
+PROCEDURE Add (VAR p: List; val: INTEGER) ;
+BEGIN
+   NEW (p) ;
+   WITH p^ DO
+  value := val ;
+  next := NIL
+   END
+END Add ;
+@end group   
+@end example
+
+@example
+@group
+PROCEDURE Unique (val: INTEGER) ;
+VAR
+   p: List ;
+BEGIN
+   printf ("new value %d\n", val);
+   p := head ;
+   (* The following line may cause an exception accessing next or
+  value.  *)
+   WHILE p^.next^.value # val DO
+  p := p^.next
+   END
+EXCEPT
+   (* Now fixup.  Determine the source of the exception and retry.  *)
+   IF head = NIL
+   THEN
+  printf ("list was empty, add sentinal\n");
+  Add (head, -1) ;
+  RETRY  (* Jump back to the begin statement.  *)  
+   ELSIF p^.next = NIL
+   THEN
+  printf ("growing the list\n");
+  Add (p^.next, val) ;
+  RETRY  (* Jump back to the begin statement.  *)
+   ELSE
+  printf ("should never reach here!\n");   
+   END
+END Unique ;
+@end group   
+@end example
+
+@example
+@group
+PROCEDURE unique ;
+VAR
+   i: CARDINAL ;
+BEGIN
+   FOR i := 0 TO HIGH (Unsorted) DO
+  Unique (Unsorted[i])
+   END ;
+   Display
+END unique ;
+
+BEGIN
+   head := NIL ;
+   unique
+END lazyunique.
+@end group   
+@end example
+
+@example
+@group
+new value 0
+list was empty, add sentinal
+new value 0
+growing the list
+new value 0
+new value 2
+growing the list
+new value 2
+new value 1
+growing the

[gcc r14-11269] options: Adjust cl_optimization_compare to avoid checking ICE [PR115913]

2025-02-02 Thread Lewis Hyatt via Gcc-cvs
https://gcc.gnu.org/g:1e77549e1860249abafb8fc325fc4c1885b0d8c4

commit r14-11269-g1e77549e1860249abafb8fc325fc4c1885b0d8c4
Author: Lewis Hyatt 
Date:   Sun Jan 26 18:57:00 2025 -0500

options: Adjust cl_optimization_compare to avoid checking ICE [PR115913]

At the end of a sequence like:
 #pragma GCC push_options
 ...
 #pragma GCC pop_options

the handler for pop_options calls cl_optimization_compare() (as generated by
optc-save-gen.awk) to make sure that all global state has been restored to
the value it had prior to the push_options call. The verification is
performed for almost all entries in the global_options struct. This leads to
unexpected checking asserts, as discussed in the PR, in case the state of
warnings-related options has been intentionally modified in between
push_options and pop_options via a call to #pragma GCC diagnostic. Address
that by skipping the verification for CL_WARNING-flagged options.

gcc/ChangeLog:

PR middle-end/115913
* optc-save-gen.awk (cl_optimization_compare): Skip options with
CL_WARNING flag.

gcc/testsuite/ChangeLog:

PR middle-end/115913
* c-c++-common/cpp/pr115913.c: New test.

Diff:
---
 gcc/optc-save-gen.awk | 5 +
 gcc/testsuite/c-c++-common/cpp/pr115913.c | 7 +++
 2 files changed, 12 insertions(+)

diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk
index a3af88e37760..2d36e58677b6 100644
--- a/gcc/optc-save-gen.awk
+++ b/gcc/optc-save-gen.awk
@@ -1467,6 +1467,11 @@ for (i = 0; i < n_opts; i++) {
if (name == "")
continue;
 
+   # We do not want to compare warning-related options, since they
+   # might have been modified by a #pragma GCC diagnostic.
+   if (flag_set_p("Warning", flags[i]))
+   continue;
+
if (name in checked_options)
continue;
checked_options[name]++
diff --git a/gcc/testsuite/c-c++-common/cpp/pr115913.c 
b/gcc/testsuite/c-c++-common/cpp/pr115913.c
new file mode 100644
index ..b9d10cda8d24
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr115913.c
@@ -0,0 +1,7 @@
+/* { dg-do preprocess } */
+/* PR middle-end/115913 */
+#pragma GCC push_options
+#pragma GCC diagnostic warning "-Wundef"
+/* The call to cl_optimization_compare performed by pop_options should not
+   lead to a checking failure.  */
+#pragma GCC pop_options


[gcc r13-9361] options: Adjust cl_optimization_compare to avoid checking ICE [PR115913]

2025-02-02 Thread Lewis Hyatt via Gcc-cvs
https://gcc.gnu.org/g:e097b376f170d531b86e6e6dc763db0ab5a8700d

commit r13-9361-ge097b376f170d531b86e6e6dc763db0ab5a8700d
Author: Lewis Hyatt 
Date:   Sun Jan 26 18:57:00 2025 -0500

options: Adjust cl_optimization_compare to avoid checking ICE [PR115913]

At the end of a sequence like:
 #pragma GCC push_options
 ...
 #pragma GCC pop_options

the handler for pop_options calls cl_optimization_compare() (as generated by
optc-save-gen.awk) to make sure that all global state has been restored to
the value it had prior to the push_options call. The verification is
performed for almost all entries in the global_options struct. This leads to
unexpected checking asserts, as discussed in the PR, in case the state of
warnings-related options has been intentionally modified in between
push_options and pop_options via a call to #pragma GCC diagnostic. Address
that by skipping the verification for CL_WARNING-flagged options.

gcc/ChangeLog:

PR middle-end/115913
* optc-save-gen.awk (cl_optimization_compare): Skip options with
CL_WARNING flag.

gcc/testsuite/ChangeLog:

PR middle-end/115913
* c-c++-common/cpp/pr115913.c: New test.

Diff:
---
 gcc/optc-save-gen.awk | 5 +
 gcc/testsuite/c-c++-common/cpp/pr115913.c | 7 +++
 2 files changed, 12 insertions(+)

diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk
index d2cb53c477fd..05bb408d 100644
--- a/gcc/optc-save-gen.awk
+++ b/gcc/optc-save-gen.awk
@@ -1467,6 +1467,11 @@ for (i = 0; i < n_opts; i++) {
if (name == "")
continue;
 
+   # We do not want to compare warning-related options, since they
+   # might have been modified by a #pragma GCC diagnostic.
+   if (flag_set_p("Warning", flags[i]))
+   continue;
+
if (name in checked_options)
continue;
checked_options[name]++
diff --git a/gcc/testsuite/c-c++-common/cpp/pr115913.c 
b/gcc/testsuite/c-c++-common/cpp/pr115913.c
new file mode 100644
index ..b9d10cda8d24
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr115913.c
@@ -0,0 +1,7 @@
+/* { dg-do preprocess } */
+/* PR middle-end/115913 */
+#pragma GCC push_options
+#pragma GCC diagnostic warning "-Wundef"
+/* The call to cl_optimization_compare performed by pop_options should not
+   lead to a checking failure.  */
+#pragma GCC pop_options


[gcc r15-7326] Add tunables for input buffer

2025-02-02 Thread Andi Kleen via Gcc-cvs
https://gcc.gnu.org/g:ae814afad900edf1f19850985614398e0875618c

commit r15-7326-gae814afad900edf1f19850985614398e0875618c
Author: Andi Kleen 
Date:   Wed Dec 25 11:54:13 2024 -0800

Add tunables for input buffer

The input machinery to read the source code independent of the lexer
has a range of hard coded maximum array sizes that can impact performance.
Make them tunable.

input.cc is part of libcommon so it cannot direct access params
without a level of indirection.

gcc/ChangeLog:

PR preprocessor/118168
* input.cc (file_cache::tune): New function.
* input.h (class file_cache): Make tunables non const.
* params.opt: Add new tunables.
* toplev.cc (toplev::main): Initialize input buffer context
tunables.

Diff:
---
 gcc/input.cc   | 18 +-
 gcc/input.h|  4 +++-
 gcc/params.opt |  8 
 gcc/toplev.cc  |  2 ++
 4 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/gcc/input.cc b/gcc/input.cc
index 9f3cc6651e83..8605202fed2c 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -79,6 +79,10 @@ public:
   void evict ();
   void set_content (const char *buf, size_t sz);
 
+  static void tune(size_t line_record_size_) {
+  line_record_size = line_record_size_;
+  }
+
  private:
   /* These are information used to store a line boundary.  */
   class line_info
@@ -116,7 +120,7 @@ public:
   bool goto_next_line ();
 
   static const size_t buffer_size = 4 * 1024;
-  static const size_t line_record_size = 100;
+  static size_t line_record_size;
 
   /* The number of time this file has been accessed.  This is used
  to designate which file cache to evict from the cache
@@ -192,6 +196,18 @@ public:
 
 };
 
+size_t file_cache_slot::line_record_size = 100;
+
+/* Tune file_cache.  */
+void
+file_cache::tune (size_t num_file_slots_, size_t lines)
+{
+  num_file_slots = num_file_slots_;
+  file_cache_slot::tune (lines);
+}
+
+size_t file_cache::num_file_slots = 16;
+
 static const char *
 find_end_of_line (const char *s, size_t len);
 
diff --git a/gcc/input.h b/gcc/input.h
index 18ccf4429fc5..a60afe80681f 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -161,13 +161,15 @@ class file_cache
 const char *buffer,
 size_t sz);
 
+  static void tune(size_t num_file_slots_, size_t lines);
+
  private:
   file_cache_slot *evicted_cache_tab_entry (unsigned *highest_use_count);
   file_cache_slot *add_file (const char *file_path);
   file_cache_slot *lookup_file (const char *file_path);
 
  private:
-  static const size_t num_file_slots = 16;
+  static size_t num_file_slots;
   file_cache_slot *m_file_slots;
   input_context m_input_context;
 };
diff --git a/gcc/params.opt b/gcc/params.opt
index b5e7800d7e49..5d234a607c02 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -134,6 +134,14 @@ Maximum size (in bytes) of objects tracked bytewise by 
dead store elimination.
 Common Joined UInteger Var(param_early_inlining_insns) Init(6) Optimization 
Param
 Maximal estimated growth of function body caused by early inlining of single 
call.
 
+-param=file-cache-files=
+Common Joined UInteger Var(param_file_cache_files) Init(16) Param
+Max number of files in the file cache.
+
+-param=file-cache-lines=
+Common Joined UInteger Var(param_file_cache_lines) Init(100) Param
+Max number of lines to index into file cache.
+
 -param=fsm-scale-path-stmts=
 Common Joined UInteger Var(param_fsm_scale_path_stmts) Init(2) IntegerRange(1, 
10) Param Optimization
 Scale factor to apply to the number of statements in a threading path crossing 
a loop backedge when comparing to max-jump-thread-duplication-stmts.
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index d45a12cab45f..e03af8b18056 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -2333,6 +2333,8 @@ toplev::main (int argc, char **argv)
  UNKNOWN_LOCATION, global_dc,
  targetm.target_option.override);
 
+  file_cache::tune (param_file_cache_files, param_file_cache_lines);
+
   handle_common_deferred_options ();
 
   init_local_tick ();


[gcc r15-7327] Rebalance file_cache input line cache dynamically

2025-02-02 Thread Andi Kleen via Gcc-cvs
https://gcc.gnu.org/g:4a992ecad0f302f69c4f6c42708c737eabaa60dc

commit r15-7327-g4a992ecad0f302f69c4f6c42708c737eabaa60dc
Author: Andi Kleen 
Date:   Wed Dec 25 14:41:49 2024 -0800

Rebalance file_cache input line cache dynamically

The input context file_cache maintains an array of anchors
to speed up accessing lines before the previous line.
The array has a fixed upper size and the algorithm relies
on the linemap reporting the maximum number of lines in the file
in advance to compute the position of each anchor in the cache.

This doesn't work for C which doesn't know the maximum number
of lines before the files has finished parsing. The code
has a fallback for this, but it is quite inefficient and
effectively defeats the cache, so many accesses have to
go through most of the input buffer to compute line
boundaries. For large files this can be very costly
as demonstrated in PR118168.

Use a different algorithm to maintain the cache without
needing the maximum number of lines in advance. When the cache
runs out of entries and the gap to the last line anchor gets
too large, prune every second entry in the cache. This maintains
even spacing of the line anchors without requiring the maximum
index.

For the original PR this moves the overhead of enabling
-Wmisleading-indentation to 32% with the default cache size.
With a 10k entry cache it becomes noise.

  cc1 -O0 -fsyntax-only mypy.c   -quiet  ran
1.03 ± 0.05 times faster than cc1 -O0 -fsyntax-only  mypy.c   -quiet 
-Wmisleading-indentation --param=file-cache-lines=1
1.09 ± 0.08 times faster than cc1 -O0 -fsyntax-only  mypy.c   -quiet 
-Wmisleading-indentation --param=file-cache-lines=1000
1.32 ± 0.07 times faster than cc1 -O0 -fsyntax-only  mypy.c   -quiet 
-Wmisleading-indentation

The code could be further optimized, e.g. use the vectorized
line search functions the preprocessor uses.

Also it seems the input cache always reads the whole file into
memory, so perhaps it should just be using file mmap if possible.

gcc/ChangeLog:

PR preprocessor/118168
* input.cc (file_cache_slot::get_next_line): Use new algorithm
to maintain
(file_cache_slot::read_line_num): Use binary search for lookup.

Diff:
---
 gcc/input.cc | 132 +++
 1 file changed, 43 insertions(+), 89 deletions(-)

diff --git a/gcc/input.cc b/gcc/input.cc
index 8605202fed2c..b314328359f4 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -108,6 +108,11 @@ public:
 line_info ()
   :line_num (0), start_pos (0), end_pos (0)
 {}
+
+static bool less_than(const line_info &a, const line_info &b)
+{
+  return a.line_num < b.line_num;
+}
   };
 
   bool needs_read_p () const;
@@ -178,10 +183,8 @@ public:
   /* This is a record of the beginning and end of the lines we've seen
  while reading the file.  This is useful to avoid walking the data
  from the beginning when we are asked to read a line that is
- before LINE_START_IDX above.  Note that the maximum size of this
- record is line_record_size, so that the memory consumption
- doesn't explode.  We thus scale total_lines down to
- line_record_size.  */
+ before LINE_START_IDX above.  When the lines exceed line_record_size
+ this is scaled down dynamically, with the line_info becoming anchors.  */
   vec m_line_record;
 
   void offset_buffer (int offset)
@@ -885,38 +888,33 @@ file_cache_slot::get_next_line (char **line, ssize_t 
*line_len)
 
   ++m_line_num;
 
-  /* Before we update our line record, make sure the hint about the
- total number of lines of the file is correct.  If it's not, then
- we give up recording line boundaries from now on.  */
-  bool update_line_record = true;
-  if (m_line_num > m_total_lines)
-update_line_record = false;
-
-/* Now update our line record so that re-reading lines from the
+  /* Now update our line record so that re-reading lines from the
  before m_line_start_idx is faster.  */
-  if (update_line_record
-  && m_line_record.length () < line_record_size)
+  size_t rlen = m_line_record.length ();
+  /* Only update when beyond the previously cached region.  */
+  if (rlen == 0 || m_line_record[rlen - 1].line_num < m_line_num)
 {
-  /* If the file lines fits in the line record, we just record all
-its lines ...*/
-  if (m_total_lines <= line_record_size
- && m_line_num > m_line_record.length ())
+  size_t spacing = rlen >= 2 ?
+   m_line_record[rlen - 1].line_num - m_line_record[rlen - 2].line_num : 1;
+  size_t delta = rlen >= 1 ?
+   m_line_num - m_line_record[rlen - 1].line_num : 1;
+
+  /* If we're too far beyond drop half of the lines to rebalance.  */
+  if (rlen == line_record_size && delta >= spacing*2)
+ 

[gcc r15-7328] Remove m_total_lines support from input cache

2025-02-02 Thread Andi Kleen via Gcc-cvs
https://gcc.gnu.org/g:33acec612423efd2d9db9ffc808c4d103840dcd2

commit r15-7328-g33acec612423efd2d9db9ffc808c4d103840dcd2
Author: Andi Kleen 
Date:   Wed Dec 25 14:42:09 2024 -0800

Remove m_total_lines support from input cache

With the new cache maintenance algorithm we don't need the
maximum number of lines anymore. Remove all the code for that.

gcc/ChangeLog:

PR preprocessor/118168
* input.cc (total_lines_num): Remove.
(file_cache_slot::evict): Ditto.
(file_cache_slot::create): Ditto.
(file_cache_slot::set_content): Ditto.
(file_cache_slot::file_cache_slot): Ditto.
(file_cache_slot::dump): Ditto.

Diff:
---
 gcc/input.cc | 45 +
 1 file changed, 1 insertion(+), 44 deletions(-)

diff --git a/gcc/input.cc b/gcc/input.cc
index b314328359f4..64cb85eeed0e 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -165,16 +165,6 @@ public:
  means we've read no line so far.  */
   size_t m_line_num;
 
-  /* This is the total number of lines of the current file.  At the
- moment, we try to get this information from the line map
- subsystem.  Note that this is just a hint.  When using the C++
- front-end, this hint is correct because the input file is then
- completely tokenized before parsing starts; so the line map knows
- the number of lines before compilation really starts.  For e.g,
- the C front-end, it can happen that we start emitting diagnostics
- before the line map has seen the end of the file.  */
-  size_t m_total_lines;
-
   /* Could this file be missing a trailing newline on its final line?
  Initially true (to cope with empty files), set to true/false
  as each line is read.  */
@@ -317,25 +307,6 @@ expand_location_1 (const line_maps *set,
   return xloc;
 }
 
-/* Return the total lines number that have been read so far by the
-   line map (in the preprocessor) so far.  For languages like C++ that
-   entirely preprocess the input file before starting to parse, this
-   equals the actual number of lines of the file.  */
-
-static size_t
-total_lines_num (const char *file_path)
-{
-  size_t r = 0;
-  location_t l = 0;
-  if (linemap_get_file_highest_location (line_table, file_path, &l))
-{
-  gcc_assert (l >= RESERVED_LOCATION_COUNT);
-  expanded_location xloc = expand_location (l);
-  r = xloc.line;
-}
-  return r;
-}
-
 /* Lookup the cache used for the content of a given file accessed by
caret diagnostic.  Return the found cached file, or NULL if no
cached file was found.  */
@@ -425,7 +396,6 @@ file_cache_slot::evict ()
   m_line_num = 0;
   m_line_record.truncate (0);
   m_use_count = 0;
-  m_total_lines = 0;
   m_missing_trailing_newline = true;
 }
 
@@ -525,7 +495,6 @@ file_cache_slot::create (const file_cache::input_context 
&in_context,
   /* Ensure that this cache entry doesn't get evicted next time
  add_file_to_cache_tab is called.  */
   m_use_count = ++highest_use_count;
-  m_total_lines = total_lines_num (file_path);
   m_missing_trailing_newline = true;
 
 
@@ -572,17 +541,6 @@ file_cache_slot::set_content (const char *buf, size_t sz)
   fclose (m_fp);
   m_fp = nullptr;
 }
-
-  /* Compute m_total_lines based on content of buffer.  */
-  m_total_lines = 0;
-  const char *line_start = m_data;
-  size_t remaining_size = sz;
-  while (const char *line_end = find_end_of_line (line_start, remaining_size))
-{
-  ++m_total_lines;
-  remaining_size -= line_end + 1 - line_start;
-  line_start = line_end + 1;
-}
 }
 
 /* file_cache's ctor.  */
@@ -639,7 +597,7 @@ file_cache::lookup_or_add_file (const char *file_path)
 file_cache_slot::file_cache_slot ()
 : m_use_count (0), m_file_path (NULL), m_fp (NULL), m_error (false), m_data 
(0),
   m_alloc_offset (0), m_size (0), m_nb_read (0), m_line_start_idx (0),
-  m_line_num (0), m_total_lines (0), m_missing_trailing_newline (true)
+  m_line_num (0), m_missing_trailing_newline (true)
 {
   m_line_record.create (0);
 }
@@ -679,7 +637,6 @@ file_cache_slot::dump (FILE *out, int indent) const
   fprintf (out, "%*snb_read: %zi\n", indent, "", m_nb_read);
   fprintf (out, "%*sstart_line_idx: %zi\n", indent, "", m_line_start_idx);
   fprintf (out, "%*sline_num: %zi\n", indent, "", m_line_num);
-  fprintf (out, "%*stotal_lines: %zi\n", indent, "", m_total_lines);
   fprintf (out, "%*smissing_trailing_newline: %i\n",
   indent, "", (int)m_missing_trailing_newline);
   fprintf (out, "%*sline records (%i):\n",


[gcc r15-7330] Add a unit test for random access in the file cache

2025-02-02 Thread Andi Kleen via Gcc-cvs
https://gcc.gnu.org/g:75ab30f77f6d8a555aa78472b45a75a508544c68

commit r15-7330-g75ab30f77f6d8a555aa78472b45a75a508544c68
Author: Andi Kleen 
Date:   Sat Jan 25 22:48:29 2025 -0800

Add a unit test for random access in the file cache

v2: Remove extra {}

gcc/ChangeLog:

* input.cc (check_line): New.
(test_replacement): New function to test line caching.
(input_cc_tests): Call test_replacement

Diff:
---
 gcc/input.cc | 43 +++
 1 file changed, 43 insertions(+)

diff --git a/gcc/input.cc b/gcc/input.cc
index 3416c7cdd732..66a0ac6c5302 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -2301,6 +2301,48 @@ test_make_location_nonpure_range_endpoints (const 
line_table_case &case_)
   ASSERT_FALSE (IS_ADHOC_LOC (get_finish (not_aaa_eq_bbb)));
 }
 
+/* Verify reading of a specific line LINENUM in TMP, FC.  */
+
+static void check_line (temp_source_file &tmp, file_cache &fc, int linenum)
+{
+  char_span line = fc.get_source_line (tmp.get_filename (), linenum);
+  int n;
+  /* get_buffer is not null terminated, but the sscanf stops after a number.  
*/
+  ASSERT_TRUE (sscanf (line.get_buffer (), "%d", &n) == 1);
+  ASSERT_EQ (n, linenum);
+}
+
+/* Test file cache replacement.  */
+
+static void test_replacement ()
+{
+  const int maxline = 1000;
+
+  char *vec = XNEWVEC (char, maxline * 15);
+  char *p = vec;
+  int i;
+  for (i = 1; i <= maxline; i++)
+p += sprintf (p, "%d\n", i);
+
+  temp_source_file tmp (SELFTEST_LOCATION, ".txt", vec);
+  free (vec);
+  file_cache fc;
+
+  for (i = 2; i <= maxline; i++)
+{
+  check_line (tmp, fc, i);
+  check_line (tmp, fc, i - 1);
+  if (i >= 10)
+   check_line (tmp, fc, i - 9);
+  if (i >= 350) /* Exceed the look behind cache.  */
+   check_line (tmp, fc, i - 300);
+}
+  for (i = 5; i <= maxline; i += 100)
+check_line (tmp, fc, i);
+  for (i = 1; i <= maxline; i++)
+check_line (tmp, fc, i);
+}
+
 /* Verify reading of input files (e.g. for caret-based diagnostics).  */
 
 static void
@@ -4251,6 +4293,7 @@ input_cc_tests ()
 
   test_reading_source_line ();
   test_reading_source_buffer ();
+  test_replacement ();
 
   test_line_offset_overflow ();


[gcc r15-7329] Size input line cache based on file size

2025-02-02 Thread Andi Kleen via Gcc-cvs
https://gcc.gnu.org/g:baf26fccfb51fa54fcf7c668b96cae4cdbe574b3

commit r15-7329-gbaf26fccfb51fa54fcf7c668b96cae4cdbe574b3
Author: Andi Kleen 
Date:   Thu Dec 26 13:05:57 2024 -0800

Size input line cache based on file size

While the input line cache size now tunable it's better if the compiler
auto tunes it. Otherwise large files needing random file access will
still have to search many lines to find the right lines.

Add support for allocating one line anchor per hundred input lines.
This means an overhead of ~235k per 1M input lines on 64bit, which
seems reasonable.

gcc/ChangeLog:

PR preprocessor/118168
* input.cc (file_cache_slot::get_next_line): Implement
dynamic sizing of m_line_record based on input length.
* params.opt: (param_file_cache_lines): Set to 0 to size
dynamically.

Diff:
---
 gcc/input.cc   | 11 ---
 gcc/params.opt |  4 ++--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/gcc/input.cc b/gcc/input.cc
index 64cb85eeed0e..3416c7cdd732 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -189,7 +189,7 @@ public:
 
 };
 
-size_t file_cache_slot::line_record_size = 100;
+size_t file_cache_slot::line_record_size = 0;
 
 /* Tune file_cache.  */
 void
@@ -856,8 +856,13 @@ file_cache_slot::get_next_line (char **line, ssize_t 
*line_len)
   size_t delta = rlen >= 1 ?
m_line_num - m_line_record[rlen - 1].line_num : 1;
 
+  size_t max_size = line_record_size;
+  /* One anchor per hundred input lines.  */
+  if (max_size == 0)
+   max_size = m_line_num / 100;
+
   /* If we're too far beyond drop half of the lines to rebalance.  */
-  if (rlen == line_record_size && delta >= spacing*2)
+  if (rlen == max_size && delta >= spacing*2)
{
  size_t j = 0;
  for (size_t i = 1; i < rlen; i += 2)
@@ -867,7 +872,7 @@ file_cache_slot::get_next_line (char **line, ssize_t 
*line_len)
  spacing *= 2;
}
 
-  if (rlen < line_record_size && delta >= spacing)
+  if (rlen < max_size && delta >= spacing)
m_line_record.safe_push
  (file_cache_slot::line_info (m_line_num,
   m_line_start_idx,
diff --git a/gcc/params.opt b/gcc/params.opt
index 5d234a607c02..d84e35679e6d 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -136,10 +136,10 @@ Maximal estimated growth of function body caused by early 
inlining of single cal
 
 -param=file-cache-files=
 Common Joined UInteger Var(param_file_cache_files) Init(16) Param
-Max number of files in the file cache.
+Max number of files in the file cache. When 0 this is automatically sized.
 
 -param=file-cache-lines=
-Common Joined UInteger Var(param_file_cache_lines) Init(100) Param
+Common Joined UInteger Var(param_file_cache_lines) Init(0) Param
 Max number of lines to index into file cache.
 
 -param=fsm-scale-path-stmts=