Hi,
the attached Ada testcase fails on x86/Linux (32-bit only) because the FRE
pass wrongly deletes stores as redundant:
Deleted redundant store VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[0]
{lb: 4294967292 sz: 4} = 100;
Deleted redundant store VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[1]
{lb: 4294967292 sz: 4} = 1;
Deleted redundant store VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[2]
{lb: 4294967292 sz: 4} = 2;
Deleted redundant store VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[3]
{lb: 4294967292 sz: 4} = 3;
Deleted redundant store VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[4]
{lb: 4294967292 sz: 4} = 4;
While the last 4 stores happen to be redundant (however the compiler cannot
really determine it), the first one isn't and deleting it yields wrong code.
These stores are part of a larger group of stores:
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[4294967292]{lb: 4294967292
sz: 4} = -4;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[4294967293]{lb: 4294967292
sz: 4} = -3;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[4294967294]{lb: 4294967292
sz: 4} = -2;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[4294967295]{lb: 4294967292
sz: 4} = -1;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[0]{lb: 4294967292 sz: 4} =
100;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[1]{lb: 4294967292 sz: 4} =
1;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[2]{lb: 4294967292 sz: 4} =
2;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[3]{lb: 4294967292 sz: 4} =
3;
VIEW_CONVERT_EXPR<integer[4294967292:4]>(*a.18_41)[4]{lb: 4294967292 sz: 4} =
4;
and the first 4 ones are correctly detected as *not* redundant. What changes
between the two groups of stores is the index or, more precisely, the sign of
the difference between the index and the low bound (4294967292 aka -4); it's
positive for the first group and negative for the second group. The latter
case fools ao_ref_init_from_vn_reference because it doesn't properly truncate
it to the precision of the index, like for example get_ref_base_and_extent,
so as to make it positive again in this case, which in turn fools FRE.
So the attached patch offset_int'ifies ao_ref_init_from_vn_reference the same
way get_ref_base_and_extent was offset_int'ified (in fact double_int'ified at
the time), adding the missing truncation in the process.
Bootstrapped/regtested on x86_64-suse-linux, OK for the mainline?
2015-09-16 Eric Botcazou <ebotca...@adacore.com>
* tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): Use offset_int for
offset and size computations instead of HOST_WIDE_INT.
2015-09-16 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/opt49.adb: New test.
--
Eric Botcazou
Index: tree-ssa-sccvn.c
===================================================================
--- tree-ssa-sccvn.c (revision 227805)
+++ tree-ssa-sccvn.c (working copy)
@@ -953,9 +953,9 @@ ao_ref_init_from_vn_reference (ao_ref *r
unsigned i;
tree base = NULL_TREE;
tree *op0_p = &base;
- HOST_WIDE_INT offset = 0;
- HOST_WIDE_INT max_size;
- HOST_WIDE_INT size = -1;
+ offset_int offset = 0;
+ offset_int max_size;
+ offset_int size = -1;
tree size_tree = NULL_TREE;
alias_set_type base_alias_set = -1;
@@ -971,15 +971,11 @@ ao_ref_init_from_vn_reference (ao_ref *r
if (mode == BLKmode)
size_tree = TYPE_SIZE (type);
else
- size = GET_MODE_BITSIZE (mode);
- }
- if (size_tree != NULL_TREE)
- {
- if (!tree_fits_uhwi_p (size_tree))
- size = -1;
- else
- size = tree_to_uhwi (size_tree);
+ size = int (GET_MODE_BITSIZE (mode));
}
+ if (size_tree != NULL_TREE
+ && TREE_CODE (size_tree) == INTEGER_CST)
+ size = wi::to_offset (size_tree);
/* Initially, maxsize is the same as the accessed element size.
In the following it will only grow (or become -1). */
@@ -1034,7 +1030,7 @@ ao_ref_init_from_vn_reference (ao_ref *r
/* And now the usual component-reference style ops. */
case BIT_FIELD_REF:
- offset += tree_to_shwi (op->op1);
+ offset += wi::to_offset (op->op1);
break;
case COMPONENT_REF:
@@ -1043,15 +1039,16 @@ ao_ref_init_from_vn_reference (ao_ref *r
/* We do not have a complete COMPONENT_REF tree here so we
cannot use component_ref_field_offset. Do the interesting
parts manually. */
+ tree this_offset = DECL_FIELD_OFFSET (field);
- if (op->op1
- || !tree_fits_uhwi_p (DECL_FIELD_OFFSET (field)))
+ if (op->op1 || TREE_CODE (this_offset) != INTEGER_CST)
max_size = -1;
else
{
- offset += (tree_to_uhwi (DECL_FIELD_OFFSET (field))
- * BITS_PER_UNIT);
- offset += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+ offset_int woffset = wi::lshift (wi::to_offset (this_offset),
+ LOG2_BITS_PER_UNIT);
+ woffset += wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
+ offset += woffset;
}
break;
}
@@ -1059,17 +1056,18 @@ ao_ref_init_from_vn_reference (ao_ref *r
case ARRAY_RANGE_REF:
case ARRAY_REF:
/* We recorded the lower bound and the element size. */
- if (!tree_fits_shwi_p (op->op0)
- || !tree_fits_shwi_p (op->op1)
- || !tree_fits_shwi_p (op->op2))
+ if (TREE_CODE (op->op0) != INTEGER_CST
+ || TREE_CODE (op->op1) != INTEGER_CST
+ || TREE_CODE (op->op2) != INTEGER_CST)
max_size = -1;
else
{
- HOST_WIDE_INT hindex = tree_to_shwi (op->op0);
- hindex -= tree_to_shwi (op->op1);
- hindex *= tree_to_shwi (op->op2);
- hindex *= BITS_PER_UNIT;
- offset += hindex;
+ offset_int woffset
+ = wi::sext (wi::to_offset (op->op0) - wi::to_offset (op->op1),
+ TYPE_PRECISION (TREE_TYPE (op->op0)));
+ woffset *= wi::to_offset (op->op2);
+ woffset = wi::lshift (woffset, LOG2_BITS_PER_UNIT);
+ offset += woffset;
}
break;
@@ -1102,9 +1100,6 @@ ao_ref_init_from_vn_reference (ao_ref *r
ref->ref = NULL_TREE;
ref->base = base;
- ref->offset = offset;
- ref->size = size;
- ref->max_size = max_size;
ref->ref_alias_set = set;
if (base_alias_set != -1)
ref->base_alias_set = base_alias_set;
@@ -1113,6 +1108,30 @@ ao_ref_init_from_vn_reference (ao_ref *r
/* We discount volatiles from value-numbering elsewhere. */
ref->volatile_p = false;
+ if (!wi::fits_shwi_p (size) || wi::neg_p (size))
+ {
+ ref->offset = 0;
+ ref->size = -1;
+ ref->max_size = -1;
+ return true;
+ }
+
+ ref->size = size.to_shwi ();
+
+ if (!wi::fits_shwi_p (offset))
+ {
+ ref->offset = 0;
+ ref->max_size = -1;
+ return true;
+ }
+
+ ref->offset = offset.to_shwi ();
+
+ if (!wi::fits_shwi_p (max_size) || wi::neg_p (max_size))
+ ref->max_size = -1;
+ else
+ ref->max_size = max_size.to_shwi ();
+
return true;
}
-- { dg-do run }
-- { dg-options "-O -fstack-check" }
procedure Opt49 is
function Ident (I : Integer) return Integer;
pragma No_Inline (Ident);
function Ident (I : Integer) return Integer is
begin
return I;
end;
Int_0 : Integer := Ident (0);
Int_4 : Integer := Ident (4);
A : array (-4 .. Int_4) of Integer;
begin
A := (-4 , -3 , -2 , -1 , 100 , 1 , 2 , 3 , 4);
A (-4 .. Int_0) := A (Int_0 .. 4);
if A /= (100 , 1 , 2 , 3 , 4 , 1 , 2 , 3 , 4) then
raise Program_Error;
end if;
A := (-4 , -3 , -2 , -1 , 100 , 1 , 2 , 3 , 4);
A (Int_0 .. 4) := A (-4 .. Int_0);
if A /= (-4 , -3 , -2 , -1 , -4 , -3 , -2 , -1 , 100) then
raise Program_Error;
end if;
end;