Commit cfef45c8 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/46562 (CCP currently needs iteration for &a[i])

2011-03-24  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/46562
	* tree.c (build_invariant_address): New function.
	* tree.h (build_invariant_address): Declare.
	* tree-dfa.c (get_addr_base_and_unit_offset): Wrap around
	a renamed function moved ...
	* tree-flow-inline.h (get_addr_base_and_unit_offset_1): ... here.
	Take valueization callback parameter.
	* tree-flow.h (gimple_fold_stmt_to_constant): Declare.
	* gimple-fold.h: New file.
	* tree-ssa-ccp.c (ccp_fold): Use gimple_fold_stmt_to_constant_1.
	(ccp_fold, fold_const_aggregate_ref,
	fold_ctor_reference, fold_nonarray_ctor_reference,
	fold_array_ctor_reference, fold_string_cst_ctor_reference,
	get_base_constructor): Move ...
	* gimple-fold.c: ... here.
	(gimple_fold_stmt_to_constant_1): New function
	split out from ccp_fold.  Take a valueization callback parameter.
	Valueize all operands.
	(gimple_fold_stmt_to_constant): New wrapper function.
	(fold_const_aggregate_ref_1): New function split out from
	fold_const_aggregate_ref.  Take a valueization callback parameter.
	(fold_const_aggregate_ref): Wrap fold_const_aggregate_ref_1.
	* tree-ssa-sccvn.c (simplify_binary_expression): Simplify
	invariant POINTER_PLUS_EXPRs to invariant form.
	(vn_valueize): New function.
	(try_to_simplify): Simplify by using gimple_fold_stmt_to_constant.
	* tree-vrp.c (vrp_valueize): New function.
	(vrp_visit_assignment_or_call): Use gimple_fold_stmt_to_constant
	to fold statements to constants.
	* tree-ssa-pre.c (eliminate): Properly guard propagation of
	function declarations.
	* Makefile.in (tree-ssa-sccvn.o, tree-vrp.o, gimple-fold.o,
	tree-ssa-ccp.o): Add gimple-fold.h dependencies.

	* c-c++-common/pr46562-2.c: New testcase.
	* c-c++-common/pr46562.c: Likewise.

From-SVN: r171386
parent f3e8ab19
2011-03-24 Richard Guenther <rguenther@suse.de>
PR tree-optimization/46562
* tree.c (build_invariant_address): New function.
* tree.h (build_invariant_address): Declare.
* tree-dfa.c (get_addr_base_and_unit_offset): Wrap around
a renamed function moved ...
* tree-flow-inline.h (get_addr_base_and_unit_offset_1): ... here.
Take valueization callback parameter.
* tree-flow.h (gimple_fold_stmt_to_constant): Declare.
* gimple-fold.h: New file.
* tree-ssa-ccp.c (ccp_fold): Use gimple_fold_stmt_to_constant_1.
(ccp_fold, fold_const_aggregate_ref,
fold_ctor_reference, fold_nonarray_ctor_reference,
fold_array_ctor_reference, fold_string_cst_ctor_reference,
get_base_constructor): Move ...
* gimple-fold.c: ... here.
(gimple_fold_stmt_to_constant_1): New function
split out from ccp_fold. Take a valueization callback parameter.
Valueize all operands.
(gimple_fold_stmt_to_constant): New wrapper function.
(fold_const_aggregate_ref_1): New function split out from
fold_const_aggregate_ref. Take a valueization callback parameter.
(fold_const_aggregate_ref): Wrap fold_const_aggregate_ref_1.
* tree-ssa-sccvn.c (simplify_binary_expression): Simplify
invariant POINTER_PLUS_EXPRs to invariant form.
(vn_valueize): New function.
(try_to_simplify): Simplify by using gimple_fold_stmt_to_constant.
* tree-vrp.c (vrp_valueize): New function.
(vrp_visit_assignment_or_call): Use gimple_fold_stmt_to_constant
to fold statements to constants.
* tree-ssa-pre.c (eliminate): Properly guard propagation of
function declarations.
* Makefile.in (tree-ssa-sccvn.o, tree-vrp.o, gimple-fold.o,
tree-ssa-ccp.o): Add gimple-fold.h dependencies.
2011-03-24 Richard Sandiford <richard.sandiford@linaro.org> 2011-03-24 Richard Sandiford <richard.sandiford@linaro.org>
* config/h8300/predicates.md (jump_address_operand): Fix register * config/h8300/predicates.md (jump_address_operand): Fix register
......
...@@ -2485,12 +2485,12 @@ tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \ ...@@ -2485,12 +2485,12 @@ tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
$(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(FLAGS_H) $(CFGLOOP_H) \ $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(FLAGS_H) $(CFGLOOP_H) \
alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) langhooks.h $(HASHTAB_H) $(GIMPLE_H) \ alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) langhooks.h $(HASHTAB_H) $(GIMPLE_H) \
$(TREE_INLINE_H) tree-iterator.h tree-ssa-propagate.h tree-ssa-sccvn.h \ $(TREE_INLINE_H) tree-iterator.h tree-ssa-propagate.h tree-ssa-sccvn.h \
$(PARAMS_H) tree-pretty-print.h gimple-pretty-print.h $(PARAMS_H) tree-pretty-print.h gimple-pretty-print.h gimple-fold.h
tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(GGC_H) \ $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(GGC_H) \
$(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \ $(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \
$(CFGLOOP_H) $(SCEV_H) $(TIMEVAR_H) intl.h tree-pretty-print.h \ $(CFGLOOP_H) $(SCEV_H) $(TIMEVAR_H) intl.h tree-pretty-print.h \
gimple-pretty-print.h gimple-pretty-print.h gimple-fold.h
tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \ $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
...@@ -2638,7 +2638,7 @@ gimple-fold.o : gimple-fold.c $(TREE_FLOW_H) $(CONFIG_H) \ ...@@ -2638,7 +2638,7 @@ gimple-fold.o : gimple-fold.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \ $(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \
tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) gimple-fold.h
gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
$(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \ $(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \
$(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(LANGHOOKS_DEF_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
...@@ -3103,7 +3103,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \ ...@@ -3103,7 +3103,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \ $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \ $(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \
tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) \ tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) \
$(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h $(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h gimple-fold.h
tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \ tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \
$(TM_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) \ $(TM_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) \
$(IPA_PROP_H) $(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) \ $(IPA_PROP_H) $(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) \
......
/* Gimple folding definitions.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Richard Guenther <rguenther@suse.de>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_GIMPLE_FOLD_H
#define GCC_GIMPLE_FOLD_H
#include "coretypes.h"
tree fold_const_aggregate_ref_1 (tree, tree (*) (tree));
tree fold_const_aggregate_ref (tree);
tree gimple_fold_stmt_to_constant_1 (gimple, tree (*) (tree));
tree gimple_fold_stmt_to_constant (gimple, tree (*) (tree));
#endif /* GCC_GIMPLE_FOLD_H */
...@@ -169,8 +169,9 @@ static void ...@@ -169,8 +169,9 @@ static void
dump_split_point (FILE * file, struct split_point *current) dump_split_point (FILE * file, struct split_point *current)
{ {
fprintf (file, fprintf (file,
"Split point at BB %i header time:%i header size: %i" "Split point at BB %i\n"
" split time: %i split size: %i\n bbs: ", " header time: %i header size: %i\n"
" split time: %i split size: %i\n bbs: ",
current->entry_bb->index, current->header_time, current->entry_bb->index, current->header_time,
current->header_size, current->split_time, current->split_size); current->header_size, current->split_time, current->split_size);
dump_bitmap (file, current->split_bbs); dump_bitmap (file, current->split_bbs);
...@@ -1036,12 +1037,13 @@ split_function (struct split_point *split_point) ...@@ -1036,12 +1037,13 @@ split_function (struct split_point *split_point)
/* If RETURN_BB has virtual operand PHIs, they must be removed and the /* If RETURN_BB has virtual operand PHIs, they must be removed and the
virtual operand marked for renaming as we change the CFG in a way that virtual operand marked for renaming as we change the CFG in a way that
tree-inline is not able to compensate for. tree-inline is not able to compensate for.
Note this can happen whether or not we have a return value. If we have Note this can happen whether or not we have a return value. If we have
a return value, then RETURN_BB may have PHIs for real operands too. */ a return value, then RETURN_BB may have PHIs for real operands too. */
if (return_bb != EXIT_BLOCK_PTR) if (return_bb != EXIT_BLOCK_PTR)
{ {
bool phi_p = false;
for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);) for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);)
{ {
gimple stmt = gsi_stmt (gsi); gimple stmt = gsi_stmt (gsi);
...@@ -1052,7 +1054,28 @@ split_function (struct split_point *split_point) ...@@ -1052,7 +1054,28 @@ split_function (struct split_point *split_point)
} }
mark_virtual_phi_result_for_renaming (stmt); mark_virtual_phi_result_for_renaming (stmt);
remove_phi_node (&gsi, true); remove_phi_node (&gsi, true);
phi_p = true;
} }
/* In reality we have to rename the reaching definition of the
virtual operand at return_bb as we will eventually release it
when we remove the code region we outlined.
So we have to rename all immediate virtual uses of that region
if we didn't see a PHI definition yet. */
/* ??? In real reality we want to set the reaching vdef of the
entry of the SESE region as the vuse of the call and the reaching
vdef of the exit of the SESE region as the vdef of the call. */
if (!phi_p)
for (gsi = gsi_start_bb (return_bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
if (gimple_vuse (stmt))
{
gimple_set_vuse (stmt, NULL_TREE);
update_stmt (stmt);
}
if (gimple_vdef (stmt))
break;
}
} }
/* Now create the actual clone. */ /* Now create the actual clone. */
......
2011-03-24 Richard Guenther <rguenther@suse.de>
PR tree-optimization/46562
* c-c++-common/pr46562-2.c: New testcase.
* c-c++-common/pr46562.c: Likewise.
2011-03-24 Ira Rosen <ira.rosen@linaro.org> 2011-03-24 Ira Rosen <ira.rosen@linaro.org>
* gcc.dg/vect/vect-cselim-1.c: New test. * gcc.dg/vect/vect-cselim-1.c: New test.
......
/* { dg-do compile } */
/* { dg-options "-O -fno-tree-ccp -fno-tree-forwprop -fdump-tree-fre" } */
static const int a[4] = {};
int foo(void)
{
int i = 1;
const int *p = &a[i];
return *p;
}
/* { dg-final { scan-tree-dump "= 0;" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-ccp1" } */
static const int a[4] = {};
int foo(void)
{
int i = 1;
const int *p = &a[i];
return *p;
}
/* { dg-final { scan-tree-dump "return 0;" "ccp1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */
...@@ -963,110 +963,7 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, ...@@ -963,110 +963,7 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
tree tree
get_addr_base_and_unit_offset (tree exp, HOST_WIDE_INT *poffset) get_addr_base_and_unit_offset (tree exp, HOST_WIDE_INT *poffset)
{ {
HOST_WIDE_INT byte_offset = 0; return get_addr_base_and_unit_offset_1 (exp, poffset, NULL);
/* Compute cumulative byte-offset for nested component-refs and array-refs,
and find the ultimate containing object. */
while (1)
{
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
return NULL_TREE;
case COMPONENT_REF:
{
tree field = TREE_OPERAND (exp, 1);
tree this_offset = component_ref_field_offset (exp);
HOST_WIDE_INT hthis_offset;
if (!this_offset
|| TREE_CODE (this_offset) != INTEGER_CST
|| (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
% BITS_PER_UNIT))
return NULL_TREE;
hthis_offset = TREE_INT_CST_LOW (this_offset);
hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
/ BITS_PER_UNIT);
byte_offset += hthis_offset;
}
break;
case ARRAY_REF:
case ARRAY_RANGE_REF:
{
tree index = TREE_OPERAND (exp, 1);
tree low_bound, unit_size;
/* If the resulting bit-offset is constant, track it. */
if (TREE_CODE (index) == INTEGER_CST
&& (low_bound = array_ref_low_bound (exp),
TREE_CODE (low_bound) == INTEGER_CST)
&& (unit_size = array_ref_element_size (exp),
TREE_CODE (unit_size) == INTEGER_CST))
{
HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index);
hindex -= TREE_INT_CST_LOW (low_bound);
hindex *= TREE_INT_CST_LOW (unit_size);
byte_offset += hindex;
}
else
return NULL_TREE;
}
break;
case REALPART_EXPR:
break;
case IMAGPART_EXPR:
byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
break;
case VIEW_CONVERT_EXPR:
break;
case MEM_REF:
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
{
if (!integer_zerop (TREE_OPERAND (exp, 1)))
{
double_int off = mem_ref_offset (exp);
gcc_assert (off.high == -1 || off.high == 0);
byte_offset += double_int_to_shwi (off);
}
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
}
goto done;
case TARGET_MEM_REF:
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (TMR_BASE (exp)) == ADDR_EXPR)
{
if (TMR_INDEX (exp) || TMR_INDEX2 (exp))
return NULL_TREE;
if (!integer_zerop (TMR_OFFSET (exp)))
{
double_int off = mem_ref_offset (exp);
gcc_assert (off.high == -1 || off.high == 0);
byte_offset += double_int_to_shwi (off);
}
exp = TREE_OPERAND (TMR_BASE (exp), 0);
}
goto done;
default:
goto done;
}
exp = TREE_OPERAND (exp, 0);
}
done:
*poffset = byte_offset;
return exp;
} }
/* Returns true if STMT references an SSA_NAME that has /* Returns true if STMT references an SSA_NAME that has
......
...@@ -1227,4 +1227,139 @@ make_ssa_name (tree var, gimple stmt) ...@@ -1227,4 +1227,139 @@ make_ssa_name (tree var, gimple stmt)
return make_ssa_name_fn (cfun, var, stmt); return make_ssa_name_fn (cfun, var, stmt);
} }
/* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that
denotes the starting address of the memory access EXP.
Returns NULL_TREE if the offset is not constant or any component
is not BITS_PER_UNIT-aligned.
VALUEIZE if non-NULL is used to valueize SSA names. It should return
its argument or a constant if the argument is known to be constant. */
static inline tree
get_addr_base_and_unit_offset_1 (tree exp, HOST_WIDE_INT *poffset,
tree (*valueize) (tree))
{
HOST_WIDE_INT byte_offset = 0;
/* Compute cumulative byte-offset for nested component-refs and array-refs,
and find the ultimate containing object. */
while (1)
{
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
return NULL_TREE;
case COMPONENT_REF:
{
tree field = TREE_OPERAND (exp, 1);
tree this_offset = component_ref_field_offset (exp);
HOST_WIDE_INT hthis_offset;
if (!this_offset
|| TREE_CODE (this_offset) != INTEGER_CST
|| (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
% BITS_PER_UNIT))
return NULL_TREE;
hthis_offset = TREE_INT_CST_LOW (this_offset);
hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
/ BITS_PER_UNIT);
byte_offset += hthis_offset;
}
break;
case ARRAY_REF:
case ARRAY_RANGE_REF:
{
tree index = TREE_OPERAND (exp, 1);
tree low_bound, unit_size;
if (valueize
&& TREE_CODE (index) == SSA_NAME)
index = (*valueize) (index);
/* If the resulting bit-offset is constant, track it. */
if (TREE_CODE (index) == INTEGER_CST
&& (low_bound = array_ref_low_bound (exp),
TREE_CODE (low_bound) == INTEGER_CST)
&& (unit_size = array_ref_element_size (exp),
TREE_CODE (unit_size) == INTEGER_CST))
{
HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index);
hindex -= TREE_INT_CST_LOW (low_bound);
hindex *= TREE_INT_CST_LOW (unit_size);
byte_offset += hindex;
}
else
return NULL_TREE;
}
break;
case REALPART_EXPR:
break;
case IMAGPART_EXPR:
byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
break;
case VIEW_CONVERT_EXPR:
break;
case MEM_REF:
{
tree base = TREE_OPERAND (exp, 0);
if (valueize
&& TREE_CODE (base) == SSA_NAME)
base = (*valueize) (base);
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (base) == ADDR_EXPR)
{
if (!integer_zerop (TREE_OPERAND (exp, 1)))
{
double_int off = mem_ref_offset (exp);
gcc_assert (off.high == -1 || off.high == 0);
byte_offset += double_int_to_shwi (off);
}
exp = TREE_OPERAND (base, 0);
}
goto done;
}
case TARGET_MEM_REF:
{
tree base = TREE_OPERAND (exp, 0);
if (valueize
&& TREE_CODE (base) == SSA_NAME)
base = (*valueize) (base);
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (base) == ADDR_EXPR)
{
if (TMR_INDEX (exp) || TMR_INDEX2 (exp))
return NULL_TREE;
if (!integer_zerop (TMR_OFFSET (exp)))
{
double_int off = mem_ref_offset (exp);
gcc_assert (off.high == -1 || off.high == 0);
byte_offset += double_int_to_shwi (off);
}
exp = TREE_OPERAND (base, 0);
}
goto done;
}
default:
goto done;
}
exp = TREE_OPERAND (exp, 0);
}
done:
*poffset = byte_offset;
return exp;
}
#endif /* _TREE_FLOW_INLINE_H */ #endif /* _TREE_FLOW_INLINE_H */
...@@ -594,6 +594,7 @@ extern void ssanames_print_statistics (void); ...@@ -594,6 +594,7 @@ extern void ssanames_print_statistics (void);
/* In tree-ssa-ccp.c */ /* In tree-ssa-ccp.c */
tree fold_const_aggregate_ref (tree); tree fold_const_aggregate_ref (tree);
tree gimple_fold_stmt_to_constant (gimple, tree (*)(tree));
/* In tree-ssa-dom.c */ /* In tree-ssa-dom.c */
extern void dump_dominator_optimization_stats (FILE *); extern void dump_dominator_optimization_stats (FILE *);
......
...@@ -4380,9 +4380,12 @@ eliminate (void) ...@@ -4380,9 +4380,12 @@ eliminate (void)
if (is_gimple_call (stmt) if (is_gimple_call (stmt)
&& TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME) && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
{ {
tree fn = VN_INFO (gimple_call_fn (stmt))->valnum; tree orig_fn = gimple_call_fn (stmt);
tree fn = VN_INFO (orig_fn)->valnum;
if (TREE_CODE (fn) == ADDR_EXPR if (TREE_CODE (fn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL) && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
&& useless_type_conversion_p (TREE_TYPE (orig_fn),
TREE_TYPE (fn)))
{ {
bool can_make_abnormal_goto bool can_make_abnormal_goto
= stmt_can_make_abnormal_goto (stmt); = stmt_can_make_abnormal_goto (stmt);
......
...@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h" #include "params.h"
#include "tree-ssa-propagate.h" #include "tree-ssa-propagate.h"
#include "tree-ssa-sccvn.h" #include "tree-ssa-sccvn.h"
#include "gimple-fold.h"
/* This algorithm is based on the SCC algorithm presented by Keith /* This algorithm is based on the SCC algorithm presented by Keith
Cooper and L. Taylor Simpson in "SCC-Based Value numbering" Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
...@@ -2770,6 +2771,16 @@ simplify_binary_expression (gimple stmt) ...@@ -2770,6 +2771,16 @@ simplify_binary_expression (gimple stmt)
op1 = SSA_VAL (op1); op1 = SSA_VAL (op1);
} }
/* Pointer plus constant can be represented as invariant address.
Do so to allow further propatation, see also tree forwprop. */
if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
&& host_integerp (op1, 1)
&& TREE_CODE (op0) == ADDR_EXPR
&& is_gimple_min_invariant (op0))
return build_invariant_address (TREE_TYPE (op0),
TREE_OPERAND (op0, 0),
TREE_INT_CST_LOW (op1));
/* Avoid folding if nothing changed. */ /* Avoid folding if nothing changed. */
if (op0 == gimple_assign_rhs1 (stmt) if (op0 == gimple_assign_rhs1 (stmt)
&& op1 == gimple_assign_rhs2 (stmt)) && op1 == gimple_assign_rhs2 (stmt))
...@@ -2849,6 +2860,19 @@ simplify_unary_expression (gimple stmt) ...@@ -2849,6 +2860,19 @@ simplify_unary_expression (gimple stmt)
return NULL_TREE; return NULL_TREE;
} }
/* Valueize NAME if it is an SSA name, otherwise just return it. */
static inline tree
vn_valueize (tree name)
{
if (TREE_CODE (name) == SSA_NAME)
{
tree tem = SSA_VAL (name);
return tem == VN_TOP ? name : tem;
}
return name;
}
/* Try to simplify RHS using equivalences and constant folding. */ /* Try to simplify RHS using equivalences and constant folding. */
static tree static tree
...@@ -2862,21 +2886,15 @@ try_to_simplify (gimple stmt) ...@@ -2862,21 +2886,15 @@ try_to_simplify (gimple stmt)
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME) && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
return NULL_TREE; return NULL_TREE;
/* First try constant folding based on our current lattice. */
tem = gimple_fold_stmt_to_constant (stmt, vn_valueize);
if (tem)
return tem;
/* If that didn't work try combining multiple statements. */
switch (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))) switch (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)))
{ {
case tcc_declaration:
tem = get_symbol_constant_value (gimple_assign_rhs1 (stmt));
if (tem)
return tem;
break;
case tcc_reference: case tcc_reference:
/* Do not do full-blown reference lookup here, but simplify
reads from constant aggregates. */
tem = fold_const_aggregate_ref (gimple_assign_rhs1 (stmt));
if (tem)
return tem;
/* Fallthrough for some codes that can operate on registers. */ /* Fallthrough for some codes that can operate on registers. */
if (!(TREE_CODE (gimple_assign_rhs1 (stmt)) == REALPART_EXPR if (!(TREE_CODE (gimple_assign_rhs1 (stmt)) == REALPART_EXPR
|| TREE_CODE (gimple_assign_rhs1 (stmt)) == IMAGPART_EXPR || TREE_CODE (gimple_assign_rhs1 (stmt)) == IMAGPART_EXPR
...@@ -2886,11 +2904,11 @@ try_to_simplify (gimple stmt) ...@@ -2886,11 +2904,11 @@ try_to_simplify (gimple stmt)
into binary ops, but it's debatable whether it is worth it. */ into binary ops, but it's debatable whether it is worth it. */
case tcc_unary: case tcc_unary:
return simplify_unary_expression (stmt); return simplify_unary_expression (stmt);
break;
case tcc_comparison: case tcc_comparison:
case tcc_binary: case tcc_binary:
return simplify_binary_expression (stmt); return simplify_binary_expression (stmt);
break;
default: default:
break; break;
} }
......
...@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-scalar-evolution.h" #include "tree-scalar-evolution.h"
#include "tree-ssa-propagate.h" #include "tree-ssa-propagate.h"
#include "tree-chrec.h" #include "tree-chrec.h"
#include "gimple-fold.h"
/* Type of value ranges. See value_range_d for a description of these /* Type of value ranges. See value_range_d for a description of these
...@@ -5614,6 +5615,21 @@ vrp_initialize (void) ...@@ -5614,6 +5615,21 @@ vrp_initialize (void)
} }
} }
/* Return the singleton value-range for NAME or NAME. */
static inline tree
vrp_valueize (tree name)
{
if (TREE_CODE (name) == SSA_NAME)
{
value_range_t *vr = get_value_range (name);
if (vr->type == VR_RANGE
&& (vr->min == vr->max
|| operand_equal_p (vr->min, vr->max, 0)))
return vr->min;
}
return name;
}
/* Visit assignment STMT. If it produces an interesting range, record /* Visit assignment STMT. If it produces an interesting range, record
the SSA name in *OUTPUT_P. */ the SSA name in *OUTPUT_P. */
...@@ -5637,7 +5653,12 @@ vrp_visit_assignment_or_call (gimple stmt, tree *output_p) ...@@ -5637,7 +5653,12 @@ vrp_visit_assignment_or_call (gimple stmt, tree *output_p)
{ {
value_range_t new_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; value_range_t new_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
if (code == GIMPLE_CALL) /* Try folding the statement to a constant first. */
tree tem = gimple_fold_stmt_to_constant (stmt, vrp_valueize);
if (tem && !is_overflow_infinity (tem))
set_value_range (&new_vr, VR_RANGE, tem, tem, NULL);
/* Then dispatch to value-range extracting functions. */
else if (code == GIMPLE_CALL)
extract_range_basic (&new_vr, stmt); extract_range_basic (&new_vr, stmt);
else else
extract_range_from_assignment (&new_vr, stmt); extract_range_from_assignment (&new_vr, stmt);
...@@ -6366,7 +6387,6 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p) ...@@ -6366,7 +6387,6 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p)
/* In general, assignments with virtual operands are not useful /* In general, assignments with virtual operands are not useful
for deriving ranges, with the obvious exception of calls to for deriving ranges, with the obvious exception of calls to
builtin functions. */ builtin functions. */
if ((is_gimple_call (stmt) if ((is_gimple_call (stmt)
&& gimple_call_fndecl (stmt) != NULL_TREE && gimple_call_fndecl (stmt) != NULL_TREE
&& DECL_IS_BUILTIN (gimple_call_fndecl (stmt))) && DECL_IS_BUILTIN (gimple_call_fndecl (stmt)))
......
...@@ -4013,6 +4013,20 @@ reference_alias_ptr_type (const_tree t) ...@@ -4013,6 +4013,20 @@ reference_alias_ptr_type (const_tree t)
return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base))); return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base)));
} }
/* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE
offsetted by OFFSET units. */
tree
build_invariant_address (tree type, tree base, HOST_WIDE_INT offset)
{
tree ref = fold_build2 (MEM_REF, TREE_TYPE (type),
build_fold_addr_expr (base),
build_int_cst (ptr_type_node, offset));
tree addr = build1 (ADDR_EXPR, type, ref);
recompute_tree_invariant_for_addr_expr (addr);
return addr;
}
/* Similar except don't specify the TREE_TYPE /* Similar except don't specify the TREE_TYPE
and leave the TREE_SIDE_EFFECTS as 0. and leave the TREE_SIDE_EFFECTS as 0.
It is permissible for arguments to be null, It is permissible for arguments to be null,
......
...@@ -5096,6 +5096,7 @@ extern tree build_simple_mem_ref_loc (location_t, tree); ...@@ -5096,6 +5096,7 @@ extern tree build_simple_mem_ref_loc (location_t, tree);
build_simple_mem_ref_loc (UNKNOWN_LOCATION, T) build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
extern double_int mem_ref_offset (const_tree); extern double_int mem_ref_offset (const_tree);
extern tree reference_alias_ptr_type (const_tree); extern tree reference_alias_ptr_type (const_tree);
extern tree build_invariant_address (tree, tree, HOST_WIDE_INT);
extern tree constant_boolean_node (int, tree); extern tree constant_boolean_node (int, tree);
extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree); extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment