#include "flags.h"
#include "function.h"
#include "dumpfile.h"
+#include "bitmap.h"
+#include "gimple.h"
+#include "gimple-ssa.h"
+#include "tree-ssanames.h"
+#include "tree-into-ssa.h"
+#include "tree-dfa.h"
#include "tree-ssa.h"
#include "tree-ssa-propagate.h"
#include "target.h"
#include "ipa-utils.h"
#include "gimple-pretty-print.h"
+#include "tree-ssa-address.h"
+#include "langhooks.h"
/* Return true when DECL can be referenced from current unit.
FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
that has no corresponding callgraph/varpool node
declaring the body.
3) COMDAT functions referred by external vtables that
- we devirtualize only during final copmilation stage.
+ we devirtualize only during final compilation stage.
At this time we already decided that we will not output
the function body and thus we can't reference the symbol
directly. */
{
struct varpool_node *vnode;
struct cgraph_node *node;
- symtab_node snode;
+ symtab_node *snode;
if (DECL_ABSTRACT (decl))
return false;
|| TREE_CODE (from_decl) != VAR_DECL
|| !DECL_EXTERNAL (from_decl)
|| (flag_ltrans
- && symtab_get_node (from_decl)->symbol.in_other_partition))
+ && symtab_get_node (from_decl)->in_other_partition))
return true;
/* We are folding reference from external vtable. The vtable may reffer
to a symbol keyed to other compilation unit. The other compilation
unit may be in separate DSO and the symbol may be hidden. */
if (DECL_VISIBILITY_SPECIFIED (decl)
&& DECL_EXTERNAL (decl)
- && (!(snode = symtab_get_node (decl)) || !snode->symbol.in_other_partition))
+ && (!(snode = symtab_get_node (decl)) || !snode->in_other_partition))
return false;
/* When function is public, we always can introduce new reference.
Exception are the COMDAT functions where introducing a direct
The second is important when devirtualization happens during final
compilation stage when making a new reference no longer makes callee
to be compiled. */
- if (!node || !node->symbol.definition || node->global.inlined_to)
+ if (!node || !node->definition || node->global.inlined_to)
{
gcc_checking_assert (!TREE_ASM_WRITTEN (decl));
return false;
else if (TREE_CODE (decl) == VAR_DECL)
{
vnode = varpool_get_node (decl);
- if (!vnode || !vnode->symbol.definition)
+ if (!vnode || !vnode->definition)
{
gcc_checking_assert (!TREE_ASM_WRITTEN (decl));
return false;
cval = fold_convert (TREE_TYPE (orig_cval), cval);
return cval;
}
+ if (TREE_OVERFLOW_P (cval))
+ return drop_tree_overflow (cval);
return orig_cval;
}
return false;
}
+
+/* Given a pointer value OP0, return a simplified version of an
+ indirection through OP0, or NULL_TREE if no simplification is
+ possible. Note that the resulting type may be different from
+ the type pointed to in the sense that it is still compatible
+ from the langhooks point of view. */
+
+tree
+gimple_fold_indirect_ref (tree t)
+{
+ tree ptype = TREE_TYPE (t), type = TREE_TYPE (ptype);
+ tree sub = t;
+ tree subtype;
+
+ STRIP_NOPS (sub);
+ subtype = TREE_TYPE (sub);
+ if (!POINTER_TYPE_P (subtype))
+ return NULL_TREE;
+
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (sub, 0);
+ tree optype = TREE_TYPE (op);
+ /* *&p => p */
+ if (useless_type_conversion_p (type, optype))
+ return op;
+
+ /* *(foo *)&fooarray => fooarray[0] */
+ if (TREE_CODE (optype) == ARRAY_TYPE
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (optype))) == INTEGER_CST
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
+ }
+ /* *(foo *)&complexfoo => __real__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ return fold_build1 (REALPART_EXPR, type, op);
+ /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */
+ else if (TREE_CODE (optype) == VECTOR_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ {
+ tree part_width = TYPE_SIZE (type);
+ tree index = bitsize_int (0);
+ return fold_build3 (BIT_FIELD_REF, type, op, part_width, index);
+ }
+ }
+
+ /* *(p + CST) -> ... */
+ if (TREE_CODE (sub) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+ {
+ tree addr = TREE_OPERAND (sub, 0);
+ tree off = TREE_OPERAND (sub, 1);
+ tree addrtype;
+
+ STRIP_NOPS (addr);
+ addrtype = TREE_TYPE (addr);
+
+ /* ((foo*)&vectorfoo)[1] -> BIT_FIELD_REF<vectorfoo,...> */
+ if (TREE_CODE (addr) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (addrtype)) == VECTOR_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype)))
+ && host_integerp (off, 1))
+ {
+ unsigned HOST_WIDE_INT offset = tree_low_cst (off, 1);
+ tree part_width = TYPE_SIZE (type);
+ unsigned HOST_WIDE_INT part_widthi
+ = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
+ unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+ tree index = bitsize_int (indexi);
+ if (offset / part_widthi
+ <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (addrtype)))
+ return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (addr, 0),
+ part_width, index);
+ }
+
+ /* ((foo*)&complexfoo)[1] -> __imag__ complexfoo */
+ if (TREE_CODE (addr) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (addrtype)) == COMPLEX_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
+ {
+ tree size = TYPE_SIZE_UNIT (type);
+ if (tree_int_cst_equal (size, off))
+ return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (addr, 0));
+ }
+
+ /* *(p + CST) -> MEM_REF <p, CST>. */
+ if (TREE_CODE (addr) != ADDR_EXPR
+ || DECL_P (TREE_OPERAND (addr, 0)))
+ return fold_build2 (MEM_REF, type,
+ addr,
+ build_int_cst_wide (ptype,
+ TREE_INT_CST_LOW (off),
+ TREE_INT_CST_HIGH (off)));
+ }
+
+ /* *(foo *)fooarrptr => (*fooarrptr)[0] */
+ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (subtype)))) == INTEGER_CST
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+ {
+ tree type_domain;
+ tree min_val = size_zero_node;
+ tree osub = sub;
+ sub = gimple_fold_indirect_ref (sub);
+ if (! sub)
+ sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
+ type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
+ }
+
+ return NULL_TREE;
+}