/* Fold a constant sub-tree into a single node for C-compiler
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+ 2012 Free Software Foundation, Inc.
This file is part of GCC.
indirect_base0 = true;
}
offset0 = TREE_OPERAND (arg0, 1);
- if (host_integerp (offset0, 0)
- && ((HOST_WIDE_INT) (TREE_INT_CST_LOW (offset0) * BITS_PER_UNIT)
- / BITS_PER_UNIT
- == (HOST_WIDE_INT) TREE_INT_CST_LOW (offset0)))
+ if (host_integerp (offset0, 0))
{
- bitpos0 = TREE_INT_CST_LOW (offset0) * BITS_PER_UNIT;
- offset0 = NULL_TREE;
+ HOST_WIDE_INT off = size_low_cst (offset0);
+ if ((HOST_WIDE_INT) (((unsigned HOST_WIDE_INT) off)
+ * BITS_PER_UNIT)
+ / BITS_PER_UNIT == (HOST_WIDE_INT) off)
+ {
+ bitpos0 = off * BITS_PER_UNIT;
+ offset0 = NULL_TREE;
+ }
}
}
indirect_base1 = true;
}
offset1 = TREE_OPERAND (arg1, 1);
- if (host_integerp (offset1, 0)
- && ((HOST_WIDE_INT) (TREE_INT_CST_LOW (offset1) * BITS_PER_UNIT)
- / BITS_PER_UNIT
- == (HOST_WIDE_INT) TREE_INT_CST_LOW (offset1)))
+ if (host_integerp (offset1, 0))
{
- bitpos1 = TREE_INT_CST_LOW (offset1) * BITS_PER_UNIT;
- offset1 = NULL_TREE;
+ HOST_WIDE_INT off = size_low_cst (offset1);
+ if ((HOST_WIDE_INT) (((unsigned HOST_WIDE_INT) off)
+ * BITS_PER_UNIT)
+ / BITS_PER_UNIT == (HOST_WIDE_INT) off)
+ {
+ bitpos1 = off * BITS_PER_UNIT;
+ offset1 = NULL_TREE;
+ }
}
}
}
}
+/* Try to fold a pointer difference of type TYPE two address expressions of
+ array references AREF0 and AREF1 using location LOC. Return a
+ simplified expression for the difference or NULL_TREE. */
+
+static tree
+fold_addr_of_array_ref_difference (location_t loc, tree type,
+ tree aref0, tree aref1)
+{
+ tree base0 = TREE_OPERAND (aref0, 0);
+ tree base1 = TREE_OPERAND (aref1, 0);
+ tree base_offset = build_int_cst (type, 0);
+
+ /* If the bases are array references as well, recurse. If the bases
+ are pointer indirections compute the difference of the pointers.
+ If the bases are equal, we are set. */
+ if ((TREE_CODE (base0) == ARRAY_REF
+ && TREE_CODE (base1) == ARRAY_REF
+ && (base_offset
+ = fold_addr_of_array_ref_difference (loc, type, base0, base1)))
+ || (INDIRECT_REF_P (base0)
+ && INDIRECT_REF_P (base1)
+ && (base_offset = fold_binary_loc (loc, MINUS_EXPR, type,
+ TREE_OPERAND (base0, 0),
+ TREE_OPERAND (base1, 0))))
+ || operand_equal_p (base0, base1, 0))
+ {
+ tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
+ tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
+ tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0));
+ tree diff = build2 (MINUS_EXPR, type, op0, op1);
+ return fold_build2_loc (loc, PLUS_EXPR, type,
+ base_offset,
+ fold_build2_loc (loc, MULT_EXPR, type,
+ diff, esz));
+ }
+ return NULL_TREE;
+}
+
/* Fold a binary expression of code CODE and type TYPE with operands
OP0 and OP1. LOC is the location of the resulting expression.
Return the folded expression if folding is successful. Otherwise,
&& TREE_CODE (arg1) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
{
- tree aref0 = TREE_OPERAND (arg0, 0);
- tree aref1 = TREE_OPERAND (arg1, 0);
- if (operand_equal_p (TREE_OPERAND (aref0, 0),
- TREE_OPERAND (aref1, 0), 0))
- {
- tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
- tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
- tree esz = array_ref_element_size (aref0);
- tree diff = build2 (MINUS_EXPR, type, op0, op1);
- return fold_build2_loc (loc, MULT_EXPR, type, diff,
- fold_convert_loc (loc, type, esz));
-
- }
+ tree tem = fold_addr_of_array_ref_difference (loc, type,
+ TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 0));
+ if (tem)
+ return tem;
}
if (FLOAT_TYPE_P (type)
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
- unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, hi3, lo3, mlo, mhi;
+ double_int c1, c2, c3, msk;
int width = TYPE_PRECISION (type), w;
- hi1 = TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1));
- lo1 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
- hi2 = TREE_INT_CST_HIGH (arg1);
- lo2 = TREE_INT_CST_LOW (arg1);
+ c1 = tree_to_double_int (TREE_OPERAND (arg0, 1));
+ c2 = tree_to_double_int (arg1);
/* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */
- if ((hi1 & hi2) == hi1 && (lo1 & lo2) == lo1)
+ if (double_int_equal_p (double_int_and (c1, c2), c1))
return omit_one_operand_loc (loc, type, arg1,
- TREE_OPERAND (arg0, 0));
+ TREE_OPERAND (arg0, 0));
- if (width > HOST_BITS_PER_WIDE_INT)
- {
- mhi = (unsigned HOST_WIDE_INT) -1
- >> (2 * HOST_BITS_PER_WIDE_INT - width);
- mlo = -1;
- }
- else
- {
- mhi = 0;
- mlo = (unsigned HOST_WIDE_INT) -1
- >> (HOST_BITS_PER_WIDE_INT - width);
- }
+ msk = double_int_mask (width);
/* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */
- if ((~(hi1 | hi2) & mhi) == 0 && (~(lo1 | lo2) & mlo) == 0)
+ if (double_int_zero_p (double_int_and_not (msk,
+ double_int_ior (c1, c2))))
return fold_build2_loc (loc, BIT_IOR_EXPR, type,
- TREE_OPERAND (arg0, 0), arg1);
+ TREE_OPERAND (arg0, 0), arg1);
/* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2,
unless (C1 & ~C2) | (C2 & C3) for some C3 is a mask of some
mode which allows further optimizations. */
- hi1 &= mhi;
- lo1 &= mlo;
- hi2 &= mhi;
- lo2 &= mlo;
- hi3 = hi1 & ~hi2;
- lo3 = lo1 & ~lo2;
+ c1 = double_int_and (c1, msk);
+ c2 = double_int_and (c2, msk);
+ c3 = double_int_and_not (c1, c2);
for (w = BITS_PER_UNIT;
w <= width && w <= HOST_BITS_PER_WIDE_INT;
w <<= 1)
{
unsigned HOST_WIDE_INT mask
= (unsigned HOST_WIDE_INT) -1 >> (HOST_BITS_PER_WIDE_INT - w);
- if (((lo1 | lo2) & mask) == mask
- && (lo1 & ~mask) == 0 && hi1 == 0)
+ if (((c1.low | c2.low) & mask) == mask
+ && (c1.low & ~mask) == 0 && c1.high == 0)
{
- hi3 = 0;
- lo3 = mask;
+ c3 = uhwi_to_double_int (mask);
break;
}
}
- if (hi3 != hi1 || lo3 != lo1)
+ if (!double_int_equal_p (c3, c1))
return fold_build2_loc (loc, BIT_IOR_EXPR, type,
- fold_build2_loc (loc, BIT_AND_EXPR, type,
- TREE_OPERAND (arg0, 0),
- build_int_cst_wide (type,
- lo3, hi3)),
- arg1);
+ fold_build2_loc (loc, BIT_AND_EXPR, type,
+ TREE_OPERAND (arg0, 0),
+ double_int_to_tree (type,
+ c3)),
+ arg1);
}
/* (X & Y) | Y is (X, Y). */