aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Oliva <oliva@adacore.com>2024-12-18 22:17:02 -0300
committerAlexandre Oliva <oliva@gnu.org>2024-12-18 22:17:02 -0300
commit2c55a891840425a98d951283273a11cf7bd31816 (patch)
treeaa8b761b79f8c143775c015299268b381abf959d
parent86d9951acb4ec6f6f47402abb1fe3f059beb3ddb (diff)
downloadgcc-2c55a891840425a98d951283273a11cf7bd31816.zip
gcc-2c55a891840425a98d951283273a11cf7bd31816.tar.gz
gcc-2c55a891840425a98d951283273a11cf7bd31816.tar.bz2
ifcombine field merge: do not follow a second conversion [PR118046]
The testcase shows that conversions that would impact negatively the ifcombine field merging implementation won't always have been optimized out by the time we reach ifcombine. There's probably room to support multiple conversions with extra logic, but this workaround should avoid codegen errors until that logic is figured out. for gcc/ChangeLog PR tree-optimization/118046 * gimple-fold.cc (decode_field_reference): Don't follow more than one conversion. for gcc/testsuite/ChangeLog PR tree-optimization/118046 * gcc.dg/field-merge-14.c: New.
-rw-r--r--gcc/gimple-fold.cc41
-rw-r--r--gcc/testsuite/gcc.dg/field-merge-14.c26
2 files changed, 44 insertions, 23 deletions
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 46b4874..6554b65 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -7550,17 +7550,18 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT *pbitsize,
if (! INTEGRAL_TYPE_P (TREE_TYPE (exp)))
return NULL_TREE;
- /* Drop casts, only save the outermost type. We need not worry about
- narrowing then widening casts, or vice-versa, for those that are not
- essential for the compare have already been optimized out at this
- point. */
- if (gimple_convert_def_p (exp, res_ops))
- {
- if (!outer_type)
- {
- outer_type = TREE_TYPE (exp);
- loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
- }
+ /* Drop casts, saving only the outermost type, effectively used in
+ the compare. We can deal with at most one conversion, and it may
+ appear at various points in the chain of recognized preparation
+ statements. Earlier optimizers will often have already dropped
+ unneeded extensions, but they may survive, as in PR118046. ???
+ Can we do better and allow multiple conversions, perhaps taking
+ note of the narrowest intermediate type, sign extensions and
+ whatnot? */
+ if (!outer_type && gimple_convert_def_p (exp, res_ops))
+ {
+ outer_type = TREE_TYPE (exp);
+ loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
exp = res_ops[0];
}
@@ -7597,13 +7598,10 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT *pbitsize,
}
/* Another chance to drop conversions. */
- if (gimple_convert_def_p (exp, res_ops))
+ if (!outer_type && gimple_convert_def_p (exp, res_ops))
{
- if (!outer_type)
- {
- outer_type = TREE_TYPE (exp);
- loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
- }
+ outer_type = TREE_TYPE (exp);
+ loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
exp = res_ops[0];
}
@@ -7623,13 +7621,10 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT *pbitsize,
/* Yet another chance to drop conversions. This one is allowed to
match a converting load, subsuming the load identification block
below. */
- if (gimple_convert_def_p (exp, res_ops, load))
+ if (!outer_type && gimple_convert_def_p (exp, res_ops, load))
{
- if (!outer_type)
- {
- outer_type = TREE_TYPE (exp);
- loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
- }
+ outer_type = TREE_TYPE (exp);
+ loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
if (*load)
loc[3] = gimple_location (*load);
exp = res_ops[0];
diff --git a/gcc/testsuite/gcc.dg/field-merge-14.c b/gcc/testsuite/gcc.dg/field-merge-14.c
new file mode 100644
index 0000000..91d84cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/field-merge-14.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-ifcombine-details" } */
+
+/* Check that we don't get confused by multiple conversions. */
+
+__attribute__((noipa))
+int f(int *a,int *d)
+{
+ signed char b = *a;
+ int c = b;
+ *d = c; // This store is important even if otherwise unused
+ if (c < 0 && (b&1))
+ return 1;
+ return 0;
+}
+
+int main()
+{
+ unsigned char t = 0x81;
+ int x = t, y;
+ int tt = f(&x, &y);
+ if (!tt)
+ __builtin_abort();
+}
+
+/* { dg-final { scan-tree-dump-not "optimizing" "ifcombine" } } */