From 15a47f437d2ba320aa9cb72986812f115498dbf9 Mon Sep 17 00:00:00 2001
From: "Vladimir N. Makarov" <vmakarov@redhat.com>
Date: Wed, 6 Jan 2021 14:48:53 -0500
Subject: [PATCH] [PR97978] LRA: Permit temporary allocation incorrectness
 after hard reg split.

LRA can crash when a hard register was split and the same hard register
was assigned on the previous assignment sub-pass.  The following
patch fixes this problem.

gcc/ChangeLog:

	PR rtl-optimization/97978
	* lra-int.h (lra_hard_reg_split_p): New external.
	* lra.c (lra_hard_reg_split_p): New global.
	(lra): Set up lra_hard_reg_split_p after splitting a hard reg.
	* lra-assigns.c (lra_assign): Don't check allocation correctness
	after hard reg splitting.

gcc/testsuite/ChangeLog:

	PR rtl-optimization/97978
	* gcc.target/i386/pr97978.c: New.
---
 gcc/lra-assigns.c                       |  9 +++++----
 gcc/lra-int.h                           |  1 +
 gcc/lra.c                               |  5 +++++
 gcc/testsuite/gcc.target/i386/pr97978.c | 22 ++++++++++++++++++++++
 4 files changed, 33 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr97978.c

diff --git a/gcc/lra-assigns.c b/gcc/lra-assigns.c
index 9335e4c876ed..c6a941fe6638 100644
--- a/gcc/lra-assigns.c
+++ b/gcc/lra-assigns.c
@@ -1636,10 +1636,11 @@ lra_assign (bool &fails_p)
   bitmap_initialize (&all_spilled_pseudos, &reg_obstack);
   create_live_range_start_chains ();
   setup_live_pseudos_and_spill_after_risky_transforms (&all_spilled_pseudos);
-  if (! lra_asm_error_p && flag_checking)
-    /* Check correctness of allocation for call-crossed pseudos but
-       only when there are no asm errors as in the case of errors the
-       asm is removed and it can result in incorrect allocation.  */
+  if (! lra_hard_reg_split_p && ! lra_asm_error_p && flag_checking)
+    /* Check correctness of allocation but only when there are no hard reg
+       splits and asm errors as in the case of errors explicit insns involving
+       hard regs are added or the asm is removed and this can result in
+       incorrect allocation.  */
     for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
       if (lra_reg_info[i].nrefs != 0
 	  && reg_renumber[i] >= 0
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 75ba6560bcc8..1b8f7b6ae618 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -273,6 +273,7 @@ typedef class lra_insn_recog_data *lra_insn_recog_data_t;
 
 extern FILE *lra_dump_file;
 
+extern bool lra_hard_reg_split_p;
 extern bool lra_asm_error_p;
 extern bool lra_reg_spill_p;
 
diff --git a/gcc/lra.c b/gcc/lra.c
index 380a21ac2ac9..aa49de6f154f 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -2211,6 +2211,9 @@ bitmap_head lra_subreg_reload_pseudos;
 /* File used for output of LRA debug information.  */
 FILE *lra_dump_file;
 
+/* True if we split hard reg after the last constraint sub-pass.  */
+bool lra_hard_reg_split_p;
+
 /* True if we found an asm error.  */
 bool lra_asm_error_p;
 
@@ -2359,6 +2362,7 @@ lra (FILE *f)
 	  if (live_p)
 	    lra_clear_live_ranges ();
 	  bool fails_p;
+	  lra_hard_reg_split_p = false;
 	  do
 	    {
 	      /* We need live ranges for lra_assign -- so build them.
@@ -2403,6 +2407,7 @@ lra (FILE *f)
 		  live_p = false;
 		  if (! lra_split_hard_reg_for ())
 		    break;
+		  lra_hard_reg_split_p = true;
 		}
 	    }
 	  while (fails_p);
diff --git a/gcc/testsuite/gcc.target/i386/pr97978.c b/gcc/testsuite/gcc.target/i386/pr97978.c
new file mode 100644
index 000000000000..263bca8708d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr97978.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fno-PIC" } */
+int sg;
+long int kk;
+
+void
+bp (int jz, int tj, long int li)
+{
+  if (jz == 0 || tj == 0)
+    __builtin_unreachable ();
+
+  kk = li;
+}
+
+void
+qp (void)
+{
+  ++kk;
+
+  for (;;)
+    bp (1l / sg, 0, ~0u);
+}
-- 
GitLab