This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
patch to tree-profiling branch to do escape type analysis.
- From: Kenneth Zadeck <zadeck at naturalbridge dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: "Berlin, Daniel" <dberlin at dberlin dot org>,"Hubicha, Jan" <jh at suse dot cz>, "Tice, Caroline" <ctice at apple dot com>
- Date: Tue, 18 Jan 2005 14:48:07 -0500
- Subject: patch to tree-profiling branch to do escape type analysis.
Tested on darwin. There are 4 new regressions with this patch. All of
them are instances of a known problem with the vectorizer that this
patch happens to tickle.
These are gcc.dg/vect/vect-56.c, gcc.dg/vect/vect-60.c,
gcc.dg/vect/vect-77.c, gcc.dg/vect/vect78-.c
Kenny
2005-01-18 Kenneth Zadeck <zadeck@naturalbridge.com>
* alias.c: Fixed header comment.
* c-common.c: (handle_free_attribure)
new function to handle "free" attribute.
* c=decl.c (merge_decls): process "free" attribute.
* calls.c (flags_from_decl_or_type): process "free" attribute.
* ipa-static-vars-anal.c (unique_type_id_for,
ipa_static_star_count_of_interesting_type, ipa_static_type_contained_p,
ipa_static_address_not_taken_of_field, mark_any_type_seen,
mark_type_seen,
mark_type, mark_interesting_type, parent_type_p, count_stars,
check_cast_type,
check_cast, check_function_parameter_and_return_types,
mark_interesting_addressof, type_for_uid, subtype_map_for_uid,
close_type_seen, compare_type_brand, get_name_of_type,
discover_unique_type
close_type_exposed_parameter, close_type_full_escape,
delete_addressof_map,
close_addressof, do_type_analysis, ): new function for type escape
analysis.
* ipa-static-vars-anal.c (check_operand, check_tree,
look_for_address_of,
check_call, scan_for_static_refs, ipa_init, analyze_function,
static_execute): fixed to perform type escape analysis.
* ipa-static-vars-anal.c (convert_UIDs_in_bitmap, propagate_bits):
fixed typo.
* ipa-static-vars-anal.c (searchc_env): added missing cast.
* ipa-static-vars-anal.c (get_base_var): moved from tree-gimple.c.
* ipa-static-vars-anal.c (check_call): renamed from
process_call_for_static_vars.
* ipa-static-vars-anal.c (analyze_variable): added debugging.
* ipa-static-vars-anal.c (static_execute): removed debugging.
* tree-dfa.c (create_stmt_ann) fixed typo.
* tree.c (build4_stat) fixed typo.
* tree-inline-flow.h: fixed typo.
* tree-ssa-alias.c (may_alias_p): improvements to aliasing based on
type
escape analysis.
* tree.h: added free attribute.
2005-01-18 Daniel Berlin <dberlin@dberlin.org> (committed by Kenneth
Zadeck <zadeck@naturalbridge.com>)
* c-typeck.c (build_array_ref): Build a MEM_REF instead of
an indirect_ref if we can.
(build_unary_op): Drop MEM_REF to pointer addition when you
take the address of it.
(lvalue_p): MEM_REF is the same as INDIRECT_REF here.
* emit-rtl.c (set_mem_attributes_minus_bitpos):
Handle MEM_REF.
* expr.c (expand_expr_real_1): Abort if we try to expand a MEM_REF.
* gimple-low.c (lower_memref): New function.
(lower_memrefs): Ditto.
(pass_lower_memref): Ditto.
* gimplify.c (gimplify_expr): Add gimplification of MEM_REF.
(check_pointer_types_r): Add MEM_REF.
* tree-eh.c (tree_could_trap_p): MEM_REF is like INDIRECT_REF here.
* tree-gimple.c (is_gimple_addressable): Add MEM_REF.
(is_gimple_min_lval): Ditto.
(get_base_address): Handle MEM_REF.
* tree-inline.c (estimate_num_insns_1): Ditto.
* tree-optimize.c: Add memref lowering passes
* tree-pass.h: Add pass_lower_memref.
* tree-pretty-print.c (dump_generic_node): Print out MEM_REF.
* tree-ssa-alias.c (find_ptr_dereference): Add MEM_REF handling.
* tree-ssa-loop-im.c (for_each_index): Ditto.
* tree-ssa-operands.c (get_mem_ref_operands): New function.
(build_ssa_operands): Add MEM_REF.
(get_expr_operands): Use get_mem_ref_operands.
* tree-ssa-pre (is_copy_stmt, follow_copies_till_vuse, do_eustores,
gate_eustores): new function to eliminate useless stores.
? gcc/aliasingcomment.txt
? gcc/makefile.promote
? gcc/notes
? gcc/static2.diff
Index: gcc/ChangeLog.profiling
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ChangeLog.profiling,v
retrieving revision 1.1.2.104
diff -c -3 -p -r1.1.2.104 ChangeLog.profiling
*** gcc/ChangeLog.profiling 18 Jan 2005 18:24:18 -0000 1.1.2.104
--- gcc/ChangeLog.profiling 18 Jan 2005 18:44:46 -0000
***************
*** 1,3 ****
--- 1,32 ----
+ 2005-01-18 Daniel Berlin <dberlin@dberlin.org> (committed by Kenneth Zadeck <zadeck@naturalbridge.com>)
+
+ * c-typeck.c (build_array_ref): Build a MEM_REF instead of
+ an indirect_ref if we can.
+ (build_unary_op): Drop MEM_REF to pointer addition when you
+ take the address of it.
+ (lvalue_p): MEM_REF is the same as INDIRECT_REF here.
+ * emit-rtl.c (set_mem_attributes_minus_bitpos):
+ Handle MEM_REF.
+ * expr.c (expand_expr_real_1): Abort if we try to expand a MEM_REF.
+ * gimple-low.c (lower_memref): New function.
+ (lower_memrefs): Ditto.
+ (pass_lower_memref): Ditto.
+ * gimplify.c (gimplify_expr): Add gimplification of MEM_REF.
+ (check_pointer_types_r): Add MEM_REF.
+ * tree-eh.c (tree_could_trap_p): MEM_REF is like INDIRECT_REF here.
+ * tree-gimple.c (is_gimple_addressable): Add MEM_REF.
+ (is_gimple_min_lval): Ditto.
+ (get_base_address): Handle MEM_REF.
+ * tree-inline.c (estimate_num_insns_1): Ditto.
+ * tree-optimize.c: Add memref lowering passes
+ * tree-pass.h: Add pass_lower_memref.
+ * tree-pretty-print.c (dump_generic_node): Print out MEM_REF.
+ * tree-ssa-alias.c (find_ptr_dereference): Add MEM_REF handling.
+ * tree-ssa-loop-im.c (for_each_index): Ditto.
+ * tree-ssa-operands.c (get_mem_ref_operands): New function.
+ (build_ssa_operands): Add MEM_REF.
+ (get_expr_operands): Use get_mem_ref_operands.
+
2005-01-18 Jan Hubicka <jh@suse.cz> (committed by Kenneth Zadeck <zadeck@naturalbridge.com>)
* cgraphunit.c (cgraph_optimize): fixed improperly initialized bitmap obstack.
* tree-optimize.c (tree_lowering_passes, tree_early_local_passes):
Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.179.2.32
diff -c -3 -p -r1.903.2.179.2.32 Makefile.in
*** gcc/Makefile.in 9 Jan 2005 14:16:26 -0000 1.903.2.179.2.32
--- gcc/Makefile.in 18 Jan 2005 18:44:48 -0000
*************** gimplify.o : gimplify.c $(CONFIG_H) $(SY
*** 1757,1763 ****
gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
diagnostic.h $(TREE_GIMPLE_H) tree-inline.h varray.h langhooks.h \
langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
! $(FLAGS_H) $(RTL_H) function.h $(EXPR_H) tree-pass.h
tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \
$(TM_H) coretypes.h
--- 1757,1763 ----
gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
diagnostic.h $(TREE_GIMPLE_H) tree-inline.h varray.h langhooks.h \
langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
! $(FLAGS_H) $(RTL_H) function.h $(EXPR_H) tree-pass.h pointer-set.h
tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \
$(TM_H) coretypes.h
*************** ipa_prop.o : ipa_prop.c $(CONFIG_H) $(SY
*** 1935,1941 ****
ipa-static-vars-anal.o : ipa-static-vars-anal.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) tree-inline.h langhooks.h \
pointer-set.h $(GGC_H) $(IPA_STATIC_H) $(C_COMMON_H) $(TREE_GIMPLE_H) \
! $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h
ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H)
ipa-inline.o : ipa-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
langhooks.h tree-inline.h $(FLAGS_H) $(CGRAPH_H) intl.h $(TREE_FLOW_H) \
--- 1935,1941 ----
ipa-static-vars-anal.o : ipa-static-vars-anal.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) tree-inline.h langhooks.h \
pointer-set.h $(GGC_H) $(IPA_STATIC_H) $(C_COMMON_H) $(TREE_GIMPLE_H) \
! $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h $(DIAGNOSTIC_H)
ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H)
ipa-inline.o : ipa-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
langhooks.h tree-inline.h $(FLAGS_H) $(CGRAPH_H) intl.h $(TREE_FLOW_H) \
*************** reorg.o : reorg.c $(CONFIG_H) $(SYSTEM_H
*** 2124,2130 ****
alias.o : alias.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \
hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) toplev.h output.h $(ALIAS_H) $(EMIT_RTL_H) \
$(GGC_H) function.h cselib.h $(TREE_H) $(TM_P_H) langhooks.h $(TARGET_H) \
! gt-alias.h $(TIMEVAR_H) $(CGRAPH_H)
regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-config.h \
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) function.h \
$(EXPR_H) $(BASIC_BLOCK_H) toplev.h $(TM_P_H) except.h reload.h
--- 2124,2130 ----
alias.o : alias.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \
hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) toplev.h output.h $(ALIAS_H) $(EMIT_RTL_H) \
$(GGC_H) function.h cselib.h $(TREE_H) $(TM_P_H) langhooks.h $(TARGET_H) \
! gt-alias.h $(TIMEVAR_H) $(CGRAPH_H) ipa-static.h
regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-config.h \
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) function.h \
$(EXPR_H) $(BASIC_BLOCK_H) toplev.h $(TM_P_H) except.h reload.h
Index: gcc/alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/alias.c,v
retrieving revision 1.176.2.21.2.14
diff -c -3 -p -r1.176.2.21.2.14 alias.c
*** gcc/alias.c 15 Dec 2004 22:17:26 -0000 1.176.2.21.2.14
--- gcc/alias.c 18 Jan 2005 18:44:48 -0000
*************** Software Foundation, 59 Temple Place - S
*** 45,50 ****
--- 45,96 ----
#include "cgraph.h"
#include "varray.h"
+ /* The aliasing api provided here solves related but different problems:
+
+ Say there exists (in c)
+
+ struct X {
+ struct Y y1;
+ struct Z z2;
+ } x1, *px1, *px2;
+
+ struct Y y2, *py;
+ struct Z z2, *pz;
+
+
+ py = &px1.y1;
+
+ Consider the four questions:
+
+ can a store to x1 interfere with px2->y2?
+ can a store to x1 interfere with px2->z2?
+ can a store to x1 change the value pointed to by with py?
+ can a store to x1 change the value pointed to by with pz?
+
+ the answer to these questions can be yes, yes, yes, no
+
+ The first two questions can be answered with a simple examination
+ of the type system. If structure X contains a field of type Y then
+ a store thru a pointer to an X can overwrite any field that is
+ contained (recursively) in an X (unless we know that px1 != px2).
+
+ The last two of the questions can be solved in the same way as the
+ first two questions but this is too conservative. The observation
+ is that if the address of a field is not explicitly taken and the
+ type is completely local to the compilation unit, then it is
+ impossible that a pointer to an instance of the field type overlaps
+ with an enclosing structure.
+
+ Historically in GCC, these two problems were combined and a single
+ data structure was used to represent the solution to these
+ problems. We now have two similar but different data structures,
+ The data structure to solve the last two question is similar to the
+ first, but does not contain have the fields in it whose address are
+ never taken. For types that do escape the compilation unit, the
+ data structures will have identical information.
+
+ */
+
/* The alias sets assigned to MEMs assist the back-end in determining
which MEMs can alias which other MEMs. In general, two MEMs in
different alias sets cannot alias each other, with one important
Index: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.344.2.61.2.16
diff -c -3 -p -r1.344.2.61.2.16 c-common.c
*** gcc/c-common.c 9 Jan 2005 14:16:34 -0000 1.344.2.61.2.16
--- gcc/c-common.c 18 Jan 2005 18:44:50 -0000
*************** static tree handle_tls_model_attribute (
*** 546,551 ****
--- 546,552 ----
static tree handle_no_instrument_function_attribute (tree *, tree,
tree, int, bool *);
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_free_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
bool *);
static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
*************** const struct attribute_spec c_common_att
*** 614,619 ****
--- 615,622 ----
handle_alias_attribute },
{ "no_instrument_function", 0, 0, true, false, false,
handle_no_instrument_function_attribute },
+ { "free", 0, 0, true, false, false,
+ handle_free_attribute },
{ "malloc", 0, 0, true, false, false,
handle_malloc_attribute },
{ "no_stack_limit", 0, 0, true, false, false,
*************** handle_malloc_attribute (tree *node, tre
*** 4750,4755 ****
--- 4753,4777 ----
return NULL_TREE;
}
+ /* Handle a "free" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+ static tree
+ handle_free_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+ {
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_IS_FREE (*node) = 1;
+ /* ??? TODO: Support types. */
+ else
+ {
+ warning ("%qs attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+ }
+
/* Handle a "no_limit_stack" attribute; arguments as in
struct attribute_spec.handler. */
Index: gcc/c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.334.2.80.2.19
diff -c -3 -p -r1.334.2.80.2.19 c-decl.c
*** gcc/c-decl.c 9 Jan 2005 14:16:38 -0000 1.334.2.80.2.19
--- gcc/c-decl.c 18 Jan 2005 18:44:52 -0000
*************** merge_decls (tree newdecl, tree olddecl,
*** 1677,1682 ****
--- 1677,1683 ----
TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+ DECL_IS_FREE (newdecl) |= DECL_IS_FREE (olddecl);
DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
}
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.196.2.39.2.15
diff -c -3 -p -r1.196.2.39.2.15 c-typeck.c
*** gcc/c-typeck.c 9 Jan 2005 14:16:46 -0000 1.196.2.39.2.15
--- gcc/c-typeck.c 18 Jan 2005 18:44:54 -0000
***************
*** 1,6 ****
/* Build expressions with type checking for C compiler.
! Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
! 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
--- 1,6 ----
/* Build expressions with type checking for C compiler.
! Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
! 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
*************** build_array_ref (tree array, tree index)
*** 1769,1777 ****
else if (!flag_isoc99 && !lvalue_p (foo))
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
!
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
or if the array is. */
TREE_READONLY (rval)
--- 1769,1779 ----
else if (!flag_isoc99 && !lvalue_p (foo))
pedwarn ("ISO C90 forbids subscripting non-lvalue array");
}
!
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
+
+
/* Array ref is const/volatile if the array elements are
or if the array is. */
TREE_READONLY (rval)
*************** build_array_ref (tree array, tree index)
*** 1792,1806 ****
else
{
tree ar = default_conversion (array);
!
if (ar == error_mark_node)
return ar;
gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE);
gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
! return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
! "array indexing");
}
}
--- 1794,1826 ----
else
{
tree ar = default_conversion (array);
! tree type;
! tree res;
if (ar == error_mark_node)
return ar;
gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE);
gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (ar)));
! /* If this type has no size, either we're screwed or we've issued an
! error, so it doesn't matter if we build a MEM_REF here or not. */
! if (TYPE_SIZE_UNIT (type)
! && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
! {
! res = build2 (MEM_REF, type, ar, index);
! TREE_READONLY (res) = TYPE_READONLY (TREE_TYPE (TREE_TYPE (ar)));
! TREE_SIDE_EFFECTS (res)
! |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (ar)))
! | TREE_SIDE_EFFECTS (ar));
! TREE_THIS_VOLATILE (res)
! |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (ar)))
! | TREE_THIS_VOLATILE (ar));
! return res;
! }
! else
! return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
! "array indexing");
}
}
*************** build_unary_op (enum tree_code code, tre
*** 2715,2721 ****
return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1), 1);
}
!
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
--- 2735,2750 ----
return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1), 1);
}
! /* Same for the equivalent MEM_REF */
! if (TREE_CODE (arg) == MEM_REF)
! {
! if (!c_mark_addressable (MEM_REF_SYMBOL (arg)))
! return error_mark_node;
! return build_binary_op (PLUS_EXPR,
! MEM_REF_SYMBOL (arg),
! MEM_REF_INDEX (arg), 1);
! }
!
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
*************** lvalue_p (tree ref)
*** 2792,2797 ****
--- 2821,2827 ----
case VAR_DECL:
case PARM_DECL:
case RESULT_DECL:
+ case MEM_REF:
case ERROR_MARK:
return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
&& TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
Index: gcc/calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.229.2.42.2.15
diff -c -3 -p -r1.229.2.42.2.15 calls.c
*** gcc/calls.c 9 Jan 2005 14:16:48 -0000 1.229.2.42.2.15
--- gcc/calls.c 18 Jan 2005 18:44:55 -0000
*************** flags_from_decl_or_type (tree exp)
*** 578,583 ****
--- 578,587 ----
if (DECL_IS_MALLOC (exp))
flags |= ECF_MALLOC;
+ /* The function exp may have the `free' attribute. */
+ if (DECL_IS_FREE (exp))
+ flags |= ECF_FREE;
+
/* The function exp may have the `pure' attribute. */
if (DECL_IS_PURE (exp))
flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
Index: gcc/emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.280.2.29.2.17
diff -c -3 -p -r1.280.2.29.2.17 emit-rtl.c
*** gcc/emit-rtl.c 9 Jan 2005 14:17:09 -0000 1.280.2.29.2.17
--- gcc/emit-rtl.c 18 Jan 2005 18:44:57 -0000
*************** set_mem_attributes_minus_bitpos (rtx ref
*** 1509,1514 ****
--- 1509,1515 ----
this is an INDIRECT_REF, or if TYPE_ALIGN_OK. */
if (objectp || TREE_CODE (t) == INDIRECT_REF
|| TREE_CODE (t) == ALIGN_INDIRECT_REF
+ || TREE_CODE (t) == MEM_REF
|| TYPE_ALIGN_OK (type))
align = MAX (align, TYPE_ALIGN (type));
else
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.467.2.76.2.21
diff -c -3 -p -r1.467.2.76.2.21 expr.c
*** gcc/expr.c 9 Jan 2005 14:17:10 -0000 1.467.2.76.2.21
--- gcc/expr.c 18 Jan 2005 18:44:59 -0000
*************** get_inner_reference (tree exp, HOST_WIDE
*** 5346,5352 ****
/* ??? Right now we don't do anything with DECL_OFFSET_ALIGN. */
}
break;
-
case ARRAY_REF:
case ARRAY_RANGE_REF:
{
--- 5346,5351 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 6783,6789 ****
return temp;
}
!
case ARRAY_REF:
{
--- 6782,6789 ----
return temp;
}
! case MEM_REF:
! gcc_unreachable ();
case ARRAY_REF:
{
Index: gcc/gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimple-low.c,v
retrieving revision 1.1.4.17.2.12
diff -c -3 -p -r1.1.4.17.2.12 gimple-low.c
*** gcc/gimple-low.c 9 Jan 2005 14:17:24 -0000 1.1.4.17.2.12
--- gcc/gimple-low.c 18 Jan 2005 18:44:59 -0000
*************** Software Foundation, 59 Temple Place - S
*** 41,47 ****
#include "expr.h"
#include "toplev.h"
#include "tree-pass.h"
!
struct lower_data
{
/* Block the current statement belongs to. */
--- 41,47 ----
#include "expr.h"
#include "toplev.h"
#include "tree-pass.h"
! #include "pointer-set.h"
struct lower_data
{
/* Block the current statement belongs to. */
*************** struct tree_opt_pass pass_mark_used_bloc
*** 606,608 ****
--- 606,693 ----
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
+
+ /* Lower a MEM_REF tree to it's equivalent INDIRECT_REF form. TP is a
+ pointer to the tree we are currently walking, and DATA is a pointer
+ to it's block_stmt_iterator, used for inserting whatever
+ expressions are necessary to create GIMPLE from it. */
+
+ static tree
+ lower_memref (tree *tp,
+ int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data)
+ {
+ block_stmt_iterator *bsip = (block_stmt_iterator *)data;
+ if (TREE_CODE (*tp) == MEM_REF)
+ {
+ tree indirect;
+ tree stmts;
+ tree with;
+ with = build2 (MULT_EXPR, TREE_TYPE (MEM_REF_INDEX (*tp)),
+ MEM_REF_INDEX (*tp),
+ size_in_bytes (TREE_TYPE (TREE_TYPE (MEM_REF_SYMBOL (*tp)))));
+ with = fold_convert (TREE_TYPE (MEM_REF_SYMBOL (*tp)), with);
+ with = build2 (PLUS_EXPR, TREE_TYPE (MEM_REF_SYMBOL (*tp)),
+ MEM_REF_SYMBOL (*tp), with);
+
+
+ with = force_gimple_operand (with, &stmts, false, NULL_TREE);
+ if (stmts)
+ bsi_insert_before (bsip, stmts, BSI_SAME_STMT);
+
+ indirect = build1 (INDIRECT_REF, TREE_TYPE (*tp), with);
+ TREE_READONLY (indirect) = TREE_READONLY (*tp);
+ TREE_SIDE_EFFECTS (indirect) = TREE_SIDE_EFFECTS (*tp);
+ TREE_THIS_VOLATILE (indirect) = TREE_THIS_VOLATILE (*tp);
+
+ indirect = force_gimple_operand (indirect, &stmts, false, NULL_TREE);
+ if (stmts)
+ bsi_insert_before (bsip, stmts, BSI_SAME_STMT);
+ *tp = indirect;
+ }
+ return NULL_TREE;
+ }
+
+ /* Convert MEM_REF trees into their equivalent INDIRECT_REF form
+ across the entire function. MEM_REF (symbol, index) = INDIRECT_REF
+ (symbol + (index * size in bytes of the type symbol points to)) */
+
+ static void
+ lower_memrefs (void)
+ {
+ struct pointer_set_t *visited_nodes;
+ basic_block bb;
+ FOR_ALL_BB (bb)
+ {
+ block_stmt_iterator bsi;
+ for (bsi = bsi_start (bb);
+ !bsi_end_p (bsi);
+ bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ visited_nodes = pointer_set_create ();
+ walk_tree (&stmt, lower_memref, (void *)&bsi, visited_nodes);
+ pointer_set_destroy (visited_nodes);
+
+ }
+ }
+ }
+ struct tree_opt_pass pass_lower_memref =
+ {
+ "memrefs", /* name */
+ NULL, /* gate */
+ NULL, NULL, /* IPA analysis */
+ lower_memrefs, /* execute */
+ NULL, NULL, /* IPA analysis */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+ };
+
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 1.1.2.141.2.17
diff -c -3 -p -r1.1.2.141.2.17 gimplify.c
*** gcc/gimplify.c 9 Jan 2005 14:17:24 -0000 1.1.2.141.2.17
--- gcc/gimplify.c 18 Jan 2005 18:45:01 -0000
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3765,3771 ****
is_gimple_val, fb_rvalue);
recalculate_side_effects (*expr_p);
break;
!
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF:
--- 3765,3782 ----
is_gimple_val, fb_rvalue);
recalculate_side_effects (*expr_p);
break;
! case MEM_REF:
! {
! enum gimplify_status r0, r1;
!
! r0 = gimplify_expr (&MEM_REF_SYMBOL (*expr_p), pre_p, post_p,
! is_gimple_reg, fb_rvalue);
! r1 = gimplify_expr (&MEM_REF_INDEX (*expr_p), pre_p, post_p,
! is_gimple_reg, fb_rvalue);
! recalculate_side_effects (*expr_p);
! ret = MIN (r0, r1);
! }
! break;
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3826,3832 ****
ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p,
NULL, is_gimple_val, fb_rvalue);
break;
-
case LABEL_EXPR:
ret = GS_ALL_DONE;
gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
--- 3837,3842 ----
*************** check_pointer_types_r (tree *tp, int *wa
*** 4347,4352 ****
--- 4357,4363 ----
switch (TREE_CODE (t))
{
case INDIRECT_REF:
+ case MEM_REF:
case ARRAY_REF:
otype = TREE_TYPE (t);
ptype = TREE_TYPE (TREE_OPERAND (t, 0));
Index: gcc/ipa-static-vars-anal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ipa-static-vars-anal.c,v
retrieving revision 1.1.2.6
diff -c -3 -p -r1.1.2.6 ipa-static-vars-anal.c
*** gcc/ipa-static-vars-anal.c 19 Dec 2004 19:11:09 -0000 1.1.2.6
--- gcc/ipa-static-vars-anal.c 18 Jan 2005 18:45:01 -0000
*************** Software Foundation, 59 Temple Place - S
*** 69,74 ****
--- 69,76 ----
#include "output.h"
#include "flags.h"
#include "timevar.h"
+ #include "diagnostic.h"
+ #include "langhooks.h"
/* FIXME -- PROFILE-RESTRUCTURE: change comment from DECL_UID to var-ann. */
/* This splay tree contains all of the static variables that are
*************** static bitmap module_statics_written;
*** 95,100 ****
--- 97,161 ----
code is found that clobbers all memory. */
static bitmap all_module_statics;
+ /* This bitmap contains the set of local vars that are the lhs of
+ calls to mallocs. These variables, when seen on the rhs as part of
+ a cast, the cast are not marked as doing bad things to the type
+ even though they are generally of the form
+ "foo = (type_of_foo)void_temp". */
+ static bitmap results_of_malloc;
+
+ /* Scratch bitmap for avoiding work. */
+ static bitmap been_there_done_that;
+
+ /* There are two levels of escape that types can undergo.
+
+ EXPOSED_PARAMETER - some instance of the variable is
+ passed by value into an externally visible function or some
+ instance of the variable is passed out of an externally visible
+ function as a return value. In this case any of the fields of the
+ variable that are pointer types end up having their types marked as
+ FULL_ESCAPE.
+
+ FULL_ESCAPE - when bad things happen to good types. One of the
+ following things happens to the type: (a) either an instance of the
+ variable has it's address passed to an externally visible function,
+ (b) the address is taken and some bad cast happens to the address
+ or (c) explicit arithmetic is done to the address.
+ */
+
+ enum escape_t
+ {
+ EXPOSED_PARAMETER,
+ FULL_ESCAPE
+ };
+
+ /* The following two bit vectors global_types_* correspond to
+ previous cases above. During the analysis phase, a bit is set in
+ one of these vectors if an operation of the offending class is
+ discovered to happen on the associated type. */
+
+ static bitmap global_types_exposed_parameter;
+ static bitmap global_types_full_escape;
+
+ /* All of the types seen in this compilation unit. */
+ static bitmap global_types_seen;
+ static splay_tree uid_to_type;
+
+ /* Map the several instances of a type into a single instance. These
+ can arise in several ways, nono of which can be justified except by
+ laziness and stupidity. */
+ static splay_tree uid_to_unique_type;
+ static splay_tree all_unique_types;
+
+ /* A splay tree of bitmaps. An element X in the splay tree has a bit
+ set in its bitmap at TYPE_UID (TYPE_MAIN_VARIANT (Y) if there was
+ an operation in the program of the form "&X.Y". */
+ static splay_tree uid_to_addressof_map;
+
+ /* Tree to hold the subtype maps used to mark subtypes of escaped
+ types. */
+ static splay_tree uid_to_subtype_map;
+
/* Records tree nodes seen in cgraph_create_edges. Simply using
walk_tree_without_duplicates doesn't guarantee each node is visited
once because it gets a new htab upon each recursive call from
*************** print_order (FILE* out,
*** 134,139 ****
--- 195,230 ----
fflush(out);
}
+ /* All of the "unique_type" code is a hack to get around the sleezy
+ implementation used to compile more than file. If the same type is
+ declared in several files, multiple types will appear that are the
+ same. The code in this unit chooses one "unique" instance of that
+ type as the representative and has all of the others point to
+ it. */
+
+ /* Find the unique representative for a type with UID. */
+ static int
+ unique_type_id_for (int uid)
+ {
+ splay_tree_node result =
+ splay_tree_lookup(uid_to_unique_type, (splay_tree_key) uid);
+
+ if (result)
+ return TYPE_UID((tree) result->value);
+ else
+ {
+ abort();
+ return uid;
+ }
+ }
+
+ /* Return true if the type with UID is the unique representative. */
+ static bool
+ unique_type_id_p (int uid)
+ {
+ return uid == unique_type_id_for (uid);
+ }
+
/* FIXME -- PROFILE-RESTRUCTURE: Remove this function, it becomes a nop. */
/* Convert IN_DECL bitmap which is indexed by DECL_UID to IN_ANN, a
bitmap indexed by var_ann (VAR_DECL)->uid. */
*************** convert_UIDs_in_bitmap (bitmap in_ann, b
*** 153,159 ****
tree t = (tree)n->value;
var_ann_t va = var_ann (t);
if (va)
! bitmap_set_bit(in_ann, va->uid);
}
}
}
--- 244,250 ----
tree t = (tree)n->value;
var_ann_t va = var_ann (t);
if (va)
! bitmap_set_bit (in_ann, va->uid);
}
}
}
*************** ipa_get_statics_not_written_global (tree
*** 354,359 ****
--- 445,542 ----
return NULL;
}
+ /* Return 0 if TYPE is a record or union type. Return a positive
+ number if TYPE is a pointer to a record or union. The number is
+ the number of pointer types stripped to get to the record or union
+ type. Return -1 if TYPE is none of the above. */
+
+ int
+ ipa_static_star_count_of_interesting_type (tree type)
+ {
+ int count = 0;
+ /* Strip the *'s off. */
+ while (POINTER_TYPE_P (type))
+ {
+ type = TREE_TYPE (type);
+ count++;
+ }
+
+ /* We are interested in records, and unions only. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ return count;
+ else
+ return -1;
+ }
+
+ /* Return true if the record, or union TYPE passed in escapes this
+ compilation unit. */
+
+ bool
+ ipa_static_type_contained_p (tree type)
+ {
+ int uid;
+
+ if (initialization_status == UNINITIALIZED)
+ return false;
+
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ type = TYPE_MAIN_VARIANT (type);
+ uid = unique_type_id_for (TYPE_UID (type));
+ return bitmap_bit_p (global_types_full_escape, uid);
+ }
+
+ /* Return true if no fields with type FIELD_TYPE within a record of
+ RECORD_TYPE has its address taken. */
+
+ bool
+ ipa_static_address_not_taken_of_field (tree record_type, tree field_type)
+ {
+ splay_tree_node result;
+ int uid;
+
+ if (initialization_status == UNINITIALIZED)
+ return false;
+
+ /* Strip off all of the pointer tos on the record type. Strip the
+ same number of pointer tos from the field type. If the field
+ type has fewer, it could not have been aliased. */
+ while (POINTER_TYPE_P (record_type))
+ {
+ record_type = TREE_TYPE (record_type);
+ if (POINTER_TYPE_P (field_type))
+ field_type = TREE_TYPE (field_type);
+ else
+ return true;
+ }
+
+ /* The record type must be contained. The field type may
+ escape. */
+ if (!ipa_static_type_contained_p (record_type))
+ return false;
+
+ record_type = TYPE_MAIN_VARIANT (record_type);
+ uid = unique_type_id_for (TYPE_UID (record_type));
+ result = splay_tree_lookup (uid_to_addressof_map, (splay_tree_key) uid);
+
+ if (result)
+ {
+ bitmap field_type_map = (bitmap) result->value;
+ field_type = TYPE_MAIN_VARIANT (field_type);
+ uid = unique_type_id_for (TYPE_UID (field_type));
+ /* If the bit is there, the address was taken. If not, it
+ wasn't. */
+ return !bitmap_bit_p (field_type_map, uid);
+ }
+ else
+ /* No bitmap means no addresses were taken. */
+ return true;
+ }
+
+
struct searchc_env {
struct cgraph_node **stack;
int stack_size;
*************** reduced_inorder (struct cgraph_node **or
*** 478,484 ****
node->next_cycle = NULL;
splay_tree_insert (env.nodes_marked_new,
! node->uid, (splay_tree_value)node);
}
else
node->aux = NULL;
--- 661,668 ----
node->next_cycle = NULL;
splay_tree_insert (env.nodes_marked_new,
! (splay_tree_key)node->uid,
! (splay_tree_value)node);
}
else
node->aux = NULL;
*************** reduced_inorder (struct cgraph_node **or
*** 500,520 ****
}
return env.order_pos;
}
/* Add VAR to all_module_statics and the two static_vars_to_consider*
sets. */
! static inline
! void add_static_var (tree var)
{
! /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
! DECL_UID to get the uid from the var_ann field. */
! splay_tree_insert (static_vars_to_consider_by_uid,
! DECL_UID (var), (splay_tree_value)var);
!
! /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
! DECL_UID to get the uid from the var_ann field. */
! bitmap_set_bit (all_module_statics, DECL_UID (var));
}
/* FIXME this needs to be enhanced. If we are compiling a single
--- 684,955 ----
}
return env.order_pos;
}
+
+
+
+ /* Mark a TYPE as being seen. This is only called from two places:
+ mark_type_seen which only calls it with record and union types and
+ mark_interesting_addressof which can mark any field type. */
+
+ static bool
+ mark_any_type_seen (tree type)
+ {
+ int uid;
+
+ type = TYPE_MAIN_VARIANT (type);
+ uid = TYPE_UID (type);
+ if (bitmap_bit_p (global_types_seen, uid))
+ return false;
+ else
+ {
+ splay_tree_insert (uid_to_type,
+ (splay_tree_key) uid,
+ (splay_tree_value) type);
+ bitmap_set_bit (global_types_seen, uid);
+ }
+ return true;
+ }
+
+ /* Mark the underlying record or union type of TYPE as being seen.
+ Pointer tos are stripped from the type and non record or unions are
+ not considered. */
+
+ static bool
+ mark_type_seen (tree type)
+ {
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ /* We are interested in records, and unions only. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ return mark_any_type_seen (type);
+ else
+ return false;
+ }
+
+ /* Add TYPE to the suspect type set. Return true if the bit needed to
+ be marked. */
+
+ static bool
+ mark_type (tree type, enum escape_t escape_status)
+ {
+ bitmap map = NULL;
+ int uid;
+
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ switch (escape_status)
+ {
+ case EXPOSED_PARAMETER:
+ map = global_types_exposed_parameter;
+ break;
+ case FULL_ESCAPE:
+ map = global_types_full_escape;
+ break;
+ }
+
+ uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
+ if (bitmap_bit_p (map, uid))
+ return false;
+ else
+ {
+ bitmap_set_bit (map, uid);
+ mark_type_seen (type);
+
+ if (escape_status == FULL_ESCAPE)
+ {
+ /* Effeciency hack. When things are bad, do not mess around
+ with this type anymore. */
+ bitmap_set_bit (global_types_exposed_parameter, uid);
+ }
+ }
+ return true;
+ }
+
+ /* Add interesting TYPE to the suspect type set. If the set is
+ EXPOSED_PARAMETER and the TYPE is a pointer type, the set is
+ changed to FULL_ESCAPE. */
+
+ static void
+ mark_interesting_type (tree type, enum escape_t escape_status)
+ {
+ if (ipa_static_star_count_of_interesting_type (type) >= 0)
+ {
+ if ((escape_status == EXPOSED_PARAMETER)
+ && POINTER_TYPE_P (type))
+ /* EXPOSED_PARAMETERs are only structs or unions are passed by
+ value. Anything passed by reference to an external
+ function fully exposes the type. */
+ mark_type (type, FULL_ESCAPE);
+ else
+ mark_type (type, escape_status);
+ }
+ }
+
+ /* Return true if PARENT is supertype of CHILD. Both types must be
+ known to be structures or unions. */
+
+ static bool
+ parent_type_p (tree parent, tree child)
+ {
+ int i;
+ tree binfo, base_binfo;
+ if (TYPE_BINFO (parent))
+ for (binfo = TYPE_BINFO (parent), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree binfotype = BINFO_TYPE (base_binfo);
+ if (binfotype == child)
+ return true;
+ else if (parent_type_p (binfotype, child))
+ return true;
+ }
+ return false;
+ }
+
+ /* Return the number of pointer tos for TYPE and return TYPE with all
+ of these stripped off. */
+
+ static int
+ count_stars (tree* type_ptr)
+ {
+ tree type = *type_ptr;
+ int i = 0;
+ while (POINTER_TYPE_P (type))
+ {
+ type = TREE_TYPE (type);
+ i++;
+ }
+
+ *type_ptr = type;
+ return i;
+ }
+
+ enum cast_type {
+ CT_UP,
+ CT_DOWN,
+ CT_SIDEWAYS,
+ CT_USELESS
+ };
+
+ /* Check the cast FROM_TYPE to TO_TYPE. This function requires that
+ the two types have already passed the
+ ipa_static_star_count_of_interesting_type test. */
+
+ static enum cast_type
+ check_cast_type (tree to_type, tree from_type)
+ {
+ int to_stars = count_stars (&to_type);
+ int from_stars = count_stars (&from_type);
+ if (to_stars != from_stars)
+ return CT_SIDEWAYS;
+
+ if (to_type == from_type)
+ return CT_USELESS;
+
+ if (parent_type_p (to_type, from_type)) return CT_UP;
+ if (parent_type_p (from_type, to_type)) return CT_DOWN;
+ return CT_SIDEWAYS;
+ }
+
+ /* Check a cast FROM this variable, TO_TYPE. Mark the escaping types
+ if appropriate. */
+ static void
+ check_cast (tree to_type, tree from)
+ {
+ tree from_type = TYPE_MAIN_VARIANT (TREE_TYPE (from));
+ bool to_interesting_type, from_interesting_type;
+
+ to_type = TYPE_MAIN_VARIANT (to_type);
+ if (from_type == to_type)
+ return;
+
+ to_interesting_type =
+ ipa_static_star_count_of_interesting_type (to_type) >= 0;
+ from_interesting_type =
+ ipa_static_star_count_of_interesting_type (from_type) >= 0;
+
+ if (to_interesting_type)
+ if (from_interesting_type)
+ {
+ /* Both types are interesting. This can be one of four types
+ of cast: useless, up, down, or sideways. We do not care
+ about up or useless. Sideways casts are always bad and
+ both sides get marked as escaping. Downcasts are not
+ interesting here because if type is marked as escaping, all
+ of it's subtypes escape. */
+ switch (check_cast_type (to_type, from_type))
+ {
+ case CT_UP:
+ case CT_USELESS:
+ case CT_DOWN:
+ mark_type_seen (to_type);
+ mark_type_seen (from_type);
+ break;
+
+ case CT_SIDEWAYS:
+ mark_type (to_type, FULL_ESCAPE);
+ mark_type (from_type, FULL_ESCAPE);
+ break;
+ }
+ }
+ else
+ {
+ /* If this is a cast from the local that is a result from a
+ call to malloc, do not mark the cast as bad. */
+ if (DECL_P (from) && !bitmap_bit_p (results_of_malloc, DECL_UID (from)))
+ mark_type (to_type, FULL_ESCAPE);
+ else
+ mark_type_seen (to_type);
+ }
+ else if (from_interesting_type)
+ mark_type (from_type, FULL_ESCAPE);
+ }
+
+ /* Register the parameter and return types of function FN as
+ escaping. */
+ static void
+ check_function_parameter_and_return_types (tree fn, bool escapes)
+ {
+ tree arg;
+
+ for (arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ arg && TREE_VALUE (arg) != void_type_node;
+ arg = TREE_CHAIN (arg))
+ {
+ if (escapes)
+ mark_interesting_type (arg, EXPOSED_PARAMETER);
+ else
+ mark_type_seen (arg);
+ }
+
+ if (escapes)
+ mark_interesting_type (TREE_TYPE (TREE_TYPE (fn)), EXPOSED_PARAMETER);
+ else
+ mark_type_seen (TREE_TYPE (TREE_TYPE (fn)));
+ }
/* Add VAR to all_module_statics and the two static_vars_to_consider*
sets. */
! static inline void
! add_static_var (tree var)
{
! int uid = DECL_UID (var);
! if (!bitmap_bit_p (all_module_statics, uid))
! {
! /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
! DECL_UID to get the uid from the var_ann field. */
! splay_tree_insert (static_vars_to_consider_by_uid,
! uid, (splay_tree_value)var);
!
! /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
! DECL_UID to get the uid from the var_ann field. */
! bitmap_set_bit (all_module_statics, uid);
! }
}
/* FIXME this needs to be enhanced. If we are compiling a single
*************** check_operand (ipa_local_static_vars_inf
*** 584,606 ****
{
if (!t) return;
/* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
get the uid from the var_ann field. */
! if ((TREE_CODE (t) == VAR_DECL)
! && has_proper_scope_for_analysis (local, t, checking_write))
{
! if (checking_write)
{
! if (local)
! bitmap_set_bit (local->statics_written_by_decl_uid, DECL_UID (t));
! /* Mark the write so we can tell which statics are
! readonly. */
! bitmap_set_bit (module_statics_written, DECL_UID (t));
}
- else if (local)
- bitmap_set_bit (local->statics_read_by_decl_uid, DECL_UID (t));
}
- else return;
}
/* Examine tree T for references to static variables. All internal
--- 1019,1048 ----
{
if (!t) return;
+ /* This is an assignment from a function, register the types as
+ escaping. */
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ check_function_parameter_and_return_types (t, true);
+
/* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
get the uid from the var_ann field. */
! else if (TREE_CODE (t) == VAR_DECL)
{
! mark_type_seen (TREE_TYPE (t));
! if (has_proper_scope_for_analysis (local, t, checking_write))
{
! if (checking_write)
! {
! if (local)
! bitmap_set_bit (local->statics_written_by_decl_uid, DECL_UID (t));
! /* Mark the write so we can tell which statics are
! readonly. */
! bitmap_set_bit (module_statics_written, DECL_UID (t));
! }
! else if (local)
! bitmap_set_bit (local->statics_read_by_decl_uid, DECL_UID (t));
}
}
}
/* Examine tree T for references to static variables. All internal
*************** check_tree (ipa_local_static_vars_info_t
*** 626,632 ****
/* The bottom of an indirect reference can only be read, not
written. So just recurse and whatever we find, check it against
the read bitmaps. */
! if (INDIRECT_REF_P (t))
{
check_tree (local, TREE_OPERAND (t, 0), false);
--- 1068,1074 ----
/* The bottom of an indirect reference can only be read, not
written. So just recurse and whatever we find, check it against
the read bitmaps. */
! if (INDIRECT_REF_P (t) || TREE_CODE (t) == MEM_REF)
{
check_tree (local, TREE_OPERAND (t, 0), false);
*************** check_tree (ipa_local_static_vars_info_t
*** 644,653 ****
}
}
! if (SSA_VAR_P (t))
check_operand (local, t, checking_write);
}
/* Scan tree T to see if there are any addresses taken in within T. */
static void
--- 1086,1153 ----
}
}
! if (SSA_VAR_P (t) || (TREE_CODE (t) == FUNCTION_DECL))
check_operand (local, t, checking_write);
}
+ /* Given a memory reference T, will return the variable at the bottom
+ of the access. Unlike get_base_address, this will recurse thru
+ INDIRECT_REFS. */
+
+ static tree
+ get_base_var (tree t)
+ {
+ if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
+ return t;
+
+ while (!SSA_VAR_P (t)
+ && (!CONSTANT_CLASS_P (t))
+ && TREE_CODE (t) != LABEL_DECL
+ && TREE_CODE (t) != FUNCTION_DECL
+ && TREE_CODE (t) != CONST_DECL)
+ {
+ t = TREE_OPERAND (t, 0);
+ }
+ return t;
+ }
+
+ /* Create an address_of edge FROM_TYPE.TO_TYPE. */
+ static void
+ mark_interesting_addressof (tree to_type, tree from_type)
+ {
+ from_type = TYPE_MAIN_VARIANT (from_type);
+ to_type = TYPE_MAIN_VARIANT (to_type);
+ if (ipa_static_star_count_of_interesting_type (from_type) == 0)
+ {
+ int uid = TYPE_UID (from_type);
+ bitmap from_type_map;
+ splay_tree_node result =
+ splay_tree_lookup (uid_to_addressof_map, (splay_tree_key) uid);
+
+ if (result)
+ from_type_map = (bitmap) result->value;
+ else
+ {
+ from_type_map = BITMAP_ALLOC (&ipa_obstack);
+ splay_tree_insert (uid_to_addressof_map,
+ uid,
+ (splay_tree_value)from_type_map);
+ }
+ bitmap_set_bit (from_type_map, TYPE_UID (to_type));
+ mark_type_seen (from_type);
+ mark_any_type_seen (to_type);
+ }
+ else
+ {
+ fprintf(stderr, "trying to mark the address of pointer type ");
+ print_generic_expr (stderr, from_type, 0);
+ fprintf(stderr, "\n");
+ abort ();
+ }
+ }
+
+
+
/* Scan tree T to see if there are any addresses taken in within T. */
static void
*************** look_for_address_of (ipa_local_static_va
*** 656,661 ****
--- 1156,1177 ----
if (TREE_CODE (t) == ADDR_EXPR)
{
tree x = get_base_var (t);
+ tree cref = TREE_OPERAND (t, 0);
+
+ /* If we have an expression of the form "&a.b.c.d", mark a.b,
+ b.c and c.d. as having it's address taken. */
+ tree fielddecl = NULL_TREE;
+ while (cref!= x)
+ {
+ if (TREE_CODE (cref) == COMPONENT_REF)
+ {
+ fielddecl = TREE_OPERAND (cref, 1);
+ mark_interesting_addressof (TREE_TYPE (fielddecl),
+ DECL_FIELD_CONTEXT (fielddecl));
+ }
+ cref = TREE_OPERAND (cref, 0);
+ }
+
if (TREE_CODE (x) == VAR_DECL)
{
if (has_proper_scope_for_analysis (local, x, false))
*************** look_for_address_of (ipa_local_static_va
*** 673,678 ****
--- 1189,1225 ----
}
+ /* Scan tree T to see if there are any casts within it.
+ LHS Is the LHS of the expression involving the cast. */
+
+ static void
+ look_for_casts (tree lhs __attribute__((unused)), tree t)
+ {
+ if (is_gimple_cast (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR)
+ {
+ tree castfromvar = TREE_OPERAND (t, 0);
+ check_cast (TREE_TYPE (t), castfromvar);
+ }
+ else if (TREE_CODE (t) == COMPONENT_REF
+ || TREE_CODE (t) == INDIRECT_REF
+ || TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ tree base = get_base_address (t);
+ while (t != base)
+ {
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
+ {
+ /* This may be some part of a component ref.
+ IE it may be a.b.VIEW_CONVERT_EXPR<weird_type>(c).d, AFAIK.
+ castfromref will give you a.b.c, not a. */
+ tree castfromref = TREE_OPERAND (t, 0);
+ check_cast (TREE_TYPE (t), castfromref);
+ }
+ }
+ }
+ }
+
/* Check to see if T is a read or address of operation on a static var
we are interested in analyzing. LOCAL is passed in to get access to
its bit vectors. */
*************** get_asm_expr_operands (ipa_local_static_
*** 774,786 ****
parameter is the tree node for the caller and the second operand is
the tree node for the entire call expression. */
! static void
! process_call_for_static_vars(ipa_local_static_vars_info_t local, tree call_expr)
{
int flags = call_expr_flags(call_expr);
tree operandList = TREE_OPERAND (call_expr, 1);
tree operand;
tree callee_t = get_callee_fndecl (call_expr);
struct cgraph_node* callee;
enum availability avail = AVAIL_NOT_AVAILABLE;
--- 1321,1335 ----
parameter is the tree node for the caller and the second operand is
the tree node for the entire call expression. */
! static bool
! check_call (ipa_local_static_vars_info_t local,
! tree call_expr)
{
int flags = call_expr_flags(call_expr);
tree operandList = TREE_OPERAND (call_expr, 1);
tree operand;
tree callee_t = get_callee_fndecl (call_expr);
+ tree argument;
struct cgraph_node* callee;
enum availability avail = AVAIL_NOT_AVAILABLE;
*************** process_call_for_static_vars(ipa_local_s
*** 806,814 ****
--- 1355,1395 ----
if (callee_t)
{
+ tree arg_type;
+ tree last_arg_type;
callee = cgraph_node(callee_t);
avail = cgraph_function_body_availability (callee);
+ /* If the function is FREE or a wrapper it is allowed to make an
+ implicit cast to void* without causing the type to
+ escape. */
+ if (!flags & ECF_FREE)
+ {
+ /* Check that there are no implicit casts in the passing of
+ parameters. */
+ operand = operandList;
+ for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (callee_t));
+ arg_type && TREE_VALUE (arg_type) != void_type_node;
+ arg_type = TREE_CHAIN (arg_type))
+ {
+ operand = TREE_CHAIN (operand);
+ argument = TREE_VALUE (operand);
+ check_cast (arg_type, argument);
+ last_arg_type = arg_type;
+ }
+
+ /* In the case where we have a var_args function, we need to
+ check the remaining parameters against the last argument. */
+ arg_type = last_arg_type;
+ for (;
+ operand != NULL_TREE;
+ operand = TREE_CHAIN (operand))
+ {
+ argument = TREE_VALUE (operand);
+ check_cast (arg_type, argument);
+ }
+ }
+
/* When bad things happen to bad functions, they cannot be const
or pure. */
if (local && local->pure_const_not_set_in_source)
*************** process_call_for_static_vars(ipa_local_s
*** 833,869 ****
look because if there is also code, we need to mark the variables
it is reading from. */
if (flags & ECF_CONST)
! return;
!
! if (!local) return;
/* The callee is either unknown (indirect call) or there is just no
! scanable code for it (external call) . We look to see if there
are any bits available for the callee (such as by declaration or
because it is builtin) and process solely on the basis of those
bits. */
if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
{
! if (flags & ECF_PURE)
{
! local->calls_read_all = true;
! if (local->pure_const_not_set_in_source
! && local->pure_const_state == IPA_CONST)
! local->pure_const_state = IPA_PURE;
}
! else
{
! local->calls_read_all = true;
! local->calls_write_all = true;
! if (local->pure_const_not_set_in_source)
! local->pure_const_state = IPA_NEITHER;
}
}
else
{
/* We have the code and we will scan it for the effects. */
! if (flags & ECF_PURE)
{
/* Since we have the code for the function, we do not need to
set calls_read_all, we can determine the precise reads
--- 1414,1465 ----
look because if there is also code, we need to mark the variables
it is reading from. */
if (flags & ECF_CONST)
! return false;
/* The callee is either unknown (indirect call) or there is just no
! scannable code for it (external call) . We look to see if there
are any bits available for the callee (such as by declaration or
because it is builtin) and process solely on the basis of those
bits. */
if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
{
! /* If this is a direct call to an external function, mark all of
! the parameter and return types. */
! for (operand = operandList;
! operand != NULL_TREE;
! operand = TREE_CHAIN (operand))
{
! mark_interesting_type (TREE_TYPE (TREE_VALUE (operand)),
! EXPOSED_PARAMETER);
}
!
! if (callee_t)
! mark_interesting_type (TREE_TYPE (TREE_TYPE (callee_t)),
! EXPOSED_PARAMETER);
!
! if (local)
{
! if (flags & ECF_PURE)
! {
! local->calls_read_all = true;
! if (local->pure_const_not_set_in_source
! && local->pure_const_state == IPA_CONST)
! local->pure_const_state = IPA_PURE;
! }
! else
! {
! local->calls_read_all = true;
! local->calls_write_all = true;
! if (local->pure_const_not_set_in_source)
! local->pure_const_state = IPA_NEITHER;
! }
}
}
else
{
/* We have the code and we will scan it for the effects. */
! if (local && (flags & ECF_PURE))
{
/* Since we have the code for the function, we do not need to
set calls_read_all, we can determine the precise reads
*************** process_call_for_static_vars(ipa_local_s
*** 873,878 ****
--- 1469,1476 ----
local->pure_const_state = IPA_PURE;
}
}
+
+ return (flags & ECF_MALLOC);
}
/* FIXME -- PROFILE-RESTRUCTURE: Change to walk by explicitly walking
*************** scan_for_static_refs (tree *tp,
*** 909,928 ****
case MODIFY_EXPR:
{
/* First look on the lhs and see what variable is stored to */
tree rhs = TREE_OPERAND (t, 1);
! check_lhs_var (local, TREE_OPERAND (t, 0));
/* Next check the operands on the rhs to see if they are ok. */
switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
{
! case tcc_binary:
! check_rhs_var (local, TREE_OPERAND (rhs, 0));
! check_rhs_var (local, TREE_OPERAND (rhs, 1));
break;
case tcc_unary:
! check_rhs_var (local, TREE_OPERAND (rhs, 0));
break;
case tcc_reference:
check_rhs_var (local, rhs);
break;
case tcc_declaration:
--- 1507,1569 ----
case MODIFY_EXPR:
{
/* First look on the lhs and see what variable is stored to */
+ tree lhs = TREE_OPERAND (t, 0);
tree rhs = TREE_OPERAND (t, 1);
!
! check_lhs_var (local, lhs);
! check_cast (TREE_TYPE (lhs), rhs);
!
! /* For the purposes of figuring out what the cast affects */
/* Next check the operands on the rhs to see if they are ok. */
switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
{
! case tcc_binary:
! {
! tree op0 = TREE_OPERAND (rhs, 0);
! tree op1 = TREE_OPERAND (rhs, 1);
!
! /* If this is pointer arithmetic of any sort, then we
! need to mark the types as bad. For binary
! operations, no binary operator we currently support
! is always "safe" in regard to what it would do to
! pointers for purposes of determining which types
! escape. It is possible that min and max under the
! right set of circumstances and if the moon is in the
! correct place could be safe, but it is hard to see
! how this is worth the effort. */
!
! if (POINTER_TYPE_P (TREE_TYPE (op0)))
! mark_interesting_type (TREE_TYPE (op0), FULL_ESCAPE);
! if (POINTER_TYPE_P (TREE_TYPE (op1)))
! mark_interesting_type (TREE_TYPE (op1), FULL_ESCAPE);
!
! look_for_casts (lhs, op0);
! look_for_casts (lhs, op1);
! check_rhs_var (local, op0);
! check_rhs_var (local, op1);
! }
break;
case tcc_unary:
! {
! tree op0 = TREE_OPERAND (rhs, 0);
! /* For unary operations, if the operation is NEGATE or ABS on
! a pointer, this is also considered pointer arithmetic and thus,
! bad for business. */
! if ((TREE_CODE (op0) == NEGATE_EXPR
! || TREE_CODE (op0) == ABS_EXPR)
! && POINTER_TYPE_P (TREE_TYPE (op0)))
! {
! mark_interesting_type (TREE_TYPE (op0), FULL_ESCAPE);
! }
! check_rhs_var (local, op0);
! look_for_casts (lhs, op0);
! look_for_casts (lhs, rhs);
! }
!
break;
case tcc_reference:
+ look_for_casts (lhs, rhs);
check_rhs_var (local, rhs);
break;
case tcc_declaration:
*************** scan_for_static_refs (tree *tp,
*** 932,941 ****
switch (TREE_CODE (rhs))
{
case ADDR_EXPR:
check_rhs_var (local, rhs);
break;
case CALL_EXPR:
! process_call_for_static_vars (local, rhs);
break;
default:
break;
--- 1573,1587 ----
switch (TREE_CODE (rhs))
{
case ADDR_EXPR:
+ look_for_casts (lhs, TREE_OPERAND (rhs, 0));
check_rhs_var (local, rhs);
break;
case CALL_EXPR:
! /* If this is a call to malloc, squirrel away the
! result so we do mark the resulting cast as being
! bad. */
! if (check_call (local, rhs))
! bitmap_set_bit (results_of_malloc, DECL_UID (lhs));
break;
default:
break;
*************** scan_for_static_refs (tree *tp,
*** 967,973 ****
break;
case CALL_EXPR:
! process_call_for_static_vars (local, t);
*walk_subtrees = 0;
break;
--- 1613,1619 ----
break;
case CALL_EXPR:
! check_call (local, t);
*walk_subtrees = 0;
break;
*************** scan_for_static_refs (tree *tp,
*** 982,987 ****
--- 1628,1634 ----
return NULL;
}
+
/* Lookup the tree node for the static variable that has UID. */
static tree
get_static_decl_by_uid (int index)
*************** propagate_bits (struct cgraph_node *x)
*** 1047,1053 ****
if (y_global->statics_read_by_decl_uid
== all_module_statics)
{
! BITMAP_XFREE(x_global->statics_read_by_decl_uid);
x_global->statics_read_by_decl_uid
= all_module_statics;
}
--- 1694,1700 ----
if (y_global->statics_read_by_decl_uid
== all_module_statics)
{
! BITMAP_XFREE (x_global->statics_read_by_decl_uid);
x_global->statics_read_by_decl_uid
= all_module_statics;
}
*************** propagate_bits (struct cgraph_node *x)
*** 1064,1070 ****
if (y_global->statics_written_by_decl_uid
== all_module_statics)
{
! BITMAP_XFREE(x_global->statics_written_by_decl_uid);
x_global->statics_written_by_decl_uid
= all_module_statics;
}
--- 1711,1717 ----
if (y_global->statics_written_by_decl_uid
== all_module_statics)
{
! BITMAP_XFREE (x_global->statics_written_by_decl_uid);
x_global->statics_written_by_decl_uid
= all_module_statics;
}
*************** merge_callee_local_info (struct cgraph_n
*** 1145,1151 ****
/* The init routine for analyzing global static variable usage. See
comments at top for description. */
!
static void
ipa_init (void)
{
--- 1792,1798 ----
/* The init routine for analyzing global static variable usage. See
comments at top for description. */
! int cant_touch = 0;
static void
ipa_init (void)
{
*************** ipa_init (void)
*** 1160,1165 ****
--- 1807,1820 ----
module_statics_escape = BITMAP_ALLOC (&ipa_obstack);
module_statics_written = BITMAP_ALLOC (&ipa_obstack);
all_module_statics = BITMAP_ALLOC (&ipa_obstack);
+ global_types_seen = BITMAP_ALLOC (&ipa_obstack);
+ global_types_exposed_parameter = BITMAP_ALLOC (&ipa_obstack);
+ global_types_full_escape = BITMAP_ALLOC (&ipa_obstack);
+ results_of_malloc = BITMAP_ALLOC (&ipa_obstack);
+ cant_touch = 1;
+ uid_to_type = splay_tree_new (splay_tree_compare_ints, 0, 0);
+ uid_to_subtype_map = splay_tree_new (splay_tree_compare_ints, 0, 0);
+ uid_to_addressof_map = splay_tree_new (splay_tree_compare_ints, 0, 0);
/* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once
*************** analyze_variable (struct cgraph_varpool_
*** 1188,1200 ****
break;
case FINISHED:
! /* fprintf(stderr, */
! /* "AV analyze_variable called after execute for variable %s\n" , */
! /* lang_hooks.decl_printable_name (global, 2)); */
! /*abort ();*/
break;
}
if (TREE_CODE (global) == VAR_DECL)
{
if (DECL_INITIAL (global))
--- 1843,1862 ----
break;
case FINISHED:
! fprintf(stderr,
! "AV analyze_variable called after execute for variable %s\n" ,
! lang_hooks.decl_printable_name (global, 2));
! abort ();
break;
}
+ /* If this variable has exposure beyond the compilation unit, add
+ it's type to the global types. */
+ if (vnode->externally_visible)
+ mark_interesting_type (TREE_TYPE (global), FULL_ESCAPE);
+ else
+ mark_type_seen (TREE_TYPE (global));
+
if (TREE_CODE (global) == VAR_DECL)
{
if (DECL_INITIAL (global))
*************** analyze_function (struct cgraph_node *fn
*** 1238,1243 ****
--- 1900,1910 ----
/* fprintf(stderr, "cfg=%x\n", */
/* DECL_STRUCT_FUNCTION (fn->decl) -> cfg); */
+ /* If this function can be called from the outside, register the
+ types as escaping. */
+ check_function_parameter_and_return_types (decl, fn->local.externally_visible);
+
+
/* Add the info to the tree's annotation. */
fn->static_vars_info = info;
var_ann->static_vars_info = info;
*************** analyze_function (struct cgraph_node *fn
*** 1292,1300 ****
for (step = BLOCK_VARS (DECL_INITIAL (decl));
step;
step = TREE_CHAIN (step))
! if (DECL_INITIAL (step))
! walk_tree (&DECL_INITIAL (step), scan_for_static_refs,
! fn, visited_nodes);
}
/* Also look here for private statics. */
--- 1959,1971 ----
for (step = BLOCK_VARS (DECL_INITIAL (decl));
step;
step = TREE_CHAIN (step))
! {
! if (DECL_INITIAL (step))
! walk_tree (&DECL_INITIAL (step), scan_for_static_refs,
! fn, visited_nodes);
! mark_type_seen (TREE_TYPE (step));
! }
!
}
/* Also look here for private statics. */
*************** analyze_function (struct cgraph_node *fn
*** 1309,1323 ****
if (DECL_INITIAL (var) && TREE_STATIC (var))
walk_tree (&DECL_INITIAL (var), scan_for_static_refs,
fn, visited_nodes);
}
}
}
/* Produce the global information by preforming a transitive closure
on the local information that was produced by ipa_analyze_function
and ipa_analyze_variable. */
-
static void
static_execute (void)
{
--- 1980,2493 ----
if (DECL_INITIAL (var) && TREE_STATIC (var))
walk_tree (&DECL_INITIAL (var), scan_for_static_refs,
fn, visited_nodes);
+ mark_type_seen (TREE_TYPE (var));
}
}
}
+
+
+ /* Convert a type_UID into a type. */
+ static tree
+ type_for_uid (int uid)
+ {
+ splay_tree_node result =
+ splay_tree_lookup (uid_to_type, (splay_tree_key) uid);
+
+ if (result)
+ return (tree) result->value;
+ else return NULL;
+ }
+
+ /* Return the a bitmap with the subtypes of the type for UID. If it
+ does not exist, return either NULL or a new bitmap depending on the
+ value of CREATE. */
+
+ static bitmap
+ subtype_map_for_uid (int uid, bool create)
+ {
+ splay_tree_node result =
+ splay_tree_lookup (uid_to_subtype_map, (splay_tree_key) uid);
+
+ if (result)
+ return (bitmap) result->value;
+ else if (create)
+ {
+ bitmap subtype_map = BITMAP_ALLOC (&ipa_obstack);
+ splay_tree_insert (uid_to_subtype_map,
+ uid,
+ (splay_tree_value)subtype_map);
+ return subtype_map;
+ }
+ else return NULL;
+ }
+
+ /* Mark all of the supertypes and field types of TYPE as being seen.
+ Also accumulate the subtypes for each type so that
+ close_types_full_escape can mark a subtype as escaping if the
+ supertype escapes. */
+
+ static void
+ close_type_seen (tree type)
+ {
+ tree field;
+ int i, uid;
+ tree binfo, base_binfo;
+
+ /* See thru all pointer tos. */
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ type = TYPE_MAIN_VARIANT (type);
+ uid = TYPE_UID (type);
+
+ if (bitmap_bit_p (been_there_done_that, uid))
+ return;
+ bitmap_set_bit (been_there_done_that, uid);
+
+ /* If we are doing a language with a type heirarchy, mark all of
+ the superclasses. */
+ if (TYPE_BINFO (type))
+ for (binfo = TYPE_BINFO (type), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree binfo_type = BINFO_TYPE (base_binfo);
+ bitmap subtype_map = subtype_map_for_uid
+ (TYPE_UID (TYPE_MAIN_VARIANT (binfo_type)), true);
+ bitmap_set_bit (subtype_map, uid);
+ if (mark_type_seen (binfo_type))
+ close_type_seen (binfo_type);
+ }
+
+ /* If the field is a struct or union type, mark all of the
+ subfields. */
+ for (field = TYPE_FIELDS (type);
+ field;
+ field = TREE_CHAIN (field))
+ {
+ tree field_type;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ field_type = TREE_TYPE (field);
+ if (ipa_static_star_count_of_interesting_type (field_type) >= 0)
+ if (mark_type_seen (field_type))
+ close_type_seen (field_type);
+ }
+ }
+
+ struct type_brand_s
+ {
+ char* name;
+ int seq;
+ };
+
+ /* Splay tree comparison function on type_brand_s structures. */
+
+ static int
+ compare_type_brand (splay_tree_key sk1, splay_tree_key sk2)
+ {
+ struct type_brand_s * k1 = (struct type_brand_s *) sk1;
+ struct type_brand_s * k2 = (struct type_brand_s *) sk2;
+
+ int value = strcmp(k1->name, k2->name);
+ if (value == 0)
+ return k2->seq - k1->seq;
+ else
+ return value;
+ }
+
+ /* Get the name of TYPE or return the string "<UNNAMED>". */
+ static char*
+ get_name_of_type (tree type)
+ {
+ tree name = TYPE_NAME (type);
+
+ if (!name)
+ /* Unnamed type, do what you like here. */
+ return (char*)"<UNNAMED>";
+
+ /* It will be a TYPE_DECL in the case of a typedef, otherwise, an
+ identifier_node */
+ if (TREE_CODE (name) == TYPE_DECL)
+ {
+ /* Each DECL has a DECL_NAME field which contains an
+ IDENTIFIER_NODE. (Some decls, most often labels, may have
+ zero as the DECL_NAME). */
+ if (DECL_NAME (name))
+ return (char*)IDENTIFIER_POINTER (DECL_NAME (name));
+ else
+ /* Unnamed type, do what you like here. */
+ return (char*)"<UNNAMED>";
+ }
+ else if (TREE_CODE (name) == IDENTIFIER_NODE)
+ return (char*)IDENTIFIER_POINTER (name);
+ else
+ return (char*)"<UNNAMED>";
+ }
+
+
+ /* Use a completely lame algorithm for removing duplicate types. This
+ code should not be here except for a bad implementation of whole
+ program compilation. */
+ /* Return either TYPE if this is first time TYPE has been seen an
+ compatible TYPE that has already been processed. */
+
+ static tree
+ discover_unique_type (tree type)
+ {
+ struct type_brand_s * brand = xmalloc(sizeof(struct type_brand_s));
+ int i = 0;
+ splay_tree_node result;
+
+ while (1)
+ {
+ brand->name = get_name_of_type (type);
+ brand->seq = i;
+ result = splay_tree_lookup (all_unique_types, (splay_tree_key) brand);
+ if (result)
+ {
+ tree other_type = (tree) result->value;
+ if (lang_hooks.types_compatible_p (type, other_type) == 1)
+ {
+ free (brand);
+ return other_type;
+ }
+ /* Not compatible, look for next instance with same name. */
+ }
+ else
+ {
+ /* No more instances, create new one. */
+ brand->seq = i++;
+ splay_tree_insert (all_unique_types,
+ (splay_tree_key) brand,
+ (splay_tree_value) type);
+
+ return type;
+ }
+ i++;
+ }
+ }
+
+ /* Take a TYPE that has been passed by value to an external function
+ and mark all of the fields that have pointer types as escaping. For
+ any of the non pointer types that are structures or unions,
+ recurse. TYPE is never a pointer type. */
+
+ static void
+ close_type_exposed_parameter (tree type)
+ {
+ tree field;
+ int uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
+
+ if (bitmap_bit_p (been_there_done_that, uid))
+ return;
+ bitmap_set_bit (been_there_done_that, uid);
+
+ /* If the field is a struct or union type, mark all of the
+ subfields. */
+ for (field = TYPE_FIELDS (type);
+ field;
+ field = TREE_CHAIN (field))
+ {
+ tree field_type;
+
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ field_type = TREE_TYPE (field);
+ mark_interesting_type (field_type, EXPOSED_PARAMETER);
+
+ if (ipa_static_star_count_of_interesting_type (field_type) == 0)
+ close_type_exposed_parameter (field_type);
+ }
+ }
+
+ /* The next function handles the case where a type fully escapes.
+ This means that not only does the type itself escape,
+
+ a) the type of every field recursively escapes
+ b) the type of every subtype escapes as well as the super as well
+ as all of the pointer to types for each field.
+
+ Note that pointer to types are not marked as escaping. If the
+ pointed to type escapes, the pointer to type also escapes.
+
+ Take a TYPE that has had the address taken for an instance of it
+ and mark all of the types for its fields as having their addresses
+ taken. */
+
+ static void
+ close_type_full_escape (tree type)
+ {
+ tree field;
+ unsigned int i;
+ int uid;
+ tree binfo, base_binfo;
+ bitmap_iterator bi;
+ bitmap subtype_map;
+
+ /* Strip off any pointer types. */
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ type = TYPE_MAIN_VARIANT (type);
+ uid = TYPE_UID (type);
+
+ if (bitmap_bit_p (been_there_done_that, uid))
+ return;
+ bitmap_set_bit (been_there_done_that, uid);
+
+ subtype_map = subtype_map_for_uid (uid, false);
+
+ /* If we are doing a language with a type heirarchy, mark all of
+ the superclasses. */
+ if (TYPE_BINFO (type))
+ for (binfo = TYPE_BINFO (type), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree binfotype = BINFO_TYPE (base_binfo);
+ if (ipa_static_star_count_of_interesting_type (binfotype) >= 0)
+ if (mark_type (binfotype, FULL_ESCAPE))
+ close_type_full_escape (binfotype);
+ }
+
+ /* Mark as escaped any types that have been down casted to
+ this type. */
+ if (subtype_map)
+ EXECUTE_IF_SET_IN_BITMAP (subtype_map, 0, i, bi)
+ {
+ tree subtype = type_for_uid (i);
+ if (mark_type (subtype, FULL_ESCAPE))
+ close_type_full_escape (subtype);
+ }
+
+ /* If the field is a struct or union type, mark all of the
+ subfields. */
+ for (field = TYPE_FIELDS (type);
+ field;
+ field = TREE_CHAIN (field))
+ {
+ tree field_type;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ field_type = TREE_TYPE (field);
+ if (ipa_static_star_count_of_interesting_type (field_type) >= 0)
+ if (mark_type (field_type, FULL_ESCAPE))
+ close_type_full_escape (field_type);
+ }
+ }
+
+ /* It is not necessary to carry around the addressof map for any
+ escaping TYPE. */
+
+ static void
+ delete_addressof_map (tree from_type)
+ {
+ int uid = TYPE_UID (TYPE_MAIN_VARIANT (from_type));
+ splay_tree_node result =
+ splay_tree_lookup (uid_to_addressof_map, (splay_tree_key) uid);
+
+ if (result)
+ {
+ bitmap map = (bitmap) result->value;
+ BITMAP_XFREE (map);
+ splay_tree_remove (uid_to_addressof_map, (splay_tree_key) uid);
+ }
+ }
+
+ /* Transitively close the addressof bitmap for the type with UID.
+ This means that if we had a.b and b.c, a would have both b an c in
+ it's maps. */
+
+ static bitmap
+ close_addressof (int uid)
+ {
+ bitmap_iterator bi;
+ splay_tree_node result =
+ splay_tree_lookup (uid_to_addressof_map, (splay_tree_key) uid);
+ bitmap map = NULL;
+ bitmap new_map;
+ unsigned int i;
+
+ if (result)
+ map = (bitmap) result->value;
+ else
+ return NULL;
+
+ if (bitmap_bit_p (been_there_done_that, uid))
+ return map;
+ bitmap_set_bit (been_there_done_that, uid);
+
+ /* The new_map will have all of the bits for the enclosed fields and
+ will have the unique id version of the old map. */
+ new_map = BITMAP_ALLOC (&ipa_obstack);
+
+ EXECUTE_IF_SET_IN_BITMAP (map, 0, i, bi)
+ {
+ int new_uid = unique_type_id_for (i);
+ bitmap submap = close_addressof (new_uid);
+ bitmap_set_bit (new_map, new_uid);
+ if (submap)
+ bitmap_ior_into (new_map, submap);
+ }
+ result->value = (splay_tree_value) new_map;
+
+ BITMAP_FREE (map);
+ return new_map;
+ }
+
+ /* Do all of the closures to discover which types escape the
+ compilation unit. */
+
+ static void
+ do_type_analysis (void)
+ {
+ unsigned int i;
+ bitmap_iterator bi;
+ splay_tree_node result;
+
+ been_there_done_that = BITMAP_ALLOC (&ipa_obstack);
+
+ /* Examine the types that we have directly seen in scanning the code
+ and add to that any contained types or superclasses. */
+
+ EXECUTE_IF_SET_IN_BITMAP (global_types_seen, 0, i, bi)
+ {
+ tree type = type_for_uid (i);
+ /* Only look at records and unions with no pointer tos. */
+ if (ipa_static_star_count_of_interesting_type (type) == 0)
+ close_type_seen (type);
+ }
+ bitmap_clear (been_there_done_that);
+
+ /* Map the duplicate types to a single unique type. This is a hack
+ it is not a general algorithm. */
+ uid_to_unique_type = splay_tree_new (splay_tree_compare_ints, 0, 0);
+ all_unique_types = splay_tree_new (compare_type_brand, 0, 0);
+
+ EXECUTE_IF_SET_IN_BITMAP (global_types_seen, 0, i, bi)
+ {
+ tree unique_type = discover_unique_type (type_for_uid (i));
+ splay_tree_insert (uid_to_unique_type,
+ (splay_tree_key) i,
+ (splay_tree_value) unique_type);
+ if (0)
+ fprintf(stderr, "dta i=%d,%d j=%d,%s\n", i,
+ TYPE_UID(type_for_uid(i)),
+ TYPE_UID(unique_type), get_name_of_type(unique_type));
+ }
+
+ /* Get rid of the temporary data structures used to find the unique
+ type. */
+ result = splay_tree_min (all_unique_types);
+ while (result)
+ {
+ struct type_brand_s * b = (struct type_brand_s *) result->key;
+ splay_tree_remove (all_unique_types, result->key);
+ free (b);
+ result = splay_tree_min (all_unique_types);
+ }
+ splay_tree_delete (all_unique_types);
+ all_unique_types = NULL;
+
+ /* Examine all of the types passed by value and mark any enclosed
+ pointer types as escaping. */
+
+ EXECUTE_IF_SET_IN_BITMAP (global_types_exposed_parameter, 0, i, bi)
+ {
+ close_type_exposed_parameter (type_for_uid (i));
+ }
+ bitmap_clear (been_there_done_that);
+
+ /* Close the types for escape. If something escapes, then any
+ enclosed types escape as well as any subtypes. */
+
+ EXECUTE_IF_SET_IN_BITMAP (global_types_full_escape, 0, i, bi)
+ {
+ tree type = type_for_uid (i);
+ close_type_full_escape (type);
+ }
+ bitmap_clear (been_there_done_that);
+
+ result = splay_tree_min (uid_to_addressof_map);
+ while (result)
+ {
+ int uid = result->key;
+ tree type = type_for_uid (uid);
+ if (bitmap_bit_p (global_types_full_escape, uid))
+ /* If the type escaped, we will never use the map, so get rid
+ of it. */
+ delete_addressof_map (type);
+ else
+ {
+ if (unique_type_id_p (uid))
+ /* Close the addressof map, i.e. copy all of the
+ transitive substructures up to this level. */
+ close_addressof (uid);
+ else
+ /* This type is not the unique designate, so get rid of
+ it. */
+ delete_addressof_map (type);
+ }
+ result = splay_tree_successor (uid_to_addressof_map, uid);
+ }
+
+ /* If a type is set in global_types_full_escape, make sure that the
+ unique type is also set in that map. */
+ EXECUTE_IF_SET_IN_BITMAP (global_types_full_escape, 0, i, bi)
+ {
+ unsigned int j = unique_type_id_for (i);
+ if (i != j)
+ {
+ bitmap_set_bit(global_types_full_escape, j);
+ bitmap_clear_bit(global_types_full_escape, i);
+ }
+ }
+
+ if (0)
+ {
+ EXECUTE_IF_SET_IN_BITMAP (global_types_seen, 0, i, bi)
+ {
+ /* The pointer types are in the global_types_full_escape bitmap
+ but not in the backwards map. */
+ tree type = type_for_uid (i);
+ fprintf(stderr, "type ");
+ print_generic_expr (stderr, type, 0);
+ if (bitmap_bit_p (global_types_full_escape, i))
+ fprintf(stderr, " escaped\n");
+ else if (i == unique_type_id_p (i))
+ fprintf(stderr, " contained\n");
+ else
+ fprintf(stderr, " replaced\n");
+ }
+ }
+
+ /* Get rid of the subtype map. */
+ result = splay_tree_min (uid_to_subtype_map);
+ while (result)
+ {
+ bitmap b = (bitmap)result->value;
+ BITMAP_XFREE(b);
+ splay_tree_remove (uid_to_subtype_map, result->key);
+ result = splay_tree_min (uid_to_subtype_map);
+ }
+ splay_tree_delete (uid_to_subtype_map);
+ uid_to_subtype_map = NULL;
+
+ BITMAP_XFREE (global_types_exposed_parameter);
+ BITMAP_XFREE (been_there_done_that);
+ BITMAP_XFREE (results_of_malloc);
+
+ cant_touch = 0;
+ }
+
+
/* Produce the global information by preforming a transitive closure
on the local information that was produced by ipa_analyze_function
and ipa_analyze_variable. */
static void
static_execute (void)
{
*************** static_execute (void)
*** 1508,1523 ****
break;
}
- /* if (l->pure_const_state == IPA_PURE) */
- /* { */
- /* fprintf (stderr, " before %s(%d)=%d\n", cgraph_node_name (node), */
- /* node->uid, l->pure_const_state); */
- /* l->pure_const_state = IPA_NEITHER; */
-
-
- /* } */
-
-
/* Any variables that are not in all_module_statics are
removed from the local maps. This will include all of the
variables that were found to escape in the function
--- 2678,2683 ----
*************** static_execute (void)
*** 1732,1737 ****
--- 2892,2899 ----
}
}
+ do_type_analysis ();
+
/* Cleanup. */
for (i = 0; i < order_pos; i++ )
{
*************** static_execute (void)
*** 1748,1759 ****
node_g->statics_not_read_by_decl_uid = BITMAP_ALLOC (&ipa_obstack);
node_g->statics_not_written_by_decl_uid = BITMAP_ALLOC (&ipa_obstack);
- /* FIXME -- PROFILE-RESTRUCTURE: Delete next 4 assignments. */
- node_g->statics_read_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
- node_g->statics_written_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
- node_g->statics_not_read_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
- node_g->statics_not_written_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
-
if (node_g->statics_read_by_decl_uid != all_module_statics)
{
bitmap_and_compl (node_g->statics_not_read_by_decl_uid,
--- 2910,2915 ----
*************** static_execute (void)
*** 1766,1771 ****
--- 2922,2933 ----
all_module_statics,
node_g->statics_written_by_decl_uid);
+ /* FIXME -- PROFILE-RESTRUCTURE: Delete next 4 assignments. */
+ node_g->statics_read_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
+ node_g->statics_written_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
+ node_g->statics_not_read_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
+ node_g->statics_not_written_by_ann_uid = BITMAP_ALLOC (&ipa_obstack);
+
w = node;
while (w)
{
Index: gcc/ipa-static.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ipa-static.h,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 ipa-static.h
*** gcc/ipa-static.h 3 Dec 2004 03:58:45 -0000 1.1.2.2
--- gcc/ipa-static.h 18 Jan 2005 18:45:01 -0000
*************** bitmap ipa_get_statics_read_global (tree
*** 120,124 ****
--- 120,128 ----
bitmap ipa_get_statics_written_global (tree fn);
bitmap ipa_get_statics_not_read_global (tree fn);
bitmap ipa_get_statics_not_written_global (tree fn);
+ bool ipa_static_type_contained_p (tree type);
+ bool ipa_static_address_not_taken_of_field (tree record_type, tree field_type);
+ int ipa_static_star_count_of_interesting_type (tree type);
+
#endif /* GCC_IPA_STATIC_H */
Index: gcc/tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dfa.c,v
retrieving revision 1.1.4.217.2.16
diff -c -3 -p -r1.1.4.217.2.16 tree-dfa.c
*** gcc/tree-dfa.c 15 Dec 2004 22:19:14 -0000 1.1.4.217.2.16
--- gcc/tree-dfa.c 18 Jan 2005 18:45:02 -0000
*************** create_stmt_ann (tree t)
*** 450,456 ****
return ann;
}
-
/* Create a new annotation for a tree T. */
tree_ann_t
--- 450,455 ----
Index: gcc/tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-eh.c,v
retrieving revision 1.1.2.23.2.13
diff -c -3 -p -r1.1.2.23.2.13 tree-eh.c
*** gcc/tree-eh.c 9 Jan 2005 14:17:45 -0000 1.1.2.23.2.13
--- gcc/tree-eh.c 18 Jan 2005 18:45:02 -0000
*************** tree_could_trap_p (tree expr)
*** 1833,1838 ****
--- 1833,1839 ----
return !in_array_bounds_p (expr);
+ case MEM_REF:
case INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
Index: gcc/tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow-inline.h,v
retrieving revision 1.1.2.66.2.9
diff -c -3 -p -r1.1.2.66.2.9 tree-flow-inline.h
*** gcc/tree-flow-inline.h 9 Jan 2005 14:17:45 -0000 1.1.2.66.2.9
--- gcc/tree-flow-inline.h 18 Jan 2005 18:45:02 -0000
*************** get_stmt_ann (tree stmt)
*** 66,72 ****
return (ann) ? ann : create_stmt_ann (stmt);
}
-
/* Return the annotation type for annotation ANN. */
static inline enum tree_ann_type
ann_type (tree_ann_t ann)
--- 66,71 ----
Index: gcc/tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 1.1.4.187.2.22
diff -c -3 -p -r1.1.4.187.2.22 tree-flow.h
*** gcc/tree-flow.h 15 Dec 2004 22:19:15 -0000 1.1.4.187.2.22
--- gcc/tree-flow.h 18 Jan 2005 18:45:03 -0000
*************** bool tree_duplicate_loop_to_header_edge
*** 705,710 ****
--- 705,711 ----
unsigned int *, int);
struct loop *tree_ssa_loop_version (struct loops *, struct loop *, tree,
basic_block *);
+ void set_ref_original (tree, tree);
/* In tree-ssa-loop-im.c */
/* The possibilities of statement movement. */
Index: gcc/tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.1.2.12
diff -c -3 -p -r2.1.2.12 tree-gimple.c
*** gcc/tree-gimple.c 16 Dec 2004 01:20:26 -0000 2.1.2.12
--- gcc/tree-gimple.c 18 Jan 2005 18:45:03 -0000
*************** is_gimple_condexpr (tree t)
*** 160,167 ****
bool
is_gimple_addressable (tree t)
{
! return (is_gimple_id (t) || handled_component_p (t)
! || INDIRECT_REF_P (t));
}
/* Return true if T is function invariant. Or rather a restricted
--- 160,167 ----
bool
is_gimple_addressable (tree t)
{
! return (is_gimple_id (t) || handled_component_p (t)
! || TREE_CODE (t) == MEM_REF || INDIRECT_REF_P (t));
}
/* Return true if T is function invariant. Or rather a restricted
*************** bool
*** 379,385 ****
is_gimple_min_lval (tree t)
{
return (is_gimple_id (t)
! || TREE_CODE (t) == INDIRECT_REF);
}
/* Return true if T is a typecast operation. */
--- 379,386 ----
is_gimple_min_lval (tree t)
{
return (is_gimple_id (t)
! || TREE_CODE (t) == INDIRECT_REF
! || TREE_CODE (t) == MEM_REF);
}
/* Return true if T is a typecast operation. */
*************** get_call_expr_in (tree t)
*** 419,445 ****
return NULL_TREE;
}
- /* Given a memory reference T, will return the variable at the bottom
- of the access. Unlike get_base_address below, this will recurse
- thru INDIRECT_REFS. */
-
- tree
- get_base_var (tree t)
- {
- if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
- return t;
-
- while (!SSA_VAR_P (t)
- && (!CONSTANT_CLASS_P (t))
- && TREE_CODE (t) != LABEL_DECL
- && TREE_CODE (t) != FUNCTION_DECL
- && TREE_CODE (t) != CONST_DECL)
- {
- t = TREE_OPERAND (t, 0);
- }
- return t;
- }
-
/* Given a memory reference expression T, return its base address.
The base address of a memory reference expression is the main
object being referenced. For instance, the base address for
--- 420,425 ----
*************** get_base_address (tree t)
*** 458,464 ****
if (SSA_VAR_P (t)
|| TREE_CODE (t) == STRING_CST
|| TREE_CODE (t) == CONSTRUCTOR
! || INDIRECT_REF_P (t))
return t;
else
return NULL_TREE;
--- 438,445 ----
if (SSA_VAR_P (t)
|| TREE_CODE (t) == STRING_CST
|| TREE_CODE (t) == CONSTRUCTOR
! || INDIRECT_REF_P (t)
! || TREE_CODE (t) == MEM_REF)
return t;
else
return NULL_TREE;
Index: gcc/tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.26.2.83.2.27
diff -c -3 -p -r1.26.2.83.2.27 tree-inline.c
*** gcc/tree-inline.c 15 Jan 2005 21:14:34 -0000 1.26.2.83.2.27
--- gcc/tree-inline.c 18 Jan 2005 18:45:04 -0000
*************** estimate_num_insns_1 (tree *tp, int *wal
*** 1723,1728 ****
--- 1723,1729 ----
case BLOCK:
case COMPONENT_REF:
case BIT_FIELD_REF:
+ case MEM_REF:
case INDIRECT_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
Index: gcc/tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.122.2.33
diff -c -3 -p -r1.1.4.122.2.33 tree-optimize.c
*** gcc/tree-optimize.c 18 Jan 2005 18:24:19 -0000 1.1.4.122.2.33
--- gcc/tree-optimize.c 18 Jan 2005 18:45:04 -0000
*************** init_tree_optimization_passes (void)
*** 402,407 ****
--- 402,408 ----
NEXT_PASS (pass_init_datastructures);
NEXT_PASS (pass_all_optimizations);
NEXT_PASS (pass_warn_function_return);
+ NEXT_PASS (pass_lower_memref);
NEXT_PASS (pass_mudflap_2);
NEXT_PASS (pass_free_datastructures);
NEXT_PASS (pass_expand);
*************** init_tree_optimization_passes (void)
*** 411,420 ****
--- 412,423 ----
p = &pass_all_optimizations.sub;
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_maybe_create_global_var);
+ NEXT_PASS (pass_lower_memref);
NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_early_warn_uninitialized);
+ NEXT_PASS (pass_eliminate_useless_stores);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_redundant_phi);
Index: gcc/tree-pass.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pass.h,v
retrieving revision 1.1.2.12.2.15
diff -c -3 -p -r1.1.2.12.2.15 tree-pass.h
*** gcc/tree-pass.h 9 Jan 2005 14:17:49 -0000 1.1.2.12.2.15
--- gcc/tree-pass.h 18 Jan 2005 18:45:04 -0000
*************** extern struct tree_opt_pass pass_expand;
*** 193,200 ****
extern struct tree_opt_pass pass_rest_of_compilation;
extern struct tree_opt_pass pass_fre;
extern struct tree_opt_pass pass_linear_transform;
extern struct tree_opt_pass pass_maybe_create_global_var;
!
extern struct tree_opt_pass pass_ipa_inline;
extern struct tree_opt_pass pass_ipa_static;
--- 193,201 ----
extern struct tree_opt_pass pass_rest_of_compilation;
extern struct tree_opt_pass pass_fre;
extern struct tree_opt_pass pass_linear_transform;
+ extern struct tree_opt_pass pass_eliminate_useless_stores;
extern struct tree_opt_pass pass_maybe_create_global_var;
! extern struct tree_opt_pass pass_lower_memref;
extern struct tree_opt_pass pass_ipa_inline;
extern struct tree_opt_pass pass_ipa_static;
Index: gcc/tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 1.1.2.73.2.17
diff -c -3 -p -r1.1.2.73.2.17 tree-pretty-print.c
*** gcc/tree-pretty-print.c 15 Dec 2004 22:19:20 -0000 1.1.2.73.2.17
--- gcc/tree-pretty-print.c 18 Jan 2005 18:45:04 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 444,449 ****
--- 444,458 ----
NIY;
break;
+ case MEM_REF:
+ {
+ dump_generic_node (buffer, MEM_REF_SYMBOL (node), spc, flags, false);
+ pp_string (buffer, "[");
+ dump_generic_node (buffer, MEM_REF_INDEX (node), spc, flags, false);
+ pp_string (buffer, "]");
+ }
+ break;
+
case ARRAY_TYPE:
{
tree tmp;
Index: gcc/tree-ssa-alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-alias.c,v
retrieving revision 1.1.2.1.2.15
diff -c -3 -p -r1.1.2.1.2.15 tree-ssa-alias.c
*** gcc/tree-ssa-alias.c 9 Jan 2005 14:17:50 -0000 1.1.2.1.2.15
--- gcc/tree-ssa-alias.c 18 Jan 2005 18:45:05 -0000
*************** Boston, MA 02111-1307, USA. */
*** 42,48 ****
#include "tree-pass.h"
#include "convert.h"
#include "params.h"
!
/* Structure to map a variable to its alias set and keep track of the
virtual operands that will be needed to represent it. */
--- 42,48 ----
#include "tree-pass.h"
#include "convert.h"
#include "params.h"
! #include "ipa-static.h"
/* Structure to map a variable to its alias set and keep track of the
virtual operands that will be needed to represent it. */
*************** struct alias_stats_d
*** 124,129 ****
--- 124,131 ----
unsigned int simple_resolved;
unsigned int tbaa_queries;
unsigned int tbaa_resolved;
+ unsigned int structnoaddress_queries;
+ unsigned int structnoaddress_resolved;
};
*************** find_ptr_dereference (tree *tp, int *wal
*** 575,580 ****
--- 577,585 ----
if (INDIRECT_REF_P (*tp)
&& TREE_OPERAND (*tp, 0) == ptr)
return *tp;
+ else if (TREE_CODE (*tp) == MEM_REF
+ && MEM_REF_SYMBOL (*tp) == ptr)
+ return *tp;
return NULL_TREE;
}
*************** may_alias_p (tree ptr, HOST_WIDE_INT mem
*** 1638,1643 ****
--- 1643,1705 ----
return false;
}
+ /* If var is a record or union type, ptr cannot point into var
+ unless there is some operation explicit address operation in the
+ program that can reference a field of the ptr's dereferenced
+ type. This also assumes that the types of both var and ptr are
+ contained within the compilation unit, and that there is no fancy
+ addressing arithmetic associated with any of the types
+ involved. */
+
+ {
+ tree ptr_type = TREE_TYPE (ptr);
+
+ /* The star counts are -1 if the type at the end of the pointer_to
+ chain is not a record or union type. */
+ if (ipa_static_star_count_of_interesting_type (var) >= 0)
+ {
+ int ptr_star_count = 0;
+ /* ipa_static_star_count_of_interesting_type is a little too
+ restrictive for the pointer type, need to allow pointers to
+ primitive types as long as those types cannot be pointers
+ to everything. */
+ /* Strip the *'s off. */
+ while (POINTER_TYPE_P (ptr_type))
+ {
+ ptr_type = TREE_TYPE (ptr_type);
+ ptr_star_count++;
+ }
+
+ /* There does not appear to be a better test to see if the
+ pointer type was one of the pointer to everything
+ types. */
+ if (TREE_CODE (ptr_type) == CHAR_TYPE
+ && TREE_CODE (ptr_type) == VOID_TYPE)
+ ptr_star_count = -1;
+
+ if (ptr_star_count > 0)
+ {
+ alias_stats.structnoaddress_queries++;
+ if (ipa_static_address_not_taken_of_field (TREE_TYPE (var),
+ TREE_TYPE (ptr_type)))
+ {
+ alias_stats.structnoaddress_resolved++;
+ alias_stats.alias_noalias++;
+ return false;
+ }
+ }
+ else if (ptr_star_count == 0)
+ {
+ /* If ptr_type was not really a pointer to type, it cannot
+ alias. */
+ alias_stats.structnoaddress_queries++;
+ alias_stats.structnoaddress_resolved++;
+ alias_stats.alias_noalias++;
+ return false;
+ }
+ }
+ }
+
alias_stats.alias_mayalias++;
return true;
}
*************** dump_alias_stats (FILE *file)
*** 2236,2241 ****
--- 2298,2307 ----
alias_stats.tbaa_queries);
fprintf (file, "Total TBAA resolved:\t%u\n",
alias_stats.tbaa_resolved);
+ fprintf (file, "Total non-addressable structure type queries:\t%u\n",
+ alias_stats.structnoaddress_queries);
+ fprintf (file, "Total non-addressable structure type resolved:\t%u\n",
+ alias_stats.structnoaddress_resolved);
}
Index: gcc/tree-ssa-loop-im.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop-im.c,v
retrieving revision 2.3.2.8
diff -c -3 -p -r2.3.2.8 tree-ssa-loop-im.c
*** gcc/tree-ssa-loop-im.c 16 Dec 2004 01:20:35 -0000 2.3.2.8
--- gcc/tree-ssa-loop-im.c 18 Jan 2005 18:45:05 -0000
*************** for_each_index (tree *addr_p, bool (*cbc
*** 174,179 ****
--- 174,191 ----
case RESULT_DECL:
return true;
+ case MEM_REF:
+ idx = &MEM_REF_SYMBOL (*addr_p);
+ if (*idx
+ && !cbck (*addr_p, idx, data))
+ return false;
+ return true;
+ idx = &MEM_REF_INDEX (*addr_p);
+ if (*idx
+ && !cbck (*addr_p, idx, data))
+ return false;
+ return true;
+
default:
gcc_unreachable ();
}
Index: gcc/tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 1.1.2.9.2.17
diff -c -3 -p -r1.1.2.9.2.17 tree-ssa-operands.c
*** gcc/tree-ssa-operands.c 15 Dec 2004 22:19:27 -0000 1.1.2.9.2.17
--- gcc/tree-ssa-operands.c 18 Jan 2005 18:45:06 -0000
*************** static void note_addressable (tree, stmt
*** 141,146 ****
--- 141,147 ----
static void get_expr_operands (tree, tree *, int);
static void get_asm_expr_operands (tree);
static void get_indirect_ref_operands (tree, tree, int);
+ static void get_mem_ref_operands (tree, tree *, int);
static void get_call_expr_operands (tree, tree);
static inline void append_def (tree *);
static inline void append_use (tree *);
*************** build_ssa_operands (tree stmt, stmt_ann_
*** 912,918 ****
if (TREE_CODE (lhs) == VIEW_CONVERT_EXPR)
lhs = TREE_OPERAND (lhs, 0);
! if (TREE_CODE (lhs) != ARRAY_REF && TREE_CODE (lhs) != ARRAY_RANGE_REF
&& TREE_CODE (lhs) != COMPONENT_REF
&& TREE_CODE (lhs) != BIT_FIELD_REF
&& TREE_CODE (lhs) != REALPART_EXPR
--- 913,921 ----
if (TREE_CODE (lhs) == VIEW_CONVERT_EXPR)
lhs = TREE_OPERAND (lhs, 0);
! if (TREE_CODE (lhs) != ARRAY_REF
! && TREE_CODE (lhs) != MEM_REF
! && TREE_CODE (lhs) != ARRAY_RANGE_REF
&& TREE_CODE (lhs) != COMPONENT_REF
&& TREE_CODE (lhs) != BIT_FIELD_REF
&& TREE_CODE (lhs) != REALPART_EXPR
*************** get_expr_operands (tree stmt, tree *expr
*** 1092,1097 ****
--- 1095,1104 ----
get_indirect_ref_operands (stmt, expr, flags);
return;
+ case MEM_REF:
+ get_mem_ref_operands (stmt, expr_p, flags);
+ return;
+
case ARRAY_REF:
case ARRAY_RANGE_REF:
/* Treat array references as references to the virtual variable
*************** get_expr_operands (tree stmt, tree *expr
*** 1167,1172 ****
--- 1174,1180 ----
if (TREE_CODE (op) == WITH_SIZE_EXPR)
op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) == ARRAY_REF
+ || TREE_CODE (op) == MEM_REF
|| TREE_CODE (op) == ARRAY_RANGE_REF
|| TREE_CODE (op) == COMPONENT_REF
|| TREE_CODE (op) == REALPART_EXPR
*************** get_indirect_ref_operands (tree stmt, tr
*** 1374,1380 ****
/* Stores into INDIRECT_REF operands are never killing definitions. */
flags &= ~opf_kill_def;
!
if (SSA_VAR_P (ptr))
{
struct ptr_info_def *pi = NULL;
--- 1382,1388 ----
/* Stores into INDIRECT_REF operands are never killing definitions. */
flags &= ~opf_kill_def;
!
if (SSA_VAR_P (ptr))
{
struct ptr_info_def *pi = NULL;
*************** get_indirect_ref_operands (tree stmt, tr
*** 1453,1458 ****
--- 1461,1525 ----
get_expr_operands (stmt, pptr, opf_none);
}
+ /* A subroutine of get_expr_operands to handle MEM_REF. */
+
+ static void
+ get_mem_ref_operands (tree stmt, tree *expr_p, int flags)
+ {
+ stmt_ann_t s_ann = stmt_ann (stmt);
+ tree expr = *expr_p;
+ tree ptr;
+
+ /* First record the real operands. */
+ get_expr_operands (stmt, &MEM_REF_INDEX (expr), opf_none);
+
+ ptr = MEM_REF_SYMBOL (expr);
+
+ if (SSA_VAR_P (ptr))
+ {
+ struct ptr_info_def *pi = NULL;
+
+ /* If PTR has flow-sensitive points-to information, use it. */
+ if (TREE_CODE (ptr) == SSA_NAME
+ && (pi = SSA_NAME_PTR_INFO (ptr)) != NULL
+ && pi->name_mem_tag)
+ {
+ /* PTR has its own memory tag. Use it. */
+ add_stmt_operand (&pi->name_mem_tag, s_ann, flags);
+ }
+ else
+ {
+ /* If PTR is not an SSA_NAME or it doesn't have a name
+ tag, use its type memory tag. */
+ var_ann_t v_ann;
+
+ /* If we are emitting debugging dumps, display a warning if
+ PTR is an SSA_NAME with no flow-sensitive alias
+ information. That means that we may need to compute
+ aliasing again. */
+ if (dump_file
+ && TREE_CODE (ptr) == SSA_NAME
+ && pi == NULL)
+ {
+ fprintf (dump_file,
+ "NOTE: no flow-sensitive alias info for ");
+ print_generic_expr (dump_file, ptr, dump_flags);
+ fprintf (dump_file, " in ");
+ print_generic_stmt (dump_file, stmt, dump_flags);
+ }
+
+ if (TREE_CODE (ptr) == SSA_NAME)
+ ptr = SSA_NAME_VAR (ptr);
+ v_ann = var_ann (ptr);
+ if (v_ann->type_mem_tag)
+ add_stmt_operand (&v_ann->type_mem_tag, s_ann, flags);
+ }
+ }
+ /* Add a use operand for the base pointer */
+ get_expr_operands (stmt, &MEM_REF_SYMBOL (expr), opf_none);
+
+ }
+
/* A subroutine of get_expr_operands to handle CALL_EXPR. */
static void
Index: gcc/tree-ssa-pre.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-pre.c,v
retrieving revision 1.1.4.129.2.15
diff -c -3 -p -r1.1.4.129.2.15 tree-ssa-pre.c
*** gcc/tree-ssa-pre.c 15 Dec 2004 22:19:27 -0000 1.1.4.129.2.15
--- gcc/tree-ssa-pre.c 18 Jan 2005 18:45:06 -0000
*************** struct tree_opt_pass pass_fre =
*** 2176,2178 ****
--- 2176,2307 ----
TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
0 /* letter */
};
+
+ /* Return true if T is a copy statement between two ssa names. */
+
+ static bool
+ is_copy_stmt (tree t)
+ {
+
+ if (TREE_CODE (t) != MODIFY_EXPR)
+ return false;
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
+ && TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME)
+ return true;
+ return false;
+ }
+
+ /* Starting from START, walk copy statements till we hit a statement with a
+ VUSE or a non-copy statement. */
+
+ static tree
+ follow_copies_till_vuse (tree start)
+ {
+ if (NUM_VUSES (VUSE_OPS (stmt_ann (start))) != 0)
+ return start;
+ if (is_copy_stmt (start))
+ return follow_copies_till_vuse (SSA_NAME_DEF_STMT (TREE_OPERAND (start, 1)));
+ return NULL;
+ }
+
+ /* Gate and execute functions for eliminate useless stores.
+ The goal here is to recognize the pattern *x = ... *x, and eliminate the
+ store because the value hasn't changed. Store copy/const prop won't
+ do this because making *more* loads (IE propagating *x) is not a win, so it
+ ignores them.
+ This pass is currently geared completely towards static variable store
+ elimination.
+ */
+
+ static void
+ do_eustores (void)
+ {
+ basic_block bb;
+ /* For each basic block
+ For each statement (STMT) in the block
+ if STMT is a stores of the pattern *x = y
+ follow the chain of definitions for y, until we hit a non-copy
+ statement or a statement with a vuse.
+ if the statement we arrive at is a vuse of the operand we killed,
+ accessed through the same memory operation, then we have a
+ useless store (because it is *x = ... = *x).
+ */
+
+ FOR_EACH_BB (bb)
+ {
+ block_stmt_iterator bsi;
+ for (bsi = bsi_start (bb);
+ !bsi_end_p (bsi);)
+ {
+ tree stmt = bsi_stmt (bsi);
+ stmt_ann_t ann = stmt_ann (stmt);
+ tree startat;
+ tree kill;
+ tree found;
+
+
+ if (NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) != 1
+ || TREE_CODE (stmt) != MODIFY_EXPR
+ || TREE_CODE (TREE_OPERAND (stmt, 1)) != SSA_NAME)
+ {
+ bsi_next (&bsi);
+ continue;
+ }
+ kill = V_MUST_DEF_KILL (V_MUST_DEF_OPS (ann), 0);
+ startat = TREE_OPERAND (stmt, 1);
+ startat = SSA_NAME_DEF_STMT (startat);
+ found = follow_copies_till_vuse (startat);
+ if (found)
+ {
+ stmt_ann_t foundann = stmt_ann (found);
+ if (NUM_VUSES (VUSE_OPS (foundann)) != 1
+ || VUSE_OP (VUSE_OPS (foundann), 0) != kill
+ || !operand_equal_p (TREE_OPERAND (found, 1), TREE_OPERAND (stmt, 0), 0))
+ {
+ bsi_next (&bsi);
+ continue;
+ }
+ if (dump_file)
+ {
+ fprintf (dump_file, "Eliminating useless store ");
+ print_generic_stmt (dump_file, stmt, 0);
+ }
+ bitmap_set_bit (vars_to_rename,
+ var_ann (TREE_OPERAND (stmt, 0))->uid);
+
+ bsi_remove (&bsi);
+ }
+ else
+ {
+ bsi_next (&bsi);
+ continue;
+ }
+ }
+
+ }
+ }
+
+ static bool
+ gate_eustores(void)
+ {
+ return flag_unit_at_a_time != 0;
+ }
+
+ struct tree_opt_pass pass_eliminate_useless_stores =
+ {
+ "eustores", /* name */
+ gate_eustores, /* gate */
+ NULL, NULL, /* IPA analysis */
+ do_eustores, /* execute */
+ NULL, NULL, /* IPA modification */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_cfg | PROP_ssa | PROP_alias, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_rename_vars | TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
+ 0 /* letter */
+ };
Index: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.263.2.80.2.17
diff -c -3 -p -r1.263.2.80.2.17 tree.c
*** gcc/tree.c 9 Jan 2005 14:17:55 -0000 1.263.2.80.2.17
--- gcc/tree.c 18 Jan 2005 18:45:08 -0000
*************** build4_stat (enum tree_code code, tree t
*** 2674,2679 ****
--- 2674,2680 ----
return t;
}
+
/* Backup definition for non-gcc build compilers. */
tree
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.52.2.24.2.13
diff -c -3 -p -r1.52.2.24.2.13 tree.def
*** gcc/tree.def 9 Jan 2005 14:17:57 -0000 1.52.2.24.2.13
--- gcc/tree.def 18 Jan 2005 18:45:08 -0000
*************** DEFTREECODE (WITH_SIZE_EXPR, "with_size_
*** 921,926 ****
--- 921,933 ----
generated by the builtin targetm.vectorize.mask_for_load_builtin_decl. */
DEFTREECODE (REALIGN_LOAD_EXPR, "realign_load", tcc_expression, 3)
+ /* Array like memory addressing for pointers. Operands are SYMBOL
+ (static or global variable),INDEX (register), STEP (integer
+ constant) Corresponding address is SYMBOL + (INDEX * TYPE_SIZE_UNIT
+ (TREE_TYPE (SYMBOL))). */
+
+ DEFTREECODE (MEM_REF, "mem_ref", tcc_reference, 2)
+
/*
Local variables:
mode:c
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.169.2.21
diff -c -3 -p -r1.342.2.169.2.21 tree.h
*** gcc/tree.h 9 Jan 2005 14:17:58 -0000 1.342.2.169.2.21
--- gcc/tree.h 18 Jan 2005 18:45:10 -0000
*************** struct tree_vec GTY(())
*** 1172,1180 ****
#define TREE_OPERAND(NODE, I) TREE_OPERAND_CHECK (NODE, I)
#define TREE_COMPLEXITY(NODE) (EXPR_CHECK (NODE)->exp.complexity)
! /* In INDIRECT_REF, ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF. */
! #define REF_ORIGINAL(NODE) TREE_CHAIN (TREE_CHECK3 (NODE, \
! INDIRECT_REF, ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF))
/* In a LOOP_EXPR node. */
#define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
--- 1172,1180 ----
#define TREE_OPERAND(NODE, I) TREE_OPERAND_CHECK (NODE, I)
#define TREE_COMPLEXITY(NODE) (EXPR_CHECK (NODE)->exp.complexity)
! /* In INDIRECT_REF, ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF, MEM_REF. */
! #define REF_ORIGINAL(NODE) TREE_CHAIN (TREE_CHECK4 (NODE, \
! INDIRECT_REF, ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF, MEM_REF))
/* In a LOOP_EXPR node. */
#define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
*************** struct tree_vec GTY(())
*** 1241,1246 ****
--- 1241,1250 ----
#define CASE_HIGH(NODE) TREE_OPERAND ((NODE), 1)
#define CASE_LABEL(NODE) TREE_OPERAND ((NODE), 2)
+ /* The operands of a MEM_REF. */
+ #define MEM_REF_SYMBOL(NODE) (TREE_OPERAND (MEM_REF_CHECK (NODE), 0))
+ #define MEM_REF_INDEX(NODE) (TREE_OPERAND (MEM_REF_CHECK (NODE), 1))
+
/* The operands of a BIND_EXPR. */
#define BIND_EXPR_VARS(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 0))
#define BIND_EXPR_BODY(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 1))
*************** struct tree_binfo GTY (())
*** 2162,2171 ****
/* Nonzero in a FUNCTION_DECL means this function should be treated
as if it were a malloc, meaning it returns a pointer that is
! not an alias. */
#define DECL_IS_MALLOC(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.malloc_flag)
/* Nonzero in a FUNCTION_DECL means this function should be treated
as "pure" function (like const function, but may read global memory). */
#define DECL_IS_PURE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.pure_flag)
--- 2166,2180 ----
/* Nonzero in a FUNCTION_DECL means this function should be treated
as if it were a malloc, meaning it returns a pointer that is
! not an alias. It also means that even though it returns a void*
! pointer, the value returned does not cause the type to escape. */
#define DECL_IS_MALLOC(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.malloc_flag)
/* Nonzero in a FUNCTION_DECL means this function should be treated
+ as if it were a free, meaning it takes a pointer to a void* but the cast for this pararmeter does not cause the type to escape. */
+ #define DECL_IS_FREE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.free_flag)
+
+ /* Nonzero in a FUNCTION_DECL means this function should be treated
as "pure" function (like const function, but may read global memory). */
#define DECL_IS_PURE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.pure_flag)
*************** struct tree_decl GTY(())
*** 2361,2371 ****
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned lang_flag_7 : 1;
!
unsigned possibly_inlined : 1;
unsigned preserve_flag: 1;
unsigned gimple_formal_temp : 1;
! /* 13 unused bits. */
union tree_decl_u1 {
/* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
--- 2370,2381 ----
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned lang_flag_7 : 1;
!
unsigned possibly_inlined : 1;
unsigned preserve_flag: 1;
unsigned gimple_formal_temp : 1;
! unsigned free_flag : 1;
! /* 11 unused bits. */
union tree_decl_u1 {
/* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
*************** extern rtx emit_line_note (location_t);
*** 3674,3679 ****
--- 3684,3691 ----
#define ECF_ALWAYS_RETURN 512
/* Create libcall block around the call. */
#define ECF_LIBCALL_BLOCK 1024
+ /* Nonzero if this is a call to free or a related function. */
+ #define ECF_FREE 2048
extern int flags_from_decl_or_type (tree);
extern int call_expr_flags (tree);
*************** extern tree walk_tree_without_duplicates
*** 3794,3800 ****
/* In tree-dump.c */
/* Different tree dump places. When you add new tree dump places,
! extend the DUMP_FILES array in tree-dump.c. */
enum tree_dump_index
{
TDI_none, /* No dump */
--- 3806,3812 ----
/* In tree-dump.c */
/* Different tree dump places. When you add new tree dump places,
! / extend the DUMP_FILES array in tree-dump.c. */
enum tree_dump_index
{
TDI_none, /* No dump */
*************** extern bool in_gimple_form;
*** 3925,3931 ****
extern bool thread_through_all_blocks (void);
/* In tree-gimple.c. */
- extern tree get_base_var (tree t);
extern tree get_base_address (tree t);
#endif /* GCC_TREE_H */
--- 3937,3937 ----