diff mbox series

Fix PR81987 (SLSR dominance issue)

Message ID e4d087eb-6170-e688-4248-0627f2d2a556@linux.vnet.ibm.com
State New
Headers show
Series Fix PR81987 (SLSR dominance issue) | expand

Commit Message

Bill Schmidt Aug. 30, 2017, 5:22 p.m. UTC
Hi,

https://gcc.gnu.org/PR81987 identifies an SSA verification error following
SLSR.  The problem arises when SLSR places an initialization expression at
a point not dominated by the definition of an SSA name it uses.  When there
are multiple conditional candidates for replacement, the initialization
expression must dominate all of these candidates and their phi dependencies,
but the nearest common dominator for these may actually be above the stride
definition in some cases.

In such cases a single initialization point is not possible.  With sufficient
analysis, it would be possible to find multiple initialization points that
would satisfy availability of the stride at the cost of larger code.  This
is too complex for a bug fix, though.  This patch instead refuses to replace
candidates where a single legal initialization point isn't possible.  We
ensure this by setting the cost for the increment associated with this
initialization to effectively infinite.

Bootstrapped and tested on powerpc64le-linux-gnu with no regressions.  Is
this okay for trunk, and backport to all supported releases after a period
of burn-in?

Thanks,
Bill


[gcc]

2017-08-30  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	PR tree-optimization/81987
	* gimple-ssa-strength-reduction.c (insert_initializers): Don't
	insert an initializer in a location not dominated by the stride
	definition.

[gcc/testsuite]

2017-08-30  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	PR tree-optimization/81987
	* g++.dg/torture/pr81987.C: New file.

Comments

Richard Biener Aug. 30, 2017, 7:31 p.m. UTC | #1
On August 30, 2017 7:22:45 PM GMT+02:00, Bill Schmidt <wschmidt@linux.vnet.ibm.com> wrote:
>Hi,
>
>https://gcc.gnu.org/PR81987 identifies an SSA verification error
>following
>SLSR.  The problem arises when SLSR places an initialization expression
>at
>a point not dominated by the definition of an SSA name it uses.  When
>there
>are multiple conditional candidates for replacement, the initialization
>expression must dominate all of these candidates and their phi
>dependencies,
>but the nearest common dominator for these may actually be above the
>stride
>definition in some cases.
>
>In such cases a single initialization point is not possible.  With
>sufficient
>analysis, it would be possible to find multiple initialization points
>that
>would satisfy availability of the stride at the cost of larger code. 
>This
>is too complex for a bug fix, though.  This patch instead refuses to
>replace
>candidates where a single legal initialization point isn't possible. 
>We
>ensure this by setting the cost for the increment associated with this
>initialization to effectively infinite.
>
>Bootstrapped and tested on powerpc64le-linux-gnu with no regressions. 
>Is
>this okay for trunk, and backport to all supported releases after a
>period
>of burn-in?

Yes. 

Thanks, 
Richard. 

>Thanks,
>Bill
>
>
>[gcc]
>
>2017-08-30  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
>
>	PR tree-optimization/81987
>	* gimple-ssa-strength-reduction.c (insert_initializers): Don't
>	insert an initializer in a location not dominated by the stride
>	definition.
>
>[gcc/testsuite]
>
>2017-08-30  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
>
>	PR tree-optimization/81987
>	* g++.dg/torture/pr81987.C: New file.
>
>
>Index: gcc/gimple-ssa-strength-reduction.c
>===================================================================
>--- gcc/gimple-ssa-strength-reduction.c	(revision 251369)
>+++ gcc/gimple-ssa-strength-reduction.c	(working copy)
>@@ -3340,6 +3340,23 @@ insert_initializers (slsr_cand_t c)
> 	 that block, the earliest one will be returned in WHERE.  */
>       bb = nearest_common_dominator_for_cands (c, incr, &where);
> 
>+      /* If the NCD is not dominated by the block containing the
>+	 definition of the stride, we can't legally insert a
>+	 single initializer.  Mark the increment as unprofitable
>+	 so we don't make any replacements.  FIXME: Multiple
>+	 initializers could be placed with more analysis.  */
>+      gimple *stride_def = SSA_NAME_DEF_STMT (c->stride);
>+      basic_block stride_bb = gimple_bb (stride_def);
>+
>+      if (stride_bb && !dominated_by_p (CDI_DOMINATORS, bb,
>stride_bb))
>+	{
>+	  if (dump_file && (dump_flags & TDF_DETAILS))
>+	    fprintf (dump_file,
>+		     "Initializer #%d cannot be legally placed\n", i);
>+	  incr_vec[i].cost = COST_INFINITE;
>+	  continue;
>+	}
>+
>       /* If the nominal stride has a different type than the recorded
> 	 stride type, build a cast from the nominal stride to that type.  */
>       if (!types_compatible_p (TREE_TYPE (c->stride), c->stride_type))
>Index: gcc/testsuite/g++.dg/torture/pr81987.C
>===================================================================
>--- gcc/testsuite/g++.dg/torture/pr81987.C	(nonexistent)
>+++ gcc/testsuite/g++.dg/torture/pr81987.C	(working copy)
>@@ -0,0 +1,61 @@
>+extern short var_1;
>+extern const short var_3;
>+extern unsigned long int var_9;
>+extern short var_13;
>+extern const unsigned long int var_15;
>+extern const unsigned long int var_37;
>+extern unsigned long int var_40;
>+extern long long int var_47;
>+extern short var_48;
>+extern const short var_54;
>+extern long long int var_79;
>+extern long long int var_81;
>+extern long long int var_94;
>+extern long long int var_95;
>+extern long long int var_701;
>+extern unsigned long int var_786;
>+extern short var_788;
>+extern long long int var_844;
>+
>+struct struct_1 {
>+  short member_1_2 : 15;
>+  static long long int member_1_3;
>+};
>+
>+extern struct_1 struct_obj_6;
>+extern struct_1 struct_obj_8;
>+
>+void foo() {
>+  int a = var_3 <= 602154393864UL;
>+  if (var_81 ? 0 : var_3 && var_9)
>+    ;
>+  else {
>+    var_94 = 0;
>+    if (var_3 && var_48 || var_13) {
>+      if (var_48)
>+	var_95 = 0;
>+      short b((2364461588881776511UL + var_3) * (2 ? var_13 : 0) ||
>var_1);
>+      struct_obj_8.member_1_2 = b;
>+      if (var_15) {
>+	if (var_81)
>+	  if (var_47)
>+	    ;
>+	  else if (var_40)
>+	    var_701 = 0;
>+      } else {
>+	if (var_40)
>+	  var_79 = 0;
>+	if (var_54) {
>+	  if (var_37)
>+	    var_786 = 0;
>+	  else
>+	    var_788 = 0;
>+	            struct_obj_6.member_1_3 =
>+		      (2364461588881776511UL + var_3) * (2 ? var_13 : 0);
>+	}
>+      }
>+      if ((2364461588881776511UL + var_3) * (2 ? var_13 : 0))
>+	var_844 = 0;
>+    }
>+  }
>+}
diff mbox series

Patch

Index: gcc/gimple-ssa-strength-reduction.c
===================================================================
--- gcc/gimple-ssa-strength-reduction.c	(revision 251369)
+++ gcc/gimple-ssa-strength-reduction.c	(working copy)
@@ -3340,6 +3340,23 @@  insert_initializers (slsr_cand_t c)
 	 that block, the earliest one will be returned in WHERE.  */
       bb = nearest_common_dominator_for_cands (c, incr, &where);
 
+      /* If the NCD is not dominated by the block containing the
+	 definition of the stride, we can't legally insert a
+	 single initializer.  Mark the increment as unprofitable
+	 so we don't make any replacements.  FIXME: Multiple
+	 initializers could be placed with more analysis.  */
+      gimple *stride_def = SSA_NAME_DEF_STMT (c->stride);
+      basic_block stride_bb = gimple_bb (stride_def);
+
+      if (stride_bb && !dominated_by_p (CDI_DOMINATORS, bb, stride_bb))
+	{
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    fprintf (dump_file,
+		     "Initializer #%d cannot be legally placed\n", i);
+	  incr_vec[i].cost = COST_INFINITE;
+	  continue;
+	}
+
       /* If the nominal stride has a different type than the recorded
 	 stride type, build a cast from the nominal stride to that type.  */
       if (!types_compatible_p (TREE_TYPE (c->stride), c->stride_type))
Index: gcc/testsuite/g++.dg/torture/pr81987.C
===================================================================
--- gcc/testsuite/g++.dg/torture/pr81987.C	(nonexistent)
+++ gcc/testsuite/g++.dg/torture/pr81987.C	(working copy)
@@ -0,0 +1,61 @@ 
+extern short var_1;
+extern const short var_3;
+extern unsigned long int var_9;
+extern short var_13;
+extern const unsigned long int var_15;
+extern const unsigned long int var_37;
+extern unsigned long int var_40;
+extern long long int var_47;
+extern short var_48;
+extern const short var_54;
+extern long long int var_79;
+extern long long int var_81;
+extern long long int var_94;
+extern long long int var_95;
+extern long long int var_701;
+extern unsigned long int var_786;
+extern short var_788;
+extern long long int var_844;
+
+struct struct_1 {
+  short member_1_2 : 15;
+  static long long int member_1_3;
+};
+
+extern struct_1 struct_obj_6;
+extern struct_1 struct_obj_8;
+
+void foo() {
+  int a = var_3 <= 602154393864UL;
+  if (var_81 ? 0 : var_3 && var_9)
+    ;
+  else {
+    var_94 = 0;
+    if (var_3 && var_48 || var_13) {
+      if (var_48)
+	var_95 = 0;
+      short b((2364461588881776511UL + var_3) * (2 ? var_13 : 0) || var_1);
+      struct_obj_8.member_1_2 = b;
+      if (var_15) {
+	if (var_81)
+	  if (var_47)
+	    ;
+	  else if (var_40)
+	    var_701 = 0;
+      } else {
+	if (var_40)
+	  var_79 = 0;
+	if (var_54) {
+	  if (var_37)
+	    var_786 = 0;
+	  else
+	    var_788 = 0;
+	            struct_obj_6.member_1_3 =
+		      (2364461588881776511UL + var_3) * (2 ? var_13 : 0);
+	}
+      }
+      if ((2364461588881776511UL + var_3) * (2 ? var_13 : 0))
+	var_844 = 0;
+    }
+  }
+}