gcc/gcc/tree-chrec.c
Sandra Loosemore 5039610b96 tree.h (enum tree_code_class): Add tcc_vl_exp.
2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* tree.h (enum tree_code_class): Add tcc_vl_exp.
	(VL_EXP_CLASS_P): New.
	(TREE_OPERAND_CHECK): Use TREE_OPERAND_LENGTH instead of
	TREE_CODE_LENGTH.
	(TREE_OPERAND_CHECK_CODE): Likewise.
	(GIMPLE_STMT_OPERAND_CHECK): Likewise.
	(TREE_RTL_OPERAND_CHECK): Likewise.
	(tree_operand_check_failed): Make second parameter the whole tree
	instead of its code.  Fixed callers.
	(VL_EXP_CHECK): New.
	(TREE_OPERAND_LENGTH): New.
	(VL_EXP_OPERAND_LENGTH): New.
	(CALL_EXPR_FN): New.
	(CALL_EXPR_STATIC_CHAIN): New.
	(CALL_EXPR_ARGS): New.
	(CALL_EXPR_ARG): New.
	(call_expr_nargs): New.
	(CALL_EXPR_ARGP): New.
	(build_nt_call_list): Declare.
	(build_vl_exp_stat): Declare.
	(build_vl_exp): New.
	(build_call_list): Declare.
	(build_call_nary): Declare.
	(build_call_valist): Declare.
	(build_call_array): Declare.
	(call_expr_arg): Declare.
	(call_expr_argp): Declare.
	(call_expr_arglist): Declare.
	(fold_build_call_list): Declare.
	(fold_build_call_list_initializer): Declare.
	(fold_call_expr): Declare to replace fold_builtin.
	(fold_builtin_fputs): Update to agree with modified definition.
	(fold_builtin_strcpy): Likewise.
	(fold_builtin_strncpy): Likewise.
	(fold_builtin_memory_chk): Likewise.
	(fold_builtin_stxcpy_chk): Likewise.
	(fold_builtin_strncpy_chk): Likewise.
	(fold_builtin_next_arg): Likewise.
	(fold_build_call_expr): Declare.
	(fold_builtin_call_list): Declare.
	(fold_builtin_call_valist): Declare.
	(build_call_expr): Declare.
	(validate_arglist): Update to agree with modified definition.
	(tree_operand_length): New.
	(call_expr_arg_iterator): New.
	(init_call_expr_arg_iterator): New.
	(next_call_expr_arg): New.
	(first_call_expr_arg): New.
	(more_call_expr_args_p): New.
	(FOR_EACH_CALL_EXPR_ARG): New.

	* tree.c (tree_code_class_string): Add entries for tcc_vl_exp
	and tcc_gimple_stmt.
	(tree_code_size): Update documentation.  Use sizeof (tree) rather
	than sizeof (char *).
	(tree_size): Likewise.  Add case for tcc_vl_exp.
	(tree_node_structure): Add case for tcc_vl_exp.
	(contains_placeholder_p): Likewise.
	(substitute_in_expr): Likewise.
	(substitute_placeholder_in_expr): Likewise.
	(stabilize_reference_1): Likewise.
	(build3_stat): Remove logic for CALL_EXPRs.  Replace with assertion
	to diagnose breakage of this interface for constructing CALL_EXPRs.
	(build_nt): Add similar assertion here.
	(build_nt_call_list): New.
	(simple_cst_equal) <CALL_EXPR>: Rewrite to use new accessors.
	(iterative_hash_expr): Use TREE_OPERAND_LENGTH instead of
	TREE_CODE_LENGTH.
	(get_callee_fndecl): Use new CALL_EXPR accessors.
	(tree_operand_check_failed): Change parameters to pass entire node
	instead of its code, so that we can call TREE_OPERAND_LENGTH on it.
	(process_call_operands): New.
	(build_vl_exp_stat): New.
	(build_call_list): New.
	(build_call_nary): New.
	(build_call_valist): New.
	(build_call_array): New.
	(walk_tree): Use TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
	(call_expr_arglist): New.

	* tree.def (CALL_EXPR): Change representation of CALL_EXPRs to use
	tcc_vl_exp instead of a fixed-size tcc_expression.

	* doc/c-tree.texi (CALL_EXPR): Document new representation and
	accessors for CALL_EXPRs.
	(AGGR_INIT_EXPR): Likewise.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* builtins.c (c_strlen): Return NULL_TREE instead of 0.
	(expand_builtin_nonlocal_goto): Change parameter to be entire
	CALL_EXPR instead of an arglist.  Use new CALL_EXPR accessors.
	(expand_builtin_prefetch): Likewise.
	(expand_builtin_classify_type): Likewise.
	(mathfn_built_in): Return NULL_TREE instead of 0.
	(expand_errno_check): Use new CALL_EXPR accessors.
	(expand_builtin_mathfn): Use new CALL_EXPR accessors and constructors.
	Return NULL_RTX instead of 0.
	(expand_builtin_mathfn_2): Likewise.
	(expand_builtin_mathfn_3): Likewise.
	(expand_builtin_interclass_mathfn): Likewise.
	(expand_builtin_sincos): Likewise.
	(expand_builtin_cexpi): Likewise.
	(expand_builtin_int_roundingfn): Likewise.
	(expand_builtin_int_roundingfn_2): Likewise.
	(expand_builtin_pow): Likewise.
	(expand_builtin_powi): Likewise.
	(expand_builtin_strlen): Pass entire CALL_EXPR as parameter instead
	of arglist, fixing callers appropriately.  Use new CALL_EXPR
	accessors and constructors.  Return NULL_RTX instead of 0.
	(expand_builtin_strstr): Likewise.
	(expand_builtin_strchr): Likewise.
	(expand_builtin_strrchr): Likewise.
	(expand_builtin_strpbrk): Likewise.
	(expand_builtin_memcpy): Likewise.
	(expand_builtin_mempcpy): Likewise.
	(expand_builtin_mempcpy_args): New.
	(expand_builtin_memmove): Similarly to expand_builtin_mempcpy.
	(expand_builtin_memmove_args): New.
	(expand_builtin_bcopy): Similarly to expand_builtin_mempcpy.
	(expand_movstr): Likewise.
	(expand_builtin_strcpy): Likewise.
	(expand_builtin_strcpy_args): New.
	(expand_builtin_stpcpy): Similarly to expand_builtin_strcpy.
	(expand_builtin_strncpy): Likewise.
	(expand_builtin_memset): Likewise.
	(expand_builtin_memset_args): New.
	(expand_builtin_bzero): Similarly to expand_builtin_memset.
	(expand_builtin_memcmp): Likewise.
	(expand_builtin_strcmp): Likewise.
	(expand_builtin_strncmp): Likewise.
	(expand_builtin_strcat): Likewise.
	(expand_builtin_strncat): Likewise.
	(expand_builtin_strspn): Likewise.
	(expand_builtin_strcspn): Likewise.
	(expand_builtin_args_info): Likewise.
	(expand_builtin_va_start): Likewise.
	(gimplify_va_arg_expr): Likewise.
	(expand_builtin_va_end): Likewise.
	(expand_builtin_va_copy): Likewise.
	(expand_builtin_frame_address): Likewise.
	(expand_builtin_alloca): Likewise.
	(expand_builtin_bswap): Likewise.
	(expand_builtin_unop): Likewise.
	(expand_builtin_fputs): Likewise.
	(expand_builtin_expect): Likewise.
	(expand_builtin_fabs): Likewise.
	(expand_builtin_copysign): Likewise.
	(expand_builtin_printf): Likewise.
	(expand_builtin_fprintf): Likewise.
	(expand_builtin_sprintf): Likewise.
	(expand_builtin_init_trampoline): Likewise.
	(expand_builtin_signbit): Likewise.
	(expand_builtin_fork_or_exec): Likewise.
	(expand_builtin_sync_operation): Likewise.
	(expand_builtin_compare_and_swap): Likewise.
	(expand_builtin_lock_test_and_set): Likewise.
	(expand_builtin_lock_release): Likewise.
	(expand_builtin): Likewise.
	(builtin_mathfn_code): Likewise.

	(fold_builtin_constant_p): Pass call arguments individually instead
	of as an arglist, fixing callers appropriately.  Use new CALL_EXPR
	accessors and constructors.  Return NULL_TREE instead of 0.
	(fold_builtin_expect): Likewise.
	(fold_builtin_classify_type): Likewise.
	(fold_builtin_strlen): Likewise.
	(fold_builtin_nan): Likewise.
	(integer_valued_real_p): Likewise.
	(fold_trunc_transparent_mathfn): Likewise.
	(fold_fixed_mathfn): Likewise.
	(fold_builtin_cabs): Likewise.
	(fold_builtin_sqrt): Likewise.
	(fold_builtin_cbrt): Likewise.
	(fold_builtin_cos): Likewise.
	(fold_builtin_cosh): Likewise.
	(fold_builtin_tan): Likewise.
	(fold_builtin_sincos): Likewise.
	(fold_builtin_cexp): Likewise.
	(fold_builtin_trunc): Likewise.
	(fold_builtin_floor): Likewise.
	(fold_builtin_ceil): Likewise.
	(fold_builtin_round): Likewise.
	(fold_builtin_int_roundingfn): Likewise.
	(fold_builtin_bitop): Likewise.
	(fold_builtin_bswap): Likewise.
	(fold_builtin_logarithm): Likewise.
	(fold_builtin_hypot): Likewise.
	(fold_builtin_pow): Likewise.
	(fold_builtin_powi): Likewise.
	(fold_builtin_exponent): Likewise.
	(fold_builtin_memset): Likewise.
	(fold_builtin_bzero): Likewise.
	(fold_builtin_memory_op): Likewise.
	(fold_builtin_bcopy): Deleted; call site changed to invoke
	fold_builtin_memory_op directly.
	(fold_builtin_strcpy): Similarly as for fold_builtin_memory_op.
	(fold_builtin_strncpy): Likewise.
	(fold_builtin_memcmp): Likewise.
	(fold_builtin_strcmp): Likewise.
	(fold_builtin_strncmp): Likewise.
	(fold_builtin_signbit): Likewise.
	(fold_builtin_copysign): Likewise.
	(fold_builtin_isascii): Likewise.
	(fold_builtin_toascii): Likewise.
	(fold_builtin_isdigit): Likewise.
	(fold_builtin_fabs): Likewise.
	(fold_builtin_abs): Likewise.
	(fold_builtin_fmin_fmax): Likewise.
	(fold_builtin_carg): Likewise.
	(fold_builtin_classify): Likewise.
	(fold_builtin_unordered_cmp): Likewise.

	(fold_builtin_0, fold_builtin_2, fold_builtin_3, fold_builtin_4):
	New functions split out from fold_builtin_1.
	(fold_builtin_n): New.
	(fold_builtin_varargs): New.
	(fold_builtin): Deleted.  Most callers changed to use fold_call_expr
	instead.
	(fold_call_expr): New.
	(build_function_call_expr): Rewrite to use new helper function.
	(fold_builtin_call_list): New.
	(build_call_expr): New.
	(fold_builtin_call_valist): New.
	(rewrite_call_expr): New.
	(validate_arg): New.
	(validate_arglist): Change parameter to be entire CALL_EXPR instead
	of an arglist.  Change return type to bool.  Use new CALL_EXPR
	accessors.

	(fold_builtin_strstr):  Pass call arguments individually instead
	of as an arglist, fixing callers appropriately.  Use new CALL_EXPR
	accessors and constructors.  Return NULL_TREE instead of 0.
	(fold_builtin_strchr): Likewise.
	(fold_builtin_strrchr): Likewise.
	(fold_builtin_strpbrk): Likewise.
	(fold_builtin_strcat): Likewise.
	(fold_builtin_strncat): Likewise.
	(fold_builtin_strspn): Likewise.
	(fold_builtin_strcspn): Likewise.
	(fold_builtin_fputs): Likewise.
	(fold_builtin_next_arg): Likewise.
	(fold_builtin_sprintf): Likewise.

	(expand_builtin_object_size): Use new CALL_EXPR accessors.  Use
	NULL_RTX instead of 0.
	(expand_builtin_memory_chk): Likewise.
	(maybe_emit_chk_warning): Likewise.
	(maybe_emit_sprintf_chk_warning): Likewise.

	(fold_builtin_object_size): Pass call arguments individually instead
	of as an arglist, fixing callers appropriately.  Use new CALL_EXPR
	accessors and constructors.  Return NULL_TREE instead of 0.
	(fold_builtin_memory_chk): Likewise.
	(fold_builtin_stxcpy_chk): Likewise.
	(fold_builtin_strncpy_chk): Likewise.
	(fold_builtin_strcat_chk): Likewise.
	(fold_builtin_strcat_chk): Likewise.
	(fold_builtin_strncat_chk): Likewise.
	(fold_builtin_sprintf_chk): Likewise.
	(fold_builtin_snprintf_chk): Likewise.
	(fold_builtin_printf): Likewise.
	(fold_builtin_vprintf): Likewise.

	* fold-const.c (negate_expr_p): Use new CALL_EXPR accessors and
	constructors.
	(operand_equal_p): Add separate tcc_vl_exp/CALL_EXPR case.
	(make_range): Use TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
	(extract_muldiv_1): Add VL_EXP_CLASS_P case.
	(fold_mathfn_compare): Use new CALL_EXPR accessors and constructors.
	(fold_unary): Likewise.
	(fold_binary): Likewise.
	(fold_ternary): Remove CALL_EXPR case, since they are no longer
	ternary expressions.
	(fold): Add logic for tcc_vl_exp.
	(fold_checksum_tree):  Make it know about tcc_vl_exp.  Use
	TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
	(fold_build3_stat): Add assertion to flag broken interface for
	constructing CALL_EXPRs.
	(fold_build_call_list): New.
	(fold_build_call_list_initializer): New.
	(tree_expr_nonnegative_p): Use new CALL_EXPR accessors and
	constructors.
	(fold_strip_sign_ops): Likewise.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* tree-dump.c (dequeue_and_dump) <CALL_EXPR>: Use new CALL_EXPR
	accessors and dump arguments explicitly.

	* tree-pretty-print.c (do_niy): Use TREE_OPERAND_LENGTH instead of
	TREE_CODE_LENGTH.
	(dump_generic_node): Use new CALL_EXPR accessors and walk arguments
	explicitly.
	(print_call_name): Use new CALL_EXPR accessors.

	* print-tree.c (print_node): Add case tcc_vl_exp.  Print
	CALL_EXPR arguments explicitly instead of as a list.  Use
	TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.

	* tree-vrp.c (stmt_interesting_for_vrp): Use new CALL_EXPR accessors.
	(vrp_visit_stmt): Likewise.

	* tree-ssa-loop-im.c (outermost_invariant_loop_expr):  Make it
	know about tcc_vl_exp.  Use TREE_OPERAND_LENGTH instead of
	TREE_CODE_LENGTH.
	(force_move_till_expr): Likewise.

	* targhooks.c (default_external_stack_protect_fail): Use
	build_call_expr instead of build_function_call_expr.
	(default_hidden_stack_protect_fail): Likewise.

	* tree-complex.c (expand_complex_libcall): Use build_call_expr to
	build the call.

	* cgraphbuild.c (build_cgraph_edges): Use new CALL_EXPR accessors
	and walk arguments explicitly.

	* tree-ssa-loop-niter.c (simplify_replace_tree): Use
	TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
	(expand_simple_operations): Likewise.
	(infer_loop_bounds_from_array): Use new CALL_EXPR accessors.

	* gengtype.c (adjust_field_tree_exp): Use TREE_OPERAND_LENGTH instead
	of TREE_CODE_LENGTH.
	(walk_type): Tweak walking of arrays not to blow up on CALL_EXPRs.

	* optabs.c (expand_widen_pattern-expr): Use TREE_OPERAND_LENGTH
	instead of TREE_CODE_LENGTH.

	* value_prof.c (tree_ic): Use new CALL_EXPR accessors.
	(tree_ic_transform): Likewise.
	(interesting_stringop_to_profile_p): Pass entire CALL_EXPR as
	parameter instead of arglist.  Fix callers.
	(tree_stringop_fixed_value): Use new CALL_EXPR accessors.
	(tree_stringops_transform): Likewise.
	(tree_indirect_call_to_profile): Likewise.
	(tree_stringops_values_to_profile): Likewise.

	* tree-tailcall.c (find_tail_calls): Use new CALL_EXPR iterator.
	(eliminate_tail_call): Likewise.

	* ipa-cp.c (ipcp_update_callgraph): Use new CALL_EXPR accessors.

	* tree-scalar-evolution.c (chrec_contains_symbols_defined_in_loop):
	Use TREE_OPERAND_LENGTH and generalize to handle any number of
	operands.
	(instantiate_parameters_1): Can't handle tcc_vl_exp here.

	* omp-low.c (build_omp_barrier): Use build_call_expr.
	(lower_rec_input_clauses): Likewise.
	(lower_reduction_clauses): Likewise.
	(expand_parallel_call): Likewise.
	(maybe_catch_exception): Likewise.
	(expand_omp_for_generic): Likewise.
	(expand_omp_for_static_nochunk): Likewise.
	(expand_omp_sections): Likewise.
	(lower_omp_single_simple): Likewise.
	(lower_omp_single_copy): Likewise.
	(lower_omp_master): Likewise.
	(lower_omp_ordered): Likewise.
	(lower_omp_critical): Likewise.

	* ipa-reference.c (check-call): Use new CALL_EXPR iterator.
	(scan_for_static_refs): Create tcc_vl_exp case for CALL_EXPR.

	* tree-gimple.c (is_gimple_call_addr): Fix doc.
	(recalculate_side_effects): Use TREE_OPERAND_LENGTH instead of
	TREE_CODE_LENGTH.  Add tcc_vl_exp case.

	* tree-chrec.c (chrec_contains_symbols): Use TREE_OPERAND_LENGTH
	and generalize to handle any number of operands.
	(chrec_contains_undetermined): Likewise.
	(tree_contains_chrecs): Likewise.
	(evolution_function_is_invariant_rec_p): Use TREE_OPERAND_LENGTH.

	* cgraphunit.c (update_call_expr): Use new CALL_EXPR accessors.

	* tree-ssa-ccp.c (ccp_fold): Use new CALL_EXPR accessors.  Use
	fold_call_expr instead of fold_builtin.
	(ccp_fold_builtin): Likewise.  Update calls into builtins.c to
	match declarations there.
	(fold_stmt): Use new CALL_EXPR constructor and accessors.  Doc
	updates.

	* tree-ssa-loop-ivopts.c (expr_invariant_in_loop_p): Use
	TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.

	* ipa-pure-const.c (check_call): Use new CALL_EXPR accessors.
	(scan_function): Add case tcc_vl_exp for CALL_EXPR.

	* tree-stdarg.c (execute_optimize_stdarg): Use new CALL_EXPR
	accessors.

	* tree-ssa-math-opts.c (execute_cse_sincos_1): Use build_call_expr.
	(execute_cse_sincos): Use new CALL_EXPR accessors.

	* tree-ssa-alias.c (find_used_portions): Use new CALL_EXPR iterator.

	* gimple-low.c (lower_function_body): Use build_call_expr.
	(lower_builtin_setjmp): Likewise.

	* expr.c (emit_block_move_via_libcall): Use build_call_expr.
	(set_storage_via_libcall): Likewise.
	(safe_from_p): Add tcc_vl_exp case.  Use TREE_OPERAND_LENGTH
	instead of TREE_CODE_LENGTH.
	(expand_expr_real_1): Use new CALL_EXPR accessors.

	* tree-browser.c (store_child_info): Use TREE_OPERAND_LENGTH and
	generalize to handle any number of operands.
	(TB_parent_eq): Likewise.

	* predict.c (expr_expected_value): Use new CALL_EXPR accessors.
	(strip_builtin_expect): Likewise.

	* function.c (gimplify_parameters): Use build_call_expr.

	* tree-vectorizer.c (vect_is_simple_reduction): Use TREE_OPERAND_LENGTH
	instead of TREE_CODE_LENGTH.

	* ipa-type-escape.c (check_call): Use new CALL_EXPR iterators.
	(scan_for_refs): Add case tcc_vl_exp for CALL_EXPR.

	* tree-data-ref.c (get_references_in_stmt): Use new CALL_EXPR
	iterators.

	* gimplify.c (build_stack_save_restore): Use build_call_expr.
	(gimplify_decl_expr): Likewise.
	(gimplify_call_expr): Use fold_call_expr instead of fold_builtin.
	Use new CALL_EXPR iterators.
	(gimplify_modify_expr_to_memcpy): Use build_call_expr.
	(gimplify_modify_expr_to_memset): Likewise.
	(gimplify_variable_sized_compare): Likewise.
	(gimplify_omp_atomic_fetch_op): Likewise.
	(gimplify_omp_atomic_pipeline): Likewise.
	(gimplify_omp_atomic_mutex): Likewise.
	(gimplify_function_tree): Likewise.

	* calls.c (alloca_call_p): Use new CALL_EXPR accessors.
	(call_expr_flags): Likewise.
	(expand_call): Likewise.

	* except.c (expand_builtin_eh_return_data_regno): Pass entire
	CALL_EXPR as parameter instead of arglist.  Use new CALL_EXPR 
        accessors.

	* coverage.c (create_coverage): Use build_call_expr.

	* tree-ssa-pre.c (expression_node_pool, list_node_pool): Delete.
	(temp_call_expr_obstack): New.
	(pool_copy_list): Delete.
	(temp_copy_call_expr): New.
	(phi_translate): Add case tcc_vl_exp for CALL_EXPR.  Use new
	CALL_EXPR accessors.  Get rid of special goo for copying argument
	lists and use temp_copy_call_expr instead.
	(valid_in_sets): Add case tcc_vl_exp for CALL_EXPR.  Use new
	CALL_EXPR accessors.
	(create_expression_by_pieces): Likewise.  Use build_call_array
	to construct the result instead of fold_build3.
	(create_value_expr_from): Add tcc_vl_exp.  Delete special goo for
	dealing with argument lists.
	(init_pre): Remove references to expression_node_pool and
	list_node_pool.  Init temp_call_expr_obstack instead.
	(fini_pre): Remove references to expression_node_pool and
	list_node_pool.

	* tree-sra.c (sra_walk_call_expr): Use new CALL_EXPR accessors
	and walk arguments explicitly instead of as a list.

	* tree-mudflap.c (mf_build_check_statement_for): Use build_call_expr.
	(mx_register_decls): Likewise.
	(mudflap_register_call): Likewise.
	(mudflap_finish_file): Likewise.

	* ipa-prop.c (ipa_callsite_compute_count): Use new CALL_EXPR accessors.
	(ipa_callsite_compute_param): Likewise.

	* tree-vect-patterns.c (vect_recog_pow_pattern): Use new CALL_EXPR
	accessors and constructor.

	* tree-nested.c (convert_nl_goto_reference): Use new CALL_EXPR
	accessors and constructor.
	(convert_tramp_reference): Likewise. 
	(convert_call_expr): Likewise.
	(finalize_nesting_tree_1): Likewise.

	* tree-ssa.c (tree_ssa_useless_type_conversion): Use new CALL_EXPR
	accessors.

	* tree-ssa-loop-prefetch.c (issue_prefetch_ref): Use build_call_expr.

	* tree-inline.c (initialize_inlined_parameters): Pass entire
	CALL_EXPR as parameter instead of arglist.  Use new CALL_EXPR
	accessors.
	(estimate_num_insns_1): Use new CALL_EXPR accessors.
	(expand_call_inline): Tidy up call to initialize_inlined_parameters.

	* tree-vect-transform.c (vect_create_epilog_for_reduction):  Use
	TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
	(vectorizable_reduction): Likewise.
	(vectorizable_call): Use new CALL_EXPR iterators.
	(vectorizable_conversion): Use build_call_expr.
	(vectorizable_operation): Use TREE_OPERAND_LENGTH.
	(vect_gen_widened_results_half): Use build_call_expr.
	(vect_setup_realignment): Likewise.
	(vectorizable_live_operation): Use TREE_OPERAND_LENGTH.

	* tree-object-size.c (alloc_object_size): Use new CALL_EXPR accessors.
	(pass_through_call): Likewise.
	(compute_object_sizes): Likewise.  Use fold_call_expr instead of
	fold_builtin.

	* tree-profile.c (tree_gen_interval_profiler): Use build_call_expr.
	(tree_gen_pow2_profiler): Likewise.
	(tree_gen_one_value_profiler): Likewise.
	(tree_gen_ic_func_profiler): Likewise.
	(tree_gen_average_profiler): Likewise.
	(tree_gen_ior_profiler): Likewise.

	* tree-ssa-structalias.c (get_constraint_for): Add case tcc_vl_exp.
	(find_func_aliases): Use new CALL_EXPR accessors.  Add case
	tcc_vl_exp.  Use TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.

	* tree-ssa-reassoc.c (get_rank): Use TREE_OPERAND_LENGTH instead
	of TREE_CODE_LENGTH.

	* stmt.c (warn_if_unused_value): Use TREE_OPERAND_LENGTH instead
	of TREE_CODE_LENGTH.

	* convert.c (convert_to_real): Use new CALL_EXPR accessors and
	constructor.
	(convert_to_integer): Likewise.

	* tree-ssa-operands.c (get_call_expr_operands): Use new CALL_EXPR
	accessors.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* config/alpha/alpha.c (alpha_expand_builtin): Use new CALL_EXPR
	accessors.
	* config/frv/frv.c (frv_expand_builtin): Likewise.
	* config/s390/s390.c (s390_expand_builtin): Likewise.

	* config/sparc/sparc.c (sparc_gimplify_va_arg): Use build_call_expr.
	(sparc_expand_builtin): Use new CALL_EXPR accessors.

	* config/i386/i386.c (ix86_function_ok_for_sibcall): Likewise.
	(ix86_expand_binop_builtin): Pass entire CALL_EXPR as parameter
	instead of arglist.  Use new CALL_EXPR accessors on it.  Fix callers.
	(ix86_expand_store_builtin): Likewise.
	(ix86_expand_unop_builtin): Likewise.
	(ix86_expand_unop1_builtin): Likewise.
	(ix86_expand_sse_compare): Likewise.
	(ix86_expand_sse_comi): Likewise.
	(ix86_expand_vec_init_builtin): Likewise.
	(ix86_expand_vec_ext_builtin): Likewise.
	(ix86_expand_vec_set_builtin): Likewise.
	(ix86_expand_builtin): Use new CALL_EXPR accessors.

	* config/sh/sh.c (sh_expand_builtin): Use new CALL_EXPR accessors.
	* config/c4x/c4x.c (c4x_expand_builtin): Likewise.

	* config/iq2000/iq2000.c (expand_one_builtin): Pass entire CALL_EXPR
	instead of arglist.  Use new CALL_EXPR accessors.  Fix callers.
	(iq2000_expand_builtin): Use new CALL_EXPR accessors.

	* config/rs6000/rs6000-c.c (altivec_build_resolved_builtin): Use
	build_call_expr.
	* config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Likewise.
	(rs6000_expand_unop_builtin): Pass entire CALL_EXPR instead of
	arglist.  Use new CALL_EXPR accessors.  Fix callers.
	(altivec_expand_abs_builtin): Likewise.
	(rs6000_expand_binop_builtin): Likewise.
	(altivec_expand_predicate_builtin): Likewise.
	(altivec_expand_lv_builtin): Likewise.
	(spe_expand_stv_builtin): Likewise.
	(altivec_expand_stv_builtin): Likewise.
	(rs6000_expand_ternop_builtin): Likewise.
	(altivec_expand_ld_builtin): Use new CALL_EXPR accessors.
	(altivec_expand_st_builtin): Likewise.
	(altivec_expand_dst_builtin): Likewise.
	(altivec_expand_vec_init_builtin): Pass entire CALL_EXPR instead of
	arglist.  Use new CALL_EXPR accessors.  Fix callers.
	(altivec_expand_vec_set_builtin): Likewise.
	(altivec_expand_vec_ext_builtin): Likewise.
	(altivec_expand_builtin): Use new CALL_EXPR accessors.
	(spe_expand_builtin): Likewise.
	(spe_expand_predicate_builtin): Pass entire CALL_EXPR instead of
	arglist.  Use new CALL_EXPR accessors.  Fix callers.
	(spe_expand_evsel_builtin): Likewise.
	(rs6000_expand_builtin): Use new CALL_EXPR accessors.  VCFUX and
	FCFSX cases must construct whole new CALL_EXPR, not just arglist.

	* config/arm/arm.c (arm_expand_binop_builtin): Pass entire CALL_EXPR
	instead of arglist.  Use new CALL_EXPR accessors.  Fix callers.
	(arm_expand_unop_builtin): Likewise.
	(arm_expand_builtin): Use new CALL_EXPR accessors.

	* config/mips/mips.c (mips_expand_builtin):  Use new CALL_EXPR
	accessors.

	* config/bfin/bfin.c (bfin_expand_binop_builtin): Pass entire CALL_EXPR
	instead of arglist.  Use new CALL_EXPR accessors.  Fix callers.
	(bfin_expand_unop_builtin): Likewise.
	(bfin_expand_builtin): Use new CALL_EXPR accessors.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* c-semantics.c (build_stmt): Add internal diagnostic check.

	* c-pretty-print.c (pp_c_postfix_expression): Use new CALL_EXPR
	accessors.  Print arguments explicitly instead of as a list.

	* c-typeck.c (build_function_call): Use new CALL_EXPR constructors.

	* c-omp.c (c_finish_omp_barrier): Use build_call_expr.
	(c_finish_omp_flish): Likewise.

	* c-common.c (verify_tree): Use new CALL_EXPR accessors.  Traverse
	arguments explicitly instead of as a list.  Use TREE_OPERAND_LENGTH
	instead of TREE_CODE_LENGTH.
	(check_function_arguments_recurse): Use new CALL_EXPR accessors.
	(c_warn_unused_result): Likewise.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* cp-tree.def (AGGR_INIT_EXPR): Adjust documentation.
	Change class to tcc_vl_exp.

	* call.c (build_call): Use build_call_list instead 
	of build3. 
	(build_over_call): Likewise.
	(build_new_method_call): Use build_min_non_dep_call_list 
	instead of build_min_non_dep.

	* error.c (dump_call_expr_args): New function.
	(dump_aggr_init_expr_args): New function.
	(dump_expr) <AGGR_INIT_EXPR, CALL_EXPR, INDIRECT_REF>: Use them. 
	Update to use new CALL_EXPR and AGGR_INIT_EXPR accessor macros.

	* cvt.c (convert_to_void): Use build_call_array instead
	of build3; use new AGGR_INIT_EXPR accessor macros.

	* mangle.c (write_expression): Use TREE_OPERAND_LENGTH
	instead of TREE_CODE_LENGTH.

	* dump.c (cp_dump_tree) <AGGR_INIT_EXPR>: Update to use new
	AGGR_INIT_EXPR accessor macros.

	* cp-gimplify.c (cp_gimplify_init_expr): Use 
	AGGR_INIT_EXPR_SLOT to set the slot operand.

	* cp-tree.h (AGGR_INIT_EXPR_FN): New macro.
	(AGGR_INIT_EXPR_SLOT): New macro.
	(AGGR_INIT_EXPR_ARG): New macro.
	(aggr_init_expr_nargs): New macro.
	(AGGR_INIT_EXPR_ARGP): New macro.
	(aggr_init_expr_arg_iterator): New.
	(init_aggr_init_expr_arg_iterator): New.
	(next_aggr_init_expr_arg): New.
	(first_aggr_init_expr_arg): New.
	(more_aggr_init_expr_args_p): New.
	(FOR_EACH_AGGR_INIT_EXPR_ARG): New.
	(stabilize_aggr_init): New declaration.
	(build_min_non_dep_call_list): Likewise.

	* tree.c (process_aggr_init_operands): New function.
	(build_aggr_init_array) New function.
	(build_cplus_new): Update to use new CALL_EXPR and
	AGGR_INIT_EXPR accessor macros. Replace use of build3 with
	build_aggr_init_array.
	(build_min_non_dep_call_list) New function.
	(build_min_nt): Assert input code parameter is not a variable
	length expression class.
	(build_min, build_min_non_dep): Likewise.
	(cp_tree_equal) <CALL_EXPR>: Iterate through the arguments
	to check for equality instead of recursing. Handle tcc_vl_exp
	tree code classes.
	(stabilize_call): Update to only handle CALL_EXPRs, not 
	AGGR_INIT_EXPRs; use new CALL_EXPR accessor macros.
	(stabilize_aggr_init): New function.
	(stabilize_init): Use it.

	* cxx-pretty-print.c (pp_cxx_postfix_expression)
	<AGGR_INIT_EXPR, CALL_EXPR>: Update to use new CALL_EXPR and
	AGGR_INIT_EXPR accessor macros and argument iterators.
	
	* pt.c (tsubst_copy) <CALL_EXPR>: Replace build_nt with
	build_vl_exp. Iterate through the operands, recursively 
	processing each one.
	(tsubst_copy_and_build) <CALL_EXPR>: Update to use new
	CALL_EXPR accessor macros.
	(value_dependent_expression_p) <default>: Handle tcc_vl_exp
	tree code classes. Use TREE_OPERAND_LENGTH instead of 
	TREE_CODE_LENGTH.

	* semantics.c (finish_call_expr): Use build_nt_call_list
	instead of build_nt.
	(simplify_aggr_init_expr): Update to use new AGGR_INIT_EXPR 
	accessor macros. Use build_call_array to construct the 
	CALL_EXPR node instead of build3
	
	* decl2.c (build_offset_ref_call_from_tree): Use 
	build_nt_call_list and build_min_non_dep_call_list instead
	of build_min_nt and build_min_non_dep.

	* parser.c (cp_parser_postfix_expression) <CPP_OPEN_PAREN>:
	Use build_nt_call_list instead of build_min_nt.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* java-tree.h (BUILD_MONITOR_ENTER): Use build_call_nary instead
	of build3.
	(BUILD_MONITOR_EXIT): Likewise.

	* java-gimplify.c (java_gimplify_component_ref): Use build_call_expr.
	(java_gimplify_modify_expr): Likewise.

	* class.c (cache_this_class_ref): Use build_call_expr.
	(build_static_field_ref): Likewise.
	(emit_indirect_register_classes): Likewise.
	(emit_register_classes): Likewise.

	* resource.c (write_resource_constructor): Use build_call_expr.

	* builtins.c (builtin_creator_function): Change interpretation of
	the second parameter to be the whole CALL_EXPR instead of the arglist.
	(max_builtin): Tweak parameter list.  Use new CALL_EXPR accessors.
	(min_builtin): Likewise.
	(abs_builtin): Likewise.
	(java_build_function_call_expr): Likewise.
	(convert_real): Likewise.
	(UNMARSHAL3): Likewise.
	(UNMARSHAL4): Likewise.
	(UNMARSHAL5): Likewise.
	(build_arglist_for_builtin): Delete.  Fix callers to use
	build_call_expr instead.
	(putObject_builtin): Tweak parameter list.  Use new CALL_EXPR
	accessors.
	(compareAndSwapInt_builtin): Likewise.
	(compareAndSwapLong_builtin): Likewise.
	(compareAndSwapObject_builtin): Likewise.
	(putVolatile_builtin): Likewise.
	(getVolatile_builtin): Likewise.
	(VMSupportsCS8_builtin): Likewise.
	(check_for_builtin): Pass entire CALL_EXPR to builtin expander
	instead of arglist.

	* expr.c (build_java_athrow): Use build_call_nary instead of build3.
	(build_java_throw_out_of_bounds_exception): Likewise.
	(java_check_reference): Likewise.
	(build_java_arraystore_check): Likewise.
	(build_newarray): Likewise.
	(build_anewarray): Likewise.
	(expand_java_multinewarray): Use build_call_list instead of build3.
	(build_java_monitor): Use build_call_nary instead of build3.
	(java_create_object): Likewise.
	(expand_java_NEW): Likewise.
	(build_instanceof): Likewise.
	(expand_java_CHECKCAST): Likewise.
	(build_java_soft_divmod): Likewise.
	(build_java_binop): Likewise.
	(build_field_ref): Likewise.
	(build_class_init): Likewise.
	(rewrite_arglist_getcaller): Use build_call_expr.
	(build_invokeinterface):  Use build_call_nary instead of build3.
	(expand_invoke): Use build_call_list instead of build3.
	(build_jni_stub): Use build_call_nary, build_call_list, or
	build_call_expr instead	of build3.
	(expand_java_field_op): Use build_call_expr instead of build3.
	(force_evaluation_order): Use new CALL_EXPR accessors.

	* lang.c (java_get_callee_fndecl): Use new CALL_EXPR accessors.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* objc-act.c (receiver_is_class_object): Use new CALL_EXPR accessors.
	(objc_get_callee_fndecl): Likewise.

2007-02-15  Sandra Loosemore  <sandra@codesourcery.com>
	    Brooks Moses  <brooks.moses@codesourcery.com>
	    Lee Millward  <lee.millward@codesourcery.com>

	* trans-expr.c (gfc_conv_power_op): Use build_call_expr.
	(gfc_conv_string_tmp): Likewise.
	(gfc_conv_concat_op): Likewise.
	(gfc_build_compare_string): Likewise.
	(gfc_conv_function_call): Use build_call_list instead of build3.

	* trans-array.c (gfc_trans_allocate_array_storage): Use
	build_call_expr.
	(gfc_grow_array): Likewise.
	(gfc_trans_array_ctor_element): Likewise.
	(gfc_trans_array_constructor_value): Likewise.
	(gfc_array_allocate): Likewise.
	(gfc_array_deallocate): Likewise.
	(gfc_trans_auto_array_allocation): Likewise.
	(gfc_trans_dummy_array_bias): Likewise.
	(gfc_conv_array_parameter): Likewise.
	(gfc_trans_dealloc_allocated): Likewise.
	(gfc_duplicate_allocatable): Likewise.

	* trans-openmp.c (gfc_trans_omp_barrier): Use build_call_expr.
	(gfc_trans_omp_flush): Likewise.

	* trans-stmt.c (gfc_conv_elementel_dependencies): Use build_call_expr.
	(gfc_trans_pause): Likewise.
	(gfc_trans_stop): Likewise.
	(gfc_trans_character_select): Likewise.
	(gfc_do_allocate): Likewise.
	(gfc_trans_assign_need_temp): Likewise.
	(gfc_trans_pointer_assign_need_temp): Likewise.
	(gfc_trans_forall_1): Likewise.
	(gfc_trans_where_2): Likewise.
	(gfc_trans_allocate): Likewise.
	(gfc_trans_deallocate): Likewise.

	* trans.c (gfc_trans_runtime_check): Use build_call_expr.

	* trans-io.c (gfc_trans_open): Use build_call_expr.
	(gfc_trans_close): Likewise.
	(build_filepos): Likewise.
	(gfc_trans_inquire): Likewise.
	(NML_FIRST_ARG): Delete.
	(NML_ADD_ARG): Delete.
	(transfer_namelist_element): Use build_call_expr.
	(build_dt): Likewise.
	(gfc_trans_dt_end): Likewise.
	(transfer_expr): Likewise.
	(transfer_array-desc): Likewise.

	* trans-decl.c (gfc_generate_function_code): Use build_call_expr.
	(gfc_generate_constructors): Likewise.

	* trans-intrinsic.c (gfc_conv_intrinsic_ctime): Use build_call_expr.
	(gfc_conv_intrinsic_fdate): Likewise.
	(gfc_conv_intrinsic_ttynam): Likewise.
	(gfc_conv_intrinsic_array_transfer): Likewise.
	(gfc_conv_associated): Likewise.
	(gfc_conv_intrinsic_si_kind): Likewise.
	(gfc_conv_intrinsic_trim): Likewise.
	(gfc_conv_intrinsic_repeat: Likewise.
	(gfc_conv_intrinsic_iargc): Likewise.

Co-Authored-By: Brooks Moses <brooks.moses@codesourcery.com>
Co-Authored-By: Lee Millward <lee.millward@codesourcery.com>

From-SVN: r122018
2007-02-15 18:50:49 -05:00

1389 lines
37 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Chains of recurrences.
Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Sebastian Pop <pop@cri.ensmp.fr>
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 2, 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 COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* This file implements operations on chains of recurrences. Chains
of recurrences are used for modeling evolution functions of scalar
variables.
*/
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "ggc.h"
#include "tree.h"
#include "real.h"
#include "diagnostic.h"
#include "cfgloop.h"
#include "tree-flow.h"
#include "tree-chrec.h"
#include "tree-pass.h"
#include "params.h"
#include "tree-scalar-evolution.h"
/* Extended folder for chrecs. */
/* Determines whether CST is not a constant evolution. */
static inline bool
is_not_constant_evolution (tree cst)
{
return (TREE_CODE (cst) == POLYNOMIAL_CHREC);
}
/* Fold CODE for a polynomial function and a constant. */
static inline tree
chrec_fold_poly_cst (enum tree_code code,
tree type,
tree poly,
tree cst)
{
gcc_assert (poly);
gcc_assert (cst);
gcc_assert (TREE_CODE (poly) == POLYNOMIAL_CHREC);
gcc_assert (!is_not_constant_evolution (cst));
gcc_assert (type == chrec_type (poly));
switch (code)
{
case PLUS_EXPR:
return build_polynomial_chrec
(CHREC_VARIABLE (poly),
chrec_fold_plus (type, CHREC_LEFT (poly), cst),
CHREC_RIGHT (poly));
case MINUS_EXPR:
return build_polynomial_chrec
(CHREC_VARIABLE (poly),
chrec_fold_minus (type, CHREC_LEFT (poly), cst),
CHREC_RIGHT (poly));
case MULT_EXPR:
return build_polynomial_chrec
(CHREC_VARIABLE (poly),
chrec_fold_multiply (type, CHREC_LEFT (poly), cst),
chrec_fold_multiply (type, CHREC_RIGHT (poly), cst));
default:
return chrec_dont_know;
}
}
/* Fold the addition of two polynomial functions. */
static inline tree
chrec_fold_plus_poly_poly (enum tree_code code,
tree type,
tree poly0,
tree poly1)
{
tree left, right;
struct loop *loop0 = get_chrec_loop (poly0);
struct loop *loop1 = get_chrec_loop (poly1);
gcc_assert (poly0);
gcc_assert (poly1);
gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC);
gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC);
gcc_assert (chrec_type (poly0) == chrec_type (poly1));
gcc_assert (type == chrec_type (poly0));
/*
{a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2,
{a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2,
{a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */
if (flow_loop_nested_p (loop0, loop1))
{
if (code == PLUS_EXPR)
return build_polynomial_chrec
(CHREC_VARIABLE (poly1),
chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)),
CHREC_RIGHT (poly1));
else
return build_polynomial_chrec
(CHREC_VARIABLE (poly1),
chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)),
chrec_fold_multiply (type, CHREC_RIGHT (poly1),
SCALAR_FLOAT_TYPE_P (type)
? build_real (type, dconstm1)
: build_int_cst_type (type, -1)));
}
if (flow_loop_nested_p (loop1, loop0))
{
if (code == PLUS_EXPR)
return build_polynomial_chrec
(CHREC_VARIABLE (poly0),
chrec_fold_plus (type, CHREC_LEFT (poly0), poly1),
CHREC_RIGHT (poly0));
else
return build_polynomial_chrec
(CHREC_VARIABLE (poly0),
chrec_fold_minus (type, CHREC_LEFT (poly0), poly1),
CHREC_RIGHT (poly0));
}
/* This function should never be called for chrecs of loops that
do not belong to the same loop nest. */
gcc_assert (loop0 == loop1);
if (code == PLUS_EXPR)
{
left = chrec_fold_plus
(type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
right = chrec_fold_plus
(type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
}
else
{
left = chrec_fold_minus
(type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
right = chrec_fold_minus
(type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
}
if (chrec_zerop (right))
return left;
else
return build_polynomial_chrec
(CHREC_VARIABLE (poly0), left, right);
}
/* Fold the multiplication of two polynomial functions. */
static inline tree
chrec_fold_multiply_poly_poly (tree type,
tree poly0,
tree poly1)
{
tree t0, t1, t2;
int var;
struct loop *loop0 = get_chrec_loop (poly0);
struct loop *loop1 = get_chrec_loop (poly1);
gcc_assert (poly0);
gcc_assert (poly1);
gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC);
gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC);
gcc_assert (chrec_type (poly0) == chrec_type (poly1));
gcc_assert (type == chrec_type (poly0));
/* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2,
{a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2,
{a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */
if (flow_loop_nested_p (loop0, loop1))
/* poly0 is a constant wrt. poly1. */
return build_polynomial_chrec
(CHREC_VARIABLE (poly1),
chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0),
CHREC_RIGHT (poly1));
if (flow_loop_nested_p (loop1, loop0))
/* poly1 is a constant wrt. poly0. */
return build_polynomial_chrec
(CHREC_VARIABLE (poly0),
chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1),
CHREC_RIGHT (poly0));
gcc_assert (loop0 == loop1);
/* poly0 and poly1 are two polynomials in the same variable,
{a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */
/* "a*c". */
t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
/* "a*d + b*c + b*d". */
t1 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1));
t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type,
CHREC_RIGHT (poly0),
CHREC_LEFT (poly1)));
t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type,
CHREC_RIGHT (poly0),
CHREC_RIGHT (poly1)));
/* "2*b*d". */
t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type)
? build_real (type, dconst2)
: build_int_cst (type, 2), t2);
var = CHREC_VARIABLE (poly0);
return build_polynomial_chrec (var, t0,
build_polynomial_chrec (var, t1, t2));
}
/* When the operands are automatically_generated_chrec_p, the fold has
to respect the semantics of the operands. */
static inline tree
chrec_fold_automatically_generated_operands (tree op0,
tree op1)
{
if (op0 == chrec_dont_know
|| op1 == chrec_dont_know)
return chrec_dont_know;
if (op0 == chrec_known
|| op1 == chrec_known)
return chrec_known;
if (op0 == chrec_not_analyzed_yet
|| op1 == chrec_not_analyzed_yet)
return chrec_not_analyzed_yet;
/* The default case produces a safe result. */
return chrec_dont_know;
}
/* Fold the addition of two chrecs. */
static tree
chrec_fold_plus_1 (enum tree_code code, tree type,
tree op0, tree op1)
{
if (automatically_generated_chrec_p (op0)
|| automatically_generated_chrec_p (op1))
return chrec_fold_automatically_generated_operands (op0, op1);
switch (TREE_CODE (op0))
{
case POLYNOMIAL_CHREC:
switch (TREE_CODE (op1))
{
case POLYNOMIAL_CHREC:
return chrec_fold_plus_poly_poly (code, type, op0, op1);
default:
if (code == PLUS_EXPR)
return build_polynomial_chrec
(CHREC_VARIABLE (op0),
chrec_fold_plus (type, CHREC_LEFT (op0), op1),
CHREC_RIGHT (op0));
else
return build_polynomial_chrec
(CHREC_VARIABLE (op0),
chrec_fold_minus (type, CHREC_LEFT (op0), op1),
CHREC_RIGHT (op0));
}
default:
switch (TREE_CODE (op1))
{
case POLYNOMIAL_CHREC:
if (code == PLUS_EXPR)
return build_polynomial_chrec
(CHREC_VARIABLE (op1),
chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
CHREC_RIGHT (op1));
else
return build_polynomial_chrec
(CHREC_VARIABLE (op1),
chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
chrec_fold_multiply (type, CHREC_RIGHT (op1),
SCALAR_FLOAT_TYPE_P (type)
? build_real (type, dconstm1)
: build_int_cst_type (type, -1)));
default:
{
int size = 0;
if ((tree_contains_chrecs (op0, &size)
|| tree_contains_chrecs (op1, &size))
&& size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
return build2 (code, type, op0, op1);
else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
return fold_build2 (code, type,
fold_convert (type, op0),
fold_convert (type, op1));
else
return chrec_dont_know;
}
}
}
}
/* Fold the addition of two chrecs. */
tree
chrec_fold_plus (tree type,
tree op0,
tree op1)
{
if (automatically_generated_chrec_p (op0)
|| automatically_generated_chrec_p (op1))
return chrec_fold_automatically_generated_operands (op0, op1);
if (integer_zerop (op0))
return op1;
if (integer_zerop (op1))
return op0;
return chrec_fold_plus_1 (PLUS_EXPR, type, op0, op1);
}
/* Fold the subtraction of two chrecs. */
tree
chrec_fold_minus (tree type,
tree op0,
tree op1)
{
if (automatically_generated_chrec_p (op0)
|| automatically_generated_chrec_p (op1))
return chrec_fold_automatically_generated_operands (op0, op1);
if (integer_zerop (op1))
return op0;
return chrec_fold_plus_1 (MINUS_EXPR, type, op0, op1);
}
/* Fold the multiplication of two chrecs. */
tree
chrec_fold_multiply (tree type,
tree op0,
tree op1)
{
if (automatically_generated_chrec_p (op0)
|| automatically_generated_chrec_p (op1))
return chrec_fold_automatically_generated_operands (op0, op1);
switch (TREE_CODE (op0))
{
case POLYNOMIAL_CHREC:
switch (TREE_CODE (op1))
{
case POLYNOMIAL_CHREC:
return chrec_fold_multiply_poly_poly (type, op0, op1);
default:
if (integer_onep (op1))
return op0;
if (integer_zerop (op1))
return build_int_cst (type, 0);
return build_polynomial_chrec
(CHREC_VARIABLE (op0),
chrec_fold_multiply (type, CHREC_LEFT (op0), op1),
chrec_fold_multiply (type, CHREC_RIGHT (op0), op1));
}
default:
if (integer_onep (op0))
return op1;
if (integer_zerop (op0))
return build_int_cst (type, 0);
switch (TREE_CODE (op1))
{
case POLYNOMIAL_CHREC:
return build_polynomial_chrec
(CHREC_VARIABLE (op1),
chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
chrec_fold_multiply (type, CHREC_RIGHT (op1), op0));
default:
if (integer_onep (op1))
return op0;
if (integer_zerop (op1))
return build_int_cst (type, 0);
return fold_build2 (MULT_EXPR, type, op0, op1);
}
}
}
/* Operations. */
/* Evaluate the binomial coefficient. Return NULL_TREE if the intermediate
calculation overflows, otherwise return C(n,k) with type TYPE. */
static tree
tree_fold_binomial (tree type, tree n, unsigned int k)
{
unsigned HOST_WIDE_INT lidx, lnum, ldenom, lres, ldum;
HOST_WIDE_INT hidx, hnum, hdenom, hres, hdum;
unsigned int i;
tree res;
/* Handle the most frequent cases. */
if (k == 0)
return build_int_cst (type, 1);
if (k == 1)
return fold_convert (type, n);
/* Check that k <= n. */
if (TREE_INT_CST_HIGH (n) == 0
&& TREE_INT_CST_LOW (n) < k)
return NULL_TREE;
/* Numerator = n. */
lnum = TREE_INT_CST_LOW (n);
hnum = TREE_INT_CST_HIGH (n);
/* Denominator = 2. */
ldenom = 2;
hdenom = 0;
/* Index = Numerator-1. */
if (lnum == 0)
{
hidx = hnum - 1;
lidx = ~ (unsigned HOST_WIDE_INT) 0;
}
else
{
hidx = hnum;
lidx = lnum - 1;
}
/* Numerator = Numerator*Index = n*(n-1). */
if (mul_double (lnum, hnum, lidx, hidx, &lnum, &hnum))
return NULL_TREE;
for (i = 3; i <= k; i++)
{
/* Index--. */
if (lidx == 0)
{
hidx--;
lidx = ~ (unsigned HOST_WIDE_INT) 0;
}
else
lidx--;
/* Numerator *= Index. */
if (mul_double (lnum, hnum, lidx, hidx, &lnum, &hnum))
return NULL_TREE;
/* Denominator *= i. */
mul_double (ldenom, hdenom, i, 0, &ldenom, &hdenom);
}
/* Result = Numerator / Denominator. */
div_and_round_double (EXACT_DIV_EXPR, 1, lnum, hnum, ldenom, hdenom,
&lres, &hres, &ldum, &hdum);
res = build_int_cst_wide (type, lres, hres);
return int_fits_type_p (res, type) ? res : NULL_TREE;
}
/* Helper function. Use the Newton's interpolating formula for
evaluating the value of the evolution function. */
static tree
chrec_evaluate (unsigned var, tree chrec, tree n, unsigned int k)
{
tree arg0, arg1, binomial_n_k;
tree type = TREE_TYPE (chrec);
struct loop *var_loop = get_loop (var);
while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
&& flow_loop_nested_p (var_loop, get_chrec_loop (chrec)))
chrec = CHREC_LEFT (chrec);
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
&& CHREC_VARIABLE (chrec) == var)
{
arg0 = chrec_evaluate (var, CHREC_RIGHT (chrec), n, k + 1);
if (arg0 == chrec_dont_know)
return chrec_dont_know;
binomial_n_k = tree_fold_binomial (type, n, k);
if (!binomial_n_k)
return chrec_dont_know;
arg1 = fold_build2 (MULT_EXPR, type,
CHREC_LEFT (chrec), binomial_n_k);
return chrec_fold_plus (type, arg0, arg1);
}
binomial_n_k = tree_fold_binomial (type, n, k);
if (!binomial_n_k)
return chrec_dont_know;
return fold_build2 (MULT_EXPR, type, chrec, binomial_n_k);
}
/* Evaluates "CHREC (X)" when the varying variable is VAR.
Example: Given the following parameters,
var = 1
chrec = {3, +, 4}_1
x = 10
The result is given by the Newton's interpolating formula:
3 * \binom{10}{0} + 4 * \binom{10}{1}.
*/
tree
chrec_apply (unsigned var,
tree chrec,
tree x)
{
tree type = chrec_type (chrec);
tree res = chrec_dont_know;
if (automatically_generated_chrec_p (chrec)
|| automatically_generated_chrec_p (x)
/* When the symbols are defined in an outer loop, it is possible
to symbolically compute the apply, since the symbols are
constants with respect to the varying loop. */
|| chrec_contains_symbols_defined_in_loop (chrec, var))
return chrec_dont_know;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "(chrec_apply \n");
if (TREE_CODE (x) == INTEGER_CST && SCALAR_FLOAT_TYPE_P (type))
x = build_real_from_int_cst (type, x);
if (evolution_function_is_affine_p (chrec))
{
/* "{a, +, b} (x)" -> "a + b*x". */
x = chrec_convert (type, x, NULL_TREE);
res = chrec_fold_multiply (type, CHREC_RIGHT (chrec), x);
if (!integer_zerop (CHREC_LEFT (chrec)))
res = chrec_fold_plus (type, CHREC_LEFT (chrec), res);
}
else if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
res = chrec;
else if (TREE_CODE (x) == INTEGER_CST
&& tree_int_cst_sgn (x) == 1)
/* testsuite/.../ssa-chrec-38.c. */
res = chrec_evaluate (var, chrec, x, 0);
else
res = chrec_dont_know;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " (varying_loop = %d\n", var);
fprintf (dump_file, ")\n (chrec = ");
print_generic_expr (dump_file, chrec, 0);
fprintf (dump_file, ")\n (x = ");
print_generic_expr (dump_file, x, 0);
fprintf (dump_file, ")\n (res = ");
print_generic_expr (dump_file, res, 0);
fprintf (dump_file, "))\n");
}
return res;
}
/* Replaces the initial condition in CHREC with INIT_COND. */
tree
chrec_replace_initial_condition (tree chrec,
tree init_cond)
{
if (automatically_generated_chrec_p (chrec))
return chrec;
gcc_assert (chrec_type (chrec) == chrec_type (init_cond));
switch (TREE_CODE (chrec))
{
case POLYNOMIAL_CHREC:
return build_polynomial_chrec
(CHREC_VARIABLE (chrec),
chrec_replace_initial_condition (CHREC_LEFT (chrec), init_cond),
CHREC_RIGHT (chrec));
default:
return init_cond;
}
}
/* Returns the initial condition of a given CHREC. */
tree
initial_condition (tree chrec)
{
if (automatically_generated_chrec_p (chrec))
return chrec;
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
return initial_condition (CHREC_LEFT (chrec));
else
return chrec;
}
/* Returns a univariate function that represents the evolution in
LOOP_NUM. Mask the evolution of any other loop. */
tree
hide_evolution_in_other_loops_than_loop (tree chrec,
unsigned loop_num)
{
struct loop *loop = get_loop (loop_num), *chloop;
if (automatically_generated_chrec_p (chrec))
return chrec;
switch (TREE_CODE (chrec))
{
case POLYNOMIAL_CHREC:
chloop = get_chrec_loop (chrec);
if (chloop == loop)
return build_polynomial_chrec
(loop_num,
hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec),
loop_num),
CHREC_RIGHT (chrec));
else if (flow_loop_nested_p (chloop, loop))
/* There is no evolution in this loop. */
return initial_condition (chrec);
else
{
gcc_assert (flow_loop_nested_p (loop, chloop));
return hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec),
loop_num);
}
default:
return chrec;
}
}
/* Returns the evolution part of CHREC in LOOP_NUM when RIGHT is
true, otherwise returns the initial condition in LOOP_NUM. */
static tree
chrec_component_in_loop_num (tree chrec,
unsigned loop_num,
bool right)
{
tree component;
struct loop *loop = get_loop (loop_num), *chloop;
if (automatically_generated_chrec_p (chrec))
return chrec;
switch (TREE_CODE (chrec))
{
case POLYNOMIAL_CHREC:
chloop = get_chrec_loop (chrec);
if (chloop == loop)
{
if (right)
component = CHREC_RIGHT (chrec);
else
component = CHREC_LEFT (chrec);
if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC
|| CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec))
return component;
else
return build_polynomial_chrec
(loop_num,
chrec_component_in_loop_num (CHREC_LEFT (chrec),
loop_num,
right),
component);
}
else if (flow_loop_nested_p (chloop, loop))
/* There is no evolution part in this loop. */
return NULL_TREE;
else
{
gcc_assert (flow_loop_nested_p (loop, chloop));
return chrec_component_in_loop_num (CHREC_LEFT (chrec),
loop_num,
right);
}
default:
if (right)
return NULL_TREE;
else
return chrec;
}
}
/* Returns the evolution part in LOOP_NUM. Example: the call
evolution_part_in_loop_num ({{0, +, 1}_1, +, 2}_1, 1) returns
{1, +, 2}_1 */
tree
evolution_part_in_loop_num (tree chrec,
unsigned loop_num)
{
return chrec_component_in_loop_num (chrec, loop_num, true);
}
/* Returns the initial condition in LOOP_NUM. Example: the call
initial_condition_in_loop_num ({{0, +, 1}_1, +, 2}_2, 2) returns
{0, +, 1}_1 */
tree
initial_condition_in_loop_num (tree chrec,
unsigned loop_num)
{
return chrec_component_in_loop_num (chrec, loop_num, false);
}
/* Set or reset the evolution of CHREC to NEW_EVOL in loop LOOP_NUM.
This function is essentially used for setting the evolution to
chrec_dont_know, for example after having determined that it is
impossible to say how many times a loop will execute. */
tree
reset_evolution_in_loop (unsigned loop_num,
tree chrec,
tree new_evol)
{
struct loop *loop = get_loop (loop_num);
gcc_assert (chrec_type (chrec) == chrec_type (new_evol));
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
&& flow_loop_nested_p (loop, get_chrec_loop (chrec)))
{
tree left = reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec),
new_evol);
tree right = reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec),
new_evol);
return build3 (POLYNOMIAL_CHREC, TREE_TYPE (left),
build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)),
left, right);
}
while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
&& CHREC_VARIABLE (chrec) == loop_num)
chrec = CHREC_LEFT (chrec);
return build_polynomial_chrec (loop_num, chrec, new_evol);
}
/* Merges two evolution functions that were found by following two
alternate paths of a conditional expression. */
tree
chrec_merge (tree chrec1,
tree chrec2)
{
if (chrec1 == chrec_dont_know
|| chrec2 == chrec_dont_know)
return chrec_dont_know;
if (chrec1 == chrec_known
|| chrec2 == chrec_known)
return chrec_known;
if (chrec1 == chrec_not_analyzed_yet)
return chrec2;
if (chrec2 == chrec_not_analyzed_yet)
return chrec1;
if (eq_evolutions_p (chrec1, chrec2))
return chrec1;
return chrec_dont_know;
}
/* Observers. */
/* Helper function for is_multivariate_chrec. */
static bool
is_multivariate_chrec_rec (tree chrec, unsigned int rec_var)
{
if (chrec == NULL_TREE)
return false;
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
{
if (CHREC_VARIABLE (chrec) != rec_var)
return true;
else
return (is_multivariate_chrec_rec (CHREC_LEFT (chrec), rec_var)
|| is_multivariate_chrec_rec (CHREC_RIGHT (chrec), rec_var));
}
else
return false;
}
/* Determine whether the given chrec is multivariate or not. */
bool
is_multivariate_chrec (tree chrec)
{
if (chrec == NULL_TREE)
return false;
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
return (is_multivariate_chrec_rec (CHREC_LEFT (chrec),
CHREC_VARIABLE (chrec))
|| is_multivariate_chrec_rec (CHREC_RIGHT (chrec),
CHREC_VARIABLE (chrec)));
else
return false;
}
/* Determines whether the chrec contains symbolic names or not. */
bool
chrec_contains_symbols (tree chrec)
{
int i, n;
if (chrec == NULL_TREE)
return false;
if (TREE_CODE (chrec) == SSA_NAME
|| TREE_CODE (chrec) == VAR_DECL
|| TREE_CODE (chrec) == PARM_DECL
|| TREE_CODE (chrec) == FUNCTION_DECL
|| TREE_CODE (chrec) == LABEL_DECL
|| TREE_CODE (chrec) == RESULT_DECL
|| TREE_CODE (chrec) == FIELD_DECL)
return true;
n = TREE_OPERAND_LENGTH (chrec);
for (i = 0; i < n; i++)
if (chrec_contains_symbols (TREE_OPERAND (chrec, i)))
return true;
return false;
}
/* Determines whether the chrec contains undetermined coefficients. */
bool
chrec_contains_undetermined (tree chrec)
{
int i, n;
if (chrec == chrec_dont_know
|| chrec == chrec_not_analyzed_yet
|| chrec == NULL_TREE)
return true;
n = TREE_OPERAND_LENGTH (chrec);
for (i = 0; i < n; i++)
if (chrec_contains_undetermined (TREE_OPERAND (chrec, i)))
return true;
return false;
}
/* Determines whether the tree EXPR contains chrecs, and increment
SIZE if it is not a NULL pointer by an estimation of the depth of
the tree. */
bool
tree_contains_chrecs (tree expr, int *size)
{
int i, n;
if (expr == NULL_TREE)
return false;
if (size)
(*size)++;
if (tree_is_chrec (expr))
return true;
n = TREE_OPERAND_LENGTH (expr);
for (i = 0; i < n; i++)
if (tree_contains_chrecs (TREE_OPERAND (expr, i), size))
return true;
return false;
}
/* Recursive helper function. */
static bool
evolution_function_is_invariant_rec_p (tree chrec, int loopnum)
{
if (evolution_function_is_constant_p (chrec))
return true;
if (TREE_CODE (chrec) == SSA_NAME
&& expr_invariant_in_loop_p (get_loop (loopnum), chrec))
return true;
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
{
if (CHREC_VARIABLE (chrec) == (unsigned) loopnum
|| !evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec),
loopnum)
|| !evolution_function_is_invariant_rec_p (CHREC_LEFT (chrec),
loopnum))
return false;
return true;
}
switch (TREE_OPERAND_LENGTH (chrec))
{
case 2:
if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 1),
loopnum))
return false;
case 1:
if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 0),
loopnum))
return false;
return true;
default:
return false;
}
return false;
}
/* Return true if CHREC is invariant in loop LOOPNUM, false otherwise. */
bool
evolution_function_is_invariant_p (tree chrec, int loopnum)
{
if (evolution_function_is_constant_p (chrec))
return true;
if (current_loops != NULL)
return evolution_function_is_invariant_rec_p (chrec, loopnum);
return false;
}
/* Determine whether the given tree is an affine multivariate
evolution. */
bool
evolution_function_is_affine_multivariate_p (tree chrec)
{
if (chrec == NULL_TREE)
return false;
switch (TREE_CODE (chrec))
{
case POLYNOMIAL_CHREC:
if (evolution_function_is_constant_p (CHREC_LEFT (chrec)))
{
if (evolution_function_is_constant_p (CHREC_RIGHT (chrec)))
return true;
else
{
if (TREE_CODE (CHREC_RIGHT (chrec)) == POLYNOMIAL_CHREC
&& CHREC_VARIABLE (CHREC_RIGHT (chrec))
!= CHREC_VARIABLE (chrec)
&& evolution_function_is_affine_multivariate_p
(CHREC_RIGHT (chrec)))
return true;
else
return false;
}
}
else
{
if (evolution_function_is_constant_p (CHREC_RIGHT (chrec))
&& TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC
&& CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec)
&& evolution_function_is_affine_multivariate_p
(CHREC_LEFT (chrec)))
return true;
else
return false;
}
default:
return false;
}
}
/* Determine whether the given tree is a function in zero or one
variables. */
bool
evolution_function_is_univariate_p (tree chrec)
{
if (chrec == NULL_TREE)
return true;
switch (TREE_CODE (chrec))
{
case POLYNOMIAL_CHREC:
switch (TREE_CODE (CHREC_LEFT (chrec)))
{
case POLYNOMIAL_CHREC:
if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_LEFT (chrec)))
return false;
if (!evolution_function_is_univariate_p (CHREC_LEFT (chrec)))
return false;
break;
default:
break;
}
switch (TREE_CODE (CHREC_RIGHT (chrec)))
{
case POLYNOMIAL_CHREC:
if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_RIGHT (chrec)))
return false;
if (!evolution_function_is_univariate_p (CHREC_RIGHT (chrec)))
return false;
break;
default:
break;
}
default:
return true;
}
}
/* Returns the number of variables of CHREC. Example: the call
nb_vars_in_chrec ({{0, +, 1}_5, +, 2}_6) returns 2. */
unsigned
nb_vars_in_chrec (tree chrec)
{
if (chrec == NULL_TREE)
return 0;
switch (TREE_CODE (chrec))
{
case POLYNOMIAL_CHREC:
return 1 + nb_vars_in_chrec
(initial_condition_in_loop_num (chrec, CHREC_VARIABLE (chrec)));
default:
return 0;
}
}
/* Returns true if TYPE is a type in that we cannot directly perform
arithmetics, even though it is a scalar type. */
static bool
avoid_arithmetics_in_type_p (tree type)
{
/* Ada frontend uses subtypes -- an arithmetic cannot be directly performed
in the subtype, but a base type must be used, and the result then can
be casted to the subtype. */
if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
return true;
return false;
}
static tree chrec_convert_1 (tree, tree, tree, bool);
/* Converts BASE and STEP of affine scev to TYPE. LOOP is the loop whose iv
the scev corresponds to. AT_STMT is the statement at that the scev is
evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume that
the rules for overflow of the given language apply (e.g., that signed
arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
tests, but also to enforce that the result follows them. Returns true if the
conversion succeeded, false otherwise. */
bool
convert_affine_scev (struct loop *loop, tree type,
tree *base, tree *step, tree at_stmt,
bool use_overflow_semantics)
{
tree ct = TREE_TYPE (*step);
bool enforce_overflow_semantics;
bool must_check_src_overflow, must_check_rslt_overflow;
tree new_base, new_step;
/* If we cannot perform arithmetic in TYPE, avoid creating an scev. */
if (avoid_arithmetics_in_type_p (type))
return false;
/* In general,
(TYPE) (BASE + STEP * i) = (TYPE) BASE + (TYPE -- sign extend) STEP * i,
but we must check some assumptions.
1) If [BASE, +, STEP] wraps, the equation is not valid when precision
of CT is smaller than the precision of TYPE. For example, when we
cast unsigned char [254, +, 1] to unsigned, the values on left side
are 254, 255, 0, 1, ..., but those on the right side are
254, 255, 256, 257, ...
2) In case that we must also preserve the fact that signed ivs do not
overflow, we must additionally check that the new iv does not wrap.
For example, unsigned char [125, +, 1] casted to signed char could
become a wrapping variable with values 125, 126, 127, -128, -127, ...,
which would confuse optimizers that assume that this does not
happen. */
must_check_src_overflow = TYPE_PRECISION (ct) < TYPE_PRECISION (type);
enforce_overflow_semantics = (use_overflow_semantics
&& nowrap_type_p (type));
if (enforce_overflow_semantics)
{
/* We can avoid checking whether the result overflows in the following
cases:
-- must_check_src_overflow is true, and the range of TYPE is superset
of the range of CT -- i.e., in all cases except if CT signed and
TYPE unsigned.
-- both CT and TYPE have the same precision and signedness, and we
verify instead that the source does not overflow (this may be
easier than verifying it for the result, as we may use the
information about the semantics of overflow in CT). */
if (must_check_src_overflow)
{
if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (ct))
must_check_rslt_overflow = true;
else
must_check_rslt_overflow = false;
}
else if (TYPE_UNSIGNED (ct) == TYPE_UNSIGNED (type)
&& TYPE_PRECISION (ct) == TYPE_PRECISION (type))
{
must_check_rslt_overflow = false;
must_check_src_overflow = true;
}
else
must_check_rslt_overflow = true;
}
else
must_check_rslt_overflow = false;
if (must_check_src_overflow
&& scev_probably_wraps_p (*base, *step, at_stmt, loop,
use_overflow_semantics))
return false;
new_base = chrec_convert_1 (type, *base, at_stmt,
use_overflow_semantics);
/* The step must be sign extended, regardless of the signedness
of CT and TYPE. This only needs to be handled specially when
CT is unsigned -- to avoid e.g. unsigned char [100, +, 255]
(with values 100, 99, 98, ...) from becoming signed or unsigned
[100, +, 255] with values 100, 355, ...; the sign-extension is
performed by default when CT is signed. */
new_step = *step;
if (TYPE_PRECISION (type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct))
new_step = chrec_convert_1 (signed_type_for (ct), new_step, at_stmt,
use_overflow_semantics);
new_step = chrec_convert_1 (type, new_step, at_stmt, use_overflow_semantics);
if (automatically_generated_chrec_p (new_base)
|| automatically_generated_chrec_p (new_step))
return false;
if (must_check_rslt_overflow
/* Note that in this case we cannot use the fact that signed variables
do not overflow, as this is what we are verifying for the new iv. */
&& scev_probably_wraps_p (new_base, new_step, at_stmt, loop, false))
return false;
*base = new_base;
*step = new_step;
return true;
}
/* Convert CHREC to TYPE. When the analyzer knows the context in
which the CHREC is built, it sets AT_STMT to the statement that
contains the definition of the analyzed variable, otherwise the
conversion is less accurate: the information is used for
determining a more accurate estimation of the number of iterations.
By default AT_STMT could be safely set to NULL_TREE.
The following rule is always true: TREE_TYPE (chrec) ==
TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE (CHREC_RIGHT (chrec)).
An example of what could happen when adding two chrecs and the type
of the CHREC_RIGHT is different than CHREC_LEFT is:
{(uint) 0, +, (uchar) 10} +
{(uint) 0, +, (uchar) 250}
that would produce a wrong result if CHREC_RIGHT is not (uint):
{(uint) 0, +, (uchar) 4}
instead of
{(uint) 0, +, (uint) 260}
*/
tree
chrec_convert (tree type, tree chrec, tree at_stmt)
{
return chrec_convert_1 (type, chrec, at_stmt, true);
}
/* Convert CHREC to TYPE. When the analyzer knows the context in
which the CHREC is built, it sets AT_STMT to the statement that
contains the definition of the analyzed variable, otherwise the
conversion is less accurate: the information is used for
determining a more accurate estimation of the number of iterations.
By default AT_STMT could be safely set to NULL_TREE.
USE_OVERFLOW_SEMANTICS is true if this function should assume that
the rules for overflow of the given language apply (e.g., that signed
arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
tests, but also to enforce that the result follows them. */
static tree
chrec_convert_1 (tree type, tree chrec, tree at_stmt,
bool use_overflow_semantics)
{
tree ct, res;
tree base, step;
struct loop *loop;
if (automatically_generated_chrec_p (chrec))
return chrec;
ct = chrec_type (chrec);
if (ct == type)
return chrec;
if (!evolution_function_is_affine_p (chrec))
goto keep_cast;
loop = get_chrec_loop (chrec);
base = CHREC_LEFT (chrec);
step = CHREC_RIGHT (chrec);
if (convert_affine_scev (loop, type, &base, &step, at_stmt,
use_overflow_semantics))
return build_polynomial_chrec (loop->num, base, step);
/* If we cannot propagate the cast inside the chrec, just keep the cast. */
keep_cast:
res = fold_convert (type, chrec);
/* Don't propagate overflows. */
if (CONSTANT_CLASS_P (res))
TREE_OVERFLOW (res) = 0;
/* But reject constants that don't fit in their type after conversion.
This can happen if TYPE_MIN_VALUE or TYPE_MAX_VALUE are not the
natural values associated with TYPE_PRECISION and TYPE_UNSIGNED,
and can cause problems later when computing niters of loops. Note
that we don't do the check before converting because we don't want
to reject conversions of negative chrecs to unsigned types. */
if (TREE_CODE (res) == INTEGER_CST
&& TREE_CODE (type) == INTEGER_TYPE
&& !int_fits_type_p (res, type))
res = chrec_dont_know;
return res;
}
/* Convert CHREC to TYPE, without regard to signed overflows. Returns the new
chrec if something else than what chrec_convert would do happens, NULL_TREE
otherwise. */
tree
chrec_convert_aggressive (tree type, tree chrec)
{
tree inner_type, left, right, lc, rc;
if (automatically_generated_chrec_p (chrec)
|| TREE_CODE (chrec) != POLYNOMIAL_CHREC)
return NULL_TREE;
inner_type = TREE_TYPE (chrec);
if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type))
return NULL_TREE;
/* If we cannot perform arithmetic in TYPE, avoid creating an scev. */
if (avoid_arithmetics_in_type_p (type))
return NULL_TREE;
left = CHREC_LEFT (chrec);
right = CHREC_RIGHT (chrec);
lc = chrec_convert_aggressive (type, left);
if (!lc)
lc = chrec_convert (type, left, NULL_TREE);
rc = chrec_convert_aggressive (type, right);
if (!rc)
rc = chrec_convert (type, right, NULL_TREE);
return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc);
}
/* Returns true when CHREC0 == CHREC1. */
bool
eq_evolutions_p (tree chrec0,
tree chrec1)
{
if (chrec0 == NULL_TREE
|| chrec1 == NULL_TREE
|| TREE_CODE (chrec0) != TREE_CODE (chrec1))
return false;
if (chrec0 == chrec1)
return true;
switch (TREE_CODE (chrec0))
{
case INTEGER_CST:
return operand_equal_p (chrec0, chrec1, 0);
case POLYNOMIAL_CHREC:
return (CHREC_VARIABLE (chrec0) == CHREC_VARIABLE (chrec1)
&& eq_evolutions_p (CHREC_LEFT (chrec0), CHREC_LEFT (chrec1))
&& eq_evolutions_p (CHREC_RIGHT (chrec0), CHREC_RIGHT (chrec1)));
default:
return false;
}
}
/* Returns EV_GROWS if CHREC grows (assuming that it does not overflow),
EV_DECREASES if it decreases, and EV_UNKNOWN if we cannot determine
which of these cases happens. */
enum ev_direction
scev_direction (tree chrec)
{
tree step;
if (!evolution_function_is_affine_p (chrec))
return EV_DIR_UNKNOWN;
step = CHREC_RIGHT (chrec);
if (TREE_CODE (step) != INTEGER_CST)
return EV_DIR_UNKNOWN;
if (tree_int_cst_sign_bit (step))
return EV_DIR_DECREASES;
else
return EV_DIR_GROWS;
}