From 31de92e39bbeffb9f1641d292e94b48f70809ae1 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 18 Sep 2019 18:07:06 +0000 Subject: tree-parloops.c (report_ploop_op): Copy from report_vect_op. 2019-09-18 Richard Biener * tree-parloops.c (report_ploop_op): Copy from report_vect_op. (parloops_valid_reduction_input_p): Copy from valid_reduction_input_p. (parloops_is_slp_reduction): Copy from vect_is_slp_reduction. (parloops_needs_fold_left_reduction_p): Copy from needs_fold_left_reduction_p. (parloops_is_simple_reduction): Copy from vect_is_simple_reduction. (parloops_force_simple_reduction): Copy from vect_force_simple_reduction. (gather_scalar_reductions): Adjust. * tree-vect-loop.c (vect_force_simple_reduction): Make static. * tree-vectorizer.h (vect_force_simple_reduction): Remove. From-SVN: r275896 --- gcc/ChangeLog | 16 ++ gcc/tree-parloops.c | 726 +++++++++++++++++++++++++++++++++++++++++++++++++- gcc/tree-vect-loop.c | 4 +- gcc/tree-vectorizer.h | 5 +- 4 files changed, 739 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c4b27bf..edf8028 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,21 @@ 2019-09-18 Richard Biener + * tree-parloops.c (report_ploop_op): Copy from report_vect_op. + (parloops_valid_reduction_input_p): Copy from + valid_reduction_input_p. + (parloops_is_slp_reduction): Copy from vect_is_slp_reduction. + (parloops_needs_fold_left_reduction_p): Copy from + needs_fold_left_reduction_p. + (parloops_is_simple_reduction): Copy from + vect_is_simple_reduction. + (parloops_force_simple_reduction): Copy from + vect_force_simple_reduction. + (gather_scalar_reductions): Adjust. + * tree-vect-loop.c (vect_force_simple_reduction): Make static. + * tree-vectorizer.h (vect_force_simple_reduction): Remove. + +2019-09-18 Richard Biener + * tree-vectorizer.h (get_initial_def_for_reduction): Remove. * tree-vect-loop.c (get_initial_def_for_reduction): Make static. diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index f5cb411..b6bb49b 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -88,7 +88,8 @@ along with GCC; see the file COPYING3. If not see More info can also be found at http://gcc.gnu.org/wiki/AutoParInGCC */ /* Reduction handling: - currently we use vect_force_simple_reduction() to detect reduction patterns. + currently we use code inspired by vect_force_simple_reduction to detect + reduction patterns. The code transformation will be introduced by an example. @@ -182,6 +183,717 @@ parloop */ +/* Error reporting helper for parloops_is_simple_reduction below. GIMPLE + statement STMT is printed with a message MSG. */ + +static void +report_ploop_op (dump_flags_t msg_type, gimple *stmt, const char *msg) +{ + dump_printf_loc (msg_type, vect_location, "%s%G", msg, stmt); +} + +/* DEF_STMT_INFO occurs in a loop that contains a potential reduction + operation. Return true if the results of DEF_STMT_INFO are something + that can be accumulated by such a reduction. */ + +static bool +parloops_valid_reduction_input_p (stmt_vec_info def_stmt_info) +{ + return (is_gimple_assign (def_stmt_info->stmt) + || is_gimple_call (def_stmt_info->stmt) + || STMT_VINFO_DEF_TYPE (def_stmt_info) == vect_induction_def + || (gimple_code (def_stmt_info->stmt) == GIMPLE_PHI + && STMT_VINFO_DEF_TYPE (def_stmt_info) == vect_internal_def + && !is_loop_header_bb_p (gimple_bb (def_stmt_info->stmt)))); +} + +/* Detect SLP reduction of the form: + + #a1 = phi + a2 = operation (a1) + a3 = operation (a2) + a4 = operation (a3) + a5 = operation (a4) + + #a = phi + + PHI is the reduction phi node (#a1 = phi above) + FIRST_STMT is the first reduction stmt in the chain + (a2 = operation (a1)). + + Return TRUE if a reduction chain was detected. */ + +static bool +parloops_is_slp_reduction (loop_vec_info loop_info, gimple *phi, + gimple *first_stmt) +{ + class loop *loop = (gimple_bb (phi))->loop_father; + class loop *vect_loop = LOOP_VINFO_LOOP (loop_info); + enum tree_code code; + gimple *loop_use_stmt = NULL; + stmt_vec_info use_stmt_info; + tree lhs; + imm_use_iterator imm_iter; + use_operand_p use_p; + int nloop_uses, size = 0, n_out_of_loop_uses; + bool found = false; + + if (loop != vect_loop) + return false; + + auto_vec reduc_chain; + lhs = PHI_RESULT (phi); + code = gimple_assign_rhs_code (first_stmt); + while (1) + { + nloop_uses = 0; + n_out_of_loop_uses = 0; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + + /* Check if we got back to the reduction phi. */ + if (use_stmt == phi) + { + loop_use_stmt = use_stmt; + found = true; + break; + } + + if (flow_bb_inside_loop_p (loop, gimple_bb (use_stmt))) + { + loop_use_stmt = use_stmt; + nloop_uses++; + } + else + n_out_of_loop_uses++; + + /* There are can be either a single use in the loop or two uses in + phi nodes. */ + if (nloop_uses > 1 || (n_out_of_loop_uses && nloop_uses)) + return false; + } + + if (found) + break; + + /* We reached a statement with no loop uses. */ + if (nloop_uses == 0) + return false; + + /* This is a loop exit phi, and we haven't reached the reduction phi. */ + if (gimple_code (loop_use_stmt) == GIMPLE_PHI) + return false; + + if (!is_gimple_assign (loop_use_stmt) + || code != gimple_assign_rhs_code (loop_use_stmt) + || !flow_bb_inside_loop_p (loop, gimple_bb (loop_use_stmt))) + return false; + + /* Insert USE_STMT into reduction chain. */ + use_stmt_info = loop_info->lookup_stmt (loop_use_stmt); + reduc_chain.safe_push (use_stmt_info); + + lhs = gimple_assign_lhs (loop_use_stmt); + size++; + } + + if (!found || loop_use_stmt != phi || size < 2) + return false; + + /* Swap the operands, if needed, to make the reduction operand be the second + operand. */ + lhs = PHI_RESULT (phi); + for (unsigned i = 0; i < reduc_chain.length (); ++i) + { + gassign *next_stmt = as_a (reduc_chain[i]->stmt); + if (gimple_assign_rhs2 (next_stmt) == lhs) + { + tree op = gimple_assign_rhs1 (next_stmt); + stmt_vec_info def_stmt_info = loop_info->lookup_def (op); + + /* Check that the other def is either defined in the loop + ("vect_internal_def"), or it's an induction (defined by a + loop-header phi-node). */ + if (def_stmt_info + && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt)) + && parloops_valid_reduction_input_p (def_stmt_info)) + { + lhs = gimple_assign_lhs (next_stmt); + continue; + } + + return false; + } + else + { + tree op = gimple_assign_rhs2 (next_stmt); + stmt_vec_info def_stmt_info = loop_info->lookup_def (op); + + /* Check that the other def is either defined in the loop + ("vect_internal_def"), or it's an induction (defined by a + loop-header phi-node). */ + if (def_stmt_info + && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt)) + && parloops_valid_reduction_input_p (def_stmt_info)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "swapping oprnds: %G", + next_stmt); + + swap_ssa_operands (next_stmt, + gimple_assign_rhs1_ptr (next_stmt), + gimple_assign_rhs2_ptr (next_stmt)); + update_stmt (next_stmt); + + if (CONSTANT_CLASS_P (gimple_assign_rhs1 (next_stmt))) + LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true; + } + else + return false; + } + + lhs = gimple_assign_lhs (next_stmt); + } + + /* Build up the actual chain. */ + for (unsigned i = 0; i < reduc_chain.length () - 1; ++i) + { + REDUC_GROUP_FIRST_ELEMENT (reduc_chain[i]) = reduc_chain[0]; + REDUC_GROUP_NEXT_ELEMENT (reduc_chain[i]) = reduc_chain[i+1]; + } + REDUC_GROUP_FIRST_ELEMENT (reduc_chain.last ()) = reduc_chain[0]; + REDUC_GROUP_NEXT_ELEMENT (reduc_chain.last ()) = NULL; + + /* Save the chain for further analysis in SLP detection. */ + LOOP_VINFO_REDUCTION_CHAINS (loop_info).safe_push (reduc_chain[0]); + REDUC_GROUP_SIZE (reduc_chain[0]) = size; + + return true; +} + +/* Return true if we need an in-order reduction for operation CODE + on type TYPE. NEED_WRAPPING_INTEGRAL_OVERFLOW is true if integer + overflow must wrap. */ + +static bool +parloops_needs_fold_left_reduction_p (tree type, tree_code code, + bool need_wrapping_integral_overflow) +{ + /* CHECKME: check for !flag_finite_math_only too? */ + if (SCALAR_FLOAT_TYPE_P (type)) + switch (code) + { + case MIN_EXPR: + case MAX_EXPR: + return false; + + default: + return !flag_associative_math; + } + + if (INTEGRAL_TYPE_P (type)) + { + if (!operation_no_trapping_overflow (type, code)) + return true; + if (need_wrapping_integral_overflow + && !TYPE_OVERFLOW_WRAPS (type) + && operation_can_overflow (code)) + return true; + return false; + } + + if (SAT_FIXED_POINT_TYPE_P (type)) + return true; + + return false; +} + + +/* Function parloops_is_simple_reduction + + (1) Detect a cross-iteration def-use cycle that represents a simple + reduction computation. We look for the following pattern: + + loop_header: + a1 = phi < a0, a2 > + a3 = ... + a2 = operation (a3, a1) + + or + + a3 = ... + loop_header: + a1 = phi < a0, a2 > + a2 = operation (a3, a1) + + such that: + 1. operation is commutative and associative and it is safe to + change the order of the computation + 2. no uses for a2 in the loop (a2 is used out of the loop) + 3. no uses of a1 in the loop besides the reduction operation + 4. no uses of a1 outside the loop. + + Conditions 1,4 are tested here. + Conditions 2,3 are tested in vect_mark_stmts_to_be_vectorized. + + (2) Detect a cross-iteration def-use cycle in nested loops, i.e., + nested cycles. + + (3) Detect cycles of phi nodes in outer-loop vectorization, i.e., double + reductions: + + a1 = phi < a0, a2 > + inner loop (def of a3) + a2 = phi < a3 > + + (4) Detect condition expressions, ie: + for (int i = 0; i < N; i++) + if (a[i] < val) + ret_val = a[i]; + +*/ + +static stmt_vec_info +parloops_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, + bool *double_reduc, + bool need_wrapping_integral_overflow, + enum vect_reduction_type *v_reduc_type) +{ + gphi *phi = as_a (phi_info->stmt); + class loop *loop = (gimple_bb (phi))->loop_father; + class loop *vect_loop = LOOP_VINFO_LOOP (loop_info); + bool nested_in_vect_loop = flow_loop_nested_p (vect_loop, loop); + gimple *phi_use_stmt = NULL; + enum tree_code orig_code, code; + tree op1, op2, op3 = NULL_TREE, op4 = NULL_TREE; + tree type; + tree name; + imm_use_iterator imm_iter; + use_operand_p use_p; + bool phi_def; + + *double_reduc = false; + *v_reduc_type = TREE_CODE_REDUCTION; + + tree phi_name = PHI_RESULT (phi); + /* ??? If there are no uses of the PHI result the inner loop reduction + won't be detected as possibly double-reduction by vectorizable_reduction + because that tries to walk the PHI arg from the preheader edge which + can be constant. See PR60382. */ + if (has_zero_uses (phi_name)) + return NULL; + unsigned nphi_def_loop_uses = 0; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, phi_name) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + + if (!flow_bb_inside_loop_p (loop, gimple_bb (use_stmt))) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "intermediate value used outside loop.\n"); + + return NULL; + } + + nphi_def_loop_uses++; + phi_use_stmt = use_stmt; + } + + edge latch_e = loop_latch_edge (loop); + tree loop_arg = PHI_ARG_DEF_FROM_EDGE (phi, latch_e); + if (TREE_CODE (loop_arg) != SSA_NAME) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "reduction: not ssa_name: %T\n", loop_arg); + return NULL; + } + + stmt_vec_info def_stmt_info = loop_info->lookup_def (loop_arg); + if (!def_stmt_info + || !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt))) + return NULL; + + if (gassign *def_stmt = dyn_cast (def_stmt_info->stmt)) + { + name = gimple_assign_lhs (def_stmt); + phi_def = false; + } + else if (gphi *def_stmt = dyn_cast (def_stmt_info->stmt)) + { + name = PHI_RESULT (def_stmt); + phi_def = true; + } + else + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "reduction: unhandled reduction operation: %G", + def_stmt_info->stmt); + return NULL; + } + + unsigned nlatch_def_loop_uses = 0; + auto_vec lcphis; + bool inner_loop_of_double_reduc = false; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, name) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + if (flow_bb_inside_loop_p (loop, gimple_bb (use_stmt))) + nlatch_def_loop_uses++; + else + { + /* We can have more than one loop-closed PHI. */ + lcphis.safe_push (as_a (use_stmt)); + if (nested_in_vect_loop + && (STMT_VINFO_DEF_TYPE (loop_info->lookup_stmt (use_stmt)) + == vect_double_reduction_def)) + inner_loop_of_double_reduc = true; + } + } + + /* If this isn't a nested cycle or if the nested cycle reduction value + is used ouside of the inner loop we cannot handle uses of the reduction + value. */ + if ((!nested_in_vect_loop || inner_loop_of_double_reduc) + && (nlatch_def_loop_uses > 1 || nphi_def_loop_uses > 1)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "reduction used in loop.\n"); + return NULL; + } + + /* If DEF_STMT is a phi node itself, we expect it to have a single argument + defined in the inner loop. */ + if (phi_def) + { + gphi *def_stmt = as_a (def_stmt_info->stmt); + op1 = PHI_ARG_DEF (def_stmt, 0); + + if (gimple_phi_num_args (def_stmt) != 1 + || TREE_CODE (op1) != SSA_NAME) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "unsupported phi node definition.\n"); + + return NULL; + } + + gimple *def1 = SSA_NAME_DEF_STMT (op1); + if (gimple_bb (def1) + && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)) + && loop->inner + && flow_bb_inside_loop_p (loop->inner, gimple_bb (def1)) + && is_gimple_assign (def1) + && is_a (phi_use_stmt) + && flow_bb_inside_loop_p (loop->inner, gimple_bb (phi_use_stmt))) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, + "detected double reduction: "); + + *double_reduc = true; + return def_stmt_info; + } + + return NULL; + } + + /* If we are vectorizing an inner reduction we are executing that + in the original order only in case we are not dealing with a + double reduction. */ + bool check_reduction = true; + if (flow_loop_nested_p (vect_loop, loop)) + { + gphi *lcphi; + unsigned i; + check_reduction = false; + FOR_EACH_VEC_ELT (lcphis, i, lcphi) + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_phi_result (lcphi)) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + if (! flow_bb_inside_loop_p (vect_loop, gimple_bb (use_stmt))) + check_reduction = true; + } + } + + gassign *def_stmt = as_a (def_stmt_info->stmt); + code = orig_code = gimple_assign_rhs_code (def_stmt); + + if (nested_in_vect_loop && !check_reduction) + { + /* FIXME: Even for non-reductions code generation is funneled + through vectorizable_reduction for the stmt defining the + PHI latch value. So we have to artificially restrict ourselves + for the supported operations. */ + switch (get_gimple_rhs_class (code)) + { + case GIMPLE_BINARY_RHS: + case GIMPLE_TERNARY_RHS: + break; + default: + /* Not supported by vectorizable_reduction. */ + if (dump_enabled_p ()) + report_ploop_op (MSG_MISSED_OPTIMIZATION, def_stmt, + "nested cycle: not handled operation: "); + return NULL; + } + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, "detected nested cycle: "); + return def_stmt_info; + } + + /* We can handle "res -= x[i]", which is non-associative by + simply rewriting this into "res += -x[i]". Avoid changing + gimple instruction for the first simple tests and only do this + if we're allowed to change code at all. */ + if (code == MINUS_EXPR && gimple_assign_rhs2 (def_stmt) != phi_name) + code = PLUS_EXPR; + + if (code == COND_EXPR) + { + if (! nested_in_vect_loop) + *v_reduc_type = COND_REDUCTION; + + op3 = gimple_assign_rhs1 (def_stmt); + if (COMPARISON_CLASS_P (op3)) + { + op4 = TREE_OPERAND (op3, 1); + op3 = TREE_OPERAND (op3, 0); + } + if (op3 == phi_name || op4 == phi_name) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_MISSED_OPTIMIZATION, def_stmt, + "reduction: condition depends on previous" + " iteration: "); + return NULL; + } + + op1 = gimple_assign_rhs2 (def_stmt); + op2 = gimple_assign_rhs3 (def_stmt); + } + else if (!commutative_tree_code (code) || !associative_tree_code (code)) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_MISSED_OPTIMIZATION, def_stmt, + "reduction: not commutative/associative: "); + return NULL; + } + else if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS) + { + op1 = gimple_assign_rhs1 (def_stmt); + op2 = gimple_assign_rhs2 (def_stmt); + } + else + { + if (dump_enabled_p ()) + report_ploop_op (MSG_MISSED_OPTIMIZATION, def_stmt, + "reduction: not handled operation: "); + return NULL; + } + + if (TREE_CODE (op1) != SSA_NAME && TREE_CODE (op2) != SSA_NAME) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_MISSED_OPTIMIZATION, def_stmt, + "reduction: both uses not ssa_names: "); + + return NULL; + } + + type = TREE_TYPE (gimple_assign_lhs (def_stmt)); + if ((TREE_CODE (op1) == SSA_NAME + && !types_compatible_p (type,TREE_TYPE (op1))) + || (TREE_CODE (op2) == SSA_NAME + && !types_compatible_p (type, TREE_TYPE (op2))) + || (op3 && TREE_CODE (op3) == SSA_NAME + && !types_compatible_p (type, TREE_TYPE (op3))) + || (op4 && TREE_CODE (op4) == SSA_NAME + && !types_compatible_p (type, TREE_TYPE (op4)))) + { + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_NOTE, vect_location, + "reduction: multiple types: operation type: " + "%T, operands types: %T,%T", + type, TREE_TYPE (op1), TREE_TYPE (op2)); + if (op3) + dump_printf (MSG_NOTE, ",%T", TREE_TYPE (op3)); + + if (op4) + dump_printf (MSG_NOTE, ",%T", TREE_TYPE (op4)); + dump_printf (MSG_NOTE, "\n"); + } + + return NULL; + } + + /* Check whether it's ok to change the order of the computation. + Generally, when vectorizing a reduction we change the order of the + computation. This may change the behavior of the program in some + cases, so we need to check that this is ok. One exception is when + vectorizing an outer-loop: the inner-loop is executed sequentially, + and therefore vectorizing reductions in the inner-loop during + outer-loop vectorization is safe. */ + if (check_reduction + && *v_reduc_type == TREE_CODE_REDUCTION + && parloops_needs_fold_left_reduction_p (type, code, + need_wrapping_integral_overflow)) + *v_reduc_type = FOLD_LEFT_REDUCTION; + + /* Reduction is safe. We're dealing with one of the following: + 1) integer arithmetic and no trapv + 2) floating point arithmetic, and special flags permit this optimization + 3) nested cycle (i.e., outer loop vectorization). */ + stmt_vec_info def1_info = loop_info->lookup_def (op1); + stmt_vec_info def2_info = loop_info->lookup_def (op2); + if (code != COND_EXPR && !def1_info && !def2_info) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, + "reduction: no defs for operands: "); + return NULL; + } + + /* Check that one def is the reduction def, defined by PHI, + the other def is either defined in the loop ("vect_internal_def"), + or it's an induction (defined by a loop-header phi-node). */ + + if (def2_info + && def2_info->stmt == phi + && (code == COND_EXPR + || !def1_info + || !flow_bb_inside_loop_p (loop, gimple_bb (def1_info->stmt)) + || parloops_valid_reduction_input_p (def1_info))) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, "detected reduction: "); + return def_stmt_info; + } + + if (def1_info + && def1_info->stmt == phi + && (code == COND_EXPR + || !def2_info + || !flow_bb_inside_loop_p (loop, gimple_bb (def2_info->stmt)) + || parloops_valid_reduction_input_p (def2_info))) + { + if (! nested_in_vect_loop && orig_code != MINUS_EXPR) + { + /* Check if we can swap operands (just for simplicity - so that + the rest of the code can assume that the reduction variable + is always the last (second) argument). */ + if (code == COND_EXPR) + { + /* Swap cond_expr by inverting the condition. */ + tree cond_expr = gimple_assign_rhs1 (def_stmt); + enum tree_code invert_code = ERROR_MARK; + enum tree_code cond_code = TREE_CODE (cond_expr); + + if (TREE_CODE_CLASS (cond_code) == tcc_comparison) + { + bool honor_nans = HONOR_NANS (TREE_OPERAND (cond_expr, 0)); + invert_code = invert_tree_comparison (cond_code, honor_nans); + } + if (invert_code != ERROR_MARK) + { + TREE_SET_CODE (cond_expr, invert_code); + swap_ssa_operands (def_stmt, + gimple_assign_rhs2_ptr (def_stmt), + gimple_assign_rhs3_ptr (def_stmt)); + } + else + { + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, + "detected reduction: cannot swap operands " + "for cond_expr"); + return NULL; + } + } + else + swap_ssa_operands (def_stmt, gimple_assign_rhs1_ptr (def_stmt), + gimple_assign_rhs2_ptr (def_stmt)); + + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, + "detected reduction: need to swap operands: "); + + if (CONSTANT_CLASS_P (gimple_assign_rhs1 (def_stmt))) + LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true; + } + else + { + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, "detected reduction: "); + } + + return def_stmt_info; + } + + /* Try to find SLP reduction chain. */ + if (! nested_in_vect_loop + && code != COND_EXPR + && orig_code != MINUS_EXPR + && parloops_is_slp_reduction (loop_info, phi, def_stmt)) + { + if (dump_enabled_p ()) + report_ploop_op (MSG_NOTE, def_stmt, + "reduction: detected reduction chain: "); + + return def_stmt_info; + } + + /* Look for the expression computing loop_arg from loop PHI result. */ + if (check_reduction_path (vect_location, loop, phi, loop_arg, code)) + return def_stmt_info; + + if (dump_enabled_p ()) + { + report_ploop_op (MSG_MISSED_OPTIMIZATION, def_stmt, + "reduction: unknown pattern: "); + } + + return NULL; +} + +/* Wrapper around vect_is_simple_reduction, which will modify code + in-place if it enables detection of more reductions. Arguments + as there. */ + +stmt_vec_info +parloops_force_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, + bool *double_reduc, + bool need_wrapping_integral_overflow) +{ + enum vect_reduction_type v_reduc_type; + stmt_vec_info def_info + = parloops_is_simple_reduction (loop_info, phi_info, double_reduc, + need_wrapping_integral_overflow, + &v_reduc_type); + if (def_info) + { + STMT_VINFO_REDUC_TYPE (phi_info) = v_reduc_type; + STMT_VINFO_REDUC_DEF (phi_info) = def_info; + STMT_VINFO_REDUC_TYPE (def_info) = v_reduc_type; + STMT_VINFO_REDUC_DEF (def_info) = phi_info; + } + return def_info; +} + /* Minimal number of iterations of a loop that should be executed in each thread. */ #define MIN_PER_THREAD PARAM_VALUE (PARAM_PARLOOPS_MIN_PER_THREAD) @@ -2615,9 +3327,9 @@ gather_scalar_reductions (loop_p loop, reduction_info_table_type *reduction_list continue; stmt_vec_info reduc_stmt_info - = vect_force_simple_reduction (simple_loop_info, - simple_loop_info->lookup_stmt (phi), - &double_reduc, true); + = parloops_force_simple_reduction (simple_loop_info, + simple_loop_info->lookup_stmt (phi), + &double_reduc, true); if (!reduc_stmt_info || !valid_reduction_p (reduc_stmt_info)) continue; @@ -2664,9 +3376,9 @@ gather_scalar_reductions (loop_p loop, reduction_info_table_type *reduction_list stmt_vec_info inner_phi_info = simple_loop_info->lookup_stmt (inner_phi); stmt_vec_info inner_reduc_stmt_info - = vect_force_simple_reduction (simple_loop_info, - inner_phi_info, - &double_reduc, true); + = parloops_force_simple_reduction (simple_loop_info, + inner_phi_info, + &double_reduc, true); gcc_assert (!double_reduc); if (!inner_reduc_stmt_info || !valid_reduction_p (inner_reduc_stmt_info)) diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index a455a6d..daf3370 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -154,6 +154,8 @@ along with GCC; see the file COPYING3. If not see */ static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *); +static stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info, + bool *, bool); /* Subroutine of vect_determine_vf_for_stmt that handles only one statement. VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE @@ -3361,7 +3363,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, in-place if it enables detection of more reductions. Arguments as there. */ -stmt_vec_info +static stmt_vec_info vect_force_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, bool *double_reduc, bool need_wrapping_integral_overflow) diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 40ff8b7..ee6fe9a 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1611,11 +1611,8 @@ extern tree vect_create_addr_base_for_vector_ref (stmt_vec_info, gimple_seq *, tree, tree = NULL_TREE); /* In tree-vect-loop.c. */ -/* FORNOW: Used in tree-parloops.c. */ -extern stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info, - bool *, bool); extern widest_int vect_iv_limit_for_full_masking (loop_vec_info loop_vinfo); -/* Used in gimple-loop-interchange.c. */ +/* Used in gimple-loop-interchange.c and tree-parloops.c. */ extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree, enum tree_code); /* Drive for loop analysis stage. */ -- cgit v1.1 From 6f1628c9df05591721192193f6364e316e45c6c1 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 18 Sep 2019 18:11:24 +0000 Subject: [ARM] Cleanup multiply patterns Cleanup the 32-bit multiply patterns. Merge the pre-Armv6 with the Armv6 patterns, remove useless alternatives and order the accumulator operands to prefer MLA Ra, Rb, Rc, Ra whenever feasible. gcc/ * config/arm/arm.md (arm_mulsi3): Remove pattern. (arm_mulsi3_v6): Likewise. (mulsi3addsi_v6): Likewise. (mulsi3subsi): Likewise. (mul): Add new multiply pattern. (mla): Likewise. (mls): Likewise. From-SVN: r275897 --- gcc/ChangeLog | 10 ++++++ gcc/config/arm/arm.md | 90 ++++++++++++++++++++------------------------------- 2 files changed, 45 insertions(+), 55 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index edf8028..2b55a3f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-09-18 Wilco Dijkstra + + * config/arm/arm.md (arm_mulsi3): Remove pattern. + (arm_mulsi3_v6): Likewise. + (mulsi3addsi_v6): Likewise. + (mulsi3subsi): Likewise. + (mul): Add new multiply pattern. + (mla): Likewise. + (mls): Likewise. + 2019-09-18 Richard Biener * tree-parloops.c (report_ploop_op): Copy from report_vect_op. diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 6513c2d..4ffc771 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1595,28 +1595,46 @@ "" ) -;; Use `&' and then `0' to prevent the operands 0 and 1 being the same -(define_insn "*arm_mulsi3" - [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") - (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") - (match_operand:SI 1 "s_register_operand" "%0,r")))] - "TARGET_32BIT && !arm_arch6" +;; Use `&' and then `0' to prevent operands 0 and 2 being the same +(define_insn "*mul" + [(set (match_operand:SI 0 "s_register_operand" "=l,r,&r,&r") + (mult:SI (match_operand:SI 2 "s_register_operand" "l,r,r,r") + (match_operand:SI 1 "s_register_operand" "%0,r,0,r")))] + "TARGET_32BIT" "mul%?\\t%0, %2, %1" [(set_attr "type" "mul") - (set_attr "predicable" "yes")] + (set_attr "predicable" "yes") + (set_attr "arch" "t2,v6,nov6,nov6") + (set_attr "length" "4") + (set_attr "predicable_short_it" "yes,no,*,*")] ) -(define_insn "*arm_mulsi3_v6" - [(set (match_operand:SI 0 "s_register_operand" "=l,l,r") - (mult:SI (match_operand:SI 1 "s_register_operand" "0,l,r") - (match_operand:SI 2 "s_register_operand" "l,0,r")))] - "TARGET_32BIT && arm_arch6" - "mul%?\\t%0, %1, %2" - [(set_attr "type" "mul") +;; MLA and MLS instruction. Use operand 1 for the accumulator to prefer +;; reusing the same register. + +(define_insn "*mla" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r,&r,&r") + (plus:SI + (mult:SI (match_operand:SI 3 "s_register_operand" "r,r,r,r") + (match_operand:SI 2 "s_register_operand" "%r,r,0,r")) + (match_operand:SI 1 "s_register_operand" "r,0,r,r")))] + "TARGET_32BIT" + "mla%?\\t%0, %3, %2, %1" + [(set_attr "type" "mla") (set_attr "predicable" "yes") - (set_attr "arch" "t2,t2,*") - (set_attr "length" "4") - (set_attr "predicable_short_it" "yes,yes,no")] + (set_attr "arch" "v6,nov6,nov6,nov6")] +) + +(define_insn "*mls" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (minus:SI + (match_operand:SI 1 "s_register_operand" "r") + (mult:SI (match_operand:SI 3 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r"))))] + "TARGET_32BIT && arm_arch_thumb2" + "mls%?\\t%0, %3, %2, %1" + [(set_attr "type" "mla") + (set_attr "predicable" "yes")] ) (define_insn "*mulsi3_compare0" @@ -1673,32 +1691,6 @@ (set_attr "type" "muls")] ) -;; Unnamed templates to match MLA instruction. - -(define_insn "*mulsi3addsi" - [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r") - (plus:SI - (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r") - (match_operand:SI 1 "s_register_operand" "%0,r,0,r")) - (match_operand:SI 3 "s_register_operand" "r,r,0,0")))] - "TARGET_32BIT && !arm_arch6" - "mla%?\\t%0, %2, %1, %3" - [(set_attr "type" "mla") - (set_attr "predicable" "yes")] -) - -(define_insn "*mulsi3addsi_v6" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (plus:SI - (mult:SI (match_operand:SI 2 "s_register_operand" "r") - (match_operand:SI 1 "s_register_operand" "r")) - (match_operand:SI 3 "s_register_operand" "r")))] - "TARGET_32BIT && arm_arch6" - "mla%?\\t%0, %2, %1, %3" - [(set_attr "type" "mla") - (set_attr "predicable" "yes")] -) - (define_insn "*mulsi3addsi_compare0" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV @@ -1763,18 +1755,6 @@ (set_attr "type" "mlas")] ) -(define_insn "*mulsi3subsi" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (minus:SI - (match_operand:SI 3 "s_register_operand" "r") - (mult:SI (match_operand:SI 2 "s_register_operand" "r") - (match_operand:SI 1 "s_register_operand" "r"))))] - "TARGET_32BIT && arm_arch_thumb2" - "mls%?\\t%0, %2, %1, %3" - [(set_attr "type" "mla") - (set_attr "predicable" "yes")] -) - (define_expand "maddsidi4" [(set (match_operand:DI 0 "s_register_operand") (plus:DI -- cgit v1.1 From 901083b9bdf69a7b1382f9682c6fd1d5759667dd Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 18 Sep 2019 18:12:38 +0000 Subject: tree-vect-loop.c (vect_is_simple_reduction): Remove operand swapping. 2019-09-18 Richard Biener * tree-vect-loop.c (vect_is_simple_reduction): Remove operand swapping. (vectorize_fold_left_reduction): Remove assert. (vectorizable_reduction): Also expect COND_EXPR non-reduction operand in position 2. Remove assert. From-SVN: r275898 --- gcc/ChangeLog | 8 +++++++ gcc/tree-vect-loop.c | 61 ++++------------------------------------------------ 2 files changed, 12 insertions(+), 57 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2b55a3f..13d5cb9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-18 Richard Biener + + * tree-vect-loop.c (vect_is_simple_reduction): Remove operand + swapping. + (vectorize_fold_left_reduction): Remove assert. + (vectorizable_reduction): Also expect COND_EXPR non-reduction + operand in position 2. Remove assert. + 2019-09-18 Wilco Dijkstra * config/arm/arm.md (arm_mulsi3): Remove pattern. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index daf3370..bcd9639 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -3280,56 +3280,8 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, || !flow_bb_inside_loop_p (loop, gimple_bb (def2_info->stmt)) || vect_valid_reduction_input_p (def2_info))) { - if (! nested_in_vect_loop && orig_code != MINUS_EXPR) - { - /* Check if we can swap operands (just for simplicity - so that - the rest of the code can assume that the reduction variable - is always the last (second) argument). */ - if (code == COND_EXPR) - { - /* Swap cond_expr by inverting the condition. */ - tree cond_expr = gimple_assign_rhs1 (def_stmt); - enum tree_code invert_code = ERROR_MARK; - enum tree_code cond_code = TREE_CODE (cond_expr); - - if (TREE_CODE_CLASS (cond_code) == tcc_comparison) - { - bool honor_nans = HONOR_NANS (TREE_OPERAND (cond_expr, 0)); - invert_code = invert_tree_comparison (cond_code, honor_nans); - } - if (invert_code != ERROR_MARK) - { - TREE_SET_CODE (cond_expr, invert_code); - swap_ssa_operands (def_stmt, - gimple_assign_rhs2_ptr (def_stmt), - gimple_assign_rhs3_ptr (def_stmt)); - } - else - { - if (dump_enabled_p ()) - report_vect_op (MSG_NOTE, def_stmt, - "detected reduction: cannot swap operands " - "for cond_expr"); - return NULL; - } - } - else - swap_ssa_operands (def_stmt, gimple_assign_rhs1_ptr (def_stmt), - gimple_assign_rhs2_ptr (def_stmt)); - - if (dump_enabled_p ()) - report_vect_op (MSG_NOTE, def_stmt, - "detected reduction: need to swap operands: "); - - if (CONSTANT_CLASS_P (gimple_assign_rhs1 (def_stmt))) - LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true; - } - else - { - if (dump_enabled_p ()) - report_vect_op (MSG_NOTE, def_stmt, "detected reduction: "); - } - + if (dump_enabled_p ()) + report_vect_op (MSG_NOTE, def_stmt, "detected reduction: "); return def_stmt_info; } @@ -5969,7 +5921,6 @@ vectorize_fold_left_reduction (stmt_vec_info stmt_info, gcc_assert (!nested_in_vect_loop_p (loop, stmt_info)); gcc_assert (ncopies == 1); gcc_assert (TREE_CODE_LENGTH (code) == binary_op); - gcc_assert (reduc_index == (code == MINUS_EXPR ? 0 : 1)); gcc_assert (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == FOLD_LEFT_REDUCTION); @@ -6542,9 +6493,9 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, reduc_index = i; } - if (i == 1 && code == COND_EXPR) + if (code == COND_EXPR) { - /* Record how value of COND_EXPR is defined. */ + /* Record how the non-reduction-def value of COND_EXPR is defined. */ if (dt == vect_constant_def) { cond_reduc_dt = dt; @@ -6622,10 +6573,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, return false; } - /* vect_is_simple_reduction ensured that operand 2 is the - loop-carried operand. */ - gcc_assert (reduc_index == 2); - /* Loop peeling modifies initial value of reduction PHI, which makes the reduction stmt to be transformed different to the original stmt analyzed. We need to record reduction code for -- cgit v1.1 From 0800e23ecf42b8323c226041f3982cd7856061c9 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 18 Sep 2019 18:22:55 +0000 Subject: [ARM] Cleanup highpart multiply patterns Cleanup the various highpart multiply patterns using iterators. As a result the signed and unsigned variants and the pre-Armv6 multiply operand constraints are all handled in a single pattern and simple expander. gcc/ * config/arm/arm.md (smulsi3_highpart): Use and iterators. (smulsi3_highpart_nov6): Remove pattern. (smulsi3_highpart_v6): Likewise. (umulsi3_highpart): Likewise. (umulsi3_highpart_nov6): Likewise. (umulsi3_highpart_v6): Likewise. (mull_high): Add new combined multiply pattern. From-SVN: r275899 --- gcc/ChangeLog | 10 +++++++ gcc/config/arm/arm.md | 80 +++++++-------------------------------------------- 2 files changed, 21 insertions(+), 69 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 13d5cb9..8b76a62 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -8,6 +8,16 @@ 2019-09-18 Wilco Dijkstra + * config/arm/arm.md (smulsi3_highpart): Use and iterators. + (smulsi3_highpart_nov6): Remove pattern. + (smulsi3_highpart_v6): Likewise. + (umulsi3_highpart): Likewise. + (umulsi3_highpart_nov6): Likewise. + (umulsi3_highpart_v6): Likewise. + (mull_high): Add new combined multiply pattern. + +2019-09-18 Wilco Dijkstra + * config/arm/arm.md (arm_mulsi3): Remove pattern. (arm_mulsi3_v6): Likewise. (mulsi3addsi_v6): Likewise. diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 4ffc771..b47e196 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1895,92 +1895,34 @@ (set_attr "predicable" "yes")] ) -(define_expand "smulsi3_highpart" +(define_expand "mulsi3_highpart" [(parallel [(set (match_operand:SI 0 "s_register_operand") (truncate:SI (lshiftrt:DI (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand"))) + (SE:DI (match_operand:SI 1 "s_register_operand")) + (SE:DI (match_operand:SI 2 "s_register_operand"))) (const_int 32)))) (clobber (match_scratch:SI 3 ""))])] "TARGET_32BIT" "" ) -(define_insn "*smulsi3_highpart_nov6" - [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") +(define_insn "*mull_high" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r,&r") (truncate:SI (lshiftrt:DI (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) + (SE:DI (match_operand:SI 1 "s_register_operand" "%r,0,r")) + (SE:DI (match_operand:SI 2 "s_register_operand" "r,r,r"))) (const_int 32)))) - (clobber (match_scratch:SI 3 "=&r,&r"))] - "TARGET_32BIT && !arm_arch6" - "smull%?\\t%3, %0, %2, %1" - [(set_attr "type" "smull") - (set_attr "predicable" "yes")] -) - -(define_insn "*smulsi3_highpart_v6" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (truncate:SI - (lshiftrt:DI - (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=r"))] - "TARGET_32BIT && arm_arch6" - "smull%?\\t%3, %0, %2, %1" - [(set_attr "type" "smull") - (set_attr "predicable" "yes")] -) - -(define_expand "umulsi3_highpart" - [(parallel - [(set (match_operand:SI 0 "s_register_operand") - (truncate:SI - (lshiftrt:DI - (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 ""))])] + (clobber (match_scratch:SI 3 "=r,&r,&r"))] "TARGET_32BIT" - "" -) - -(define_insn "*umulsi3_highpart_nov6" - [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") - (truncate:SI - (lshiftrt:DI - (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=&r,&r"))] - "TARGET_32BIT && !arm_arch6" - "umull%?\\t%3, %0, %2, %1" + "mull%?\\t%3, %0, %2, %1" [(set_attr "type" "umull") - (set_attr "predicable" "yes")] -) - -(define_insn "*umulsi3_highpart_v6" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (truncate:SI - (lshiftrt:DI - (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=r"))] - "TARGET_32BIT && arm_arch6" - "umull%?\\t%3, %0, %2, %1" - [(set_attr "type" "umull") - (set_attr "predicable" "yes")] + (set_attr "predicable" "yes") + (set_attr "arch" "v6,nov6,nov6")] ) (define_insn "mulhisi3" -- cgit v1.1 From 22a8ab772c37dc6250f2b22afe1e91b55fda41f5 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 18 Sep 2019 18:33:30 +0000 Subject: [ARM] Cleanup 64-bit multiplies Cleanup 64-bit multiplies. Combine the expanders using iterators. Merge the signed/unsigned multiplies as well as the pre-Armv6 and Armv6 variants. Split DImode operands early into parallel sets inside the MULL/MLAL instructions - this improves register allocation and avoids subreg issues due to other DImode operations splitting early. gcc/ * config/arm/arm.md (maddsidi4): Remove expander. (mulsidi3adddi): Remove pattern. (mulsidi3adddi_v6): Likewise. (mulsidi3_nov6): Likewise. (mulsidi3_v6): Likewise. (umulsidi3): Remove expander. (umulsidi3_nov6): Remove pattern. (umulsidi3_v6): Likewise. (umulsidi3adddi): Likewise. (umulsidi3adddi_v6): Likewise. (mulsidi3): Add combined expander. (maddsidi4): Likewise. (mull): Add combined umull and smull pattern. (mlal): Likewise. * config/arm/iterators.md (Us): Add new iterator. From-SVN: r275901 --- gcc/ChangeLog | 18 +++++ gcc/config/arm/arm.md | 174 ++++++++++++++------------------------------ gcc/config/arm/iterators.md | 1 + 3 files changed, 74 insertions(+), 119 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8b76a62..6be55cd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2019-09-18 Wilco Dijkstra + + * config/arm/arm.md (maddsidi4): Remove expander. + (mulsidi3adddi): Remove pattern. + (mulsidi3adddi_v6): Likewise. + (mulsidi3_nov6): Likewise. + (mulsidi3_v6): Likewise. + (umulsidi3): Remove expander. + (umulsidi3_nov6): Remove pattern. + (umulsidi3_v6): Likewise. + (umulsidi3adddi): Likewise. + (umulsidi3adddi_v6): Likewise. + (mulsidi3): Add combined expander. + (maddsidi4): Likewise. + (mull): Add combined umull and smull pattern. + (mlal): Likewise. + * config/arm/iterators.md (Us): Add new iterator. + 2019-09-18 Richard Biener * tree-vect-loop.c (vect_is_simple_reduction): Remove operand diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index b47e196..0054ed4 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1755,144 +1755,80 @@ (set_attr "type" "mlas")] ) -(define_expand "maddsidi4" - [(set (match_operand:DI 0 "s_register_operand") - (plus:DI - (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand"))) - (match_operand:DI 3 "s_register_operand")))] - "TARGET_32BIT" - "") - -(define_insn "*mulsidi3adddi" - [(set (match_operand:DI 0 "s_register_operand" "=&r") - (plus:DI - (mult:DI - (sign_extend:DI (match_operand:SI 2 "s_register_operand" "%r")) - (sign_extend:DI (match_operand:SI 3 "s_register_operand" "r"))) - (match_operand:DI 1 "s_register_operand" "0")))] - "TARGET_32BIT && !arm_arch6" - "smlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "smlal") - (set_attr "predicable" "yes")] -) - -(define_insn "*mulsidi3adddi_v6" - [(set (match_operand:DI 0 "s_register_operand" "=r") - (plus:DI - (mult:DI - (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r")) - (sign_extend:DI (match_operand:SI 3 "s_register_operand" "r"))) - (match_operand:DI 1 "s_register_operand" "0")))] - "TARGET_32BIT && arm_arch6" - "smlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "smlal") - (set_attr "predicable" "yes")] -) - ;; 32x32->64 widening multiply. -;; As with mulsi3, the only difference between the v3-5 and v6+ -;; versions of these patterns is the requirement that the output not -;; overlap the inputs, but that still means we have to have a named -;; expander and two different starred insns. +;; The only difference between the v3-5 and v6+ versions is the requirement +;; that the output does not overlap with either input. -(define_expand "mulsidi3" +(define_expand "mulsidi3" [(set (match_operand:DI 0 "s_register_operand") (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand"))))] + (SE:DI (match_operand:SI 1 "s_register_operand")) + (SE:DI (match_operand:SI 2 "s_register_operand"))))] "TARGET_32BIT" - "" -) - -(define_insn "*mulsidi3_nov6" - [(set (match_operand:DI 0 "s_register_operand" "=&r") - (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "TARGET_32BIT && !arm_arch6" - "smull%?\\t%Q0, %R0, %1, %2" - [(set_attr "type" "smull") - (set_attr "predicable" "yes")] -) - -(define_insn "*mulsidi3_v6" - [(set (match_operand:DI 0 "s_register_operand" "=r") - (mult:DI - (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")) - (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "TARGET_32BIT && arm_arch6" - "smull%?\\t%Q0, %R0, %1, %2" - [(set_attr "type" "smull") - (set_attr "predicable" "yes")] + { + emit_insn (gen_mull (gen_lowpart (SImode, operands[0]), + gen_highpart (SImode, operands[0]), + operands[1], operands[2])); + DONE; + } ) -(define_expand "umulsidi3" - [(set (match_operand:DI 0 "s_register_operand") - (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand"))))] +(define_insn "mull" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (mult:SI + (match_operand:SI 2 "s_register_operand" "%r,r") + (match_operand:SI 3 "s_register_operand" "r,r"))) + (set (match_operand:SI 1 "s_register_operand" "=r,&r") + (truncate:SI + (lshiftrt:DI + (mult:DI (SE:DI (match_dup 2)) (SE:DI (match_dup 3))) + (const_int 32))))] "TARGET_32BIT" - "" -) - -(define_insn "*umulsidi3_nov6" - [(set (match_operand:DI 0 "s_register_operand" "=&r") - (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "TARGET_32BIT && !arm_arch6" - "umull%?\\t%Q0, %R0, %1, %2" - [(set_attr "type" "umull") - (set_attr "predicable" "yes")] -) - -(define_insn "*umulsidi3_v6" - [(set (match_operand:DI 0 "s_register_operand" "=r") - (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))] - "TARGET_32BIT && arm_arch6" - "umull%?\\t%Q0, %R0, %1, %2" + "mull%?\\t%0, %1, %2, %3" [(set_attr "type" "umull") - (set_attr "predicable" "yes")] + (set_attr "predicable" "yes") + (set_attr "arch" "v6,nov6")] ) -(define_expand "umaddsidi4" +(define_expand "maddsidi4" [(set (match_operand:DI 0 "s_register_operand") (plus:DI (mult:DI - (zero_extend:DI (match_operand:SI 1 "s_register_operand")) - (zero_extend:DI (match_operand:SI 2 "s_register_operand"))) + (SE:DI (match_operand:SI 1 "s_register_operand")) + (SE:DI (match_operand:SI 2 "s_register_operand"))) (match_operand:DI 3 "s_register_operand")))] "TARGET_32BIT" - "") - -(define_insn "*umulsidi3adddi" - [(set (match_operand:DI 0 "s_register_operand" "=&r") - (plus:DI - (mult:DI - (zero_extend:DI (match_operand:SI 2 "s_register_operand" "%r")) - (zero_extend:DI (match_operand:SI 3 "s_register_operand" "r"))) - (match_operand:DI 1 "s_register_operand" "0")))] - "TARGET_32BIT && !arm_arch6" - "umlal%?\\t%Q0, %R0, %3, %2" - [(set_attr "type" "umlal") - (set_attr "predicable" "yes")] + { + emit_insn (gen_mlal (gen_lowpart (SImode, operands[0]), + gen_lowpart (SImode, operands[3]), + gen_highpart (SImode, operands[0]), + gen_highpart (SImode, operands[3]), + operands[1], operands[2])); + DONE; + } ) -(define_insn "*umulsidi3adddi_v6" - [(set (match_operand:DI 0 "s_register_operand" "=r") - (plus:DI - (mult:DI - (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r")) - (zero_extend:DI (match_operand:SI 3 "s_register_operand" "r"))) - (match_operand:DI 1 "s_register_operand" "0")))] - "TARGET_32BIT && arm_arch6" - "umlal%?\\t%Q0, %R0, %3, %2" +(define_insn "mlal" + [(set (match_operand:SI 0 "s_register_operand" "=r,&r") + (plus:SI + (mult:SI + (SE:DI (match_operand:SI 4 "s_register_operand" "%r,r")) + (SE:DI (match_operand:SI 5 "s_register_operand" "r,r"))) + (match_operand:SI 1 "s_register_operand" "0,0"))) + (set (match_operand:SI 2 "s_register_operand" "=r,&r") + (plus:SI + (truncate:SI + (lshiftrt:DI + (plus:DI + (mult:DI (SE:DI (match_dup 4)) (SE:DI (match_dup 5))) + (zero_extend:DI (match_dup 1))) + (const_int 32))) + (match_operand:SI 3 "s_register_operand" "2,2")))] + "TARGET_32BIT" + "mlal%?\\t%0, %2, %4, %5" [(set_attr "type" "umlal") - (set_attr "predicable" "yes")] + (set_attr "predicable" "yes") + (set_attr "arch" "v6,nov6")] ) (define_expand "mulsi3_highpart" diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index fa6f0c0..c29897a 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -796,6 +796,7 @@ ;; Assembler mnemonics for signedness of widening operations. (define_code_attr US [(sign_extend "s") (zero_extend "u")]) +(define_code_attr Us [(sign_extend "") (zero_extend "u")]) ;; Signedness suffix for float->fixed conversions. Empty for signed ;; conversion. -- cgit v1.1 From 101a0841b6fad201172e90f716d6c1866d7b0a36 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 18 Sep 2019 19:49:19 +0000 Subject: i386: Increase Skylake SImode pseudo register store cost On Skylake, SImode store cost isn't less than half cost of 128-bit vector store. This patch increases Skylake SImode pseudo register store cost to make it the same as QImode and HImode. gcc/ PR target/91446 * config/i386/x86-tune-costs.h (skylake_cost): Increase SImode pseudo register store cost from 3 to 6 to make it the same as QImode and HImode. gcc/testsuite/ PR target/91446 * gcc.target/i386/pr91446.c: New test. From-SVN: r275905 --- gcc/ChangeLog | 7 +++++++ gcc/config/i386/x86-tune-costs.h | 2 +- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/i386/pr91446.c | 24 ++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr91446.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6be55cd..d74b19f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-18 H.J. Lu + + PR target/91446 + * config/i386/x86-tune-costs.h (skylake_cost): Increase SImode + pseudo register store cost from 3 to 6 to make it the same as + QImode and HImode. + 2019-09-18 Wilco Dijkstra * config/arm/arm.md (maddsidi4): Remove expander. diff --git a/gcc/config/i386/x86-tune-costs.h b/gcc/config/i386/x86-tune-costs.h index 00edece..42c9c25 100644 --- a/gcc/config/i386/x86-tune-costs.h +++ b/gcc/config/i386/x86-tune-costs.h @@ -1638,7 +1638,7 @@ struct processor_costs skylake_cost = { {4, 4, 4}, /* cost of loading integer registers in QImode, HImode and SImode. Relative to reg-reg move (2). */ - {6, 6, 3}, /* cost of storing integer registers */ + {6, 6, 6}, /* cost of storing integer registers */ {6, 6, 6, 10, 20}, /* cost of loading SSE register in 32bit, 64bit, 128bit, 256bit and 512bit */ {8, 8, 8, 12, 24}, /* cost of storing SSE register diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index dc84ed9..8ea581d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-18 H.J. Lu + + PR target/91446 + * gcc.target/i386/pr91446.c: New test. + 2019-09-18 Eric Botcazou * gnat.dg/warn31.adb, gnat.dg/warn31.ads: New testcase. diff --git a/gcc/testsuite/gcc.target/i386/pr91446.c b/gcc/testsuite/gcc.target/i386/pr91446.c new file mode 100644 index 0000000..f7c4bea --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr91446.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -march=skylake -ftree-slp-vectorize -mtune-ctrl=^sse_typeless_stores" } */ + +typedef struct +{ + unsigned long long width, height; + long long x, y; +} info; + +extern void bar (info *); + +void +foo (unsigned long long width, unsigned long long height, + long long x, long long y) +{ + info t; + t.width = width; + t.height = height; + t.x = x; + t.y = y; + bar (&t); +} + +/* { dg-final { scan-assembler-times "vmovdqa\[^\n\r\]*xmm\[0-9\]" 2 } } */ -- cgit v1.1 From 7706f2f312a87b0c8509cccc986d6372dcd2fbcf Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 18 Sep 2019 19:50:45 +0000 Subject: i386: Restore Skylake SImode hard register store cost On Skylake, we should move integer register to SSE register without going through memory. This patch restores Skylake SImode hard register store cost to 6. gcc/ PR target/90878 * config/i386/x86-tune-costs.h (skylake_cost): Restore SImode hard register store cost to 6. gcc/testsuite/ PR target/90878 * gcc.target/i386/pr90878.c: New test. From-SVN: r275906 --- gcc/ChangeLog | 6 ++++++ gcc/config/i386/x86-tune-costs.h | 2 +- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/i386/pr90878.c | 25 +++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr90878.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d74b19f..0a20e86 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-18 H.J. Lu + PR target/90878 + * config/i386/x86-tune-costs.h (skylake_cost): Restore SImode + hard register store cost to 6. + +2019-09-18 H.J. Lu + PR target/91446 * config/i386/x86-tune-costs.h (skylake_cost): Increase SImode pseudo register store cost from 3 to 6 to make it the same as diff --git a/gcc/config/i386/x86-tune-costs.h b/gcc/config/i386/x86-tune-costs.h index 42c9c25..8e6f4b5 100644 --- a/gcc/config/i386/x86-tune-costs.h +++ b/gcc/config/i386/x86-tune-costs.h @@ -1594,7 +1594,7 @@ struct processor_costs skylake_cost = { {4, 4, 4}, /* cost of loading integer registers in QImode, HImode and SImode. Relative to reg-reg move (2). */ - {6, 6, 3}, /* cost of storing integer registers */ + {6, 6, 6}, /* cost of storing integer registers */ 2, /* cost of reg,reg fld/fst */ {6, 6, 8}, /* cost of loading fp registers in SFmode, DFmode and XFmode */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8ea581d..48e91d9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-09-18 H.J. Lu + PR target/90878 + * gcc.target/i386/pr90878.c: New test. + +2019-09-18 H.J. Lu + PR target/91446 * gcc.target/i386/pr91446.c: New test. diff --git a/gcc/testsuite/gcc.target/i386/pr90878.c b/gcc/testsuite/gcc.target/i386/pr90878.c new file mode 100644 index 0000000..18dd64b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr90878.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=skylake" } */ + +union ieee754_float + { + float f; + + struct + { + unsigned int mantissa:23; + unsigned int exponent:8; + unsigned int negative:1; + } ieee; +}; + +double +foo (float f) +{ + union ieee754_float u; + u.f = f; + u.ieee.negative = 0; + return u.f; +} + +/* { dg-final { scan-assembler-not "vcvtss2sd\[^\\n\]*\\\(%.sp\\\)" } } */ -- cgit v1.1 From 1ea956609a5a4ac12841ef86353995bd434fa1ef Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 18 Sep 2019 19:52:09 +0000 Subject: [ARM] Add logical DImode expanders We currently use default mid-end expanders for logical DImode operations. These split operations without first splitting off complex immediates or memory operands. The resulting expansions are non-optimal and allow for fewer LDRD/STRD opportunities. So add back explicit expanders which ensure memory operands and immediates are handled more efficiently. gcc/ PR target/91738 * config/arm/arm.md (di3): Expand explicitly. (one_cmpldi2): Likewise. * config/arm/arm.c (const_ok_for_dimode_op): Return true if one of the constant parts is simple. * config/arm/iterators.md (LOGICAL): Add new code iterator. (logical_op): Add new code attribute. (logical_OP): Likewise. * config/arm/predicates.md (arm_anddi_operand): Add predicate. (arm_iordi_operand): Add predicate. (arm_xordi_operand): Add predicate. From-SVN: r275907 --- gcc/ChangeLog | 14 ++++++++++++++ gcc/config/arm/arm.c | 4 ++-- gcc/config/arm/arm.md | 43 +++++++++++++++++++++++++++++++++++++++++++ gcc/config/arm/iterators.md | 5 +++++ gcc/config/arm/predicates.md | 15 +++++++++++++++ 5 files changed, 79 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0a20e86..04715c1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -13,6 +13,20 @@ 2019-09-18 Wilco Dijkstra + PR target/91738 + * config/arm/arm.md (di3): Expand explicitly. + (one_cmpldi2): Likewise. + * config/arm/arm.c (const_ok_for_dimode_op): Return true if one + of the constant parts is simple. + * config/arm/iterators.md (LOGICAL): Add new code iterator. + (logical_op): Add new code attribute. + (logical_OP): Likewise. + * config/arm/predicates.md (arm_anddi_operand): Add predicate. + (arm_iordi_operand): Add predicate. + (arm_xordi_operand): Add predicate. + +2019-09-18 Wilco Dijkstra + * config/arm/arm.md (maddsidi4): Remove expander. (mulsidi3adddi): Remove pattern. (mulsidi3adddi_v6): Likewise. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index c9ab71e..9f0975d 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -4390,8 +4390,8 @@ const_ok_for_dimode_op (HOST_WIDE_INT i, enum rtx_code code) case AND: case IOR: case XOR: - return (const_ok_for_op (hi_val, code) || hi_val == 0xFFFFFFFF) - && (const_ok_for_op (lo_val, code) || lo_val == 0xFFFFFFFF); + return const_ok_for_op (hi_val, code) || hi_val == 0xFFFFFFFF + || const_ok_for_op (lo_val, code) || lo_val == 0xFFFFFFFF; case PLUS: return arm_not_operand (hi, SImode) && arm_add_operand (lo, SImode); diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 0054ed4..d54082b 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -2035,6 +2035,49 @@ "") +; Expand logical operations. The mid-end expander does not split off memory +; operands or complex immediates, which leads to fewer LDRD/STRD instructions. +; So an explicit expander is needed to generate better code. + +(define_expand "di3" + [(set (match_operand:DI 0 "s_register_operand") + (LOGICAL:DI (match_operand:DI 1 "s_register_operand") + (match_operand:DI 2 "arm_di_operand")))] + "TARGET_32BIT" + { + rtx low = simplify_gen_binary (, SImode, + gen_lowpart (SImode, operands[1]), + gen_lowpart (SImode, operands[2])); + rtx high = simplify_gen_binary (, SImode, + gen_highpart (SImode, operands[1]), + gen_highpart_mode (SImode, DImode, + operands[2])); + + emit_insn (gen_rtx_SET (gen_lowpart (SImode, operands[0]), low)); + emit_insn (gen_rtx_SET (gen_highpart (SImode, operands[0]), high)); + DONE; + } +) + +(define_expand "one_cmpldi2" + [(set (match_operand:DI 0 "s_register_operand") + (not:DI (match_operand:DI 1 "s_register_operand")))] + "TARGET_32BIT" + { + rtx low = simplify_gen_unary (NOT, SImode, + gen_lowpart (SImode, operands[1]), + SImode); + rtx high = simplify_gen_unary (NOT, SImode, + gen_highpart_mode (SImode, DImode, + operands[1]), + SImode); + + emit_insn (gen_rtx_SET (gen_lowpart (SImode, operands[0]), low)); + emit_insn (gen_rtx_SET (gen_highpart (SImode, operands[0]), high)); + DONE; + } +) + ;; Split DImode and, ior, xor operations. Simply perform the logical ;; operation on the upper and lower halves of the registers. ;; This is needed for atomic operations in arm_split_atomic_op. diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index c29897a..5e3299e 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -239,6 +239,8 @@ ;; A list of ... (define_code_iterator IOR_XOR [ior xor]) +(define_code_iterator LOGICAL [and ior xor]) + ;; Operations on two halves of a quadword vector. (define_code_iterator VQH_OPS [plus smin smax umin umax]) @@ -285,6 +287,9 @@ (define_code_attr vfml_op [(plus "a") (minus "s")]) +(define_code_attr logical_op [(ior "ior") (xor "xor") (and "and")]) +(define_code_attr logical_OP [(ior "IOR") (xor "XOR") (and "AND")]) + ;;---------------------------------------------------------------------------- ;; Int iterators ;;---------------------------------------------------------------------------- diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 983faac..8b36e7ee 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -206,6 +206,21 @@ (and (match_code "const_int") (match_test "const_ok_for_dimode_op (INTVAL (op), PLUS)")))) +(define_predicate "arm_anddi_operand" + (ior (match_operand 0 "s_register_operand") + (and (match_code "const_int") + (match_test "const_ok_for_dimode_op (INTVAL (op), AND)")))) + +(define_predicate "arm_iordi_operand" + (ior (match_operand 0 "s_register_operand") + (and (match_code "const_int") + (match_test "const_ok_for_dimode_op (INTVAL (op), IOR)")))) + +(define_predicate "arm_xordi_operand" + (ior (match_operand 0 "s_register_operand") + (and (match_code "const_int") + (match_test "const_ok_for_dimode_op (INTVAL (op), XOR)")))) + (define_predicate "arm_addimm_operand" (ior (match_operand 0 "arm_immediate_operand") (match_operand 0 "arm_neg_immediate_operand"))) -- cgit v1.1 From ab2d47a87fe8a0989c766a0082f4598d9bf6143d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 19 Sep 2019 00:03:25 +0000 Subject: libgo: support gollvm build on arm64 linux This CL serves as part of an initial change for enabling gollvm building on arm64 linux, the rest of the change will be covered by another one to the gollvm repo. Incorporate type definition of 'uint128' to 'runtime' and 'syscall' packges, the change is not specific to arm64 linux but made available for all platforms. Verified by building and unit-testing gollvm on linux x86-64 and arm64. Verified by building and checking gccgo on linux x86-64 and arm64. Fixes golang/go#33711 Change-Id: I4720c7d810cfd4ef720962fb4104c5641b2459c0 From-SVN: r275919 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 4b7a4b3..330c458 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -09ca3c1ea8a52b5d3d6c4331c59d44e0b6bfab57 +d81ff42c367cce2110ccf5ddbadb6cc9bdf94e28 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From b9a7fd9bde14693e949d744146ab3e9bd8a05f21 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 19 Sep 2019 00:16:15 +0000 Subject: Daily bump. From-SVN: r275924 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 2d37305..c8a46c1 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190918 +20190919 -- cgit v1.1 From a923a4639434f9c845db002c8445e61cf5dda545 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Thu, 19 Sep 2019 01:19:25 +0000 Subject: RISC-V: Fix more splitters accidentally calling gen_reg_rtx. PR target/91683 * config/riscv/riscv-protos.h (riscv_split_symbol): New bool parameter. (riscv_move_integer): Likewise. * config/riscv/riscv.c (riscv_split_integer): Pass FALSE for new riscv_move_integer arg. (riscv_legitimize_move): Likewise. (riscv_force_temporary): New parameter in_splitter. Don't call force_reg if true. (riscv_unspec_offset_high): Pass FALSE for new riscv_force_temporary arg. (riscv_add_offset): Likewise. (riscv_split_symbol): New parameter in_splitter. Pass to riscv_force_temporary. (riscv_legitimize_address): Pass FALSE for new riscv_split_symbol arg. (riscv_move_integer): New parameter in_splitter. New local can_create_psuedo. Don't call riscv_split_integer or force_reg when in_splitter TRUE. (riscv_legitimize_const_move): Pass FALSE for new riscv_move_integer, riscv_split_symbol, and riscv_force_temporary args. * config/riscv/riscv.md (low+1): Pass TRUE for new riscv_move_integer arg. (low+2): Pass TRUE for new riscv_split_symbol arg. From-SVN: r275925 --- gcc/ChangeLog | 26 +++++++++++++++++++++++ gcc/config/riscv/riscv-protos.h | 4 ++-- gcc/config/riscv/riscv.c | 46 +++++++++++++++++++++++++---------------- gcc/config/riscv/riscv.md | 6 +++--- 4 files changed, 59 insertions(+), 23 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 04715c1..0510933 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2019-09-18 Jim Wilson + + PR target/91683 + * config/riscv/riscv-protos.h (riscv_split_symbol): New bool parameter. + (riscv_move_integer): Likewise. + * config/riscv/riscv.c (riscv_split_integer): Pass FALSE for new + riscv_move_integer arg. + (riscv_legitimize_move): Likewise. + (riscv_force_temporary): New parameter in_splitter. Don't call + force_reg if true. + (riscv_unspec_offset_high): Pass FALSE for new riscv_force_temporary + arg. + (riscv_add_offset): Likewise. + (riscv_split_symbol): New parameter in_splitter. Pass to + riscv_force_temporary. + (riscv_legitimize_address): Pass FALSE for new riscv_split_symbol + arg. + (riscv_move_integer): New parameter in_splitter. New local + can_create_psuedo. Don't call riscv_split_integer or force_reg when + in_splitter TRUE. + (riscv_legitimize_const_move): Pass FALSE for new riscv_move_integer, + riscv_split_symbol, and riscv_force_temporary args. + * config/riscv/riscv.md (low+1): Pass TRUE for new + riscv_move_integer arg. + (low+2): Pass TRUE for new riscv_split_symbol arg. + 2019-09-18 H.J. Lu PR target/90878 diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 69e39f7..5092294 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -44,10 +44,10 @@ extern int riscv_const_insns (rtx); extern int riscv_split_const_insns (rtx); extern int riscv_load_store_insns (rtx, rtx_insn *); extern rtx riscv_emit_move (rtx, rtx); -extern bool riscv_split_symbol (rtx, rtx, machine_mode, rtx *); +extern bool riscv_split_symbol (rtx, rtx, machine_mode, rtx *, bool); extern bool riscv_split_symbol_type (enum riscv_symbol_type); extern rtx riscv_unspec_address (rtx, enum riscv_symbol_type); -extern void riscv_move_integer (rtx, rtx, HOST_WIDE_INT, machine_mode); +extern void riscv_move_integer (rtx, rtx, HOST_WIDE_INT, machine_mode, bool); extern bool riscv_legitimize_move (machine_mode, rtx, rtx); extern rtx riscv_subword (rtx, bool); extern bool riscv_split_64bit_move_p (rtx, rtx); diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 39bf87a..b8a8778 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -508,8 +508,8 @@ riscv_split_integer (HOST_WIDE_INT val, machine_mode mode) unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32); rtx hi = gen_reg_rtx (mode), lo = gen_reg_rtx (mode); - riscv_move_integer (hi, hi, hival, mode); - riscv_move_integer (lo, lo, loval, mode); + riscv_move_integer (hi, hi, hival, mode, FALSE); + riscv_move_integer (lo, lo, loval, mode, FALSE); hi = gen_rtx_fmt_ee (ASHIFT, mode, hi, GEN_INT (32)); hi = force_reg (mode, hi); @@ -1021,9 +1021,12 @@ riscv_force_binary (machine_mode mode, enum rtx_code code, rtx x, rtx y) are allowed, copy it into a new register, otherwise use DEST. */ static rtx -riscv_force_temporary (rtx dest, rtx value) +riscv_force_temporary (rtx dest, rtx value, bool in_splitter) { - if (can_create_pseudo_p ()) + /* We can't call gen_reg_rtx from a splitter, because this might realloc + the regno_reg_rtx array, which would invalidate reg rtx pointers in the + combine undo buffer. */ + if (can_create_pseudo_p () && !in_splitter) return force_reg (Pmode, value); else { @@ -1082,7 +1085,7 @@ static rtx riscv_unspec_offset_high (rtx temp, rtx addr, enum riscv_symbol_type symbol_type) { addr = gen_rtx_HIGH (Pmode, riscv_unspec_address (addr, symbol_type)); - return riscv_force_temporary (temp, addr); + return riscv_force_temporary (temp, addr, FALSE); } /* Load an entry from the GOT for a TLS GD access. */ @@ -1130,7 +1133,8 @@ static rtx riscv_tls_add_tp_le (rtx dest, rtx base, rtx sym) is guaranteed to be a legitimate address for mode MODE. */ bool -riscv_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) +riscv_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out, + bool in_splitter) { enum riscv_symbol_type symbol_type; @@ -1146,7 +1150,7 @@ riscv_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) case SYMBOL_ABSOLUTE: { rtx high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); - high = riscv_force_temporary (temp, high); + high = riscv_force_temporary (temp, high, in_splitter); *low_out = gen_rtx_LO_SUM (Pmode, high, addr); } break; @@ -1205,8 +1209,9 @@ riscv_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset) overflow, so we need to force a sign-extension check. */ high = gen_int_mode (CONST_HIGH_PART (offset), Pmode); offset = CONST_LOW_PART (offset); - high = riscv_force_temporary (temp, high); - reg = riscv_force_temporary (temp, gen_rtx_PLUS (Pmode, high, reg)); + high = riscv_force_temporary (temp, high, FALSE); + reg = riscv_force_temporary (temp, gen_rtx_PLUS (Pmode, high, reg), + FALSE); } return plus_constant (Pmode, reg, offset); } @@ -1315,7 +1320,7 @@ riscv_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, return riscv_legitimize_tls_address (x); /* See if the address can split into a high part and a LO_SUM. */ - if (riscv_split_symbol (NULL, x, mode, &addr)) + if (riscv_split_symbol (NULL, x, mode, &addr, FALSE)) return riscv_force_address (addr, mode); /* Handle BASE + OFFSET using riscv_add_offset. */ @@ -1339,19 +1344,24 @@ riscv_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, void riscv_move_integer (rtx temp, rtx dest, HOST_WIDE_INT value, - machine_mode orig_mode) + machine_mode orig_mode, bool in_splitter) { struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS]; machine_mode mode; int i, num_ops; rtx x; + /* We can't call gen_reg_rtx from a splitter, because this might realloc + the regno_reg_rtx array, which would invalidate reg rtx pointers in the + combine undo buffer. */ + bool can_create_pseudo = can_create_pseudo_p () && ! in_splitter; + mode = GET_MODE (dest); /* We use the original mode for the riscv_build_integer call, because HImode values are given special treatment. */ num_ops = riscv_build_integer (codes, value, orig_mode); - if (can_create_pseudo_p () && num_ops > 2 /* not a simple constant */ + if (can_create_pseudo && num_ops > 2 /* not a simple constant */ && num_ops >= riscv_split_integer_cost (value)) x = riscv_split_integer (value, mode); else @@ -1361,7 +1371,7 @@ riscv_move_integer (rtx temp, rtx dest, HOST_WIDE_INT value, for (i = 1; i < num_ops; i++) { - if (!can_create_pseudo_p ()) + if (!can_create_pseudo) x = riscv_emit_set (temp, x); else x = force_reg (mode, x); @@ -1385,12 +1395,12 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) /* Split moves of big integers into smaller pieces. */ if (splittable_const_int_operand (src, mode)) { - riscv_move_integer (dest, dest, INTVAL (src), mode); + riscv_move_integer (dest, dest, INTVAL (src), mode, FALSE); return; } /* Split moves of symbolic constants into high/low pairs. */ - if (riscv_split_symbol (dest, src, MAX_MACHINE_MODE, &src)) + if (riscv_split_symbol (dest, src, MAX_MACHINE_MODE, &src, FALSE)) { riscv_emit_set (dest, src); return; @@ -1411,7 +1421,7 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) if (offset != const0_rtx && (targetm.cannot_force_const_mem (mode, src) || can_create_pseudo_p ())) { - base = riscv_force_temporary (dest, base); + base = riscv_force_temporary (dest, base, FALSE); riscv_emit_move (dest, riscv_add_offset (NULL, base, INTVAL (offset))); return; } @@ -1420,7 +1430,7 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) /* When using explicit relocs, constant pool references are sometimes not legitimate addresses. */ - riscv_split_symbol (dest, XEXP (src, 0), mode, &XEXP (src, 0)); + riscv_split_symbol (dest, XEXP (src, 0), mode, &XEXP (src, 0), FALSE); riscv_emit_move (dest, src); } @@ -1446,7 +1456,7 @@ riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) if (splittable_const_int_operand (src, mode)) { reg = gen_reg_rtx (promoted_mode); - riscv_move_integer (reg, reg, INTVAL (src), mode); + riscv_move_integer (reg, reg, INTVAL (src), mode, FALSE); } else reg = force_reg (promoted_mode, src); diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 744a027..d3c8f65 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -1285,7 +1285,7 @@ [(const_int 0)] { riscv_move_integer (operands[2], operands[0], INTVAL (operands[1]), - mode); + mode, TRUE); DONE; }) @@ -1294,11 +1294,11 @@ [(set (match_operand:P 0 "register_operand") (match_operand:P 1)) (clobber (match_operand:P 2 "register_operand"))] - "riscv_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL)" + "riscv_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL, TRUE)" [(set (match_dup 0) (match_dup 3))] { riscv_split_symbol (operands[2], operands[1], - MAX_MACHINE_MODE, &operands[3]); + MAX_MACHINE_MODE, &operands[3], TRUE); }) ;; 64-bit integer moves -- cgit v1.1 From fbd33afe4728f16789a37fe0a86fb0079d366b69 Mon Sep 17 00:00:00 2001 From: Hongtao Liu Date: Thu, 19 Sep 2019 01:21:39 +0000 Subject: Extend pass rpad to handle avx512f vcvtusi2ss vcvtusi2ss 538.imagick_r improved... Extend pass rpad to handle avx512f vcvtusi2ss vcvtusi2ss 538.imagick_r improved by 4% with single copy run on SKYLAKE workstation. gcc/ * config/i386/i386.md (*floatuns2_avx512): Add avx_partial_xmm_update. gcc/testsuie * gcc.target/i386/pr87007-3.c: New test. From-SVN: r275926 --- gcc/ChangeLog | 6 ++++++ gcc/config/i386/i386.md | 1 + gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/i386/pr87007-3.c | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr87007-3.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0510933..965d788 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Hongtao Liu + + PR target/87007 + * config/i386.md (*floatuns2_avx512): + Add avx_partial_xmm_update. + 2019-09-18 Jim Wilson PR target/91683 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 7ad9788..b7e7d12 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -5196,6 +5196,7 @@ "TARGET_AVX512F && TARGET_SSE_MATH" "vcvtusi2\t{%1, %0, %0|%0, %0, %1}" [(set_attr "type" "sseicvt") + (set_attr "avx_partial_xmm_update" "true") (set_attr "prefix" "evex") (set_attr "mode" "")]) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 48e91d9..20d22de 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Hongtao Liu + + PR target/87007 + * gcc.target/i386/pr87007-3.c: New test. + 2019-09-18 H.J. Lu PR target/90878 diff --git a/gcc/testsuite/gcc.target/i386/pr87007-3.c b/gcc/testsuite/gcc.target/i386/pr87007-3.c new file mode 100644 index 0000000..59324fd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr87007-3.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=skylake-avx512 -mfpmath=sse" } */ + +extern float f; +extern double d; +extern unsigned char c; + +void +foo (int n, int k) +{ + for (int i = 0; i != n; i++) + if(i < k) + d = c; + else + f = c; +} + +/* { dg-final { scan-assembler-times "vxorps\[^\n\r\]*xmm\[0-9\]" 1 } } */ -- cgit v1.1 From a7268fd7652406b41707af0c4b49e8523b667360 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 19 Sep 2019 06:08:33 +0000 Subject: tree-parloops.c (parloops_is_slp_reduction): Do not set LOOP_VINFO_OPERANDS_SWAPPED. 2019-09-19 Richard Biener * tree-parloops.c (parloops_is_slp_reduction): Do not set LOOP_VINFO_OPERANDS_SWAPPED. (parloops_is_simple_reduction): Likewise. * tree-vect-loop.c (_loop_vec_info::_loop_vec_info): Do not initialize operands_swapped. (_loop_vec_info::~_loop_vec_info): Do not re-canonicalize stmts. (vect_is_slp_reduction): Do not swap operands. * tree-vectorizer.h (_loop_vec_info::operands_swapped): Remove. (LOOP_VINFO_OPERANDS_SWAPPED): Likewise. From-SVN: r275928 --- gcc/ChangeLog | 12 +++++++++ gcc/tree-parloops.c | 6 ----- gcc/tree-vect-loop.c | 74 +++++---------------------------------------------- gcc/tree-vectorizer.h | 7 ----- 4 files changed, 18 insertions(+), 81 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 965d788..92fdc63 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2019-09-19 Richard Biener + + * tree-parloops.c (parloops_is_slp_reduction): Do not set + LOOP_VINFO_OPERANDS_SWAPPED. + (parloops_is_simple_reduction): Likewise. + * tree-vect-loop.c (_loop_vec_info::_loop_vec_info): Do not + initialize operands_swapped. + (_loop_vec_info::~_loop_vec_info): Do not re-canonicalize stmts. + (vect_is_slp_reduction): Do not swap operands. + * tree-vectorizer.h (_loop_vec_info::operands_swapped): Remove. + (LOOP_VINFO_OPERANDS_SWAPPED): Likewise. + 2019-09-19 Hongtao Liu PR target/87007 diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index b6bb49b..ae880e1 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -347,9 +347,6 @@ parloops_is_slp_reduction (loop_vec_info loop_info, gimple *phi, gimple_assign_rhs1_ptr (next_stmt), gimple_assign_rhs2_ptr (next_stmt)); update_stmt (next_stmt); - - if (CONSTANT_CLASS_P (gimple_assign_rhs1 (next_stmt))) - LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true; } else return false; @@ -831,9 +828,6 @@ parloops_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, if (dump_enabled_p ()) report_ploop_op (MSG_NOTE, def_stmt, "detected reduction: need to swap operands: "); - - if (CONSTANT_CLASS_P (gimple_assign_rhs1 (def_stmt))) - LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true; } else { diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index bcd9639..5ee4ee3 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -832,7 +832,6 @@ _loop_vec_info::_loop_vec_info (class loop *loop_in, vec_info_shared *shared) fully_masked_p (false), peeling_for_gaps (false), peeling_for_niter (false), - operands_swapped (false), no_data_dependencies (false), has_mask_store (false), scalar_loop_scaling (profile_probability::uninitialized ()), @@ -906,57 +905,6 @@ release_vec_loop_masks (vec_loop_masks *masks) _loop_vec_info::~_loop_vec_info () { - int nbbs; - gimple_stmt_iterator si; - int j; - - nbbs = loop->num_nodes; - for (j = 0; j < nbbs; j++) - { - basic_block bb = bbs[j]; - for (si = gsi_start_bb (bb); !gsi_end_p (si); ) - { - gimple *stmt = gsi_stmt (si); - - /* We may have broken canonical form by moving a constant - into RHS1 of a commutative op. Fix such occurrences. */ - if (operands_swapped && is_gimple_assign (stmt)) - { - enum tree_code code = gimple_assign_rhs_code (stmt); - - if ((code == PLUS_EXPR - || code == POINTER_PLUS_EXPR - || code == MULT_EXPR) - && CONSTANT_CLASS_P (gimple_assign_rhs1 (stmt))) - swap_ssa_operands (stmt, - gimple_assign_rhs1_ptr (stmt), - gimple_assign_rhs2_ptr (stmt)); - else if (code == COND_EXPR - && CONSTANT_CLASS_P (gimple_assign_rhs2 (stmt))) - { - tree cond_expr = gimple_assign_rhs1 (stmt); - enum tree_code cond_code = TREE_CODE (cond_expr); - - if (TREE_CODE_CLASS (cond_code) == tcc_comparison) - { - bool honor_nans = HONOR_NANS (TREE_OPERAND (cond_expr, - 0)); - cond_code = invert_tree_comparison (cond_code, - honor_nans); - if (cond_code != ERROR_MARK) - { - TREE_SET_CODE (cond_expr, cond_code); - swap_ssa_operands (stmt, - gimple_assign_rhs2_ptr (stmt), - gimple_assign_rhs3_ptr (stmt)); - } - } - } - } - gsi_next (&si); - } - } - free (bbs); release_vec_loop_masks (&masks); @@ -2715,7 +2663,8 @@ vect_is_slp_reduction (loop_vec_info loop_info, gimple *phi, } else { - tree op = gimple_assign_rhs2 (next_stmt); + gcc_assert (gimple_assign_rhs1 (next_stmt) == lhs); + tree op = gimple_assign_rhs2 (next_stmt); stmt_vec_info def_stmt_info = loop_info->lookup_def (op); /* Check that the other def is either defined in the loop @@ -2725,23 +2674,12 @@ vect_is_slp_reduction (loop_vec_info loop_info, gimple *phi, && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt)) && vect_valid_reduction_input_p (def_stmt_info)) { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, "swapping oprnds: %G", - next_stmt); - - swap_ssa_operands (next_stmt, - gimple_assign_rhs1_ptr (next_stmt), - gimple_assign_rhs2_ptr (next_stmt)); - update_stmt (next_stmt); - - if (CONSTANT_CLASS_P (gimple_assign_rhs1 (next_stmt))) - LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true; + lhs = gimple_assign_lhs (next_stmt); + continue; } - else - return false; - } - lhs = gimple_assign_lhs (next_stmt); + return false; + } } /* Build up the actual chain. */ diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index ee6fe9a..ac6e899 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -528,12 +528,6 @@ public: we need to peel off iterations at the end to form an epilogue loop. */ bool peeling_for_niter; - /* Reductions are canonicalized so that the last operand is the reduction - operand. If this places a constant into RHS1, this decanonicalizes - GIMPLE for other phases, so we must track when this has occurred and - fix it up. */ - bool operands_swapped; - /* True if there are no loop carried data dependencies in the loop. If loop->safelen <= 1, then this is always true, either the loop didn't have any loop carried data dependencies, or the loop is being @@ -610,7 +604,6 @@ public: #define LOOP_VINFO_REDUCTION_CHAINS(L) (L)->reduction_chains #define LOOP_VINFO_TARGET_COST_DATA(L) (L)->target_cost_data #define LOOP_VINFO_PEELING_FOR_GAPS(L) (L)->peeling_for_gaps -#define LOOP_VINFO_OPERANDS_SWAPPED(L) (L)->operands_swapped #define LOOP_VINFO_PEELING_FOR_NITER(L) (L)->peeling_for_niter #define LOOP_VINFO_NO_DATA_DEPENDENCIES(L) (L)->no_data_dependencies #define LOOP_VINFO_SCALAR_LOOP(L) (L)->scalar_loop -- cgit v1.1 From f4437882fe972b14eb5f4163de34fa9c909b5fb6 Mon Sep 17 00:00:00 2001 From: Bob Duff Date: Thu, 19 Sep 2019 08:12:34 +0000 Subject: [Ada] Rtsfind: improve comment on RTE_Available 2019-09-19 Bob Duff gcc/ada/ * rtsfind.ads (RTE_Available): Improve comment. From-SVN: r275930 --- gcc/ada/ChangeLog | 4 ++++ gcc/ada/rtsfind.ads | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index c42498e..7b4bb47 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Bob Duff + + * rtsfind.ads (RTE_Available): Improve comment. + 2019-09-18 Bob Duff * exp_ch5.adb (Expand_Assign_Array_Loop_Or_Bitfield): Move call diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads index 9d5a86c..2467f85 100644 --- a/gcc/ada/rtsfind.ads +++ b/gcc/ada/rtsfind.ads @@ -3203,6 +3203,23 @@ package Rtsfind is -- Returns true if a call to RTE will succeed without raising an exception -- and without generating an error message, i.e. if the call will obtain -- the desired entity without any problems. + -- + -- If we call this and it returns True, we should generate a call to E. + -- In other words, the compiler should not call RTE_Available (E) until + -- it has decided it wants to generate a call to E. Otherwise we can get + -- spurious dependencies and elaboration orders. + -- + -- if RTE_Available (E) -- WRONG! + -- and then + -- then + -- generate call to E; + -- + -- Should be: + -- + -- if + -- and then RTE_Available (E) -- Correct + -- then + -- generate call to E; function RTE_Record_Component (E : RE_Id) return Entity_Id; -- Given the entity defined in the above tables, as identified by the -- cgit v1.1 From 5d66b937e3d1bbdbaace1da7bc5fac8a94793108 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:12:39 +0000 Subject: [Ada] Improve handling of explicit by-reference mechanism This improves the handling of an explicit by-reference passing mechanism specified by means of the GNAT pragma Export_Function. This device sort of circumvents the rules of the language for the by-reference passing mechanism and it's then up to the programmer to ensure that the actual parameter is addressable; if it is not, the compiler will generate a temporary around the call, thus effectively passing the actual by copy. It turns out that the compiler was too conservative when determining whether the actual parameter is addressable, in particular if it's a component of a record type subject to a representation clause. The change effectively moves this computation from the front-end to the back-end, which has much more information on the layout and alignment of types and thus can be less conservative. 2019-09-19 Eric Botcazou gcc/ada/ * exp_ch6.adb (Is_Legal_Copy): Also return false for an aliased formal and a formal passed by reference in convention Ada. Add missing guard to the existing test on Is_Valued_Procedure. From-SVN: r275931 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/exp_ch6.adb | 11 ++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 7b4bb47..b0fdcf9 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Eric Botcazou + + * exp_ch6.adb (Is_Legal_Copy): Also return false for an aliased + formal and a formal passed by reference in convention Ada. Add + missing guard to the existing test on Is_Valued_Procedure. + 2019-09-19 Bob Duff * rtsfind.ads (RTE_Available): Improve comment. diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 78a1496..d3540c3 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -1859,12 +1859,16 @@ package body Exp_Ch6 is -- An attempt to copy a value of such a type can only occur if -- representation clauses give the actual a misaligned address. - if Is_By_Reference_Type (Etype (Formal)) then + if Is_By_Reference_Type (Etype (Formal)) + or else Is_Aliased (Formal) + or else (Mechanism (Formal) = By_Reference + and then not Has_Foreign_Convention (Subp)) + then -- The actual may in fact be properly aligned but there is not -- enough front-end information to determine this. In that case - -- gigi will emit an error if a copy is not legal, or generate - -- the proper code. + -- gigi will emit an error or a warning if a copy is not legal, + -- or generate the proper code. return False; @@ -1875,6 +1879,7 @@ package body Exp_Ch6 is -- be lurking. elsif Mechanism (Formal) = By_Reference + and then Ekind (Scope (Formal)) = E_Procedure and then Is_Valued_Procedure (Scope (Formal)) then Error_Msg_N -- cgit v1.1 From e516702202bcdc26181cf9fab120fcb15ca0c15d Mon Sep 17 00:00:00 2001 From: Bob Duff Date: Thu, 19 Sep 2019 08:12:47 +0000 Subject: [Ada] gnatxref: infinite loop on symbols not found This patch fixes a bug in which if a symbol is not found, gnatxref can sometimes enter an infinite loop. No impact on compilation. 2019-09-19 Bob Duff gcc/ada/ * xref_lib.adb (Get_Symbol_Name): If we reach EOF in the first loop without finding the symbol, return "???". Otherwise, it's an infinite loop. (Parse_EOL): Assert that we're not already at EOF. Remove processing of LF/CR -- there are no operating systems that use that. From-SVN: r275932 --- gcc/ada/ChangeLog | 9 +++++++++ gcc/ada/xref_lib.adb | 17 +++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index b0fdcf9..429e17f 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,12 @@ +2019-09-19 Bob Duff + + * xref_lib.adb (Get_Symbol_Name): If we reach EOF in the first + loop without finding the symbol, return "???". Otherwise, it's + an infinite loop. + (Parse_EOL): Assert that we're not already at EOF. Remove + processing of LF/CR -- there are no operating systems that use + that. + 2019-09-19 Eric Botcazou * exp_ch6.adb (Is_Legal_Copy): Also return false for an aliased diff --git a/gcc/ada/xref_lib.adb b/gcc/ada/xref_lib.adb index 4d400f3..eabf8b4 100644 --- a/gcc/ada/xref_lib.adb +++ b/gcc/ada/xref_lib.adb @@ -723,6 +723,8 @@ package body Xref_Lib is is begin loop + pragma Assert (Source (Ptr) /= EOF); + -- Skip to end of line while Source (Ptr) /= ASCII.CR and then Source (Ptr) /= ASCII.LF @@ -737,11 +739,9 @@ package body Xref_Lib is Ptr := Ptr + 1; end if; - -- Skip past CR/LF or LF/CR combination + -- Skip past CR/LF - if (Source (Ptr) = ASCII.CR or else Source (Ptr) = ASCII.LF) - and then Source (Ptr) /= Source (Ptr - 1) - then + if Source (Ptr - 1) = ASCII.CR and then Source (Ptr) = ASCII.LF then Ptr := Ptr + 1; end if; @@ -783,6 +783,7 @@ package body Xref_Lib is -- line and column in the dependent unit number Eun. For this we need -- to parse the ali file again because the parent entity is not in -- the declaration table if it did not match the search pattern. + -- If the symbol is not found, we return "???". procedure Skip_To_Matching_Closing_Bracket; -- When Ptr points to an opening square bracket, moves it to the @@ -803,6 +804,10 @@ package body Xref_Lib is -- Look for the X lines corresponding to unit Eun loop + if Ali (Ptr) = EOF then + return "???"; + end if; + if Ali (Ptr) = 'X' then Ptr := Ptr + 1; Parse_Number (Ali, Ptr, E_Eun); @@ -832,10 +837,6 @@ package body Xref_Lib is exit when Ali (Ptr) = EOF; end loop; - -- We were not able to find the symbol, this should not happen but - -- since we don't want to stop here we return a string of three - -- question marks as the symbol name. - return "???"; end Get_Symbol_Name; -- cgit v1.1 From 348c3ae62ec5579323defd9179aa6b870e0b744b Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:12:52 +0000 Subject: [Ada] Fix fallout of previous change for bit-packed arrays This fixes a regression introduced by the previous change that improved the handling of explicit by-reference mechanism. For the very specific case of a component of a bit-packed array, the front-end still needs to insert a copy around the call because this is where the rewriting into the sequence of mask-and-shifts is done for the code generator. 2019-09-19 Eric Botcazou gcc/ada/ * exp_ch6.adb (Add_Simple_Call_By_Copy_Code): Add Bit_Packed_Array parameter and documet it. Always insert a copy if it is set True. (Expand_Actuals): Adjust the calls to Add_Simple_Call_By_Copy_Code. gcc/testsuite/ * gnat.dg/pack26.adb: New testcase. From-SVN: r275933 --- gcc/ada/ChangeLog | 8 ++++++++ gcc/ada/exp_ch6.adb | 32 +++++++++++++++++++------------- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gnat.dg/pack26.adb | 23 +++++++++++++++++++++++ 4 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/pack26.adb (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 429e17f..78b1c0b 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,11 @@ +2019-09-19 Eric Botcazou + + * exp_ch6.adb (Add_Simple_Call_By_Copy_Code): Add + Bit_Packed_Array parameter and documet it. Always insert a copy + if it is set True. + (Expand_Actuals): Adjust the calls to + Add_Simple_Call_By_Copy_Code. + 2019-09-19 Bob Duff * xref_lib.adb (Get_Symbol_Name): If we reach EOF in the first diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index d3540c3..c569ca3 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -1252,10 +1252,11 @@ package body Exp_Ch6 is -- also takes care of any constraint checks required for the type -- conversion case (on both the way in and the way out). - procedure Add_Simple_Call_By_Copy_Code; + procedure Add_Simple_Call_By_Copy_Code (Bit_Packed_Array : Boolean); -- This is similar to the above, but is used in cases where we know -- that all that is needed is to simply create a temporary and copy - -- the value in and out of the temporary. + -- the value in and out of the temporary. If Bit_Packed_Array is True, + -- the procedure is called for a bit-packed array actual. procedure Add_Validation_Call_By_Copy_Code (Act : Node_Id); -- Perform copy-back for actual parameter Act which denotes a validation @@ -1269,11 +1270,11 @@ package body Exp_Ch6 is function Is_Legal_Copy return Boolean; -- Check that an actual can be copied before generating the temporary - -- to be used in the call. If the actual is of a by_reference type then - -- the program is illegal (this can only happen in the presence of - -- rep. clauses that force an incorrect alignment). If the formal is - -- a by_reference parameter imposed by a DEC pragma, emit a warning to - -- the effect that this might lead to unaligned arguments. + -- to be used in the call. If the formal is of a by_reference type or + -- is aliased, then the program is illegal (this can only happen in + -- the presence of representation clauses that force a misalignment) + -- If the formal is a by_reference parameter imposed by a DEC pragma, + -- emit a warning that this might lead to unaligned arguments. function Make_Var (Actual : Node_Id) return Entity_Id; -- Returns an entity that refers to the given actual parameter, Actual @@ -1610,7 +1611,7 @@ package body Exp_Ch6 is -- Add_Simple_Call_By_Copy_Code -- ---------------------------------- - procedure Add_Simple_Call_By_Copy_Code is + procedure Add_Simple_Call_By_Copy_Code (Bit_Packed_Array : Boolean) is Decl : Node_Id; F_Typ : Entity_Id := Etype (Formal); Incod : Node_Id; @@ -1621,7 +1622,12 @@ package body Exp_Ch6 is Temp : Entity_Id; begin - if not Is_Legal_Copy then + -- ??? We need to do the copy for a bit-packed array because this is + -- where the rewriting into a mask-and-shift sequence is done. But of + -- course this may break the program if it expects bits to be really + -- passed by reference. That's what we have done historically though. + + if not Bit_Packed_Array and then not Is_Legal_Copy then return; end if; @@ -2076,7 +2082,7 @@ package body Exp_Ch6 is -- [in] out parameters. elsif Is_Ref_To_Bit_Packed_Array (Actual) then - Add_Simple_Call_By_Copy_Code; + Add_Simple_Call_By_Copy_Code (Bit_Packed_Array => True); -- If a nonscalar actual is possibly bit-aligned, we need a copy -- because the back-end cannot cope with such objects. In other @@ -2092,7 +2098,7 @@ package body Exp_Ch6 is Component_May_Be_Bit_Aligned (Entity (Selector_Name (Actual))) and then not Represented_As_Scalar (Etype (Formal)) then - Add_Simple_Call_By_Copy_Code; + Add_Simple_Call_By_Copy_Code (Bit_Packed_Array => False); -- References to slices of bit-packed arrays are expanded @@ -2295,14 +2301,14 @@ package body Exp_Ch6 is -- Is this really necessary in all cases??? elsif Is_Ref_To_Bit_Packed_Array (Actual) then - Add_Simple_Call_By_Copy_Code; + Add_Simple_Call_By_Copy_Code (Bit_Packed_Array => True); -- If a nonscalar actual is possibly unaligned, we need a copy elsif Is_Possibly_Unaligned_Object (Actual) and then not Represented_As_Scalar (Etype (Formal)) then - Add_Simple_Call_By_Copy_Code; + Add_Simple_Call_By_Copy_Code (Bit_Packed_Array => False); -- Similarly, we have to expand slices of packed arrays here -- because the result must be byte aligned. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 20d22de..1e02628 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Eric Botcazou + + * gnat.dg/pack26.adb: New testcase. + 2019-09-19 Hongtao Liu PR target/87007 diff --git a/gcc/testsuite/gnat.dg/pack26.adb b/gcc/testsuite/gnat.dg/pack26.adb new file mode 100644 index 0000000..6365296 --- /dev/null +++ b/gcc/testsuite/gnat.dg/pack26.adb @@ -0,0 +1,23 @@ +-- { dg-do run } + +pragma Extend_System (Aux_DEC); + +with System; + +procedure Pack26 is + + type Bool_Array is array (1 .. 8) of Boolean; + pragma pack (Bool_Array); + + All_True : Bool_Array := (others => True); + Old_Value : Boolean := False; + +begin + + System.Clear_Interlocked (All_True (2), Old_Value); + + if not Old_Value then + raise Program_Error; + end if; + +end; \ No newline at end of file -- cgit v1.1 From 682c09cebada73fb80e3a36fec6a3b1a09c5781e Mon Sep 17 00:00:00 2001 From: Bob Duff Date: Thu, 19 Sep 2019 08:12:56 +0000 Subject: [Ada] Infinite loop with concatenation and aspect This patch fixes a bug where an array object initialized with a concatenation, and that has an aspect_specification for Alignment, causes the compiler goes into an infinite loop. 2019-09-19 Bob Duff gcc/ada/ * exp_ch3.adb (Rewrite_As_Renaming): Return False if there are any aspect specifications, because otherwise Insert_Actions blows up. gcc/testsuite/ * gnat.dg/concat3.adb: New testcase. From-SVN: r275934 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/exp_ch3.adb | 23 ++++++++++++++++------- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gnat.dg/concat3.adb | 14 ++++++++++++++ 4 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/concat3.adb (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 78b1c0b..7d867bf 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Bob Duff + + * exp_ch3.adb (Rewrite_As_Renaming): Return False if there are + any aspect specifications, because otherwise Insert_Actions + blows up. + 2019-09-19 Eric Botcazou * exp_ch6.adb (Add_Simple_Call_By_Copy_Code): Add diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index b08f51c..18c6aaf 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -6318,7 +6318,8 @@ package body Exp_Ch3 is ------------------------- function Rewrite_As_Renaming return Boolean is - begin + Result : constant Boolean := + -- If the object declaration appears in the form -- Obj : Ctrl_Typ := Func (...); @@ -6336,12 +6337,12 @@ package body Exp_Ch3 is -- This part is disabled for now, because it breaks GPS builds - return (False -- ??? - and then Nkind (Expr_Q) = N_Explicit_Dereference - and then not Comes_From_Source (Expr_Q) - and then Nkind (Original_Node (Expr_Q)) = N_Function_Call - and then Nkind (Object_Definition (N)) in N_Has_Entity - and then (Needs_Finalization (Entity (Object_Definition (N))))) + (False -- ??? + and then Nkind (Expr_Q) = N_Explicit_Dereference + and then not Comes_From_Source (Expr_Q) + and then Nkind (Original_Node (Expr_Q)) = N_Function_Call + and then Nkind (Object_Definition (N)) in N_Has_Entity + and then (Needs_Finalization (Entity (Object_Definition (N))))) -- If the initializing expression is for a variable with attribute -- OK_To_Rename set, then transform: @@ -6362,6 +6363,14 @@ package body Exp_Ch3 is and then Ekind (Entity (Expr_Q)) = E_Variable and then OK_To_Rename (Entity (Expr_Q)) and then Is_Entity_Name (Obj_Def)); + begin + -- Return False if there are any aspect specifications, because + -- otherwise we duplicate that corresponding implicit attribute + -- definition, and call Insert_Action, which has no place to insert + -- the attribute definition. The attribute definition is stored in + -- Aspect_Rep_Item, which is not a list. + + return Result and then No (Aspect_Specifications (N)); end Rewrite_As_Renaming; -- Local variables diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1e02628..3755221 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Bob Duff + + * gnat.dg/concat3.adb: New testcase. + 2019-09-19 Eric Botcazou * gnat.dg/pack26.adb: New testcase. diff --git a/gcc/testsuite/gnat.dg/concat3.adb b/gcc/testsuite/gnat.dg/concat3.adb new file mode 100644 index 0000000..b4df3fd --- /dev/null +++ b/gcc/testsuite/gnat.dg/concat3.adb @@ -0,0 +1,14 @@ +-- { dg-do run } +-- { dg-options "-g -O0 -gnata" } + +procedure Concat3 is + procedure Show_Bug (S : in String) + is + Str : constant String := S & "-" with Alignment => 4; + begin + null; + end Show_Bug; + +begin + Show_Bug ("BUG"); +end Concat3; \ No newline at end of file -- cgit v1.1 From 4af04d04c427e2ca78bb988cf6b1ad209a99a142 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:13:01 +0000 Subject: [Ada] Fix spurious type mismatch failure on nested instantiations This fixes a spurious type mismatch failure reported between formal and actual of a call to a subprogram that comes from the instantiation of a child generic unit that itself contains an instantiation of a slibling child generic unit, when the parent is itself a generic unit with private part. The regression was introduced by a recent change made to clear the Is_Generic_Actual_Type on the implicit full view built when a generic package is instantiated on a private type. 2019-09-19 Eric Botcazou gcc/ada/ * sem_ch12.adb (Restore_Private_Views): Comment out new code that clear the Is_Generic_Actual_Type also on the full view. gcc/testsuite/ * gnat.dg/generic_inst13.adb, gnat.dg/generic_inst13_pkg-nested_g.ads, gnat.dg/generic_inst13_pkg-ops_g.ads, gnat.dg/generic_inst13_pkg.ads: New testcase. From-SVN: r275935 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/sem_ch12.adb | 14 +++++++++++--- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/gnat.dg/generic_inst13.adb | 22 ++++++++++++++++++++++ .../gnat.dg/generic_inst13_pkg-nested_g.ads | 14 ++++++++++++++ gcc/testsuite/gnat.dg/generic_inst13_pkg-ops_g.ads | 9 +++++++++ gcc/testsuite/gnat.dg/generic_inst13_pkg.ads | 11 +++++++++++ 7 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/generic_inst13.adb create mode 100644 gcc/testsuite/gnat.dg/generic_inst13_pkg-nested_g.ads create mode 100644 gcc/testsuite/gnat.dg/generic_inst13_pkg-ops_g.ads create mode 100644 gcc/testsuite/gnat.dg/generic_inst13_pkg.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 7d867bf..5ff5f16 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Eric Botcazou + + * sem_ch12.adb (Restore_Private_Views): Comment out new code + that clear the Is_Generic_Actual_Type also on the full view. + 2019-09-19 Bob Duff * exp_ch3.adb (Rewrite_As_Renaming): Return False if there are diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 17de328..61a40eb 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -14638,9 +14638,17 @@ package body Sem_Ch12 is else Set_Is_Generic_Actual_Type (E, False); - if Is_Private_Type (E) and then Present (Full_View (E)) then - Set_Is_Generic_Actual_Type (Full_View (E), False); - end if; + -- It might seem reasonable to clear the Is_Generic_Actual_Type + -- flag also on the Full_View if the type is private, since it + -- was set also on this Full_View. However, this flag is relied + -- upon by Covers to spot "types exported from instantiations" + -- which are implicit Full_Views built for instantiations made + -- on private types and we get type mismatches if we do it when + -- the block exchanging the declarations below triggers ??? + + -- if Is_Private_Type (E) and then Present (Full_View (E)) then + -- Set_Is_Generic_Actual_Type (Full_View (E), False); + -- end if; end if; -- An unusual case of aliasing: the actual may also be directly diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3755221..69e7854 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Eric Botcazou + + * gnat.dg/generic_inst13.adb, + gnat.dg/generic_inst13_pkg-nested_g.ads, + gnat.dg/generic_inst13_pkg-ops_g.ads, + gnat.dg/generic_inst13_pkg.ads: New testcase. + 2019-09-19 Bob Duff * gnat.dg/concat3.adb: New testcase. diff --git a/gcc/testsuite/gnat.dg/generic_inst13.adb b/gcc/testsuite/gnat.dg/generic_inst13.adb new file mode 100644 index 0000000..c83b893 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic_inst13.adb @@ -0,0 +1,22 @@ +-- { dg-do compile } + +with Generic_Inst13_Pkg; +with Generic_Inst13_Pkg.Nested_G; + +procedure Generic_Inst13 is + + type Item_T is range 1 .. 16; + + package My_Inst is new Generic_Inst13_Pkg (Item_T); + + package My_Nested is new My_Inst.Nested_G; + + procedure Proc (Left, Right : My_Nested.T) is + R : constant My_Nested.List_T := My_Nested."or" (Left, Right); + begin + null; + end; + +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/generic_inst13_pkg-nested_g.ads b/gcc/testsuite/gnat.dg/generic_inst13_pkg-nested_g.ads new file mode 100644 index 0000000..edbfe94 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic_inst13_pkg-nested_g.ads @@ -0,0 +1,14 @@ +with Generic_Inst13_Pkg.Ops_G; + +generic +package Generic_Inst13_Pkg.Nested_G is + + type T is new Generic_Inst13_Pkg.T; + + package My_Operations is new Generic_Inst13_Pkg.Ops_G (T); + + subtype List_T is My_Operations.List_T; + + function "or" (Left, Right : T) return List_T renames My_Operations."or"; + +end Generic_Inst13_Pkg.Nested_G; diff --git a/gcc/testsuite/gnat.dg/generic_inst13_pkg-ops_g.ads b/gcc/testsuite/gnat.dg/generic_inst13_pkg-ops_g.ads new file mode 100644 index 0000000..0832940 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic_inst13_pkg-ops_g.ads @@ -0,0 +1,9 @@ +generic + type Data_T is private; +package Generic_Inst13_Pkg.Ops_G is + + type List_T is array (Positive range <>) of Data_T; + + function "or" (Left, Right : Data_T) return List_T is ((Left, Right)); + +end Generic_Inst13_Pkg.Ops_G; \ No newline at end of file diff --git a/gcc/testsuite/gnat.dg/generic_inst13_pkg.ads b/gcc/testsuite/gnat.dg/generic_inst13_pkg.ads new file mode 100644 index 0000000..5cdfb64 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic_inst13_pkg.ads @@ -0,0 +1,11 @@ +generic + type Component_T is private; +package Generic_Inst13_Pkg is + + type T is private; + +private + + type T is array (Boolean) of Component_T; + +end Generic_Inst13_Pkg; -- cgit v1.1 From 3aacb9ed526c68e49424ec4dc4833de8353d2a7c Mon Sep 17 00:00:00 2001 From: Raphael Amiard Date: Thu, 19 Sep 2019 08:13:06 +0000 Subject: [Ada] Add comments wrt. deallocation of bounded sets/maps 2019-09-19 Raphael Amiard gcc/ada/ * libgnat/a-cbhama.ads, libgnat/a-cbhase.ads, libgnat/a-chtgop.ads (Clear): Refine comments From-SVN: r275936 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/libgnat/a-cbhama.ads | 3 ++- gcc/ada/libgnat/a-cbhase.ads | 3 ++- gcc/ada/libgnat/a-chtgop.ads | 5 +++-- 4 files changed, 12 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 5ff5f16..f9a8bfe 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Raphael Amiard + + * libgnat/a-cbhama.ads, libgnat/a-cbhase.ads, + libgnat/a-chtgop.ads (Clear): Refine comments + 2019-09-19 Eric Botcazou * sem_ch12.adb (Restore_Private_Views): Comment out new code diff --git a/gcc/ada/libgnat/a-cbhama.ads b/gcc/ada/libgnat/a-cbhama.ads index b4d1105..0238548 100644 --- a/gcc/ada/libgnat/a-cbhama.ads +++ b/gcc/ada/libgnat/a-cbhama.ads @@ -107,7 +107,8 @@ package Ada.Containers.Bounded_Hashed_Maps is -- Equivalent to Length (Container) = 0 procedure Clear (Container : in out Map); - -- Removes all of the items from the map + -- Removes all of the items from the map. This will deallocate all memory + -- associated with this map. function Key (Position : Cursor) return Key_Type; -- Returns the key of the node designated by the cursor diff --git a/gcc/ada/libgnat/a-cbhase.ads b/gcc/ada/libgnat/a-cbhase.ads index 8f1b886..cb9150b 100644 --- a/gcc/ada/libgnat/a-cbhase.ads +++ b/gcc/ada/libgnat/a-cbhase.ads @@ -120,7 +120,8 @@ package Ada.Containers.Bounded_Hashed_Sets is -- Equivalent to Length (Container) = 0 procedure Clear (Container : in out Set); - -- Removes all of the items from the set + -- Removes all of the items from the set. This will deallocate all memory + -- associated with this set. function Element (Position : Cursor) return Element_Type; -- Returns the element of the node designated by the cursor diff --git a/gcc/ada/libgnat/a-chtgop.ads b/gcc/ada/libgnat/a-chtgop.ads index 3bb42fe..6ebb9e5 100644 --- a/gcc/ada/libgnat/a-chtgop.ads +++ b/gcc/ada/libgnat/a-chtgop.ads @@ -107,8 +107,9 @@ package Ada.Containers.Hash_Tables.Generic_Operations is procedure Clear (HT : in out Hash_Table_Type); -- Deallocates each node in hash table HT. (Note that it only deallocates - -- the nodes, not the buckets array.) Program_Error is raised if the hash - -- table is busy. + -- the nodes, not the buckets array. Also note that for bounded containers, + -- the buckets array is not dynamically allocated). Program_Error is raised + -- if the hash table is busy. procedure Move (Target, Source : in out Hash_Table_Type); -- Moves (not copies) the buckets array and nodes from Source to -- cgit v1.1 From 9415fcdad101c8c47f777345595d2306344cd9a1 Mon Sep 17 00:00:00 2001 From: Raphael Amiard Date: Thu, 19 Sep 2019 08:13:10 +0000 Subject: [Ada] Propagate documentation to formal bounded sets 2019-09-19 Raphael Amiard gcc/ada/ * libgnat/a-cfhase.ads (Set): Add comments to public primitives. From-SVN: r275937 --- gcc/ada/ChangeLog | 4 ++ gcc/ada/libgnat/a-cfhase.ads | 139 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index f9a8bfe..2e30229 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,9 @@ 2019-09-19 Raphael Amiard + * libgnat/a-cfhase.ads (Set): Add comments to public primitives. + +2019-09-19 Raphael Amiard + * libgnat/a-cbhama.ads, libgnat/a-cbhase.ads, libgnat/a-chtgop.ads (Clear): Refine comments diff --git a/gcc/ada/libgnat/a-cfhase.ads b/gcc/ada/libgnat/a-cfhase.ads index 5eb673a..3e72aef 100644 --- a/gcc/ada/libgnat/a-cfhase.ads +++ b/gcc/ada/libgnat/a-cfhase.ads @@ -355,10 +355,24 @@ is "="'Result = (E_Elements_Included (Elements (Left), Elements (Right)) and E_Elements_Included (Elements (Right), Elements (Left))); + -- For each element in Left, set equality attempts to find the equal + -- element in Right; if a search fails, then set equality immediately + -- returns False. The search works by calling Hash to find the bucket in + -- the Right set that corresponds to the Left element. If the bucket is + -- non-empty, the search calls the generic formal element equality operator + -- to compare the element (in Left) to the element of each node in the + -- bucket (in Right); the search terminates when a matching node in the + -- bucket is found, or the nodes in the bucket are exhausted. (Note that + -- element equality is called here, not Equivalent_Elements. Set equality + -- is the only operation in which element equality is used. Compare set + -- equality to Equivalent_Sets, which does call Equivalent_Elements.) function Equivalent_Sets (Left, Right : Set) return Boolean with Global => null, Post => Equivalent_Sets'Result = (Model (Left) = Model (Right)); + -- Similar to set equality, with the difference that the element in Left is + -- compared to the elements in Right using the generic formal + -- Equivalent_Elements operation instead of element equality. function To_Set (New_Item : Element_Type) return Set with Global => null, @@ -366,10 +380,14 @@ is M.Is_Singleton (Model (To_Set'Result), New_Item) and Length (To_Set'Result) = 1 and E.Get (Elements (To_Set'Result), 1) = New_Item; + -- Constructs a singleton set comprising New_Element. To_Set calls Hash to + -- determine the bucket for New_Item. function Capacity (Container : Set) return Count_Type with Global => null, Post => Capacity'Result = Container.Capacity; + -- Returns the current capacity of the set. Capacity is the maximum length + -- before which rehashing in guaranteed not to occur. procedure Reserve_Capacity (Container : in out Set; @@ -387,14 +405,21 @@ is (Elements (Container), Elements (Container)'Old) and E_Elements_Included (Elements (Container)'Old, Elements (Container)); + -- If the value of the Capacity actual parameter is less or equal to + -- Container.Capacity, then the operation has no effect. Otherwise it + -- raises Capacity_Error (as no expansion of capacity is possible for a + -- bounded form). function Is_Empty (Container : Set) return Boolean with Global => null, Post => Is_Empty'Result = (Length (Container) = 0); + -- Equivalent to Length (Container) = 0 procedure Clear (Container : in out Set) with Global => null, Post => Length (Container) = 0 and M.Is_Empty (Model (Container)); + -- Removes all of the items from the set. This will deallocate all memory + -- associated with this set. procedure Assign (Target : in out Set; Source : Set) with Global => null, @@ -407,6 +432,10 @@ is and E_Elements_Included (Elements (Target), Elements (Source)) and E_Elements_Included (Elements (Source), Elements (Target)); + -- If Target denotes the same object as Source, then the operation has no + -- effect. If the Target capacity is less than the Source length, then + -- Assign raises Capacity_Error. Otherwise, Assign clears Target and then + -- copies the (active) elements from Source to Target. function Copy (Source : Set; @@ -422,6 +451,14 @@ is Copy'Result.Capacity = Source.Capacity else Copy'Result.Capacity = Capacity); + -- Constructs a new set object whose elements correspond to Source. If the + -- Capacity parameter is 0, then the capacity of the result is the same as + -- the length of Source. If the Capacity parameter is equal or greater than + -- the length of Source, then the capacity of the result is the specified + -- value. Otherwise, Copy raises Capacity_Error. If the Modulus parameter + -- is 0, then the modulus of the result is the value returned by a call to + -- Default_Modulus with the capacity parameter determined as above; + -- otherwise the modulus of the result is the specified value. function Element (Container : Set; @@ -485,6 +522,8 @@ is and E_Elements_Included (Elements (Target), Elements (Source)'Old) and E_Elements_Included (Elements (Source)'Old, Elements (Target)); + -- Clears Target (if it's not empty), and then moves (not copies) the + -- buckets array and nodes from Source to Target. procedure Insert (Container : in out Set; @@ -541,6 +580,18 @@ is (Positions (Container), Positions (Container)'Old, Position)); + -- Conditionally inserts New_Item into the set. If New_Item is already in + -- the set, then Inserted returns False and Position designates the node + -- containing the existing element (which is not modified). If New_Item is + -- not already in the set, then Inserted returns True and Position + -- designates the newly-inserted node containing New_Item. The search for + -- an existing element works as follows. Hash is called to determine + -- New_Item's bucket; if the bucket is non-empty, then Equivalent_Elements + -- is called to compare New_Item to the element of each node in that + -- bucket. If the bucket is empty, or there were no equivalent elements in + -- the bucket, the search "fails" and the New_Item is inserted in the set + -- (and Inserted returns True); otherwise, the search "succeeds" (and + -- Inserted returns False). procedure Insert (Container : in out Set; New_Item : Element_Type) with Global => null, @@ -570,6 +621,13 @@ is (Positions (Container), Positions (Container)'Old, Find (Container, New_Item)); + -- Attempts to insert New_Item into the set, performing the usual insertion + -- search (which involves calling both Hash and Equivalent_Elements); if + -- the search succeeds (New_Item is equivalent to an element already in the + -- set, and so was not inserted), then this operation raises + -- Constraint_Error. (This version of Insert is similar to Replace, but + -- having the opposite exception behavior. It is intended for use when you + -- want to assert that the item is not already in the set.) procedure Include (Container : in out Set; New_Item : Element_Type) with Global => null, @@ -625,6 +683,13 @@ is (Positions (Container), Positions (Container)'Old, Find (Container, New_Item))); + -- Attempts to insert New_Item into the set. If an element equivalent to + -- New_Item is already in the set (the insertion search succeeded, and + -- hence New_Item was not inserted), then the value of New_Item is assigned + -- to the existing element. (This insertion operation only raises an + -- exception if cursor tampering occurs. It is intended for use when you + -- want to insert the item in the set, and you don't care whether an + -- equivalent element is already present.) procedure Replace (Container : in out Set; New_Item : Element_Type) with Global => null, @@ -648,6 +713,12 @@ is (Elements (Container)'Old, Elements (Container), P.Get (Positions (Container), Find (Container, New_Item))); + -- Searches for New_Item in the set; if the search fails (because an + -- equivalent element was not in the set), then it raises + -- Constraint_Error. Otherwise, the existing element is assigned the value + -- New_Item. (This is similar to Insert, but with the opposite exception + -- behavior. It is intended for use when you want to assert that the item + -- is already in the set.) procedure Exclude (Container : in out Set; Item : Element_Type) with Global => null, @@ -685,6 +756,13 @@ is (Positions (Container)'Old, Positions (Container), Find (Container, Item)'Old)); + -- Searches for Item in the set, and if found, removes its node from the + -- set and then deallocates it. The search works as follows. The operation + -- calls Hash to determine the item's bucket; if the bucket is not empty, + -- it calls Equivalent_Elements to compare Item to the element of each node + -- in the bucket. (This is the deletion analog of Include. It is intended + -- for use when you want to remove the item from the set, but don't care + -- whether the item is already in the set.) procedure Delete (Container : in out Set; Item : Element_Type) with Global => null, @@ -715,6 +793,12 @@ is (Positions (Container)'Old, Positions (Container), Find (Container, Item)'Old); + -- Searches for Item in the set (which involves calling both Hash and + -- Equivalent_Elements). If the search fails, then the operation raises + -- Constraint_Error. Otherwise it removes the node from the set and then + -- deallocates it. (This is the deletion analog of non-conditional + -- Insert. It is intended for use when you want to assert that the item is + -- already in the set.) procedure Delete (Container : in out Set; Position : in out Cursor) with Global => null, @@ -747,6 +831,10 @@ is (Positions (Container)'Old, Positions (Container), Position'Old); + -- Removes the node designated by Position from the set, and then + -- deallocates the node. The operation calls Hash to determine the bucket, + -- and then compares Position to each node in the bucket until there's a + -- match (it does not call Equivalent_Elements). procedure Union (Target : in out Set; Source : Set) with Global => null, @@ -795,6 +883,8 @@ is E_Right => Elements (Target), P_Left => Positions (Target)'Old, P_Right => Positions (Target)); + -- Iterates over the Source set, and conditionally inserts each element + -- into Target. function Union (Left, Right : Set) return Set with Global => null, @@ -831,6 +921,8 @@ is Model (Left), Elements (Right), Elements (Union'Result)); + -- The operation first copies the Left set to the result, and then iterates + -- over the Right set to conditionally insert each element into the result. function "or" (Left, Right : Set) return Set renames Union; @@ -866,6 +958,9 @@ is E_Right => Elements (Target)'Old, P_Left => Positions (Target), P_Right => Positions (Target)'Old); + -- Iterates over the Target set (calling First and Next), calling Find to + -- determine whether the element is in Source. If an equivalent element is + -- not found in Source, the element is deleted from Target. function Intersection (Left, Right : Set) return Set with Global => null, @@ -891,6 +986,9 @@ is and E_Elements_Included (Elements (Left), Model (Right), Elements (Intersection'Result)); + -- Iterates over the Left set, calling Find to determine whether the + -- element is in Right. If an equivalent element is found, it is inserted + -- into the result set. function "and" (Left, Right : Set) return Set renames Intersection; @@ -926,6 +1024,9 @@ is E_Right => Elements (Target)'Old, P_Left => Positions (Target), P_Right => Positions (Target)'Old); + -- Iterates over the Source (calling First and Next), calling Find to + -- determine whether the element is in Target. If an equivalent element is + -- found, it is deleted from Target. function Difference (Left, Right : Set) return Set with Global => null, @@ -955,6 +1056,9 @@ is (Elements (Left), Model (Difference'Result), Elements (Difference'Result)); + -- Iterates over the Left set, calling Find to determine whether the + -- element is in the Right set. If an equivalent element is not found, the + -- element is inserted into the result set. function "-" (Left, Right : Set) return Set renames Difference; @@ -995,6 +1099,10 @@ is and E_Elements_Included (Elements (Source), Model (Target), Elements (Target)); + -- The operation iterates over the Source set, searching for the element + -- in Target (calling Hash and Equivalent_Elements). If an equivalent + -- element is found, it is removed from Target; otherwise it is inserted + -- into Target. function Symmetric_Difference (Left, Right : Set) return Set with Global => null, @@ -1042,6 +1150,12 @@ is (Elements (Right), Model (Symmetric_Difference'Result), Elements (Symmetric_Difference'Result)); + -- The operation first iterates over the Left set. It calls Find to + -- determine whether the element is in the Right set. If no equivalent + -- element is found, the element from Left is inserted into the result. The + -- operation then iterates over the Right set, to determine whether the + -- element is in the Left set. If no equivalent element is found, the Right + -- element is inserted into the result. function "xor" (Left, Right : Set) return Set renames Symmetric_Difference; @@ -1050,10 +1164,21 @@ is Global => null, Post => Overlap'Result = not (M.No_Overlap (Model (Left), Model (Right))); + -- Iterates over the Left set (calling First and Next), calling Find to + -- determine whether the element is in the Right set. If an equivalent + -- element is found, the operation immediately returns True. The operation + -- returns False if the iteration over Left terminates without finding any + -- equivalent element in Right. function Is_Subset (Subset : Set; Of_Set : Set) return Boolean with Global => null, Post => Is_Subset'Result = (Model (Subset) <= Model (Of_Set)); + -- Iterates over Subset (calling First and Next), calling Find to determine + -- whether the element is in Of_Set. If no equivalent element is found in + -- Of_Set, the operation immediately returns False. The operation returns + -- True if the iteration over Subset terminates without finding an element + -- not in Of_Set (that is, every element in Subset is equivalent to an + -- element in Of_Set). function First (Container : Set) return Cursor with Global => null, @@ -1064,6 +1189,8 @@ is others => Has_Element (Container, First'Result) and P.Get (Positions (Container), First'Result) = 1); + -- Returns a cursor that designates the first non-empty bucket, by + -- searching from the beginning of the buckets array. function Next (Container : Set; Position : Cursor) return Cursor with Global => null, @@ -1079,6 +1206,12 @@ is Has_Element (Container, Next'Result) and then P.Get (Positions (Container), Next'Result) = P.Get (Positions (Container), Position) + 1); + -- Returns a cursor that designates the node that follows the current one + -- designated by Position. If Position designates the last node in its + -- bucket, the operation calls Hash to compute the index of this bucket, + -- and searches the buckets array for the first non-empty bucket, starting + -- from that index; otherwise, it simply follows the link to the next node + -- in the same bucket. procedure Next (Container : Set; Position : in out Cursor) with Global => null, @@ -1094,6 +1227,7 @@ is Has_Element (Container, Position) and then P.Get (Positions (Container), Position) = P.Get (Positions (Container), Position'Old) + 1); + -- Equivalent to Position := Next (Position) function Find (Container : Set; @@ -1118,6 +1252,11 @@ is and Equivalent_Elements (Element (Container, Find'Result), Item)); + -- Searches for Item in the set. Find calls Hash to determine the item's + -- bucket; if the bucket is not empty, it calls Equivalent_Elements to + -- compare Item to each element in the bucket. If the search succeeds, Find + -- returns a cursor designating the node containing the equivalent element; + -- otherwise, it returns No_Element. function Contains (Container : Set; Item : Element_Type) return Boolean with Global => null, -- cgit v1.1 From f56add9cb032cb4b22abbb33a7b867bfcbbc5f0d Mon Sep 17 00:00:00 2001 From: Bob Duff Date: Thu, 19 Sep 2019 08:13:15 +0000 Subject: [Ada] Memory leak with 'Range of a function call in a loop If a for loop starts with "for X in F (...)'Range loop", where F is a function returning an unconstrained array, then memory is leaked. This patch fixes that bug. Running these commands: gnatmake -q -f main.adb main On the following sources: with Text_IO; use Text_IO; package P is function Get_Objects return String; end P; package body P is function Get_Objects return String is begin return "xyzzy"; end Get_Objects; end P; with Text_IO; use Text_IO; pragma Warnings (Off, "an internal GNAT unit"); with System.Secondary_Stack; pragma Warnings (On, "an internal GNAT unit"); with P; use P; procedure Main is Max_Iterations : constant Integer := 1_000; procedure Leak_Call is begin for Id in Get_Objects'Range loop null; end loop; end Leak_Call; procedure SS_Info is new System.Secondary_Stack.SS_Info (Text_IO.Put_Line); begin for Iteration in 1 .. Max_Iterations loop Leak_Call; end loop; SS_Info; end Main; Should produce the following output: Secondary Stack information: Total size : 10240 bytes Current allocated space : 0 bytes Number of Chunks : 1 Default size of Chunks : 10240 2019-09-19 Bob Duff gcc/ada/ * sem_attr.adb (Resolve_Attribute): Make sure the secondary stack is properly managed in the case of a 'Range attribute in a loop. From-SVN: r275938 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/sem_attr.adb | 10 ++++++++++ 2 files changed, 16 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 2e30229..b3e94db 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Bob Duff + + * sem_attr.adb (Resolve_Attribute): Make sure the secondary + stack is properly managed in the case of a 'Range attribute in a + loop. + 2019-09-19 Raphael Amiard * libgnat/a-cfhase.ads (Set): Add comments to public primitives. diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index 4c6cba6..95de2e4 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -11570,6 +11570,16 @@ package body Sem_Attr is begin if not Is_Entity_Name (P) or else not Is_Type (Entity (P)) then Resolve (P); + + -- If the prefix is a function call returning on the secondary + -- stack, we must make sure to mark/release the stack. + + if Nkind (P) = N_Function_Call + and then Nkind (Parent (N)) = N_Loop_Parameter_Specification + and then Requires_Transient_Scope (Etype (P)) + then + Set_Uses_Sec_Stack (Scope (Current_Scope)); + end if; end if; Dims := Expressions (N); -- cgit v1.1 From 890cde5319470afab7e96e3b7953075681c015f5 Mon Sep 17 00:00:00 2001 From: Ed Schonberg Date: Thu, 19 Sep 2019 08:13:20 +0000 Subject: [Ada] Crash on predicate in full view in a generic unit This patch fixes a compiler abort on a dynamic predicate applied to the full view of a type in a generic package declaration, when the expression for the predicate is a conditionql expression that contains references to components of the full view of the type. 2019-09-19 Ed Schonberg gcc/ada/ * sem_ch13.adb (Check_Aspect_At_End_Of_Declarations): Simplify handling of expressions in predicates when the context is a generic unit. gcc/testsuite/ * gnat.dg/predicate14.adb, gnat.dg/predicate14.ads: New testcase. From-SVN: r275939 --- gcc/ada/ChangeLog | 6 ++++ gcc/ada/sem_ch13.adb | 32 +++++++++++++++----- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gnat.dg/predicate14.adb | 4 +++ gcc/testsuite/gnat.dg/predicate14.ads | 56 +++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/predicate14.adb create mode 100644 gcc/testsuite/gnat.dg/predicate14.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index b3e94db..2caf52d 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Ed Schonberg + + * sem_ch13.adb (Check_Aspect_At_End_Of_Declarations): Simplify + handling of expressions in predicates when the context is a + generic unit. + 2019-09-19 Bob Duff * sem_attr.adb (Resolve_Attribute): Make sure the secondary diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb index ef9f965..354d068 100644 --- a/gcc/ada/sem_ch13.adb +++ b/gcc/ada/sem_ch13.adb @@ -9374,17 +9374,22 @@ package body Sem_Ch13 is else -- In a generic context freeze nodes are not always generated, so - -- analyze the expression now. If the aspect is for a type, this - -- makes its potential components accessible. + -- analyze the expression now. If the aspect is for a type, we must + -- also make its potential components accessible. if not Analyzed (Freeze_Expr) and then Inside_A_Generic then if A_Id = Aspect_Dynamic_Predicate or else A_Id = Aspect_Predicate - or else A_Id = Aspect_Priority then Push_Type (Ent); - Preanalyze_Spec_Expression (Freeze_Expr, T); + Preanalyze_Spec_Expression (Freeze_Expr, Standard_Boolean); + Pop_Type (Ent); + + elsif A_Id = Aspect_Priority then + Push_Type (Ent); + Preanalyze_Spec_Expression (Freeze_Expr, Any_Integer); Pop_Type (Ent); + else Preanalyze (Freeze_Expr); end if; @@ -9395,12 +9400,23 @@ package body Sem_Ch13 is Set_Parent (End_Decl_Expr, ASN); - -- In a generic context the aspect expressions have not been - -- preanalyzed, so do it now. There are no conformance checks - -- to perform in this case. + -- In a generic context the original aspect expressions have not + -- been preanalyzed, so do it now. There are no conformance checks + -- to perform in this case. As before, we have to make components + -- visible for aspects that may reference them. if No (T) then - Check_Aspect_At_Freeze_Point (ASN); + if A_Id = Aspect_Dynamic_Predicate + or else A_Id = Aspect_Predicate + or else A_Id = Aspect_Priority + then + Push_Type (Ent); + Check_Aspect_At_Freeze_Point (ASN); + Pop_Type (Ent); + + else + Check_Aspect_At_Freeze_Point (ASN); + end if; return; -- The default values attributes may be defined in the private part, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 69e7854..7cde63d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Ed Schonberg + + * gnat.dg/predicate14.adb, gnat.dg/predicate14.ads: New + testcase. + 2019-09-19 Eric Botcazou * gnat.dg/generic_inst13.adb, diff --git a/gcc/testsuite/gnat.dg/predicate14.adb b/gcc/testsuite/gnat.dg/predicate14.adb new file mode 100644 index 0000000..3caf7a4 --- /dev/null +++ b/gcc/testsuite/gnat.dg/predicate14.adb @@ -0,0 +1,4 @@ +-- { dg-do compile } +package body Predicate14 is + procedure Dummy is null; +end Predicate14; diff --git a/gcc/testsuite/gnat.dg/predicate14.ads b/gcc/testsuite/gnat.dg/predicate14.ads new file mode 100644 index 0000000..9ed6c86 --- /dev/null +++ b/gcc/testsuite/gnat.dg/predicate14.ads @@ -0,0 +1,56 @@ +generic +package Predicate14 with + SPARK_Mode +is + + type Field_Type is (F_Initial, F_Payload, F_Final); + + type State_Type is (S_Valid, S_Invalid); + + type Cursor_Type (State : State_Type := S_Invalid) is private; + + type Cursors_Type is array (Field_Type) of Cursor_Type; + + type Context_Type is private; + + type Result_Type (Field : Field_Type := F_Initial) is + record + case Field is + when F_Initial | F_Final => + null; + when F_Payload => + Value : Integer; + end case; + end record; + + function Valid_Context (Context : Context_Type) return Boolean; + +private + + function Valid_Type (Result : Result_Type) return Boolean is + (Result.Field = F_Initial); + + type Cursor_Type (State : State_Type := S_Invalid) is + record + case State is + when S_Valid => + Value : Result_Type; + when S_Invalid => + null; + end case; + end record + with Dynamic_Predicate => + (if State = S_Valid then Valid_Type (Value)); + + type Context_Type is + record + Field : Field_Type := F_Initial; + Cursors : Cursors_Type := (others => (State => S_Invalid)); + end record; + + function Valid_Context (Context : Context_Type) return Boolean is + (for all F in Context.Cursors'Range => + (Context.Cursors (F).Value.Field = F)); + + procedure Dummy; +end Predicate14; \ No newline at end of file -- cgit v1.1 From c4f372c54f24fd24f1092fb6a09c31c7733ce8cc Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Thu, 19 Sep 2019 08:13:25 +0000 Subject: [Ada] Remove duplicated routines for getting homonym number Routines Homonym_Number and Get_Homonym_Number were exactly the same, except for minor style differences. Keep the one in Exp_Util; remove the one in Exp_Dbug. No test attached, because semantics is unaffected. 2019-09-19 Piotr Trojanek gcc/ada/ * exp_dbug.ads, exp_dbug.adb (Get_Homonym_Number): Remove. (Append_Homonym_Number): Use Homonym_Number instead of Get_Homonym_Number. * exp_util.ads, exp_util.adb (Homonym_Number): Mirror style of the removed Get_Homonym_Number routine, i.e. initialize local objects at declaration and refine the type of result. * sem_util.adb (Add_Homonym_Suffix): Use Homonym_Number instead of Get_Homonym_Number. From-SVN: r275940 --- gcc/ada/ChangeLog | 11 +++++++++++ gcc/ada/exp_dbug.adb | 23 ++--------------------- gcc/ada/exp_dbug.ads | 4 ---- gcc/ada/exp_util.adb | 8 +++----- gcc/ada/exp_util.ads | 2 +- gcc/ada/sem_util.adb | 3 +-- 6 files changed, 18 insertions(+), 33 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 2caf52d..1f3128e 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,14 @@ +2019-09-19 Piotr Trojanek + + * exp_dbug.ads, exp_dbug.adb (Get_Homonym_Number): Remove. + (Append_Homonym_Number): Use Homonym_Number instead of + Get_Homonym_Number. + * exp_util.ads, exp_util.adb (Homonym_Number): Mirror style of + the removed Get_Homonym_Number routine, i.e. initialize local + objects at declaration and refine the type of result. + * sem_util.adb (Add_Homonym_Suffix): Use Homonym_Number instead + of Get_Homonym_Number. + 2019-09-19 Ed Schonberg * sem_ch13.adb (Check_Aspect_At_End_Of_Declarations): Simplify diff --git a/gcc/ada/exp_dbug.adb b/gcc/ada/exp_dbug.adb index c2d2318..5f65098 100644 --- a/gcc/ada/exp_dbug.adb +++ b/gcc/ada/exp_dbug.adb @@ -27,6 +27,7 @@ with Alloc; with Atree; use Atree; with Debug; use Debug; with Einfo; use Einfo; +with Exp_Util; use Exp_Util; with Nlists; use Nlists; with Nmake; use Nmake; with Opt; use Opt; @@ -224,7 +225,7 @@ package body Exp_Dbug is Homonym_Numbers (Homonym_Len) := '_'; end if; - Add_Nat_To_H (Get_Homonym_Number (E)); + Add_Nat_To_H (Homonym_Number (E)); end if; end Append_Homonym_Number; @@ -1054,26 +1055,6 @@ package body Exp_Dbug is end loop; end Build_Subprogram_Instance_Renamings; - ------------------------ - -- Get_Homonym_Number -- - ------------------------ - - function Get_Homonym_Number (E : Entity_Id) return Pos is - H : Entity_Id := Homonym (E); - Nr : Pos := 1; - - begin - while Present (H) loop - if Scope (H) = Scope (E) then - Nr := Nr + 1; - end if; - - H := Homonym (H); - end loop; - - return Nr; - end Get_Homonym_Number; - ------------------------------------ -- Get_Secondary_DT_External_Name -- ------------------------------------ diff --git a/gcc/ada/exp_dbug.ads b/gcc/ada/exp_dbug.ads index ac40a40..93b9783 100644 --- a/gcc/ada/exp_dbug.ads +++ b/gcc/ada/exp_dbug.ads @@ -460,10 +460,6 @@ package Exp_Dbug is -- Subprograms for Handling Qualification -- -------------------------------------------- - function Get_Homonym_Number (E : Entity_Id) return Pos; - -- Return the homonym number for E, which is its position in the homonym - -- chain starting at 1. This is exported for use in GNATprove. - procedure Qualify_Entity_Names (N : Node_Id); -- Given a node N, that represents a block, subprogram body, or package -- body or spec, or protected or task type, sets a fully qualified name diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 06f5cc3..905e3f4 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -6795,13 +6795,11 @@ package body Exp_Util is -- Homonym_Number -- -------------------- - function Homonym_Number (Subp : Entity_Id) return Nat is - Count : Nat; - Hom : Entity_Id; + function Homonym_Number (Subp : Entity_Id) return Pos is + Hom : Entity_Id := Homonym (Subp); + Count : Pos := 1; begin - Count := 1; - Hom := Homonym (Subp); while Present (Hom) loop if Scope (Hom) = Scope (Subp) then Count := Count + 1; diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads index ab33e8d..02fb233 100644 --- a/gcc/ada/exp_util.ads +++ b/gcc/ada/exp_util.ads @@ -734,7 +734,7 @@ package Exp_Util is -- pragmas at the start of the package declaration contains -- pragma Annotate (GNATprove, External_Axiomatization); - function Homonym_Number (Subp : Entity_Id) return Nat; + function Homonym_Number (Subp : Entity_Id) return Pos; -- Here subp is the entity for a subprogram. This routine returns the -- homonym number used to disambiguate overloaded subprograms in the same -- scope (the number is used as part of constructed names to make sure that diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index 1bcda5f..b276fd2 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -33,7 +33,6 @@ with Elists; use Elists; with Errout; use Errout; with Erroutc; use Erroutc; with Exp_Ch11; use Exp_Ch11; -with Exp_Dbug; use Exp_Dbug; with Exp_Util; use Exp_Util; with Fname; use Fname; with Freeze; use Freeze; @@ -26314,7 +26313,7 @@ package body Sem_Util is if Has_Homonym (U) then declare - N : constant Pos := Get_Homonym_Number (U); + N : constant Pos := Homonym_Number (U); S : constant String := N'Img; begin if N > 1 then -- cgit v1.1 From 1dd3915be108e6dcd7adfa01de6096419092a5de Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:13:29 +0000 Subject: [Ada] Streamline comparison for equality of 2-element arrays In the general case, the comparison for equality of array objects is implemented by a local function that contains, among other things, a loop running over the elements, comparing them one by one and exiting as soon as an element is not the same in the two array objects. For the specific case of constrained 2-element arrays, this is rather heavy and unnecessarily obfuscates the control flow of the program, so this change implements a simple conjunction of comparisons for it. Running these commands: gcc -c p.ads -O -gnatD grep loop p.ads.dg On the following sources: package P is type Rec is record Re : Float; Im : Float; end record; type Arr is array (1 .. 2) of Rec; function Equal (A, B : Arr) return Boolean is (A = B); end P; Should execute silently. 2019-09-19 Eric Botcazou gcc/ada/ * exp_ch4.adb (Expand_Array_Equality): If optimization is enabled, generate a simple conjunction of comparisons for the specific case of constrained 1-dimensional 2-element arrays. Fix formatting. From-SVN: r275941 --- gcc/ada/ChangeLog | 7 +++ gcc/ada/exp_ch4.adb | 124 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 96 insertions(+), 35 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 1f3128e..37576aa 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Eric Botcazou + + * exp_ch4.adb (Expand_Array_Equality): If optimization is + enabled, generate a simple conjunction of comparisons for the + specific case of constrained 1-dimensional 2-element arrays. + Fix formatting. + 2019-09-19 Piotr Trojanek * exp_dbug.ads, exp_dbug.adb (Get_Homonym_Number): Remove. diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index a20469c..82145b4 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -1582,7 +1582,7 @@ package body Exp_Ch4 is Index_List1 : constant List_Id := New_List; Index_List2 : constant List_Id := New_List; - Actuals : List_Id; + First_Idx : Node_Id; Formals : List_Id; Func_Name : Entity_Id; Func_Body : Node_Id; @@ -1594,6 +1594,10 @@ package body Exp_Ch4 is Rtyp : Entity_Id; -- The parameter types to be used for the formals + New_Lhs : Node_Id; + New_Rhs : Node_Id; + -- The LHS and RHS converted to the parameter types + function Arr_Attr (Arr : Entity_Id; Nam : Name_Id; @@ -1962,6 +1966,82 @@ package body Exp_Ch4 is pragma Assert (Ltyp = Rtyp); end if; + -- If the array type is distinct from the type of the arguments, it + -- is the full view of a private type. Apply an unchecked conversion + -- to ensure that analysis of the code below succeeds. + + if No (Etype (Lhs)) + or else Base_Type (Etype (Lhs)) /= Base_Type (Ltyp) + then + New_Lhs := OK_Convert_To (Ltyp, Lhs); + else + New_Lhs := Lhs; + end if; + + if No (Etype (Rhs)) + or else Base_Type (Etype (Rhs)) /= Base_Type (Rtyp) + then + New_Rhs := OK_Convert_To (Rtyp, Rhs); + else + New_Rhs := Rhs; + end if; + + First_Idx := First_Index (Ltyp); + + -- If optimization is enabled and the array boils down to a couple of + -- consecutive elements, generate a simple conjunction of comparisons + -- which should be easier to optimize by the code generator. + + if Optimization_Level > 0 + and then Ltyp = Rtyp + and then Is_Constrained (Ltyp) + and then Number_Dimensions (Ltyp) = 1 + and then Nkind (First_Idx) = N_Range + and then Compile_Time_Known_Value (Low_Bound (First_Idx)) + and then Compile_Time_Known_Value (High_Bound (First_Idx)) + and then Expr_Value (High_Bound (First_Idx)) = + Expr_Value (Low_Bound (First_Idx)) + 1 + then + declare + Ctyp : constant Entity_Id := Component_Type (Ltyp); + L, R : Node_Id; + TestL, TestH : Node_Id; + Index_List : List_Id; + + begin + Index_List := New_List (New_Copy_Tree (Low_Bound (First_Idx))); + + L := + Make_Indexed_Component (Loc, + Prefix => New_Copy_Tree (New_Lhs), + Expressions => Index_List); + + R := + Make_Indexed_Component (Loc, + Prefix => New_Copy_Tree (New_Rhs), + Expressions => Index_List); + + TestL := Expand_Composite_Equality (Nod, Ctyp, L, R, Bodies); + + Index_List := New_List (New_Copy_Tree (High_Bound (First_Idx))); + + L := + Make_Indexed_Component (Loc, + Prefix => New_Lhs, + Expressions => Index_List); + + R := + Make_Indexed_Component (Loc, + Prefix => New_Rhs, + Expressions => Index_List); + + TestH := Expand_Composite_Equality (Nod, Ctyp, L, R, Bodies); + + return + Make_And_Then (Loc, Left_Opnd => TestL, Right_Opnd => TestH); + end; + end if; + -- Build list of formals for function Formals := New_List ( @@ -2004,46 +2084,20 @@ package body Exp_Ch4 is Make_Simple_Return_Statement (Loc, Expression => New_Occurrence_Of (Standard_False, Loc)))), - Handle_One_Dimension (1, First_Index (Ltyp)), + Handle_One_Dimension (1, First_Idx), Make_Simple_Return_Statement (Loc, Expression => New_Occurrence_Of (Standard_True, Loc))))); - Set_Has_Completion (Func_Name, True); - Set_Is_Inlined (Func_Name); - - -- If the array type is distinct from the type of the arguments, it - -- is the full view of a private type. Apply an unchecked conversion - -- to ensure that analysis of the call succeeds. - - declare - L, R : Node_Id; - - begin - L := Lhs; - R := Rhs; - - if No (Etype (Lhs)) - or else Base_Type (Etype (Lhs)) /= Base_Type (Ltyp) - then - L := OK_Convert_To (Ltyp, Lhs); - end if; - - if No (Etype (Rhs)) - or else Base_Type (Etype (Rhs)) /= Base_Type (Rtyp) - then - R := OK_Convert_To (Rtyp, Rhs); - end if; - - Actuals := New_List (L, R); - end; + Set_Has_Completion (Func_Name, True); + Set_Is_Inlined (Func_Name); - Append_To (Bodies, Func_Body); + Append_To (Bodies, Func_Body); - return - Make_Function_Call (Loc, - Name => New_Occurrence_Of (Func_Name, Loc), - Parameter_Associations => Actuals); + return + Make_Function_Call (Loc, + Name => New_Occurrence_Of (Func_Name, Loc), + Parameter_Associations => New_List (New_Lhs, New_Rhs)); end Expand_Array_Equality; ----------------------------- -- cgit v1.1 From 143df1f9aa4e829907d4e300a0006783fcbba71b Mon Sep 17 00:00:00 2001 From: Gary Dismukes Date: Thu, 19 Sep 2019 08:13:34 +0000 Subject: [Ada] Suppress GNAT FE up-level reference transformation for GNAT-LLVM In the case of GNAT-LLVM, the GNAT FE no longer does expansion of up-level references identified by the subprogram unnesting machinery into activation record references. This is now only done by the FE when generating C code. This expansion is already taken care of by the gnat-llvm middle phase, so there's no benefit to also doing it in the front end. 2019-09-19 Gary Dismukes gcc/ada/ * exp_unst.adb (Unnest_Subprogram): Bypass the transformation of up-level references unless Opt.Generate_C_Code is enabled. From-SVN: r275942 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/exp_unst.adb | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 37576aa..86e9f07 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Gary Dismukes + + * exp_unst.adb (Unnest_Subprogram): Bypass the transformation of + up-level references unless Opt.Generate_C_Code is enabled. + 2019-09-19 Eric Botcazou * exp_ch4.adb (Expand_Array_Equality): If optimization is diff --git a/gcc/ada/exp_unst.adb b/gcc/ada/exp_unst.adb index 8c492bc..b25b449 100644 --- a/gcc/ada/exp_unst.adb +++ b/gcc/ada/exp_unst.adb @@ -2177,11 +2177,14 @@ package body Exp_Unst is -- not need rewriting (e.g. the appearence in a conversion). -- Also ignore if no reference was specified or if the rewriting -- has already been done (this can happen if the N_Identifier - -- occurs more than one time in the tree). + -- occurs more than one time in the tree). Also ignore references + -- when not generating C code (in particular for the case of LLVM, + -- since GNAT-LLVM will handle the processing for up-level refs). if No (UPJ.Ref) or else not Is_Entity_Name (UPJ.Ref) or else not Present (Entity (UPJ.Ref)) + or else not Opt.Generate_C_Code then goto Continue; end if; -- cgit v1.1 From d8ec2787e0ba7b508c968c330b04575d2cbf97d7 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:13:38 +0000 Subject: [Ada] Implement Machine_Rounding attribute in line when possible GNAT implements Machine_Rounding as an alias for Rounding but, whereas the implementation of the latter is in line when possible, that of the former is always out of line, which is not aligned with the intent of the Ada RM. This changes the compiler to using for Machine_Rounding the same in line implementation as Rounding when possible. Running these commands: gcc -c f.adb -gnatD grep system f.adb.dg On the following sources: function F (Val : Float) return Integer is begin return Integer (Float'Machine_Rounding (Val)); end; Should execute silently. 2019-09-19 Eric Botcazou gcc/ada/ * exp_attr.adb (Is_Inline_Floating_Point_Attribute): Treat Machine_Rounding as an alias for Rounding. * sem_res.adb (Simplify_Type_Conversion): Likewise. From-SVN: r275943 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/exp_attr.adb | 12 ++++++------ gcc/ada/sem_res.adb | 4 +++- 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 86e9f07..289213e 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Eric Botcazou + + * exp_attr.adb (Is_Inline_Floating_Point_Attribute): Treat + Machine_Rounding as an alias for Rounding. + * sem_res.adb (Simplify_Type_Conversion): Likewise. + 2019-09-19 Gary Dismukes * exp_unst.adb (Unnest_Subprogram): Bypass the transformation of diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index a8e68bb..817e7ef 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -8360,13 +8360,13 @@ package body Exp_Attr is return False; end if; - -- Here we are in the integer conversion context + -- Here we are in the integer conversion context. We reuse Rounding for + -- Machine_Rounding as System.Fat_Gen, which is a permissible behavior. - -- Very probably we should also recognize the cases of Machine_Rounding - -- and unbiased rounding in this conversion context, but the back end is - -- not yet prepared to handle these cases ??? - - return Id = Attribute_Rounding or else Id = Attribute_Truncation; + return + Id = Attribute_Rounding + or else Id = Attribute_Machine_Rounding + or else Id = Attribute_Truncation; end Is_Inline_Floating_Point_Attribute; end Exp_Attr; diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb index 38de57d..28d1352 100644 --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -12439,7 +12439,8 @@ package body Sem_Res is -- ityp (x) -- with the Float_Truncate flag set to False or True respectively, - -- which is more efficient. + -- which is more efficient. We reuse Rounding for Machine_Rounding + -- as System.Fat_Gen, which is a permissible behavior. if Is_Floating_Point_Type (Opnd_Typ) and then @@ -12448,6 +12449,7 @@ package body Sem_Res is and then Conversion_OK (N))) and then Nkind (Operand) = N_Attribute_Reference and then Nam_In (Attribute_Name (Operand), Name_Rounding, + Name_Machine_Rounding, Name_Truncation) then declare -- cgit v1.1 From f5766e3b541a9fb2d4365281f5c9da4f80e9622c Mon Sep 17 00:00:00 2001 From: Yannick Moy Date: Thu, 19 Sep 2019 08:13:43 +0000 Subject: [Ada] Move SPARK borrow-checker to gnat2why codebase Unit sem_spark was implementing the borrow-checker for the support of ownership pointers in SPARK. It has been moved to gnat2why codebase to facilitate its evolution and allow the more powerful flow analysis to provide its results for better analysis on pointers. 2019-09-19 Yannick Moy gcc/ada/ * gcc-interface/Make-lang.in: Remove references to sem_spark. * sem_spark.adb, sem_spark.ads: Remove unit. From-SVN: r275944 --- gcc/ada/ChangeLog | 5 + gcc/ada/gcc-interface/Make-lang.in | 1 - gcc/ada/sem_spark.adb | 6179 ------------------------------------ gcc/ada/sem_spark.ads | 177 -- 4 files changed, 5 insertions(+), 6357 deletions(-) delete mode 100644 gcc/ada/sem_spark.adb delete mode 100644 gcc/ada/sem_spark.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 289213e..6fa4edf 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Yannick Moy + + * gcc-interface/Make-lang.in: Remove references to sem_spark. + * sem_spark.adb, sem_spark.ads: Remove unit. + 2019-09-19 Eric Botcazou * exp_attr.adb (Is_Inline_Floating_Point_Attribute): Treat diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index df5f0b3..276c41c 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -450,7 +450,6 @@ GNAT_ADA_OBJS = \ ada/sem_res.o \ ada/sem_scil.o \ ada/sem_smem.o \ - ada/sem_spark.o \ ada/sem_type.o \ ada/sem_util.o \ ada/sem_warn.o \ diff --git a/gcc/ada/sem_spark.adb b/gcc/ada/sem_spark.adb deleted file mode 100644 index e4a8b3e..0000000 --- a/gcc/ada/sem_spark.adb +++ /dev/null @@ -1,6179 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT COMPILER COMPONENTS -- --- -- --- S E M _ S P A R K -- --- -- --- B o d y -- --- -- --- Copyright (C) 2017-2019, Free Software Foundation, Inc. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT 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 distributed with GNAT; see file COPYING3. If not, go to -- --- http://www.gnu.org/licenses for a complete copy of the license. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - -with Atree; use Atree; -with Einfo; use Einfo; -with Errout; use Errout; -with Namet; use Namet; -with Nlists; use Nlists; -with Opt; use Opt; -with Osint; use Osint; -with Sem_Prag; use Sem_Prag; -with Sem_Util; use Sem_Util; -with Sem_Aux; use Sem_Aux; -with Sinfo; use Sinfo; -with Snames; use Snames; -with Treepr; use Treepr; - -with Ada.Unchecked_Deallocation; -with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables; - -package body Sem_SPARK is - - --------------------------------------------------- - -- Handling of Permissions Associated with Paths -- - --------------------------------------------------- - - package Permissions is - Elaboration_Context_Max : constant := 1009; - -- The hash range - - type Elaboration_Context_Index is range 0 .. Elaboration_Context_Max - 1; - - function Elaboration_Context_Hash - (Key : Entity_Id) return Elaboration_Context_Index; - -- The hash function - - -- Permission type associated with paths. These are related to but not - -- the same as the states associated with names used in SPARK RM 3.10: - -- Unrestricted, Observed, Borrowed, Moved. When ownership rules lead to - -- a state change for a name, this may correspond to multiple permission - -- changes for the paths corresponding to the name, its prefixes, and - -- its extensions. For example, when an object is assigned to, the - -- corresponding name gets into state Moved, while the path for the name - -- gets permission Write_Only as well as every prefix of the name, and - -- every suffix gets permission No_Access. - - type Perm_Kind_Option is - (None, - -- Special value used when no permission is passed around - - No_Access, - -- The path cannot be accessed for reading or writing. This is the - -- case for the path of a name in the Borrowed state. - - Read_Only, - -- The path can only be accessed for reading. This is the case for - -- the path of a name in the Observed state. - - Read_Write, - -- The path can be accessed for both reading and writing. This is the - -- case for the path of a name in the Unrestricted state. - - Write_Only - -- The path can only be accessed for writing. This is the case for - -- the path of a name in the Moved state. - ); - - subtype Perm_Kind is Perm_Kind_Option range No_Access .. Write_Only; - subtype Read_Perm is Perm_Kind range Read_Only .. Read_Write; - subtype Write_Perm is Perm_Kind range Read_Write .. Write_Only; - - type Perm_Tree_Wrapper; - - type Perm_Tree_Access is access Perm_Tree_Wrapper; - -- A tree of permissions is defined, where the root is a whole object - -- and tree branches follow access paths in memory. As Perm_Tree is a - -- discriminated record, a wrapper type is used for the access type - -- designating a subtree, to make it unconstrained so that it can be - -- updated. - - -- Nodes in the permission tree are of different kinds - - type Path_Kind is - (Entire_Object, -- Scalar object, or folded object of any type - Reference, -- Unfolded object of access type - Array_Component, -- Unfolded object of array type - Record_Component -- Unfolded object of record type - ); - - package Perm_Tree_Maps is new Simple_HTable - (Header_Num => Elaboration_Context_Index, - Key => Entity_Id, - Element => Perm_Tree_Access, - No_Element => null, - Hash => Elaboration_Context_Hash, - Equal => "="); - -- The instantation of a hash table, with keys being entities and values - -- being pointers to permission trees. This is used to define global - -- environment permissions (entities in that case are stand-alone - -- objects or formal parameters), as well as the permissions for the - -- extensions of a Record_Component node (entities in that case are - -- record components). - - -- The definition of permission trees. This is a tree, which has a - -- permission at each node, and depending on the type of the node, can - -- have zero, one, or more children reached through an access to tree. - - type Perm_Tree (Kind : Path_Kind := Entire_Object) is record - Permission : Perm_Kind; - -- Permission at this level in the path - - Is_Node_Deep : Boolean; - -- Whether this node is of a "deep" type, i.e. an access type or a - -- composite type containing access type subcomponents. This - -- corresponds to both "observing" and "owning" types in SPARK RM - -- 3.10. To be used when moving the path. - - Explanation : Node_Id; - -- Node that can be used in an explanation for a permission mismatch - - case Kind is - -- An entire object is either a leaf (an object which cannot be - -- extended further in a path) or a subtree in folded form (which - -- could later be unfolded further in another kind of node). The - -- field Children_Permission specifies a permission for every - -- extension of that node if that permission is different from the - -- node's permission. - - when Entire_Object => - Children_Permission : Perm_Kind; - - -- Unfolded path of access type. The permission of the object - -- pointed to is given in Get_All. - - when Reference => - Get_All : Perm_Tree_Access; - - -- Unfolded path of array type. The permission of elements is - -- given in Get_Elem. - - when Array_Component => - Get_Elem : Perm_Tree_Access; - - -- Unfolded path of record type. The permission of the components - -- is given in Component. - - when Record_Component => - Component : Perm_Tree_Maps.Instance; - end case; - end record; - - type Perm_Tree_Wrapper is record - Tree : Perm_Tree; - end record; - -- We use this wrapper in order to have unconstrained discriminants - - type Perm_Env is new Perm_Tree_Maps.Instance; - -- The definition of a permission environment for the analysis. This is - -- just a hash table from entities to permission trees. - - type Perm_Env_Access is access Perm_Env; - -- Access to permission environments - - package Env_Maps is new Simple_HTable - (Header_Num => Elaboration_Context_Index, - Key => Entity_Id, - Element => Perm_Env_Access, - No_Element => null, - Hash => Elaboration_Context_Hash, - Equal => "="); - -- The instantiation of a hash table whose elements are permission - -- environments. This hash table is used to save the environments at - -- the entry of each loop, with the key being the loop label. - - type Env_Backups is new Env_Maps.Instance; - -- The type defining the hash table saving the environments at the entry - -- of each loop. - - package Variable_Maps is new Simple_HTable - (Header_Num => Elaboration_Context_Index, - Key => Entity_Id, - Element => Node_Id, - No_Element => Empty, - Hash => Elaboration_Context_Hash, - Equal => "="); - - type Variable_Mapping is new Variable_Maps.Instance; - -- Mapping from variables to nodes denoting paths that are observed or - -- borrowed by the variable. - - -------------------- - -- Simple Getters -- - -------------------- - - -- Simple getters to avoid having .all.Tree.Field everywhere. Of course, - -- that's only for the top access, as otherwise this reverses the order - -- in accesses visually. - - function Children_Permission (T : Perm_Tree_Access) return Perm_Kind; - function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance; - function Explanation (T : Perm_Tree_Access) return Node_Id; - function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access; - function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access; - function Is_Node_Deep (T : Perm_Tree_Access) return Boolean; - function Kind (T : Perm_Tree_Access) return Path_Kind; - function Permission (T : Perm_Tree_Access) return Perm_Kind; - - ----------------------- - -- Memory Management -- - ----------------------- - - procedure Copy_Env - (From : Perm_Env; - To : in out Perm_Env); - -- Procedure to copy a permission environment - - procedure Move_Env (From, To : in out Perm_Env); - -- Procedure to move a permission environment. It frees To, moves From - -- in To and sets From to Nil. - - procedure Move_Variable_Mapping (From, To : in out Variable_Mapping); - -- Move a variable mapping, freeing memory as needed and resetting the - -- source mapping. - - procedure Copy_Tree (From, To : Perm_Tree_Access); - -- Procedure to copy a permission tree - - procedure Free_Env (PE : in out Perm_Env); - -- Procedure to free a permission environment - - procedure Free_Tree (PT : in out Perm_Tree_Access); - -- Procedure to free a permission tree - - -------------------- - -- Error Messages -- - -------------------- - - procedure Perm_Mismatch - (N : Node_Id; - Exp_Perm : Perm_Kind; - Act_Perm : Perm_Kind; - Expl : Node_Id; - Forbidden_Perm : Boolean := False); - -- Issues a continuation error message about a mismatch between a - -- desired permission Exp_Perm and a permission obtained Act_Perm. N - -- is the node on which the error is reported. - - end Permissions; - - package body Permissions is - - ------------------------- - -- Children_Permission -- - ------------------------- - - function Children_Permission (T : Perm_Tree_Access) return Perm_Kind is - begin - return T.all.Tree.Children_Permission; - end Children_Permission; - - --------------- - -- Component -- - --------------- - - function Component (T : Perm_Tree_Access) return Perm_Tree_Maps.Instance - is - begin - return T.all.Tree.Component; - end Component; - - -------------- - -- Copy_Env -- - -------------- - - procedure Copy_Env (From : Perm_Env; To : in out Perm_Env) is - Comp_From : Perm_Tree_Access; - Key_From : Perm_Tree_Maps.Key_Option; - Son : Perm_Tree_Access; - - begin - Free_Env (To); - Key_From := Get_First_Key (From); - while Key_From.Present loop - Comp_From := Get (From, Key_From.K); - pragma Assert (Comp_From /= null); - - Son := new Perm_Tree_Wrapper; - Copy_Tree (Comp_From, Son); - - Set (To, Key_From.K, Son); - Key_From := Get_Next_Key (From); - end loop; - end Copy_Env; - - --------------- - -- Copy_Tree -- - --------------- - - procedure Copy_Tree (From, To : Perm_Tree_Access) is - begin - -- Copy the direct components of the tree - - To.all := From.all; - - -- Now reallocate access components for a deep copy of the tree - - case Kind (From) is - when Entire_Object => - null; - - when Reference => - To.all.Tree.Get_All := new Perm_Tree_Wrapper; - Copy_Tree (Get_All (From), Get_All (To)); - - when Array_Component => - To.all.Tree.Get_Elem := new Perm_Tree_Wrapper; - Copy_Tree (Get_Elem (From), Get_Elem (To)); - - when Record_Component => - declare - Comp_From : Perm_Tree_Access; - Key_From : Perm_Tree_Maps.Key_Option; - Son : Perm_Tree_Access; - Hash_Table : Perm_Tree_Maps.Instance; - begin - -- We put a new hash table, so that it gets dealiased from - -- the Component (From) hash table. - To.all.Tree.Component := Hash_Table; - Key_From := Perm_Tree_Maps.Get_First_Key - (Component (From)); - - while Key_From.Present loop - Comp_From := Perm_Tree_Maps.Get - (Component (From), Key_From.K); - pragma Assert (Comp_From /= null); - Son := new Perm_Tree_Wrapper; - Copy_Tree (Comp_From, Son); - Perm_Tree_Maps.Set - (To.all.Tree.Component, Key_From.K, Son); - Key_From := Perm_Tree_Maps.Get_Next_Key - (Component (From)); - end loop; - end; - end case; - end Copy_Tree; - - ------------------------------ - -- Elaboration_Context_Hash -- - ------------------------------ - - function Elaboration_Context_Hash - (Key : Entity_Id) return Elaboration_Context_Index - is - begin - return Elaboration_Context_Index (Key mod Elaboration_Context_Max); - end Elaboration_Context_Hash; - - -------------- - -- Free_Env -- - -------------- - - procedure Free_Env (PE : in out Perm_Env) is - CompO : Perm_Tree_Access; - begin - CompO := Get_First (PE); - while CompO /= null loop - Free_Tree (CompO); - CompO := Get_Next (PE); - end loop; - - Reset (PE); - end Free_Env; - - --------------- - -- Free_Tree -- - --------------- - - procedure Free_Tree (PT : in out Perm_Tree_Access) is - procedure Free_Perm_Tree_Dealloc is - new Ada.Unchecked_Deallocation - (Perm_Tree_Wrapper, Perm_Tree_Access); - -- The deallocator for permission_trees - - begin - case Kind (PT) is - when Entire_Object => - null; - - when Reference => - Free_Tree (PT.all.Tree.Get_All); - - when Array_Component => - Free_Tree (PT.all.Tree.Get_Elem); - - when Record_Component => - declare - Comp : Perm_Tree_Access; - - begin - Comp := Perm_Tree_Maps.Get_First (Component (PT)); - while Comp /= null loop - - -- Free every Component subtree - - Free_Tree (Comp); - Comp := Perm_Tree_Maps.Get_Next (Component (PT)); - end loop; - end; - end case; - - Free_Perm_Tree_Dealloc (PT); - end Free_Tree; - - ----------------- - -- Explanation -- - ----------------- - - function Explanation (T : Perm_Tree_Access) return Node_Id is - begin - return T.all.Tree.Explanation; - end Explanation; - - ------------- - -- Get_All -- - ------------- - - function Get_All (T : Perm_Tree_Access) return Perm_Tree_Access is - begin - return T.all.Tree.Get_All; - end Get_All; - - -------------- - -- Get_Elem -- - -------------- - - function Get_Elem (T : Perm_Tree_Access) return Perm_Tree_Access is - begin - return T.all.Tree.Get_Elem; - end Get_Elem; - - ------------------ - -- Is_Node_Deep -- - ------------------ - - function Is_Node_Deep (T : Perm_Tree_Access) return Boolean is - begin - return T.all.Tree.Is_Node_Deep; - end Is_Node_Deep; - - ---------- - -- Kind -- - ---------- - - function Kind (T : Perm_Tree_Access) return Path_Kind is - begin - return T.all.Tree.Kind; - end Kind; - - -------------- - -- Move_Env -- - -------------- - - procedure Move_Env (From, To : in out Perm_Env) is - begin - Free_Env (To); - To := From; - From := Perm_Env (Perm_Tree_Maps.Nil); - end Move_Env; - - --------------------------- - -- Move_Variable_Mapping -- - --------------------------- - - procedure Move_Variable_Mapping (From, To : in out Variable_Mapping) is - begin - Reset (To); - To := From; - From := Variable_Mapping (Variable_Maps.Nil); - end Move_Variable_Mapping; - - ---------------- - -- Permission -- - ---------------- - - function Permission (T : Perm_Tree_Access) return Perm_Kind is - begin - return T.all.Tree.Permission; - end Permission; - - ------------------- - -- Perm_Mismatch -- - ------------------- - - procedure Perm_Mismatch - (N : Node_Id; - Exp_Perm : Perm_Kind; - Act_Perm : Perm_Kind; - Expl : Node_Id; - Forbidden_Perm : Boolean := False) - is - begin - Error_Msg_Sloc := Sloc (Expl); - - if Forbidden_Perm then - if Exp_Perm = No_Access then - Error_Msg_N ("\object was moved #", N); - else - raise Program_Error; - end if; - else - case Exp_Perm is - when Write_Perm => - if Act_Perm = Read_Only then - Error_Msg_N - ("\object was declared as not writeable #", N); - else - Error_Msg_N ("\object was moved #", N); - end if; - - when Read_Only => - Error_Msg_N ("\object was moved #", N); - - when No_Access => - raise Program_Error; - end case; - end if; - end Perm_Mismatch; - - end Permissions; - - use Permissions; - - -------------------------------------- - -- Analysis modes for AST traversal -- - -------------------------------------- - - -- The different modes for analysis. This allows checking whether a path - -- has the right permission, and also updating permissions when a path is - -- moved, borrowed, or observed. - - type Extended_Checking_Mode is - - (Read_Subexpr, - -- Special value used for assignment, to check that subexpressions of - -- the assigned path are readable. - - Read, - -- Default mode - - Move, - -- Move semantics. Checks that paths have Read_Write permission. After - -- moving a path, its permission and the permission of its prefixes are - -- set to Write_Only, while the permission of its extensions is set to - -- No_Access. - - Assign, - -- Used for the target of an assignment, or an actual parameter with - -- mode OUT. Checks that paths have Write_Perm permission. After - -- assigning to a path, its permission and the permission of its - -- extensions are set to Read_Write. The permission of its prefixes may - -- be normalized from Write_Only to Read_Write depending on other - -- permissions in the tree (a prefix gets permission Read_Write when all - -- its extensions become Read_Write). - - Borrow, - -- Borrow semantics. Checks that paths have Read_Write permission. After - -- borrowing a path, its permission and the permission of its prefixes - -- and extensions are set to No_Access. - - Observe - -- Observe semantics. Checks that paths have Read_Perm permission. After - -- observing a path, its permission and the permission of its prefixes - -- and extensions are set to Read_Only. - ); - - subtype Checking_Mode is Extended_Checking_Mode range Read .. Observe; - - type Result_Kind is (Folded, Unfolded); - -- The type declaration to discriminate in the Perm_Or_Tree type - - -- The result type of the function Get_Perm_Or_Tree. This returns either a - -- tree when it found the appropriate tree, or a permission when the search - -- finds a leaf and the subtree we are looking for is folded. In the last - -- case, we return instead the Children_Permission field of the leaf. - - type Perm_Or_Tree (R : Result_Kind) is record - case R is - when Folded => - Found_Permission : Perm_Kind; - Explanation : Node_Id; - when Unfolded => - Tree_Access : Perm_Tree_Access; - end case; - end record; - - type Error_Status is (OK, Error); - - ----------------------- - -- Local subprograms -- - ----------------------- - - function "<=" (P1, P2 : Perm_Kind) return Boolean; - function ">=" (P1, P2 : Perm_Kind) return Boolean; - function Glb (P1, P2 : Perm_Kind) return Perm_Kind; - function Lub (P1, P2 : Perm_Kind) return Perm_Kind; - - procedure Check_Assignment (Target : Node_Or_Entity_Id; Expr : Node_Id); - -- Handle assignment as part of an assignment statement or an object - -- declaration. - - procedure Check_Call_Statement (Call : Node_Id); - - procedure Check_Callable_Body (Body_N : Node_Id); - -- Entry point for the analysis of a subprogram or entry body - - procedure Check_Declaration (Decl : Node_Id); - - procedure Check_Declaration_Legality - (Decl : Node_Id; - Force : Boolean; - Legal : in out Boolean); - -- Check the legality of declaration Decl regarding rules not related to - -- permissions. Update Legal to False if a rule is violated. Issue an - -- error message if Force is True and Emit_Messages returns True. - - procedure Check_Expression (Expr : Node_Id; Mode : Extended_Checking_Mode); - pragma Precondition (Nkind_In (Expr, N_Index_Or_Discriminant_Constraint, - N_Range_Constraint, - N_Subtype_Indication, - N_Digits_Constraint, - N_Delta_Constraint) - or else Nkind (Expr) in N_Subexpr); - - procedure Check_Globals (Subp : Entity_Id); - -- This procedure takes a subprogram called and checks the permission of - -- globals. - - -- Checking proceduress for safe pointer usage. These procedures traverse - -- the AST, check nodes for correct permissions according to SPARK RM 3.10, - -- and update permissions depending on the node kind. The main procedure - -- Check_Node is mutually recursive with the specialized procedures that - -- follow. - - procedure Check_List (L : List_Id); - -- Calls Check_Node on each element of the list - - procedure Check_Loop_Statement (Stmt : Node_Id); - - procedure Check_Node (N : Node_Id); - -- Main traversal procedure to check safe pointer usage - - procedure Check_Old_Loop_Entry (N : Node_Id); - -- Check SPARK RM 3.10(13) regarding 'Old and 'Loop_Entry - - procedure Check_Package_Body (Pack : Node_Id); - - procedure Check_Package_Spec (Pack : Node_Id); - - procedure Check_Parameter_Or_Global - (Expr : Node_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean); - -- Check the permission of every actual parameter or global - - procedure Check_Pragma (Prag : Node_Id); - - procedure Check_Source_Of_Borrow_Or_Observe - (Expr : Node_Id; - Status : out Error_Status); - - procedure Check_Statement (Stmt : Node_Id); - - procedure Check_Type_Legality - (Typ : Entity_Id; - Force : Boolean; - Legal : in out Boolean); - -- Check that type Typ is either not deep, or that it is an observing or - -- owning type according to SPARK RM 3.10 - - function Get_Expl (N : Node_Or_Entity_Id) return Node_Id; - -- The function that takes a name as input and returns an explanation node - -- for the permission associated with it. - - function Get_Observed_Or_Borrowed_Expr (Expr : Node_Id) return Node_Id; - pragma Precondition (Is_Path_Expression (Expr)); - -- Return the expression being borrowed/observed when borrowing or - -- observing Expr. If Expr contains a call to traversal function, this is - -- the first actual of the first such call, otherwise it is Expr. - - function Get_Perm (N : Node_Or_Entity_Id) return Perm_Kind; - -- The function that takes a name as input and returns a permission - -- associated with it. - - function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree; - pragma Precondition (Is_Path_Expression (N)); - -- This function gets a node and looks recursively to find the appropriate - -- subtree for that node. If the tree is folded on that node, then it - -- returns the permission given at the right level. - - function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access; - pragma Precondition (Is_Path_Expression (N)); - -- This function gets a node and looks recursively to find the appropriate - -- subtree for that node. If the tree is folded, then it unrolls the tree - -- up to the appropriate level. - - function Get_Root_Object - (Expr : Node_Id; - Through_Traversal : Boolean := True; - Is_Traversal : Boolean := False) return Entity_Id; - -- Return the root of the path expression Expr, or Empty for an allocator, - -- NULL, or a function call. Through_Traversal is True if it should follow - -- through calls to traversal functions. Is_Traversal is True if this - -- corresponds to a value returned from a traversal function, which should - -- allow if-expressions and case-expressions that refer to the same root, - -- even if the paths are not the same in all branches. - - generic - with procedure Handle_Parameter_Or_Global - (Expr : Node_Id; - Formal_Typ : Entity_Id; - Param_Mode : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean); - procedure Handle_Globals (Subp : Entity_Id); - -- Handling of globals is factored in a generic instantiated below - - function Has_Array_Component (Expr : Node_Id) return Boolean; - pragma Precondition (Is_Path_Expression (Expr)); - -- This function gets a node and looks recursively to determine whether the - -- given path has any array component. - - procedure Hp (P : Perm_Env); - -- A procedure that outputs the hash table. This function is used only in - -- the debugger to look into a hash table. - pragma Unreferenced (Hp); - - procedure Illegal_Global_Usage (N : Node_Or_Entity_Id; E : Entity_Id); - pragma No_Return (Illegal_Global_Usage); - -- A procedure that is called when deep globals or aliased globals are used - -- without any global aspect. - - function Is_Path_Expression - (Expr : Node_Id; - Is_Traversal : Boolean := False) return Boolean; - -- Return whether Expr corresponds to a path. Is_Traversal is True if this - -- corresponds to a value returned from a traversal function, which should - -- allow if-expressions and case-expressions. - - function Is_Subpath_Expression - (Expr : Node_Id; - Is_Traversal : Boolean := False) return Boolean; - -- Return True if Expr can be part of a path expression. Is_Traversal is - -- True if this corresponds to a value returned from a traversal function, - -- which should allow if-expressions and case-expressions. - - function Is_Prefix_Or_Almost (Pref, Expr : Node_Id) return Boolean; - -- Determine if the candidate Prefix is indeed a prefix of Expr, or almost - -- a prefix, in the sense that they could still refer to overlapping memory - -- locations. - - function Is_Traversal_Function_Call (Expr : Node_Id) return Boolean; - - function Loop_Of_Exit (N : Node_Id) return Entity_Id; - -- A function that takes an exit statement node and returns the entity of - -- the loop that this statement is exiting from. - - procedure Merge_Env (Source : in out Perm_Env; Target : in out Perm_Env); - -- Merge Target and Source into Target, and then deallocate the Source - - procedure Perm_Error - (N : Node_Id; - Perm : Perm_Kind; - Found_Perm : Perm_Kind; - Expl : Node_Id; - Forbidden_Perm : Boolean := False); - -- A procedure that is called when the permissions found contradict the - -- rules established by the RM. This function is called with the node and - -- the permission that was expected, and issues an error message with the - -- appropriate values. - - procedure Perm_Error_Subprogram_End - (E : Entity_Id; - Subp : Entity_Id; - Perm : Perm_Kind; - Found_Perm : Perm_Kind; - Expl : Node_Id); - -- A procedure that is called when the permissions found contradict the - -- rules established by the RM at the end of subprograms. This function is - -- called with the node, the node of the returning function, and the - -- permission that was expected, and adds an error message with the - -- appropriate values. - - procedure Process_Path (Expr : Node_Id; Mode : Checking_Mode); - pragma Precondition (Is_Path_Expression (Expr)); - -- Check correct permission for the path in the checking mode Mode, and - -- update permissions of the path and its prefixes/extensions. - - procedure Return_Globals (Subp : Entity_Id); - -- Takes a subprogram as input, and checks that all borrowed global items - -- of the subprogram indeed have Read_Write permission at the end of the - -- subprogram execution. - - procedure Return_Parameter_Or_Global - (Id : Entity_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean); - -- Auxiliary procedure to Return_Parameters and Return_Globals - - procedure Return_Parameters (Subp : Entity_Id); - -- Takes a subprogram as input, and checks that all out parameters of the - -- subprogram indeed have Read_Write permission at the end of the - -- subprogram execution. - - procedure Set_Perm_Extensions - (T : Perm_Tree_Access; - P : Perm_Kind; - Expl : Node_Id); - -- This procedure takes an access to a permission tree and modifies the - -- tree so that any strict extensions of the given tree become of the - -- access specified by parameter P. - - procedure Set_Perm_Extensions_Move - (T : Perm_Tree_Access; - E : Entity_Id; - Expl : Node_Id); - -- Set permissions to - -- No for any extension with more .all - -- W for any deep extension with same number of .all - -- RW for any shallow extension with same number of .all - - function Set_Perm_Prefixes - (N : Node_Id; - Perm : Perm_Kind_Option; - Expl : Node_Id) return Perm_Tree_Access; - pragma Precondition (Is_Path_Expression (N)); - -- This function modifies the permissions of a given node in the permission - -- environment as well as all the prefixes of the path, to the new - -- permission Perm. The general rule here is that everybody updates the - -- permission of the subtree they are returning. - - procedure Set_Perm_Prefixes_Assign (N : Node_Id); - pragma Precondition (Is_Path_Expression (N)); - -- This procedure takes a name as an input and sets in the permission - -- tree the given permission to the given name. The general rule here is - -- that everybody updates the permission of the subtree it is returning. - -- The permission of the assigned path has been set to RW by the caller. - -- - -- Case where we have to normalize a tree after the correct permissions - -- have been assigned already. We look for the right subtree at the given - -- path, actualize its permissions, and then call the normalization on its - -- parent. - -- - -- Example: We assign x.y and x.z, and then Set_Perm_Prefixes_Assign will - -- change the permission of x to RW because all of its components have - -- permission RW. - - procedure Setup_Globals (Subp : Entity_Id); - -- Takes a subprogram as input, and sets up the environment by adding - -- global items with appropriate permissions. - - procedure Setup_Parameter_Or_Global - (Id : Entity_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean; - Expl : Node_Id); - -- Auxiliary procedure to Setup_Parameters and Setup_Globals - - procedure Setup_Parameters (Subp : Entity_Id); - -- Takes a subprogram as input, and sets up the environment by adding - -- formal parameters with appropriate permissions. - - procedure Setup_Protected_Components (Subp : Entity_Id); - -- Takes a protected operation as input, and sets up the environment by - -- adding protected components with appropriate permissions. - - ---------------------- - -- Global Variables -- - ---------------------- - - Current_Perm_Env : Perm_Env; - -- The permission environment that is used for the analysis. This - -- environment can be saved, modified, reinitialized, but should be the - -- only one valid from which to extract the permissions of the paths in - -- scope. The analysis ensures at each point that this variables contains - -- a valid permission environment with all bindings in scope. - - Inside_Procedure_Call : Boolean := False; - -- Set while checking the actual parameters of a procedure or entry call - - Inside_Elaboration : Boolean := False; - -- Set during package spec/body elaboration, during which move and local - -- observe/borrow are not allowed. As a result, no other checking is needed - -- during elaboration. - - Current_Loops_Envs : Env_Backups; - -- This variable contains saves of permission environments at each loop the - -- analysis entered. Each saved environment can be reached with the label - -- of the loop. - - Current_Loops_Accumulators : Env_Backups; - -- This variable contains the environments used as accumulators for loops, - -- that consist of the merge of all environments at each exit point of - -- the loop (which can also be the entry point of the loop in the case of - -- non-infinite loops), each of them reachable from the label of the loop. - -- We require that the environment stored in the accumulator be less - -- restrictive than the saved environment at the beginning of the loop, and - -- the permission environment after the loop is equal to the accumulator. - - Current_Borrowers : Variable_Mapping; - -- Mapping from borrowers to the path borrowed - - Current_Observers : Variable_Mapping; - -- Mapping from observers to the path observed - - -------------------- - -- Handle_Globals -- - -------------------- - - -- Generic procedure is defined first so that instantiations can be defined - -- anywhere afterwards. - - procedure Handle_Globals (Subp : Entity_Id) is - - -- Local subprograms - - procedure Handle_Globals_From_List - (First_Item : Node_Id; - Kind : Formal_Kind); - -- Handle global items from the list starting at Item - - procedure Handle_Globals_Of_Mode (Global_Mode : Name_Id); - -- Handle global items for the mode Global_Mode - - ------------------------------ - -- Handle_Globals_From_List -- - ------------------------------ - - procedure Handle_Globals_From_List - (First_Item : Node_Id; - Kind : Formal_Kind) - is - Item : Node_Id := First_Item; - E : Entity_Id; - - begin - while Present (Item) loop - E := Entity (Item); - - -- Ignore abstract states, which play no role in pointer aliasing - - if Ekind (E) = E_Abstract_State then - null; - else - Handle_Parameter_Or_Global (Expr => Item, - Formal_Typ => Retysp (Etype (Item)), - Param_Mode => Kind, - Subp => Subp, - Global_Var => True); - end if; - - Next_Global (Item); - end loop; - end Handle_Globals_From_List; - - ---------------------------- - -- Handle_Globals_Of_Mode -- - ---------------------------- - - procedure Handle_Globals_Of_Mode (Global_Mode : Name_Id) is - Kind : Formal_Kind; - - begin - case Global_Mode is - when Name_Input - | Name_Proof_In - => - Kind := E_In_Parameter; - - when Name_Output => - Kind := E_Out_Parameter; - - when Name_In_Out => - Kind := E_In_Out_Parameter; - - when others => - raise Program_Error; - end case; - - -- Check both global items from Global and Refined_Global pragmas - - Handle_Globals_From_List (First_Global (Subp, Global_Mode), Kind); - Handle_Globals_From_List - (First_Global (Subp, Global_Mode, Refined => True), Kind); - end Handle_Globals_Of_Mode; - - -- Start of processing for Handle_Globals - - begin - Handle_Globals_Of_Mode (Name_Proof_In); - Handle_Globals_Of_Mode (Name_Input); - Handle_Globals_Of_Mode (Name_Output); - Handle_Globals_Of_Mode (Name_In_Out); - end Handle_Globals; - - ---------- - -- "<=" -- - ---------- - - function "<=" (P1, P2 : Perm_Kind) return Boolean is - begin - return P2 >= P1; - end "<="; - - ---------- - -- ">=" -- - ---------- - - function ">=" (P1, P2 : Perm_Kind) return Boolean is - begin - case P2 is - when No_Access => return True; - when Read_Only => return P1 in Read_Perm; - when Write_Only => return P1 in Write_Perm; - when Read_Write => return P1 = Read_Write; - end case; - end ">="; - - ---------------------- - -- Check_Assignment -- - ---------------------- - - procedure Check_Assignment (Target : Node_Or_Entity_Id; Expr : Node_Id) is - - -- Local subprograms - - procedure Handle_Borrow - (Var : Entity_Id; - Expr : Node_Id; - Is_Decl : Boolean); - -- Update map of current borrowers - - procedure Handle_Observe - (Var : Entity_Id; - Expr : Node_Id; - Is_Decl : Boolean); - -- Update map of current observers - - ------------------- - -- Handle_Borrow -- - ------------------- - - procedure Handle_Borrow - (Var : Entity_Id; - Expr : Node_Id; - Is_Decl : Boolean) - is - Borrowed : constant Node_Id := Get_Observed_Or_Borrowed_Expr (Expr); - - begin - -- SPARK RM 3.10(7): If the type of the target is an anonymous - -- access-to-variable type (an owning access type), the source shall - -- be an owning access object [..] whose root object is the target - -- object itself. - - -- ??? In fact we could be slightly more permissive in allowing even - -- a call to a traversal function of the right form. - - if not Is_Decl - and then (Is_Traversal_Function_Call (Expr) - or else Get_Root_Object (Borrowed) /= Var) - then - if Emit_Messages then - Error_Msg_NE - ("source of assignment must have & as root" & - " (SPARK RM 3.10(7)))", - Expr, Var); - end if; - return; - end if; - - Set (Current_Borrowers, Var, Borrowed); - end Handle_Borrow; - - -------------------- - -- Handle_Observe -- - -------------------- - - procedure Handle_Observe - (Var : Entity_Id; - Expr : Node_Id; - Is_Decl : Boolean) - is - Observed : constant Node_Id := Get_Observed_Or_Borrowed_Expr (Expr); - - begin - -- ??? We are currently using the same restriction for observers - -- as for borrowers. To be seen if the SPARK RM current rule really - -- allows more uses. - - if not Is_Decl - and then (Is_Traversal_Function_Call (Expr) - or else Get_Root_Object (Observed) /= Var) - then - if Emit_Messages then - Error_Msg_NE - ("source of assignment must have & as root" & - " (SPARK RM 3.10(7)))", - Expr, Var); - end if; - return; - end if; - - Set (Current_Observers, Var, Observed); - end Handle_Observe; - - -- Local variables - - Target_Typ : constant Node_Id := Etype (Target); - Is_Decl : constant Boolean := Nkind (Target) = N_Defining_Identifier; - Target_Root : Entity_Id; - Expr_Root : Entity_Id; - Perm : Perm_Kind; - Status : Error_Status; - Dummy : Boolean := True; - - -- Start of processing for Check_Assignment - - begin - Check_Type_Legality (Target_Typ, Force => True, Legal => Dummy); - - if Is_Anonymous_Access_Type (Target_Typ) then - Check_Source_Of_Borrow_Or_Observe (Expr, Status); - - if Status /= OK then - return; - end if; - - if Is_Decl then - Target_Root := Target; - else - Target_Root := Get_Root_Object (Target); - end if; - - Expr_Root := Get_Root_Object (Expr); - - -- SPARK RM 3.10(7): For an assignment statement where the target is - -- a stand-alone object of an anonymous access-to-object type. - - pragma Assert (Present (Target_Root)); - - -- If the type of the target is an anonymous access-to-constant type - -- (an observing access type), the source shall be an owning access - -- object denoted by a name that is not in the Moved state, and whose - -- root object is not in the Moved state and is not declared at a - -- statically deeper accessibility level than that of the target - -- object. - - if Is_Access_Constant (Target_Typ) then - Perm := Get_Perm (Expr); - - if Perm = No_Access then - Perm_Error (Expr, No_Access, No_Access, - Expl => Get_Expl (Expr), - Forbidden_Perm => True); - return; - end if; - - Perm := Get_Perm (Expr_Root); - - if Perm = No_Access then - Perm_Error (Expr, No_Access, No_Access, - Expl => Get_Expl (Expr_Root), - Forbidden_Perm => True); - return; - end if; - - -- ??? check accessibility level - - -- If the type of the target is an anonymous access-to-variable - -- type (an owning access type), the source shall be an owning - -- access object denoted by a name that is in the Unrestricted - -- state, and whose root object is the target object itself. - - Check_Expression (Expr, Observe); - Handle_Observe (Target_Root, Expr, Is_Decl); - - else - Perm := Get_Perm (Expr); - - if Perm /= Read_Write then - Perm_Error (Expr, Read_Write, Perm, Expl => Get_Expl (Expr)); - return; - end if; - - if not Is_Decl then - if not Is_Entity_Name (Target) then - if Emit_Messages then - Error_Msg_N - ("target of borrow must be stand-alone variable", - Target); - end if; - return; - - elsif Target_Root /= Expr_Root then - if Emit_Messages then - Error_Msg_NE - ("source of borrow must be variable &", - Expr, Target); - end if; - return; - end if; - end if; - - Check_Expression (Expr, Borrow); - Handle_Borrow (Target_Root, Expr, Is_Decl); - end if; - - elsif Is_Deep (Target_Typ) then - - if Is_Path_Expression (Expr) then - Check_Expression (Expr, Move); - - else - if Emit_Messages then - Error_Msg_N ("expression not allowed as source of move", Expr); - end if; - return; - end if; - - else - Check_Expression (Expr, Read); - end if; - end Check_Assignment; - - -------------------------- - -- Check_Call_Statement -- - -------------------------- - - procedure Check_Call_Statement (Call : Node_Id) is - - Subp : constant Entity_Id := Get_Called_Entity (Call); - - -- Local subprograms - - procedure Check_Param (Formal : Entity_Id; Actual : Node_Id); - -- Check the permission of every actual parameter - - procedure Update_Param (Formal : Entity_Id; Actual : Node_Id); - -- Update the permission of OUT actual parameters - - ----------------- - -- Check_Param -- - ----------------- - - procedure Check_Param (Formal : Entity_Id; Actual : Node_Id) is - begin - Check_Parameter_Or_Global - (Expr => Actual, - Typ => Retysp (Etype (Formal)), - Kind => Ekind (Formal), - Subp => Subp, - Global_Var => False); - end Check_Param; - - ------------------ - -- Update_Param -- - ------------------ - - procedure Update_Param (Formal : Entity_Id; Actual : Node_Id) is - Mode : constant Entity_Kind := Ekind (Formal); - - begin - case Formal_Kind'(Mode) is - when E_Out_Parameter => - Check_Expression (Actual, Assign); - - when others => - null; - end case; - end Update_Param; - - procedure Check_Params is new - Iterate_Call_Parameters (Check_Param); - - procedure Update_Params is new - Iterate_Call_Parameters (Update_Param); - - -- Start of processing for Check_Call_Statement - - begin - Inside_Procedure_Call := True; - Check_Params (Call); - if Ekind (Get_Called_Entity (Call)) = E_Subprogram_Type then - if Emit_Messages then - Error_Msg_N - ("call through access to subprogram is not allowed in SPARK", - Call); - end if; - else - Check_Globals (Get_Called_Entity (Call)); - end if; - - Inside_Procedure_Call := False; - Update_Params (Call); - end Check_Call_Statement; - - ------------------------- - -- Check_Callable_Body -- - ------------------------- - - procedure Check_Callable_Body (Body_N : Node_Id) is - Save_In_Elab : constant Boolean := Inside_Elaboration; - Body_Id : constant Entity_Id := Defining_Entity (Body_N); - Spec_Id : constant Entity_Id := Unique_Entity (Body_Id); - Prag : constant Node_Id := SPARK_Pragma (Body_Id); - - Saved_Env : Perm_Env; - Saved_Borrowers : Variable_Mapping; - Saved_Observers : Variable_Mapping; - - begin - -- Only SPARK bodies are analyzed - - if No (Prag) - or else Get_SPARK_Mode_From_Annotation (Prag) /= Opt.On - then - return; - end if; - - Inside_Elaboration := False; - - if Ekind (Spec_Id) = E_Function - and then Is_Anonymous_Access_Type (Etype (Spec_Id)) - and then not Is_Traversal_Function (Spec_Id) - then - if Emit_Messages then - Error_Msg_N ("anonymous access type for result only allowed for " - & "traversal functions", Spec_Id); - end if; - return; - end if; - - -- Save environment and put a new one in place - - Move_Env (Current_Perm_Env, Saved_Env); - Move_Variable_Mapping (Current_Borrowers, Saved_Borrowers); - Move_Variable_Mapping (Current_Observers, Saved_Observers); - - -- Add formals and globals to the environment with adequate permissions - - if Is_Subprogram_Or_Entry (Spec_Id) then - Setup_Parameters (Spec_Id); - Setup_Globals (Spec_Id); - end if; - - -- For protected operations, add protected components to the environment - -- with adequate permissions. - - if Is_Protected_Operation (Spec_Id) then - Setup_Protected_Components (Spec_Id); - end if; - - -- Analyze the body of the subprogram - - Check_List (Declarations (Body_N)); - Check_Node (Handled_Statement_Sequence (Body_N)); - - -- Check the read-write permissions of borrowed parameters/globals - - if Ekind_In (Spec_Id, E_Procedure, E_Entry) - and then not No_Return (Spec_Id) - then - Return_Parameters (Spec_Id); - Return_Globals (Spec_Id); - end if; - - -- Restore the saved environment and free the current one - - Move_Env (Saved_Env, Current_Perm_Env); - Move_Variable_Mapping (Saved_Borrowers, Current_Borrowers); - Move_Variable_Mapping (Saved_Observers, Current_Observers); - - Inside_Elaboration := Save_In_Elab; - end Check_Callable_Body; - - ----------------------- - -- Check_Declaration -- - ----------------------- - - procedure Check_Declaration (Decl : Node_Id) is - Target : constant Entity_Id := Defining_Identifier (Decl); - Target_Typ : constant Node_Id := Etype (Target); - Expr : Node_Id; - Legal : Boolean := True; - - begin - -- Start with legality rules not related to permissions - - Check_Declaration_Legality (Decl, Force => True, Legal => Legal); - - -- Now check permission-related legality rules - - case N_Declaration'(Nkind (Decl)) is - when N_Full_Type_Declaration => - null; - - -- ??? What about component declarations with defaults. - - when N_Subtype_Declaration => - Check_Expression (Subtype_Indication (Decl), Read); - - when N_Object_Declaration => - Expr := Expression (Decl); - - if Legal and then Present (Expr) then - Check_Assignment (Target => Target, - Expr => Expr); - end if; - - -- Always add variable to the current permission environment, - -- even in the illegal case, as the rest of the analysis expects - -- to find it. - - if Is_Deep (Target_Typ) then - declare - Tree : constant Perm_Tree_Access := - new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => True, - Explanation => Decl, - Permission => Read_Write, - Children_Permission => Read_Write)); - begin - Set (Current_Perm_Env, Target, Tree); - end; - end if; - - when N_Iterator_Specification => - null; - - when N_Loop_Parameter_Specification => - null; - - -- Checking should not be called directly on these nodes - - when N_Function_Specification - | N_Entry_Declaration - | N_Procedure_Specification - | N_Component_Declaration - => - raise Program_Error; - - -- Ignored constructs for pointer checking - - when N_Formal_Object_Declaration - | N_Formal_Type_Declaration - | N_Incomplete_Type_Declaration - | N_Private_Extension_Declaration - | N_Private_Type_Declaration - | N_Protected_Type_Declaration - => - null; - - -- The following nodes are rewritten by semantic analysis - - when N_Expression_Function => - raise Program_Error; - end case; - end Check_Declaration; - - -------------------------------- - -- Check_Declaration_Legality -- - -------------------------------- - - procedure Check_Declaration_Legality - (Decl : Node_Id; - Force : Boolean; - Legal : in out Boolean) - is - function Original_Emit_Messages return Boolean renames Emit_Messages; - - function Emit_Messages return Boolean; - -- Local wrapper around generic formal parameter Emit_Messages, to - -- check the value of parameter Force before calling the original - -- Emit_Messages, and setting Legal to False. - - ------------------- - -- Emit_Messages -- - ------------------- - - function Emit_Messages return Boolean is - begin - Legal := False; - return Force and then Original_Emit_Messages; - end Emit_Messages; - - -- Local variables - - Target : constant Entity_Id := Defining_Identifier (Decl); - Target_Typ : constant Node_Id := Etype (Target); - Expr : Node_Id; - - -- Start of processing for Check_Declaration_Legality - - begin - case N_Declaration'(Nkind (Decl)) is - when N_Full_Type_Declaration => - Check_Type_Legality (Target, Force, Legal); - - when N_Subtype_Declaration => - null; - - when N_Object_Declaration => - Expr := Expression (Decl); - - Check_Type_Legality (Target_Typ, Force, Legal); - - -- A declaration of a stand-alone object of an anonymous access - -- type shall have an explicit initial value and shall occur - -- immediately within a subprogram body, an entry body, or a - -- block statement (SPARK RM 3.10(4)). - - if Is_Anonymous_Access_Type (Target_Typ) then - declare - Scop : constant Entity_Id := Scope (Target); - begin - if not Is_Local_Context (Scop) then - if Emit_Messages then - Error_Msg_N - ("object of anonymous access type must be declared " - & "immediately within a subprogram, entry or block " - & "(SPARK RM 3.10(4))", Decl); - end if; - end if; - end; - - if No (Expr) then - if Emit_Messages then - Error_Msg_N ("object of anonymous access type must be " - & "initialized (SPARK RM 3.10(4))", Decl); - end if; - end if; - end if; - - when N_Iterator_Specification => - null; - - when N_Loop_Parameter_Specification => - null; - - -- Checking should not be called directly on these nodes - - when N_Function_Specification - | N_Entry_Declaration - | N_Procedure_Specification - | N_Component_Declaration - => - raise Program_Error; - - -- Ignored constructs for pointer checking - - when N_Formal_Object_Declaration - | N_Formal_Type_Declaration - | N_Incomplete_Type_Declaration - | N_Private_Extension_Declaration - | N_Private_Type_Declaration - | N_Protected_Type_Declaration - => - null; - - -- The following nodes are rewritten by semantic analysis - - when N_Expression_Function => - raise Program_Error; - end case; - end Check_Declaration_Legality; - - ---------------------- - -- Check_Expression -- - ---------------------- - - procedure Check_Expression - (Expr : Node_Id; - Mode : Extended_Checking_Mode) - is - -- Local subprograms - - function Is_Type_Name (Expr : Node_Id) return Boolean; - -- Detect when a path expression is in fact a type name - - procedure Move_Expression (Expr : Node_Id); - -- Some subexpressions are only analyzed in Move mode. This is a - -- specialized version of Check_Expression for that case. - - procedure Move_Expression_List (L : List_Id); - -- Call Move_Expression on every expression in the list L - - procedure Read_Expression (Expr : Node_Id); - -- Most subexpressions are only analyzed in Read mode. This is a - -- specialized version of Check_Expression for that case. - - procedure Read_Expression_List (L : List_Id); - -- Call Read_Expression on every expression in the list L - - procedure Read_Indexes (Expr : Node_Id); - -- When processing a path, the index expressions and function call - -- arguments occurring on the path should be analyzed in Read mode. - - ------------------ - -- Is_Type_Name -- - ------------------ - - function Is_Type_Name (Expr : Node_Id) return Boolean is - begin - return Nkind_In (Expr, N_Expanded_Name, N_Identifier) - and then Is_Type (Entity (Expr)); - end Is_Type_Name; - - --------------------- - -- Move_Expression -- - --------------------- - - -- Distinguish the case where the argument is a path expression that - -- needs explicit moving. - - procedure Move_Expression (Expr : Node_Id) is - begin - if Is_Path_Expression (Expr) then - Check_Expression (Expr, Move); - else - Read_Expression (Expr); - end if; - end Move_Expression; - - -------------------------- - -- Move_Expression_List -- - -------------------------- - - procedure Move_Expression_List (L : List_Id) is - N : Node_Id; - begin - N := First (L); - while Present (N) loop - Move_Expression (N); - Next (N); - end loop; - end Move_Expression_List; - - --------------------- - -- Read_Expression -- - --------------------- - - procedure Read_Expression (Expr : Node_Id) is - begin - Check_Expression (Expr, Read); - end Read_Expression; - - -------------------------- - -- Read_Expression_List -- - -------------------------- - - procedure Read_Expression_List (L : List_Id) is - N : Node_Id; - begin - N := First (L); - while Present (N) loop - Read_Expression (N); - Next (N); - end loop; - end Read_Expression_List; - - ------------------ - -- Read_Indexes -- - ------------------ - - procedure Read_Indexes (Expr : Node_Id) is - - -- Local subprograms - - function Is_Singleton_Choice (Choices : List_Id) return Boolean; - -- Return whether Choices is a singleton choice - - procedure Read_Param (Formal : Entity_Id; Actual : Node_Id); - -- Call Read_Expression on the actual - - ------------------------- - -- Is_Singleton_Choice -- - ------------------------- - - function Is_Singleton_Choice (Choices : List_Id) return Boolean is - Choice : constant Node_Id := First (Choices); - begin - return List_Length (Choices) = 1 - and then Nkind (Choice) /= N_Others_Choice - and then not Nkind_In (Choice, N_Subtype_Indication, N_Range) - and then not - (Nkind_In (Choice, N_Identifier, N_Expanded_Name) - and then Is_Type (Entity (Choice))); - end Is_Singleton_Choice; - - ---------------- - -- Read_Param -- - ---------------- - - procedure Read_Param (Formal : Entity_Id; Actual : Node_Id) is - pragma Unreferenced (Formal); - begin - Read_Expression (Actual); - end Read_Param; - - procedure Read_Params is new Iterate_Call_Parameters (Read_Param); - - -- Start of processing for Read_Indexes - - begin - if not Is_Subpath_Expression (Expr) then - if Emit_Messages then - Error_Msg_N - ("name expected here for move/borrow/observe", Expr); - end if; - return; - end if; - - case N_Subexpr'(Nkind (Expr)) is - when N_Identifier - | N_Expanded_Name - | N_Null - => - null; - - when N_Explicit_Dereference - | N_Selected_Component - => - Read_Indexes (Prefix (Expr)); - - when N_Indexed_Component => - Read_Indexes (Prefix (Expr)); - Read_Expression_List (Expressions (Expr)); - - when N_Slice => - Read_Indexes (Prefix (Expr)); - Read_Expression (Discrete_Range (Expr)); - - -- The argument of an allocator is moved as part of the implicit - -- assignment. - - when N_Allocator => - Move_Expression (Expression (Expr)); - - when N_Function_Call => - Read_Params (Expr); - if Ekind (Get_Called_Entity (Expr)) = E_Subprogram_Type then - if Emit_Messages then - Error_Msg_N - ("call through access to subprogram is not allowed in " - & "SPARK", Expr); - end if; - else - Check_Globals (Get_Called_Entity (Expr)); - end if; - - when N_Op_Concat => - Read_Expression (Left_Opnd (Expr)); - Read_Expression (Right_Opnd (Expr)); - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - Read_Indexes (Expression (Expr)); - - when N_Aggregate => - declare - Assocs : constant List_Id := Component_Associations (Expr); - CL : List_Id; - Assoc : Node_Id := Nlists.First (Assocs); - Choice : Node_Id; - - begin - -- The subexpressions of an aggregate are moved as part - -- of the implicit assignments. Handle the positional - -- components first. - - Move_Expression_List (Expressions (Expr)); - - -- Handle the named components next - - while Present (Assoc) loop - CL := Choices (Assoc); - - -- For an array aggregate, we should also check that the - -- expressions used in choices are readable. - - if Is_Array_Type (Etype (Expr)) then - Choice := Nlists.First (CL); - while Present (Choice) loop - if Nkind (Choice) /= N_Others_Choice then - Read_Expression (Choice); - end if; - Next (Choice); - end loop; - end if; - - -- There can be only one element for a value of deep type - -- in order to avoid aliasing. - - if not Box_Present (Assoc) - and then Is_Deep (Etype (Expression (Assoc))) - and then not Is_Singleton_Choice (CL) - and then Emit_Messages - then - Error_Msg_F - ("singleton choice required to prevent aliasing", - First (CL)); - end if; - - -- The subexpressions of an aggregate are moved as part - -- of the implicit assignments. - - if not Box_Present (Assoc) then - Move_Expression (Expression (Assoc)); - end if; - - Next (Assoc); - end loop; - end; - - when N_Extension_Aggregate => - declare - Exprs : constant List_Id := Expressions (Expr); - Assocs : constant List_Id := Component_Associations (Expr); - CL : List_Id; - Assoc : Node_Id := Nlists.First (Assocs); - - begin - Move_Expression (Ancestor_Part (Expr)); - - -- No positional components allowed at this stage - - if Present (Exprs) then - raise Program_Error; - end if; - - while Present (Assoc) loop - CL := Choices (Assoc); - - -- Only singleton components allowed at this stage - - if not Is_Singleton_Choice (CL) then - raise Program_Error; - end if; - - -- The subexpressions of an aggregate are moved as part - -- of the implicit assignments. - - if not Box_Present (Assoc) then - Move_Expression (Expression (Assoc)); - end if; - - Next (Assoc); - end loop; - end; - - when N_If_Expression => - declare - Cond : constant Node_Id := First (Expressions (Expr)); - Then_Part : constant Node_Id := Next (Cond); - Else_Part : constant Node_Id := Next (Then_Part); - begin - Read_Expression (Cond); - Read_Indexes (Then_Part); - Read_Indexes (Else_Part); - end; - - when N_Case_Expression => - declare - Cases : constant List_Id := Alternatives (Expr); - Cur_Case : Node_Id := First (Cases); - - begin - Read_Expression (Expression (Expr)); - - while Present (Cur_Case) loop - Read_Indexes (Expression (Cur_Case)); - Next (Cur_Case); - end loop; - end; - - when N_Attribute_Reference => - pragma Assert - (Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Loop_Entry - or else - Get_Attribute_Id (Attribute_Name (Expr)) = Attribute_Update - or else - Get_Attribute_Id (Attribute_Name (Expr)) = Attribute_Image); - - Read_Expression (Prefix (Expr)); - - if Get_Attribute_Id (Attribute_Name (Expr)) = Attribute_Update - or else (Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Image - and then Is_Type_Name (Prefix (Expr))) - then - Read_Expression_List (Expressions (Expr)); - end if; - - when others => - raise Program_Error; - end case; - end Read_Indexes; - - -- Start of processing for Check_Expression - - begin - if Is_Type_Name (Expr) then - return; - - elsif Is_Path_Expression (Expr) then - if Mode /= Assign then - Read_Indexes (Expr); - end if; - - if Mode /= Read_Subexpr then - Process_Path (Expr, Mode); - end if; - - return; - end if; - - -- Expressions that are not path expressions should only be analyzed in - -- Read mode. - - if Mode /= Read then - if Emit_Messages then - Error_Msg_N ("name expected here for move/borrow/observe", Expr); - end if; - return; - end if; - - -- Special handling for nodes that may contain evaluated expressions in - -- the form of constraints. - - case Nkind (Expr) is - when N_Index_Or_Discriminant_Constraint => - declare - Assn : Node_Id := First (Constraints (Expr)); - begin - while Present (Assn) loop - case Nkind (Assn) is - when N_Discriminant_Association => - Read_Expression (Expression (Assn)); - - when others => - Read_Expression (Assn); - end case; - - Next (Assn); - end loop; - end; - return; - - when N_Range_Constraint => - Read_Expression (Range_Expression (Expr)); - return; - - when N_Subtype_Indication => - if Present (Constraint (Expr)) then - Read_Expression (Constraint (Expr)); - end if; - return; - - when N_Digits_Constraint => - Read_Expression (Digits_Expression (Expr)); - if Present (Range_Constraint (Expr)) then - Read_Expression (Range_Constraint (Expr)); - end if; - return; - - when N_Delta_Constraint => - Read_Expression (Delta_Expression (Expr)); - if Present (Range_Constraint (Expr)) then - Read_Expression (Range_Constraint (Expr)); - end if; - return; - - when others => - null; - end case; - - -- At this point Expr can only be a subexpression - - case N_Subexpr'(Nkind (Expr)) is - - when N_Binary_Op - | N_Short_Circuit - => - Read_Expression (Left_Opnd (Expr)); - Read_Expression (Right_Opnd (Expr)); - - when N_Membership_Test => - Read_Expression (Left_Opnd (Expr)); - if Present (Right_Opnd (Expr)) then - Read_Expression (Right_Opnd (Expr)); - else - declare - Cases : constant List_Id := Alternatives (Expr); - Cur_Case : Node_Id := First (Cases); - - begin - while Present (Cur_Case) loop - Read_Expression (Cur_Case); - Next (Cur_Case); - end loop; - end; - end if; - - when N_Unary_Op => - Read_Expression (Right_Opnd (Expr)); - - when N_Attribute_Reference => - declare - Aname : constant Name_Id := Attribute_Name (Expr); - Attr_Id : constant Attribute_Id := Get_Attribute_Id (Aname); - Pref : constant Node_Id := Prefix (Expr); - Args : constant List_Id := Expressions (Expr); - - begin - case Attr_Id is - - -- The following attributes take either no arguments, or - -- arguments that do not refer to evaluated expressions - -- (like Length or Loop_Entry), hence only the prefix - -- needs to be read. - - when Attribute_Address - | Attribute_Alignment - | Attribute_Callable - | Attribute_Component_Size - | Attribute_Constrained - | Attribute_First - | Attribute_First_Bit - | Attribute_Last - | Attribute_Last_Bit - | Attribute_Length - | Attribute_Loop_Entry - | Attribute_Object_Size - | Attribute_Position - | Attribute_Size - | Attribute_Terminated - | Attribute_Valid - | Attribute_Value_Size - => - Read_Expression (Pref); - - -- The following attributes take a type name as prefix, - -- hence only the arguments need to be read. - - when Attribute_Ceiling - | Attribute_Floor - | Attribute_Max - | Attribute_Min - | Attribute_Mod - | Attribute_Pos - | Attribute_Pred - | Attribute_Remainder - | Attribute_Rounding - | Attribute_Succ - | Attribute_Truncation - | Attribute_Val - | Attribute_Value - => - Read_Expression_List (Args); - - -- Attributes Image and Img either take a type name as - -- prefix with an expression in argument, or the expression - -- directly as prefix. Adapt to each case. - - when Attribute_Image - | Attribute_Img - => - if No (Args) then - Read_Expression (Pref); - else - Read_Expression_List (Args); - end if; - - -- Attribute Update takes expressions as both prefix and - -- arguments, so both need to be read. - - when Attribute_Update => - Read_Expression (Pref); - Read_Expression_List (Args); - - -- Attribute Modulus does not reference the evaluated - -- expression, so it can be ignored for this analysis. - - when Attribute_Modulus => - null; - - -- The following attributes apply to types; there are no - -- expressions to read. - - when Attribute_Class - | Attribute_Storage_Size - => - null; - - -- Postconditions should not be analyzed - - when Attribute_Old - | Attribute_Result - => - raise Program_Error; - - when others => - null; - end case; - end; - - when N_Range => - Read_Expression (Low_Bound (Expr)); - Read_Expression (High_Bound (Expr)); - - when N_If_Expression => - Read_Expression_List (Expressions (Expr)); - - when N_Case_Expression => - declare - Cases : constant List_Id := Alternatives (Expr); - Cur_Case : Node_Id := First (Cases); - - begin - while Present (Cur_Case) loop - Read_Expression (Expression (Cur_Case)); - Next (Cur_Case); - end loop; - - Read_Expression (Expression (Expr)); - end; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - Read_Expression (Expression (Expr)); - - when N_Quantified_Expression => - declare - For_In_Spec : constant Node_Id := - Loop_Parameter_Specification (Expr); - For_Of_Spec : constant Node_Id := - Iterator_Specification (Expr); - For_Of_Spec_Typ : Node_Id; - - begin - if Present (For_In_Spec) then - Read_Expression (Discrete_Subtype_Definition (For_In_Spec)); - else - Read_Expression (Name (For_Of_Spec)); - For_Of_Spec_Typ := Subtype_Indication (For_Of_Spec); - if Present (For_Of_Spec_Typ) then - Read_Expression (For_Of_Spec_Typ); - end if; - end if; - - Read_Expression (Condition (Expr)); - end; - - when N_Character_Literal - | N_Numeric_Or_String_Literal - | N_Operator_Symbol - | N_Raise_Expression - | N_Raise_xxx_Error - => - null; - - when N_Delta_Aggregate - | N_Target_Name - => - null; - - -- Procedure calls are handled in Check_Node - - when N_Procedure_Call_Statement => - raise Program_Error; - - -- Path expressions are handled before this point - - when N_Aggregate - | N_Allocator - | N_Expanded_Name - | N_Explicit_Dereference - | N_Extension_Aggregate - | N_Function_Call - | N_Identifier - | N_Indexed_Component - | N_Null - | N_Selected_Component - | N_Slice - => - raise Program_Error; - - -- The following nodes are never generated in GNATprove mode - - when N_Expression_With_Actions - | N_Reference - | N_Unchecked_Expression - => - raise Program_Error; - end case; - end Check_Expression; - - ---------------- - -- Check_List -- - ---------------- - - procedure Check_List (L : List_Id) is - N : Node_Id; - begin - N := First (L); - while Present (N) loop - Check_Node (N); - Next (N); - end loop; - end Check_List; - - -------------------------- - -- Check_Loop_Statement -- - -------------------------- - - procedure Check_Loop_Statement (Stmt : Node_Id) is - - -- Local Subprograms - - procedure Check_Is_Less_Restrictive_Env - (Exiting_Env : Perm_Env; - Entry_Env : Perm_Env); - -- This procedure checks that the Exiting_Env environment is less - -- restrictive than the Entry_Env environment. - - procedure Check_Is_Less_Restrictive_Tree - (New_Tree : Perm_Tree_Access; - Orig_Tree : Perm_Tree_Access; - E : Entity_Id); - -- Auxiliary procedure to check that the tree New_Tree is less - -- restrictive than the tree Orig_Tree for the entity E. - - procedure Perm_Error_Loop_Exit - (E : Entity_Id; - Loop_Id : Node_Id; - Perm : Perm_Kind; - Found_Perm : Perm_Kind; - Expl : Node_Id); - -- A procedure that is called when the permissions found contradict - -- the rules established by the RM at the exit of loops. This function - -- is called with the entity, the node of the enclosing loop, the - -- permission that was expected, and the permission found, and issues - -- an appropriate error message. - - ----------------------------------- - -- Check_Is_Less_Restrictive_Env -- - ----------------------------------- - - procedure Check_Is_Less_Restrictive_Env - (Exiting_Env : Perm_Env; - Entry_Env : Perm_Env) - is - Comp_Entry : Perm_Tree_Maps.Key_Option; - Iter_Entry, Iter_Exit : Perm_Tree_Access; - - begin - Comp_Entry := Get_First_Key (Entry_Env); - while Comp_Entry.Present loop - Iter_Entry := Get (Entry_Env, Comp_Entry.K); - pragma Assert (Iter_Entry /= null); - Iter_Exit := Get (Exiting_Env, Comp_Entry.K); - pragma Assert (Iter_Exit /= null); - Check_Is_Less_Restrictive_Tree - (New_Tree => Iter_Exit, - Orig_Tree => Iter_Entry, - E => Comp_Entry.K); - Comp_Entry := Get_Next_Key (Entry_Env); - end loop; - end Check_Is_Less_Restrictive_Env; - - ------------------------------------ - -- Check_Is_Less_Restrictive_Tree -- - ------------------------------------ - - procedure Check_Is_Less_Restrictive_Tree - (New_Tree : Perm_Tree_Access; - Orig_Tree : Perm_Tree_Access; - E : Entity_Id) - is - -- Local subprograms - - procedure Check_Is_Less_Restrictive_Tree_Than - (Tree : Perm_Tree_Access; - Perm : Perm_Kind; - E : Entity_Id); - -- Auxiliary procedure to check that the tree N is less restrictive - -- than the given permission P. - - procedure Check_Is_More_Restrictive_Tree_Than - (Tree : Perm_Tree_Access; - Perm : Perm_Kind; - E : Entity_Id); - -- Auxiliary procedure to check that the tree N is more restrictive - -- than the given permission P. - - ----------------------------------------- - -- Check_Is_Less_Restrictive_Tree_Than -- - ----------------------------------------- - - procedure Check_Is_Less_Restrictive_Tree_Than - (Tree : Perm_Tree_Access; - Perm : Perm_Kind; - E : Entity_Id) - is - begin - if not (Permission (Tree) >= Perm) then - Perm_Error_Loop_Exit - (E, Stmt, Permission (Tree), Perm, Explanation (Tree)); - end if; - - case Kind (Tree) is - when Entire_Object => - if not (Children_Permission (Tree) >= Perm) then - Perm_Error_Loop_Exit - (E, Stmt, Children_Permission (Tree), Perm, - Explanation (Tree)); - - end if; - - when Reference => - Check_Is_Less_Restrictive_Tree_Than - (Get_All (Tree), Perm, E); - - when Array_Component => - Check_Is_Less_Restrictive_Tree_Than - (Get_Elem (Tree), Perm, E); - - when Record_Component => - declare - Comp : Perm_Tree_Access; - begin - Comp := Perm_Tree_Maps.Get_First (Component (Tree)); - while Comp /= null loop - Check_Is_Less_Restrictive_Tree_Than (Comp, Perm, E); - Comp := - Perm_Tree_Maps.Get_Next (Component (Tree)); - end loop; - end; - end case; - end Check_Is_Less_Restrictive_Tree_Than; - - ----------------------------------------- - -- Check_Is_More_Restrictive_Tree_Than -- - ----------------------------------------- - - procedure Check_Is_More_Restrictive_Tree_Than - (Tree : Perm_Tree_Access; - Perm : Perm_Kind; - E : Entity_Id) - is - begin - if not (Perm >= Permission (Tree)) then - Perm_Error_Loop_Exit - (E, Stmt, Permission (Tree), Perm, Explanation (Tree)); - end if; - - case Kind (Tree) is - when Entire_Object => - if not (Perm >= Children_Permission (Tree)) then - Perm_Error_Loop_Exit - (E, Stmt, Children_Permission (Tree), Perm, - Explanation (Tree)); - end if; - - when Reference => - Check_Is_More_Restrictive_Tree_Than - (Get_All (Tree), Perm, E); - - when Array_Component => - Check_Is_More_Restrictive_Tree_Than - (Get_Elem (Tree), Perm, E); - - when Record_Component => - declare - Comp : Perm_Tree_Access; - begin - Comp := Perm_Tree_Maps.Get_First (Component (Tree)); - while Comp /= null loop - Check_Is_More_Restrictive_Tree_Than (Comp, Perm, E); - Comp := - Perm_Tree_Maps.Get_Next (Component (Tree)); - end loop; - end; - end case; - end Check_Is_More_Restrictive_Tree_Than; - - -- Start of processing for Check_Is_Less_Restrictive_Tree - - begin - if not (Permission (New_Tree) <= Permission (Orig_Tree)) then - Perm_Error_Loop_Exit - (E => E, - Loop_Id => Stmt, - Perm => Permission (New_Tree), - Found_Perm => Permission (Orig_Tree), - Expl => Explanation (New_Tree)); - end if; - - case Kind (New_Tree) is - - -- Potentially folded tree. We check the other tree Orig_Tree to - -- check whether it is folded or not. If folded we just compare - -- their Permission and Children_Permission, if not, then we - -- look at the Children_Permission of the folded tree against - -- the unfolded tree Orig_Tree. - - when Entire_Object => - case Kind (Orig_Tree) is - when Entire_Object => - if not (Children_Permission (New_Tree) <= - Children_Permission (Orig_Tree)) - then - Perm_Error_Loop_Exit - (E, Stmt, - Children_Permission (New_Tree), - Children_Permission (Orig_Tree), - Explanation (New_Tree)); - end if; - - when Reference => - Check_Is_More_Restrictive_Tree_Than - (Get_All (Orig_Tree), Children_Permission (New_Tree), E); - - when Array_Component => - Check_Is_More_Restrictive_Tree_Than - (Get_Elem (Orig_Tree), Children_Permission (New_Tree), E); - - when Record_Component => - declare - Comp : Perm_Tree_Access; - begin - Comp := Perm_Tree_Maps.Get_First - (Component (Orig_Tree)); - while Comp /= null loop - Check_Is_More_Restrictive_Tree_Than - (Comp, Children_Permission (New_Tree), E); - Comp := Perm_Tree_Maps.Get_Next - (Component (Orig_Tree)); - end loop; - end; - end case; - - when Reference => - case Kind (Orig_Tree) is - when Entire_Object => - Check_Is_Less_Restrictive_Tree_Than - (Get_All (New_Tree), Children_Permission (Orig_Tree), E); - - when Reference => - Check_Is_Less_Restrictive_Tree - (Get_All (New_Tree), Get_All (Orig_Tree), E); - - when others => - raise Program_Error; - end case; - - when Array_Component => - case Kind (Orig_Tree) is - when Entire_Object => - Check_Is_Less_Restrictive_Tree_Than - (Get_Elem (New_Tree), Children_Permission (Orig_Tree), E); - - when Array_Component => - Check_Is_Less_Restrictive_Tree - (Get_Elem (New_Tree), Get_Elem (Orig_Tree), E); - - when others => - raise Program_Error; - end case; - - when Record_Component => - declare - CompN : Perm_Tree_Access; - begin - CompN := - Perm_Tree_Maps.Get_First (Component (New_Tree)); - case Kind (Orig_Tree) is - when Entire_Object => - while CompN /= null loop - Check_Is_Less_Restrictive_Tree_Than - (CompN, Children_Permission (Orig_Tree), E); - - CompN := - Perm_Tree_Maps.Get_Next (Component (New_Tree)); - end loop; - - when Record_Component => - declare - - KeyO : Perm_Tree_Maps.Key_Option; - CompO : Perm_Tree_Access; - begin - KeyO := Perm_Tree_Maps.Get_First_Key - (Component (Orig_Tree)); - while KeyO.Present loop - CompN := Perm_Tree_Maps.Get - (Component (New_Tree), KeyO.K); - CompO := Perm_Tree_Maps.Get - (Component (Orig_Tree), KeyO.K); - pragma Assert (CompO /= null); - - Check_Is_Less_Restrictive_Tree (CompN, CompO, E); - - KeyO := Perm_Tree_Maps.Get_Next_Key - (Component (Orig_Tree)); - end loop; - end; - - when others => - raise Program_Error; - end case; - end; - end case; - end Check_Is_Less_Restrictive_Tree; - - -------------------------- - -- Perm_Error_Loop_Exit -- - -------------------------- - - procedure Perm_Error_Loop_Exit - (E : Entity_Id; - Loop_Id : Node_Id; - Perm : Perm_Kind; - Found_Perm : Perm_Kind; - Expl : Node_Id) - is - begin - if Emit_Messages then - Error_Msg_Node_2 := Loop_Id; - Error_Msg_N - ("insufficient permission for & when exiting loop &", E); - Perm_Mismatch (Exp_Perm => Perm, - Act_Perm => Found_Perm, - N => Loop_Id, - Expl => Expl); - end if; - end Perm_Error_Loop_Exit; - - -- Local variables - - Loop_Name : constant Entity_Id := Entity (Identifier (Stmt)); - Loop_Env : constant Perm_Env_Access := new Perm_Env; - Scheme : constant Node_Id := Iteration_Scheme (Stmt); - - -- Start of processing for Check_Loop_Statement - - begin - -- Save environment prior to the loop - - Copy_Env (From => Current_Perm_Env, To => Loop_Env.all); - - -- Add saved environment to loop environment - - Set (Current_Loops_Envs, Loop_Name, Loop_Env); - - -- If the loop is not a plain-loop, then it may either never be entered, - -- or it may be exited after a number of iterations. Hence add the - -- current permission environment as the initial loop exit environment. - -- Otherwise, the loop exit environment remains empty until it is - -- populated by analyzing exit statements. - - if Present (Iteration_Scheme (Stmt)) then - declare - Exit_Env : constant Perm_Env_Access := new Perm_Env; - - begin - Copy_Env (From => Current_Perm_Env, To => Exit_Env.all); - Set (Current_Loops_Accumulators, Loop_Name, Exit_Env); - end; - end if; - - -- Analyze loop - - if Present (Scheme) then - - -- Case of a WHILE loop - - if Present (Condition (Scheme)) then - Check_Expression (Condition (Scheme), Read); - - -- Case of a FOR loop - - else - declare - Param_Spec : constant Node_Id := - Loop_Parameter_Specification (Scheme); - Iter_Spec : constant Node_Id := Iterator_Specification (Scheme); - begin - if Present (Param_Spec) then - Check_Expression - (Discrete_Subtype_Definition (Param_Spec), Read); - else - Check_Expression (Name (Iter_Spec), Read); - if Present (Subtype_Indication (Iter_Spec)) then - Check_Expression (Subtype_Indication (Iter_Spec), Read); - end if; - end if; - end; - end if; - end if; - - Check_List (Statements (Stmt)); - - -- Check that environment gets less restrictive at end of loop - - Check_Is_Less_Restrictive_Env - (Exiting_Env => Current_Perm_Env, - Entry_Env => Loop_Env.all); - - -- Set environment to the one for exiting the loop - - declare - Exit_Env : constant Perm_Env_Access := - Get (Current_Loops_Accumulators, Loop_Name); - begin - Free_Env (Current_Perm_Env); - - -- In the normal case, Exit_Env is not null and we use it. In the - -- degraded case of a plain-loop without exit statements, Exit_Env is - -- null, and we use the initial permission environment at the start - -- of the loop to continue analysis. Any environment would be fine - -- here, since the code after the loop is dead code, but this way we - -- avoid spurious errors by having at least variables in scope inside - -- the environment. - - if Exit_Env /= null then - Copy_Env (From => Exit_Env.all, To => Current_Perm_Env); - Free_Env (Loop_Env.all); - Free_Env (Exit_Env.all); - else - Copy_Env (From => Loop_Env.all, To => Current_Perm_Env); - Free_Env (Loop_Env.all); - end if; - end; - end Check_Loop_Statement; - - ---------------- - -- Check_Node -- - ---------------- - - procedure Check_Node (N : Node_Id) is - - procedure Check_Subprogram_Contract (N : Node_Id); - -- Check the postcondition-like contracts for use of 'Old - - ------------------------------- - -- Check_Subprogram_Contract -- - ------------------------------- - - procedure Check_Subprogram_Contract (N : Node_Id) is - begin - if Nkind (N) = N_Subprogram_Declaration - or else Acts_As_Spec (N) - then - declare - E : constant Entity_Id := Unique_Defining_Entity (N); - Post : constant Node_Id := - Get_Pragma (E, Pragma_Postcondition); - Cases : constant Node_Id := - Get_Pragma (E, Pragma_Contract_Cases); - begin - Check_Old_Loop_Entry (Post); - Check_Old_Loop_Entry (Cases); - end; - - elsif Nkind (N) = N_Subprogram_Body then - declare - E : constant Entity_Id := Defining_Entity (N); - Ref_Post : constant Node_Id := - Get_Pragma (E, Pragma_Refined_Post); - begin - Check_Old_Loop_Entry (Ref_Post); - end; - end if; - end Check_Subprogram_Contract; - - -- Start of processing for Check_Node - - begin - case Nkind (N) is - when N_Declaration => - Check_Declaration (N); - - when N_Body_Stub => - Check_Node (Get_Body_From_Stub (N)); - - when N_Statement_Other_Than_Procedure_Call => - Check_Statement (N); - - when N_Procedure_Call_Statement => - Check_Call_Statement (N); - - when N_Package_Body => - if not Is_Generic_Unit (Unique_Defining_Entity (N)) then - Check_Package_Body (N); - end if; - - when N_Subprogram_Body => - if not Is_Generic_Unit (Unique_Defining_Entity (N)) then - Check_Subprogram_Contract (N); - Check_Callable_Body (N); - end if; - - when N_Entry_Body - | N_Task_Body - => - Check_Callable_Body (N); - - when N_Protected_Body => - Check_List (Declarations (N)); - - when N_Package_Declaration => - Check_Package_Spec (N); - - when N_Handled_Sequence_Of_Statements => - Check_List (Statements (N)); - - when N_Pragma => - Check_Pragma (N); - - when N_Subprogram_Declaration => - Check_Subprogram_Contract (N); - - -- Attribute references in statement position are not supported in - -- SPARK and will be rejected by GNATprove. - - when N_Attribute_Reference => - null; - - -- Ignored constructs for pointer checking - - when N_Abstract_Subprogram_Declaration - | N_At_Clause - | N_Attribute_Definition_Clause - | N_Call_Marker - | N_Delta_Constraint - | N_Digits_Constraint - | N_Empty - | N_Enumeration_Representation_Clause - | N_Exception_Declaration - | N_Exception_Renaming_Declaration - | N_Formal_Package_Declaration - | N_Formal_Subprogram_Declaration - | N_Freeze_Entity - | N_Freeze_Generic_Entity - | N_Function_Instantiation - | N_Generic_Function_Renaming_Declaration - | N_Generic_Package_Declaration - | N_Generic_Package_Renaming_Declaration - | N_Generic_Procedure_Renaming_Declaration - | N_Generic_Subprogram_Declaration - | N_Implicit_Label_Declaration - | N_Itype_Reference - | N_Label - | N_Number_Declaration - | N_Object_Renaming_Declaration - | N_Others_Choice - | N_Package_Instantiation - | N_Package_Renaming_Declaration - | N_Procedure_Instantiation - | N_Raise_xxx_Error - | N_Record_Representation_Clause - | N_Subprogram_Renaming_Declaration - | N_Task_Type_Declaration - | N_Use_Package_Clause - | N_With_Clause - | N_Use_Type_Clause - | N_Validate_Unchecked_Conversion - | N_Variable_Reference_Marker - | N_Discriminant_Association - - -- ??? check whether we should do something special for - -- N_Discriminant_Association, or maybe raise Program_Error. - => - null; - - -- Checking should not be called directly on these nodes - - when others => - raise Program_Error; - end case; - end Check_Node; - - -------------------------- - -- Check_Old_Loop_Entry -- - -------------------------- - - procedure Check_Old_Loop_Entry (N : Node_Id) is - - function Check_Attribute (N : Node_Id) return Traverse_Result; - - --------------------- - -- Check_Attribute -- - --------------------- - - function Check_Attribute (N : Node_Id) return Traverse_Result is - Attr_Id : Attribute_Id; - Aname : Name_Id; - Pref : Node_Id; - - begin - if Nkind (N) = N_Attribute_Reference then - Attr_Id := Get_Attribute_Id (Attribute_Name (N)); - Aname := Attribute_Name (N); - - if Attr_Id = Attribute_Old - or else Attr_Id = Attribute_Loop_Entry - then - Pref := Prefix (N); - - if Is_Deep (Etype (Pref)) then - if Nkind (Pref) /= N_Function_Call then - if Emit_Messages then - Error_Msg_Name_1 := Aname; - Error_Msg_N - ("prefix of % attribute must be a function call " - & "(SPARK RM 3.10(13))", Pref); - end if; - - elsif Is_Traversal_Function_Call (Pref) then - if Emit_Messages then - Error_Msg_Name_1 := Aname; - Error_Msg_N - ("prefix of % attribute should not call a traversal " - & "function (SPARK RM 3.10(13))", Pref); - end if; - end if; - end if; - end if; - end if; - - return OK; - end Check_Attribute; - - procedure Check_All is new Traverse_Proc (Check_Attribute); - - -- Start of processing for Check_Old_Loop_Entry - - begin - Check_All (N); - end Check_Old_Loop_Entry; - - ------------------------ - -- Check_Package_Body -- - ------------------------ - - procedure Check_Package_Body (Pack : Node_Id) is - Save_In_Elab : constant Boolean := Inside_Elaboration; - Spec : constant Node_Id := - Package_Specification (Corresponding_Spec (Pack)); - Id : constant Entity_Id := Defining_Entity (Pack); - Prag : constant Node_Id := SPARK_Pragma (Id); - Aux_Prag : constant Node_Id := SPARK_Aux_Pragma (Id); - Saved_Env : Perm_Env; - - begin - if Present (Prag) - and then Get_SPARK_Mode_From_Annotation (Prag) = Opt.On - then - Inside_Elaboration := True; - - -- Save environment and put a new one in place - - Move_Env (Current_Perm_Env, Saved_Env); - - -- Reanalyze package spec to have its variables in the environment - - Check_List (Visible_Declarations (Spec)); - Check_List (Private_Declarations (Spec)); - - -- Check declarations and statements in the special mode for - -- elaboration. - - Check_List (Declarations (Pack)); - - if Present (Aux_Prag) - and then Get_SPARK_Mode_From_Annotation (Aux_Prag) = Opt.On - then - Check_Node (Handled_Statement_Sequence (Pack)); - end if; - - -- Restore the saved environment and free the current one - - Move_Env (Saved_Env, Current_Perm_Env); - - Inside_Elaboration := Save_In_Elab; - end if; - end Check_Package_Body; - - ------------------------ - -- Check_Package_Spec -- - ------------------------ - - procedure Check_Package_Spec (Pack : Node_Id) is - Save_In_Elab : constant Boolean := Inside_Elaboration; - Spec : constant Node_Id := Specification (Pack); - Id : constant Entity_Id := Defining_Entity (Pack); - Prag : constant Node_Id := SPARK_Pragma (Id); - Aux_Prag : constant Node_Id := SPARK_Aux_Pragma (Id); - Saved_Env : Perm_Env; - - begin - if Present (Prag) - and then Get_SPARK_Mode_From_Annotation (Prag) = Opt.On - then - Inside_Elaboration := True; - - -- Save environment and put a new one in place - - Move_Env (Current_Perm_Env, Saved_Env); - - -- Check declarations in the special mode for elaboration - - Check_List (Visible_Declarations (Spec)); - - if Present (Aux_Prag) - and then Get_SPARK_Mode_From_Annotation (Aux_Prag) = Opt.On - then - Check_List (Private_Declarations (Spec)); - end if; - - -- Restore the saved environment and free the current one. As part of - -- the restoration, the environment of the package spec is merged in - -- the enclosing environment, which may be an enclosing - -- package/subprogram spec or body which has access to the variables - -- of the package spec. - - Merge_Env (Saved_Env, Current_Perm_Env); - - Inside_Elaboration := Save_In_Elab; - end if; - end Check_Package_Spec; - - ------------------------------- - -- Check_Parameter_Or_Global -- - ------------------------------- - - procedure Check_Parameter_Or_Global - (Expr : Node_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean) - is - Mode : Checking_Mode; - Status : Error_Status; - - begin - if not Global_Var - and then Is_Anonymous_Access_Type (Typ) - then - Check_Source_Of_Borrow_Or_Observe (Expr, Status); - - if Status /= OK then - return; - end if; - end if; - - case Kind is - when E_In_Parameter => - - -- Inputs of functions have R permission only - - if Ekind (Subp) = E_Function then - Mode := Read; - - -- Input global variables have R permission only - - elsif Global_Var then - Mode := Read; - - -- Anonymous access to constant is an observe - - elsif Is_Anonymous_Access_Type (Typ) - and then Is_Access_Constant (Typ) - then - Mode := Observe; - - -- Other access types are a borrow - - elsif Is_Access_Type (Typ) then - Mode := Borrow; - - -- Deep types other than access types define an observe - - elsif Is_Deep (Typ) then - Mode := Observe; - - -- Otherwise the variable is read - - else - Mode := Read; - end if; - - when E_Out_Parameter => - Mode := Assign; - - when E_In_Out_Parameter => - Mode := Move; - end case; - - if Mode = Assign then - Check_Expression (Expr, Read_Subexpr); - end if; - - Check_Expression (Expr, Mode); - end Check_Parameter_Or_Global; - - procedure Check_Globals_Inst is - new Handle_Globals (Check_Parameter_Or_Global); - - procedure Check_Globals (Subp : Entity_Id) renames Check_Globals_Inst; - - ------------------ - -- Check_Pragma -- - ------------------ - - procedure Check_Pragma (Prag : Node_Id) is - Prag_Id : constant Pragma_Id := Get_Pragma_Id (Prag); - Arg1 : constant Node_Id := - First (Pragma_Argument_Associations (Prag)); - Arg2 : Node_Id := Empty; - - begin - if Present (Arg1) then - Arg2 := Next (Arg1); - end if; - - case Prag_Id is - when Pragma_Check => - declare - Expr : constant Node_Id := Expression (Arg2); - begin - Check_Expression (Expr, Read); - - -- Prefix of Loop_Entry should be checked inside any assertion - -- where it may appear. - - Check_Old_Loop_Entry (Expr); - end; - - -- Prefix of Loop_Entry should be checked inside a Loop_Variant - - when Pragma_Loop_Variant => - Check_Old_Loop_Entry (Prag); - - -- There is no need to check contracts, as these can only access - -- inputs and outputs of the subprogram. Inputs are checked - -- independently for R permission. Outputs are checked - -- independently to have RW permission on exit. - - -- Postconditions are checked for correct use of 'Old, but starting - -- from the corresponding declaration, in order to avoid dealing with - -- with contracts on generic subprograms which are not handled in - -- GNATprove. - - when Pragma_Precondition - | Pragma_Postcondition - | Pragma_Contract_Cases - | Pragma_Refined_Post - => - null; - - -- The same holds for the initial condition after package - -- elaboration, for the different reason that library-level - -- variables can only be left in RW state after elaboration. - - when Pragma_Initial_Condition => - null; - - -- These pragmas should have been rewritten and/or removed in - -- GNATprove mode. - - when Pragma_Assert - | Pragma_Assert_And_Cut - | Pragma_Assume - | Pragma_Compile_Time_Error - | Pragma_Compile_Time_Warning - | Pragma_Debug - | Pragma_Loop_Invariant - => - raise Program_Error; - - when others => - null; - end case; - end Check_Pragma; - - ------------------------- - -- Check_Safe_Pointers -- - ------------------------- - - procedure Check_Safe_Pointers (N : Node_Id) is - - -- Local subprograms - - procedure Check_List (L : List_Id); - -- Call the main analysis procedure on each element of the list - - procedure Initialize; - -- Initialize global variables before starting the analysis of a body - - ---------------- - -- Check_List -- - ---------------- - - procedure Check_List (L : List_Id) is - N : Node_Id; - begin - N := First (L); - while Present (N) loop - Check_Safe_Pointers (N); - Next (N); - end loop; - end Check_List; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize is - begin - Reset (Current_Loops_Envs); - Reset (Current_Loops_Accumulators); - Reset (Current_Perm_Env); - end Initialize; - - -- Start of processing for Check_Safe_Pointers - - begin - Initialize; - - case Nkind (N) is - when N_Compilation_Unit => - Check_Safe_Pointers (Unit (N)); - - when N_Package_Body - | N_Package_Declaration - | N_Subprogram_Declaration - | N_Subprogram_Body - => - declare - E : constant Entity_Id := Defining_Entity (N); - Prag : constant Node_Id := SPARK_Pragma (E); - -- SPARK_Mode pragma in application - - begin - if Ekind (Unique_Entity (E)) in Generic_Unit_Kind then - null; - - elsif Present (Prag) then - if Get_SPARK_Mode_From_Annotation (Prag) = Opt.On then - Check_Node (N); - end if; - - elsif Nkind (N) = N_Package_Body then - Check_List (Declarations (N)); - - elsif Nkind (N) = N_Package_Declaration then - Check_List (Private_Declarations (Specification (N))); - Check_List (Visible_Declarations (Specification (N))); - end if; - end; - - when others => - null; - end case; - end Check_Safe_Pointers; - - --------------------------------------- - -- Check_Source_Of_Borrow_Or_Observe -- - --------------------------------------- - - procedure Check_Source_Of_Borrow_Or_Observe - (Expr : Node_Id; - Status : out Error_Status) - is - Root : Entity_Id; - - begin - if Is_Path_Expression (Expr) then - Root := Get_Root_Object (Expr); - else - Root := Empty; - end if; - - Status := OK; - - -- SPARK RM 3.10(3): If the target of an assignment operation is an - -- object of an anonymous access-to-object type (including copy-in for - -- a parameter), then the source shall be a name denoting a part of a - -- stand-alone object, a part of a parameter, or a call to a traversal - -- function. - - if No (Root) then - if Emit_Messages then - if Nkind (Expr) = N_Function_Call then - Error_Msg_N - ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr); - Error_Msg_N - ("\function called must be a traversal function", Expr); - else - Error_Msg_N - ("incorrect borrow or observe (SPARK RM 3.10(3))", Expr); - Error_Msg_N - ("\expression must be part of stand-alone object or " & - "parameter", - Expr); - end if; - end if; - - Status := Error; - end if; - end Check_Source_Of_Borrow_Or_Observe; - - --------------------- - -- Check_Statement -- - --------------------- - - procedure Check_Statement (Stmt : Node_Id) is - begin - case N_Statement_Other_Than_Procedure_Call'(Nkind (Stmt)) is - - -- An entry call is handled like other calls - - when N_Entry_Call_Statement => - Check_Call_Statement (Stmt); - - -- An assignment may correspond to a move, a borrow, or an observe - - when N_Assignment_Statement => - declare - Target : constant Node_Id := Name (Stmt); - - begin - -- Start with checking that the subexpressions of the target - -- path are readable, before possibly updating the permission - -- of these subexpressions in Check_Assignment. - - Check_Expression (Target, Read_Subexpr); - - Check_Assignment (Target => Target, - Expr => Expression (Stmt)); - - -- ??? We need a rule that forbids targets of assignment for - -- which the path is not known, for example when there is a - -- function call involved (which includes calls to traversal - -- functions). Otherwise there is no way to update the - -- corresponding path permission. - - if No (Get_Root_Object - (Target, Through_Traversal => False)) - then - if Emit_Messages then - Error_Msg_N ("illegal target for assignment", Target); - end if; - return; - end if; - - Check_Expression (Target, Assign); - end; - - when N_Block_Statement => - Check_List (Declarations (Stmt)); - Check_Node (Handled_Statement_Sequence (Stmt)); - - -- Remove local borrowers and observers - - declare - Decl : Node_Id := First (Declarations (Stmt)); - Var : Entity_Id; - begin - while Present (Decl) loop - if Nkind (Decl) = N_Object_Declaration then - Var := Defining_Identifier (Decl); - Remove (Current_Borrowers, Var); - Remove (Current_Observers, Var); - end if; - - Next (Decl); - end loop; - end; - - when N_Case_Statement => - declare - Alt : Node_Id; - Saved_Env : Perm_Env; - -- Copy of environment for analysis of the different cases - New_Env : Perm_Env; - -- Accumulator for the different cases - - begin - Check_Expression (Expression (Stmt), Read); - - -- Save environment - - Copy_Env (Current_Perm_Env, Saved_Env); - - -- First alternative - - Alt := First (Alternatives (Stmt)); - Check_List (Statements (Alt)); - Next (Alt); - - -- Cleanup - - Move_Env (Current_Perm_Env, New_Env); - - -- Other alternatives - - while Present (Alt) loop - - -- Restore environment - - Copy_Env (Saved_Env, Current_Perm_Env); - - -- Next alternative - - Check_List (Statements (Alt)); - Next (Alt); - - -- Merge Current_Perm_Env into New_Env - - Merge_Env (Source => Current_Perm_Env, Target => New_Env); - end loop; - - Move_Env (New_Env, Current_Perm_Env); - Free_Env (Saved_Env); - end; - - when N_Delay_Relative_Statement - | N_Delay_Until_Statement - => - Check_Expression (Expression (Stmt), Read); - - when N_Loop_Statement => - Check_Loop_Statement (Stmt); - - when N_Simple_Return_Statement => - declare - Subp : constant Entity_Id := - Return_Applies_To (Return_Statement_Entity (Stmt)); - Expr : constant Node_Id := Expression (Stmt); - begin - if Present (Expression (Stmt)) then - declare - Return_Typ : constant Entity_Id := - Etype (Expression (Stmt)); - - begin - -- SPARK RM 3.10(5): A return statement that applies - -- to a traversal function that has an anonymous - -- access-to-constant (respectively, access-to-variable) - -- result type, shall return either the literal null - -- or an access object denoted by a direct or indirect - -- observer (respectively, borrower) of the traversed - -- parameter. - - if Is_Anonymous_Access_Type (Return_Typ) then - pragma Assert (Is_Traversal_Function (Subp)); - - if Nkind (Expr) /= N_Null then - declare - Expr_Root : constant Entity_Id := - Get_Root_Object (Expr, Is_Traversal => True); - Param : constant Entity_Id := - First_Formal (Subp); - begin - if Param /= Expr_Root and then Emit_Messages then - Error_Msg_NE - ("returned value must be rooted in " - & "traversed parameter & " - & "(SPARK RM 3.10(5))", - Stmt, Param); - end if; - end; - end if; - - -- Move expression to caller - - elsif Is_Deep (Return_Typ) then - - if Is_Path_Expression (Expr) then - Check_Expression (Expr, Move); - - else - if Emit_Messages then - Error_Msg_N - ("expression not allowed as source of move", - Expr); - end if; - return; - end if; - - else - Check_Expression (Expr, Read); - end if; - - if Ekind_In (Subp, E_Procedure, E_Entry) - and then not No_Return (Subp) - then - Return_Parameters (Subp); - Return_Globals (Subp); - end if; - end; - end if; - end; - - when N_Extended_Return_Statement => - declare - Subp : constant Entity_Id := - Return_Applies_To (Return_Statement_Entity (Stmt)); - Decls : constant List_Id := Return_Object_Declarations (Stmt); - Decl : constant Node_Id := Last_Non_Pragma (Decls); - Obj : constant Entity_Id := Defining_Identifier (Decl); - Perm : Perm_Kind; - - begin - -- SPARK RM 3.10(5): return statement of traversal function - - if Is_Traversal_Function (Subp) and then Emit_Messages then - Error_Msg_N - ("extended return cannot apply to a traversal function", - Stmt); - end if; - - Check_List (Return_Object_Declarations (Stmt)); - Check_Node (Handled_Statement_Sequence (Stmt)); - - if Is_Deep (Etype (Obj)) then - Perm := Get_Perm (Obj); - - if Perm /= Read_Write then - Perm_Error (Decl, Read_Write, Perm, - Expl => Get_Expl (Obj)); - end if; - end if; - - if Ekind_In (Subp, E_Procedure, E_Entry) - and then not No_Return (Subp) - then - Return_Parameters (Subp); - Return_Globals (Subp); - end if; - end; - - -- On loop exit, merge the current permission environment with the - -- accumulator for the given loop. - - when N_Exit_Statement => - declare - Loop_Name : constant Entity_Id := Loop_Of_Exit (Stmt); - Saved_Accumulator : constant Perm_Env_Access := - Get (Current_Loops_Accumulators, Loop_Name); - Environment_Copy : constant Perm_Env_Access := - new Perm_Env; - begin - Copy_Env (Current_Perm_Env, Environment_Copy.all); - - if Saved_Accumulator = null then - Set (Current_Loops_Accumulators, - Loop_Name, Environment_Copy); - else - Merge_Env (Source => Environment_Copy.all, - Target => Saved_Accumulator.all); - -- ??? Either free Environment_Copy, or change the type - -- of loop accumulators to directly store permission - -- environments. - end if; - end; - - -- On branches, analyze each branch independently on a fresh copy of - -- the permission environment, then merge the resulting permission - -- environments. - - when N_If_Statement => - declare - Saved_Env : Perm_Env; - New_Env : Perm_Env; - -- Accumulator for the different branches - - begin - Check_Expression (Condition (Stmt), Read); - - -- Save environment - - Copy_Env (Current_Perm_Env, Saved_Env); - - -- THEN branch - - Check_List (Then_Statements (Stmt)); - Move_Env (Current_Perm_Env, New_Env); - - -- ELSIF branches - - declare - Branch : Node_Id; - begin - Branch := First (Elsif_Parts (Stmt)); - while Present (Branch) loop - - -- Restore current permission environment - - Copy_Env (Saved_Env, Current_Perm_Env); - Check_Expression (Condition (Branch), Read); - Check_List (Then_Statements (Branch)); - - -- Merge current permission environment - - Merge_Env (Source => Current_Perm_Env, Target => New_Env); - Next (Branch); - end loop; - end; - - -- ELSE branch - - -- Restore current permission environment - - Copy_Env (Saved_Env, Current_Perm_Env); - Check_List (Else_Statements (Stmt)); - - -- Merge current permission environment - - Merge_Env (Source => Current_Perm_Env, Target => New_Env); - - -- Cleanup - - Move_Env (New_Env, Current_Perm_Env); - Free_Env (Saved_Env); - end; - - -- We should ideally ignore the branch after raising an exception, - -- so that it is not taken into account in merges. For now, just - -- propagate the current environment. - - when N_Raise_Statement => - null; - - when N_Null_Statement => - null; - - -- Unsupported constructs in SPARK - - when N_Abort_Statement - | N_Accept_Statement - | N_Asynchronous_Select - | N_Code_Statement - | N_Conditional_Entry_Call - | N_Goto_Statement - | N_Requeue_Statement - | N_Selective_Accept - | N_Timed_Entry_Call - => - null; - - -- The following nodes are never generated in GNATprove mode - - when N_Compound_Statement - | N_Free_Statement - => - raise Program_Error; - end case; - end Check_Statement; - - ------------------------- - -- Check_Type_Legality -- - ------------------------- - - procedure Check_Type_Legality - (Typ : Entity_Id; - Force : Boolean; - Legal : in out Boolean) - is - function Original_Emit_Messages return Boolean renames Emit_Messages; - - function Emit_Messages return Boolean; - -- Local wrapper around generic formal parameter Emit_Messages, to - -- check the value of parameter Force before calling the original - -- Emit_Messages, and setting Legal to False. - - ------------------- - -- Emit_Messages -- - ------------------- - - function Emit_Messages return Boolean is - begin - Legal := False; - return Force and then Original_Emit_Messages; - end Emit_Messages; - - -- Local variables - - Check_Typ : constant Entity_Id := Retysp (Typ); - - -- Start of processing for Check_Type_Legality - - begin - case Type_Kind'(Ekind (Check_Typ)) is - when Access_Kind => - case Access_Kind'(Ekind (Check_Typ)) is - when E_Access_Type - | E_Anonymous_Access_Type - => - null; - when E_Access_Subtype => - Check_Type_Legality (Base_Type (Check_Typ), Force, Legal); - when E_Access_Attribute_Type => - if Emit_Messages then - Error_Msg_N ("access attribute not allowed in SPARK", - Check_Typ); - end if; - when E_Allocator_Type => - if Emit_Messages then - Error_Msg_N ("missing type resolution", Check_Typ); - end if; - when E_General_Access_Type => - if Emit_Messages then - Error_Msg_NE - ("general access type & not allowed in SPARK", - Check_Typ, Check_Typ); - end if; - when Access_Subprogram_Kind => - if Emit_Messages then - Error_Msg_NE - ("access to subprogram type & not allowed in SPARK", - Check_Typ, Check_Typ); - end if; - end case; - - when E_Array_Type - | E_Array_Subtype - => - Check_Type_Legality (Component_Type (Check_Typ), Force, Legal); - - when Record_Kind => - if Is_Deep (Check_Typ) - and then (Is_Tagged_Type (Check_Typ) - or else Is_Class_Wide_Type (Check_Typ)) - then - if Emit_Messages then - Error_Msg_NE - ("tagged type & cannot be owning in SPARK", - Check_Typ, Check_Typ); - end if; - - else - declare - Comp : Entity_Id; - begin - Comp := First_Component_Or_Discriminant (Check_Typ); - while Present (Comp) loop - - -- Ignore components which are not visible in SPARK - - if Component_Is_Visible_In_SPARK (Comp) then - Check_Type_Legality (Etype (Comp), Force, Legal); - end if; - Next_Component_Or_Discriminant (Comp); - end loop; - end; - end if; - - when Scalar_Kind - | E_String_Literal_Subtype - | Protected_Kind - | Task_Kind - | Incomplete_Kind - | E_Exception_Type - | E_Subprogram_Type - => - null; - - -- Do not check type whose full view is not SPARK - - when E_Private_Type - | E_Private_Subtype - | E_Limited_Private_Type - | E_Limited_Private_Subtype - => - null; - end case; - end Check_Type_Legality; - - -------------- - -- Get_Expl -- - -------------- - - function Get_Expl (N : Node_Or_Entity_Id) return Node_Id is - begin - -- Special case for the object declared in an extended return statement - - if Nkind (N) = N_Defining_Identifier then - declare - C : constant Perm_Tree_Access := - Get (Current_Perm_Env, Unique_Entity (N)); - begin - pragma Assert (C /= null); - return Explanation (C); - end; - - -- The expression is a call to a traversal function - - elsif Is_Traversal_Function_Call (N) then - return N; - - -- The expression is directly rooted in an object - - elsif Present (Get_Root_Object (N, Through_Traversal => False)) then - declare - Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N); - begin - case Tree_Or_Perm.R is - when Folded => - return Tree_Or_Perm.Explanation; - - when Unfolded => - pragma Assert (Tree_Or_Perm.Tree_Access /= null); - return Explanation (Tree_Or_Perm.Tree_Access); - end case; - end; - - -- The expression is a function call, an allocation, or null - - else - return N; - end if; - end Get_Expl; - - ----------------------------------- - -- Get_Observed_Or_Borrowed_Expr -- - ----------------------------------- - - function Get_Observed_Or_Borrowed_Expr (Expr : Node_Id) return Node_Id is - - function Find_Func_Call (Expr : Node_Id) return Node_Id; - -- Search for function calls in the prefixes of Expr - - -------------------- - -- Find_Func_Call -- - -------------------- - - function Find_Func_Call (Expr : Node_Id) return Node_Id is - begin - case Nkind (Expr) is - when N_Expanded_Name - | N_Identifier - => - return Empty; - - when N_Explicit_Dereference - | N_Indexed_Component - | N_Selected_Component - | N_Slice - => - return Find_Func_Call (Prefix (Expr)); - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return Find_Func_Call (Expression (Expr)); - - when N_Function_Call => - return Expr; - - when others => - raise Program_Error; - end case; - end Find_Func_Call; - - B_Expr : Node_Id := Expr; - - begin - -- Search for the first call to a traversal function in Expr. If there - -- is one, its first parameter is the borrowed expression. Otherwise, - -- it is Expr. - - loop - declare - Call : constant Node_Id := Find_Func_Call (B_Expr); - begin - exit when No (Call); - pragma Assert (Is_Traversal_Function_Call (Call)); - B_Expr := First_Actual (Call); - end; - end loop; - - return B_Expr; - end Get_Observed_Or_Borrowed_Expr; - - -------------- - -- Get_Perm -- - -------------- - - function Get_Perm (N : Node_Or_Entity_Id) return Perm_Kind is - begin - -- Special case for the object declared in an extended return statement - - if Nkind (N) = N_Defining_Identifier then - declare - C : constant Perm_Tree_Access := - Get (Current_Perm_Env, Unique_Entity (N)); - begin - pragma Assert (C /= null); - return Permission (C); - end; - - -- The expression is a call to a traversal function - - elsif Is_Traversal_Function_Call (N) then - declare - Callee : constant Entity_Id := Get_Called_Entity (N); - begin - if Is_Access_Constant (Etype (Callee)) then - return Read_Only; - else - return Read_Write; - end if; - end; - - -- The expression is directly rooted in an object - - elsif Present (Get_Root_Object (N, Through_Traversal => False)) then - declare - Tree_Or_Perm : constant Perm_Or_Tree := Get_Perm_Or_Tree (N); - begin - case Tree_Or_Perm.R is - when Folded => - return Tree_Or_Perm.Found_Permission; - - when Unfolded => - pragma Assert (Tree_Or_Perm.Tree_Access /= null); - return Permission (Tree_Or_Perm.Tree_Access); - end case; - end; - - -- The expression is a function call, an allocation, or null - - else - return Read_Write; - end if; - end Get_Perm; - - ---------------------- - -- Get_Perm_Or_Tree -- - ---------------------- - - function Get_Perm_Or_Tree (N : Node_Id) return Perm_Or_Tree is - begin - case Nkind (N) is - - when N_Expanded_Name - | N_Identifier - => - declare - C : constant Perm_Tree_Access := - Get (Current_Perm_Env, Unique_Entity (Entity (N))); - begin - -- Except during elaboration, the root object should have been - -- declared and entered into the current permission - -- environment. - - if not Inside_Elaboration - and then C = null - then - Illegal_Global_Usage (N, N); - end if; - - return (R => Unfolded, Tree_Access => C); - end; - - -- For a nonterminal path, we get the permission tree of its - -- prefix, and then get the subtree associated with the extension, - -- if unfolded. If folded, we return the permission associated with - -- children. - - when N_Explicit_Dereference - | N_Indexed_Component - | N_Selected_Component - | N_Slice - => - declare - C : constant Perm_Or_Tree := Get_Perm_Or_Tree (Prefix (N)); - begin - case C.R is - - -- Some earlier prefix was already folded, return the - -- permission found. - - when Folded => - return C; - - when Unfolded => - case Kind (C.Tree_Access) is - - -- If the prefix tree is already folded, return the - -- children permission. - - when Entire_Object => - return (R => Folded, - Found_Permission => - Children_Permission (C.Tree_Access), - Explanation => - Explanation (C.Tree_Access)); - - when Reference => - pragma Assert (Nkind (N) = N_Explicit_Dereference); - return (R => Unfolded, - Tree_Access => Get_All (C.Tree_Access)); - - when Record_Component => - pragma Assert (Nkind (N) = N_Selected_Component); - declare - Comp : constant Entity_Id := - Original_Record_Component - (Entity (Selector_Name (N))); - D : constant Perm_Tree_Access := - Perm_Tree_Maps.Get - (Component (C.Tree_Access), Comp); - begin - pragma Assert (D /= null); - return (R => Unfolded, - Tree_Access => D); - end; - - when Array_Component => - pragma Assert (Nkind (N) = N_Indexed_Component - or else - Nkind (N) = N_Slice); - pragma Assert (Get_Elem (C.Tree_Access) /= null); - return (R => Unfolded, - Tree_Access => Get_Elem (C.Tree_Access)); - end case; - end case; - end; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return Get_Perm_Or_Tree (Expression (N)); - - when others => - raise Program_Error; - end case; - end Get_Perm_Or_Tree; - - ------------------- - -- Get_Perm_Tree -- - ------------------- - - function Get_Perm_Tree (N : Node_Id) return Perm_Tree_Access is - begin - return Set_Perm_Prefixes (N, None, Empty); - end Get_Perm_Tree; - - --------------------- - -- Get_Root_Object -- - --------------------- - - function Get_Root_Object - (Expr : Node_Id; - Through_Traversal : Boolean := True; - Is_Traversal : Boolean := False) return Entity_Id - is - function GRO (Expr : Node_Id) return Entity_Id; - -- Local wrapper on the actual function, to propagate the values of - -- optional parameters. - - --------- - -- GRO -- - --------- - - function GRO (Expr : Node_Id) return Entity_Id is - begin - return Get_Root_Object (Expr, Through_Traversal, Is_Traversal); - end GRO; - - Get_Root_Object : Boolean; - pragma Unmodified (Get_Root_Object); - -- Local variable to mask the name of function Get_Root_Object, to - -- prevent direct call. Instead GRO wrapper should be called. - - -- Start of processing for Get_Root_Object - - begin - if not Is_Subpath_Expression (Expr, Is_Traversal) then - if Emit_Messages then - Error_Msg_N ("name expected here for path", Expr); - end if; - return Empty; - end if; - - case Nkind (Expr) is - when N_Expanded_Name - | N_Identifier - => - return Entity (Expr); - - when N_Explicit_Dereference - | N_Indexed_Component - | N_Selected_Component - | N_Slice - => - return GRO (Prefix (Expr)); - - -- There is no root object for an (extension) aggregate, allocator, - -- concat, or NULL. - - when N_Aggregate - | N_Allocator - | N_Extension_Aggregate - | N_Null - | N_Op_Concat - => - return Empty; - - -- In the case of a call to a traversal function, the root object is - -- the root of the traversed parameter. Otherwise there is no root - -- object. - - when N_Function_Call => - if Through_Traversal - and then Is_Traversal_Function_Call (Expr) - then - return GRO (First_Actual (Expr)); - else - return Empty; - end if; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return GRO (Expression (Expr)); - - when N_Attribute_Reference => - pragma Assert - (Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Loop_Entry - or else - Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Update - or else Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Image); - return Empty; - - when N_If_Expression => - if Is_Traversal then - declare - Cond : constant Node_Id := First (Expressions (Expr)); - Then_Part : constant Node_Id := Next (Cond); - Else_Part : constant Node_Id := Next (Then_Part); - Then_Root : constant Entity_Id := GRO (Then_Part); - Else_Root : constant Entity_Id := GRO (Else_Part); - begin - if Nkind (Then_Part) = N_Null then - return Else_Root; - elsif Nkind (Else_Part) = N_Null then - return Then_Part; - elsif Then_Root = Else_Root then - return Then_Root; - else - if Emit_Messages then - Error_Msg_N - ("same name expected here in each branch", Expr); - end if; - return Empty; - end if; - end; - else - if Emit_Messages then - Error_Msg_N ("name expected here for path", Expr); - end if; - return Empty; - end if; - - when N_Case_Expression => - if Is_Traversal then - declare - Cases : constant List_Id := Alternatives (Expr); - Cur_Case : Node_Id := First (Cases); - Cur_Root : Entity_Id; - Common_Root : Entity_Id := Empty; - - begin - while Present (Cur_Case) loop - Cur_Root := GRO (Expression (Cur_Case)); - - if Common_Root = Empty then - Common_Root := Cur_Root; - elsif Common_Root /= Cur_Root then - if Emit_Messages then - Error_Msg_N - ("same name expected here in each branch", Expr); - end if; - return Empty; - end if; - Next (Cur_Case); - end loop; - - return Common_Root; - end; - else - if Emit_Messages then - Error_Msg_N ("name expected here for path", Expr); - end if; - return Empty; - end if; - - when others => - raise Program_Error; - end case; - end Get_Root_Object; - - --------- - -- Glb -- - --------- - - function Glb (P1, P2 : Perm_Kind) return Perm_Kind - is - begin - case P1 is - when No_Access => - return No_Access; - - when Read_Only => - case P2 is - when No_Access - | Write_Only - => - return No_Access; - - when Read_Perm => - return Read_Only; - end case; - - when Write_Only => - case P2 is - when No_Access - | Read_Only - => - return No_Access; - - when Write_Perm => - return Write_Only; - end case; - - when Read_Write => - return P2; - end case; - end Glb; - - ------------------------- - -- Has_Array_Component -- - ------------------------- - - function Has_Array_Component (Expr : Node_Id) return Boolean is - begin - case Nkind (Expr) is - when N_Expanded_Name - | N_Identifier - => - return False; - - when N_Explicit_Dereference - | N_Selected_Component - => - return Has_Array_Component (Prefix (Expr)); - - when N_Indexed_Component - | N_Slice - => - return True; - - when N_Allocator - | N_Null - | N_Function_Call - => - return False; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return Has_Array_Component (Expression (Expr)); - - when others => - raise Program_Error; - end case; - end Has_Array_Component; - - -------- - -- Hp -- - -------- - - procedure Hp (P : Perm_Env) is - Elem : Perm_Tree_Maps.Key_Option; - - begin - Elem := Get_First_Key (P); - while Elem.Present loop - Print_Node_Briefly (Elem.K); - Elem := Get_Next_Key (P); - end loop; - end Hp; - - -------------------------- - -- Illegal_Global_Usage -- - -------------------------- - - procedure Illegal_Global_Usage (N : Node_Or_Entity_Id; E : Entity_Id) - is - begin - Error_Msg_NE ("cannot use global variable & of deep type", N, E); - Error_Msg_N ("\without prior declaration in a Global aspect", N); - Errout.Finalize (Last_Call => True); - Errout.Output_Messages; - Exit_Program (E_Errors); - end Illegal_Global_Usage; - - ------------- - -- Is_Deep -- - ------------- - - function Is_Deep (Typ : Entity_Id) return Boolean is - begin - case Type_Kind'(Ekind (Retysp (Typ))) is - when Access_Kind => - return True; - - when E_Array_Type - | E_Array_Subtype - => - return Is_Deep (Component_Type (Retysp (Typ))); - - when Record_Kind => - declare - Comp : Entity_Id; - begin - Comp := First_Component_Or_Discriminant (Retysp (Typ)); - while Present (Comp) loop - - -- Ignore components not visible in SPARK - - if Component_Is_Visible_In_SPARK (Comp) - and then Is_Deep (Etype (Comp)) - then - return True; - end if; - Next_Component_Or_Discriminant (Comp); - end loop; - end; - return False; - - when Scalar_Kind - | E_String_Literal_Subtype - | Protected_Kind - | Task_Kind - | Incomplete_Kind - | E_Exception_Type - | E_Subprogram_Type - => - return False; - - -- Ignore full view of types if it is not in SPARK - - when E_Private_Type - | E_Private_Subtype - | E_Limited_Private_Type - | E_Limited_Private_Subtype - => - return False; - end case; - end Is_Deep; - - -------------- - -- Is_Legal -- - -------------- - - function Is_Legal (N : Node_Id) return Boolean is - Legal : Boolean := True; - - begin - case Nkind (N) is - when N_Declaration => - Check_Declaration_Legality (N, Force => False, Legal => Legal); - when others => - null; - end case; - - return Legal; - end Is_Legal; - - ---------------------- - -- Is_Local_Context -- - ---------------------- - - function Is_Local_Context (Scop : Entity_Id) return Boolean is - begin - return Is_Subprogram_Or_Entry (Scop) - or else Ekind (Scop) = E_Block; - end Is_Local_Context; - - ------------------------ - -- Is_Path_Expression -- - ------------------------ - - function Is_Path_Expression - (Expr : Node_Id; - Is_Traversal : Boolean := False) return Boolean - is - function IPE (Expr : Node_Id) return Boolean; - -- Local wrapper on the actual function, to propagate the values of - -- optional parameter Is_Traversal. - - --------- - -- IPE -- - --------- - - function IPE (Expr : Node_Id) return Boolean is - begin - return Is_Path_Expression (Expr, Is_Traversal); - end IPE; - - Is_Path_Expression : Boolean; - pragma Unmodified (Is_Path_Expression); - -- Local variable to mask the name of function Is_Path_Expression, to - -- prevent direct call. Instead IPE wrapper should be called. - - -- Start of processing for Is_Path_Expression - - begin - case Nkind (Expr) is - when N_Expanded_Name - | N_Explicit_Dereference - | N_Identifier - | N_Indexed_Component - | N_Selected_Component - | N_Slice - => - return True; - - -- Special value NULL corresponds to an empty path - - when N_Null => - return True; - - -- Object returned by an (extension) aggregate, an allocator, or - -- a function call corresponds to a path. - - when N_Aggregate - | N_Allocator - | N_Extension_Aggregate - | N_Function_Call - => - return True; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return IPE (Expression (Expr)); - - -- When returning from a traversal function, consider an - -- if-expression as a possible path expression. - - when N_If_Expression => - if Is_Traversal then - declare - Cond : constant Node_Id := First (Expressions (Expr)); - Then_Part : constant Node_Id := Next (Cond); - Else_Part : constant Node_Id := Next (Then_Part); - begin - return IPE (Then_Part) - and then IPE (Else_Part); - end; - else - return False; - end if; - - -- When returning from a traversal function, consider - -- a case-expression as a possible path expression. - - when N_Case_Expression => - if Is_Traversal then - declare - Cases : constant List_Id := Alternatives (Expr); - Cur_Case : Node_Id := First (Cases); - - begin - while Present (Cur_Case) loop - if not IPE (Expression (Cur_Case)) then - return False; - end if; - Next (Cur_Case); - end loop; - - return True; - end; - else - return False; - end if; - - when others => - return False; - end case; - end Is_Path_Expression; - - ------------------------- - -- Is_Prefix_Or_Almost -- - ------------------------- - - function Is_Prefix_Or_Almost (Pref, Expr : Node_Id) return Boolean is - - type Expr_Array is array (Positive range <>) of Node_Id; - -- Sequence of expressions that make up a path - - function Get_Expr_Array (Expr : Node_Id) return Expr_Array; - pragma Precondition (Is_Path_Expression (Expr)); - -- Return the sequence of expressions that make up a path - - -------------------- - -- Get_Expr_Array -- - -------------------- - - function Get_Expr_Array (Expr : Node_Id) return Expr_Array is - begin - case Nkind (Expr) is - when N_Expanded_Name - | N_Identifier - => - return Expr_Array'(1 => Expr); - - when N_Explicit_Dereference - | N_Indexed_Component - | N_Selected_Component - | N_Slice - => - return Get_Expr_Array (Prefix (Expr)) & Expr; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return Get_Expr_Array (Expression (Expr)); - - when others => - raise Program_Error; - end case; - end Get_Expr_Array; - - -- Local variables - - Prefix_Path : constant Expr_Array := Get_Expr_Array (Pref); - Expr_Path : constant Expr_Array := Get_Expr_Array (Expr); - - Prefix_Root : constant Node_Id := Prefix_Path (1); - Expr_Root : constant Node_Id := Expr_Path (1); - - Common_Len : constant Positive := - Positive'Min (Prefix_Path'Length, Expr_Path'Length); - - -- Start of processing for Is_Prefix_Or_Almost - - begin - if Entity (Prefix_Root) /= Entity (Expr_Root) then - return False; - end if; - - for J in 2 .. Common_Len loop - declare - Prefix_Elt : constant Node_Id := Prefix_Path (J); - Expr_Elt : constant Node_Id := Expr_Path (J); - begin - case Nkind (Prefix_Elt) is - when N_Explicit_Dereference => - if Nkind (Expr_Elt) /= N_Explicit_Dereference then - return False; - end if; - - when N_Selected_Component => - if Nkind (Expr_Elt) /= N_Selected_Component - or else Original_Record_Component - (Entity (Selector_Name (Prefix_Elt))) - /= Original_Record_Component - (Entity (Selector_Name (Expr_Elt))) - then - return False; - end if; - - when N_Indexed_Component - | N_Slice - => - if not Nkind_In (Expr_Elt, N_Indexed_Component, N_Slice) then - return False; - end if; - - when others => - raise Program_Error; - end case; - end; - end loop; - - -- If the expression path is longer than the prefix one, then at this - -- point the prefix property holds. - - if Expr_Path'Length > Prefix_Path'Length then - return True; - - -- Otherwise check if none of the remaining path elements in the - -- candidate prefix involve a dereference. - - else - for J in Common_Len + 1 .. Prefix_Path'Length loop - if Nkind (Prefix_Path (J)) = N_Explicit_Dereference then - return False; - end if; - end loop; - - return True; - end if; - end Is_Prefix_Or_Almost; - - --------------------------- - -- Is_Subpath_Expression -- - --------------------------- - - function Is_Subpath_Expression - (Expr : Node_Id; - Is_Traversal : Boolean := False) return Boolean - is - begin - return Is_Path_Expression (Expr, Is_Traversal) - - or else (Nkind_In (Expr, N_Qualified_Expression, - N_Type_Conversion, - N_Unchecked_Type_Conversion) - and then Is_Subpath_Expression (Expression (Expr))) - - or else (Nkind (Expr) = N_Attribute_Reference - and then - (Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Update - or else - Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Loop_Entry - or else - Get_Attribute_Id (Attribute_Name (Expr)) = - Attribute_Image)) - - or else Nkind (Expr) = N_Op_Concat; - end Is_Subpath_Expression; - - --------------------------- - -- Is_Traversal_Function -- - --------------------------- - - function Is_Traversal_Function (E : Entity_Id) return Boolean is - begin - return Ekind (E) = E_Function - - -- A function is said to be a traversal function if the result type of - -- the function is an anonymous access-to-object type, - - and then Is_Anonymous_Access_Type (Etype (E)) - - -- the function has at least one formal parameter, - - and then Present (First_Formal (E)) - - -- and the function's first parameter is of an access type. - - and then Is_Access_Type (Retysp (Etype (First_Formal (E)))); - end Is_Traversal_Function; - - -------------------------------- - -- Is_Traversal_Function_Call -- - -------------------------------- - - function Is_Traversal_Function_Call (Expr : Node_Id) return Boolean is - begin - return Nkind (Expr) = N_Function_Call - and then Present (Get_Called_Entity (Expr)) - and then Is_Traversal_Function (Get_Called_Entity (Expr)); - end Is_Traversal_Function_Call; - - ------------------ - -- Loop_Of_Exit -- - ------------------ - - function Loop_Of_Exit (N : Node_Id) return Entity_Id is - Nam : Node_Id := Name (N); - Stmt : Node_Id := N; - begin - if No (Nam) then - while Present (Stmt) loop - Stmt := Parent (Stmt); - if Nkind (Stmt) = N_Loop_Statement then - Nam := Identifier (Stmt); - exit; - end if; - end loop; - end if; - return Entity (Nam); - end Loop_Of_Exit; - - --------- - -- Lub -- - --------- - - function Lub (P1, P2 : Perm_Kind) return Perm_Kind is - begin - case P1 is - when No_Access => - return P2; - - when Read_Only => - case P2 is - when No_Access - | Read_Only - => - return Read_Only; - - when Write_Perm => - return Read_Write; - end case; - - when Write_Only => - case P2 is - when No_Access - | Write_Only - => - return Write_Only; - - when Read_Perm => - return Read_Write; - end case; - - when Read_Write => - return Read_Write; - end case; - end Lub; - - --------------- - -- Merge_Env -- - --------------- - - procedure Merge_Env (Source : in out Perm_Env; Target : in out Perm_Env) is - - -- Local subprograms - - procedure Apply_Glb_Tree - (A : Perm_Tree_Access; - P : Perm_Kind); - - procedure Merge_Trees - (Target : Perm_Tree_Access; - Source : Perm_Tree_Access); - - -------------------- - -- Apply_Glb_Tree -- - -------------------- - - procedure Apply_Glb_Tree - (A : Perm_Tree_Access; - P : Perm_Kind) - is - begin - A.all.Tree.Permission := Glb (Permission (A), P); - - case Kind (A) is - when Entire_Object => - A.all.Tree.Children_Permission := - Glb (Children_Permission (A), P); - - when Reference => - Apply_Glb_Tree (Get_All (A), P); - - when Array_Component => - Apply_Glb_Tree (Get_Elem (A), P); - - when Record_Component => - declare - Comp : Perm_Tree_Access; - begin - Comp := Perm_Tree_Maps.Get_First (Component (A)); - while Comp /= null loop - Apply_Glb_Tree (Comp, P); - Comp := Perm_Tree_Maps.Get_Next (Component (A)); - end loop; - end; - end case; - end Apply_Glb_Tree; - - ----------------- - -- Merge_Trees -- - ----------------- - - procedure Merge_Trees - (Target : Perm_Tree_Access; - Source : Perm_Tree_Access) - is - Perm : constant Perm_Kind := - Glb (Permission (Target), Permission (Source)); - - begin - pragma Assert (Is_Node_Deep (Target) = Is_Node_Deep (Source)); - Target.all.Tree.Permission := Perm; - - case Kind (Target) is - when Entire_Object => - declare - Child_Perm : constant Perm_Kind := - Children_Permission (Target); - - begin - case Kind (Source) is - when Entire_Object => - Target.all.Tree.Children_Permission := - Glb (Child_Perm, Children_Permission (Source)); - - when Reference => - Copy_Tree (Source, Target); - Target.all.Tree.Permission := Perm; - Apply_Glb_Tree (Get_All (Target), Child_Perm); - - when Array_Component => - Copy_Tree (Source, Target); - Target.all.Tree.Permission := Perm; - Apply_Glb_Tree (Get_Elem (Target), Child_Perm); - - when Record_Component => - Copy_Tree (Source, Target); - Target.all.Tree.Permission := Perm; - declare - Comp : Perm_Tree_Access; - - begin - Comp := - Perm_Tree_Maps.Get_First (Component (Target)); - while Comp /= null loop - -- Apply glb tree on every component subtree - - Apply_Glb_Tree (Comp, Child_Perm); - Comp := Perm_Tree_Maps.Get_Next - (Component (Target)); - end loop; - end; - end case; - end; - - when Reference => - case Kind (Source) is - when Entire_Object => - Apply_Glb_Tree (Get_All (Target), - Children_Permission (Source)); - - when Reference => - Merge_Trees (Get_All (Target), Get_All (Source)); - - when others => - raise Program_Error; - - end case; - - when Array_Component => - case Kind (Source) is - when Entire_Object => - Apply_Glb_Tree (Get_Elem (Target), - Children_Permission (Source)); - - when Array_Component => - Merge_Trees (Get_Elem (Target), Get_Elem (Source)); - - when others => - raise Program_Error; - - end case; - - when Record_Component => - case Kind (Source) is - when Entire_Object => - declare - Child_Perm : constant Perm_Kind := - Children_Permission (Source); - - Comp : Perm_Tree_Access; - - begin - Comp := Perm_Tree_Maps.Get_First - (Component (Target)); - while Comp /= null loop - -- Apply glb tree on every component subtree - - Apply_Glb_Tree (Comp, Child_Perm); - Comp := - Perm_Tree_Maps.Get_Next (Component (Target)); - end loop; - end; - - when Record_Component => - declare - Key_Source : Perm_Tree_Maps.Key_Option; - CompTarget : Perm_Tree_Access; - CompSource : Perm_Tree_Access; - - begin - Key_Source := Perm_Tree_Maps.Get_First_Key - (Component (Source)); - - while Key_Source.Present loop - CompSource := Perm_Tree_Maps.Get - (Component (Source), Key_Source.K); - CompTarget := Perm_Tree_Maps.Get - (Component (Target), Key_Source.K); - - pragma Assert (CompSource /= null); - Merge_Trees (CompTarget, CompSource); - - Key_Source := Perm_Tree_Maps.Get_Next_Key - (Component (Source)); - end loop; - end; - - when others => - raise Program_Error; - end case; - end case; - end Merge_Trees; - - -- Local variables - - CompTarget : Perm_Tree_Access; - CompSource : Perm_Tree_Access; - KeyTarget : Perm_Tree_Maps.Key_Option; - - -- Start of processing for Merge_Env - - begin - KeyTarget := Get_First_Key (Target); - -- Iterate over every tree of the environment in the target, and merge - -- it with the source if there is such a similar one that exists. If - -- there is none, then skip. - while KeyTarget.Present loop - - CompSource := Get (Source, KeyTarget.K); - CompTarget := Get (Target, KeyTarget.K); - - pragma Assert (CompTarget /= null); - - if CompSource /= null then - Merge_Trees (CompTarget, CompSource); - Remove (Source, KeyTarget.K); - end if; - - KeyTarget := Get_Next_Key (Target); - end loop; - - -- Iterate over every tree of the environment of the source. And merge - -- again. If there is not any tree of the target then just copy the tree - -- from source to target. - declare - KeySource : Perm_Tree_Maps.Key_Option; - begin - KeySource := Get_First_Key (Source); - while KeySource.Present loop - - CompSource := Get (Source, KeySource.K); - CompTarget := Get (Target, KeySource.K); - - if CompTarget = null then - CompTarget := new Perm_Tree_Wrapper'(CompSource.all); - Copy_Tree (CompSource, CompTarget); - Set (Target, KeySource.K, CompTarget); - else - Merge_Trees (CompTarget, CompSource); - end if; - - KeySource := Get_Next_Key (Source); - end loop; - end; - - Free_Env (Source); - end Merge_Env; - - ---------------- - -- Perm_Error -- - ---------------- - - procedure Perm_Error - (N : Node_Id; - Perm : Perm_Kind; - Found_Perm : Perm_Kind; - Expl : Node_Id; - Forbidden_Perm : Boolean := False) - is - procedure Set_Root_Object - (Path : Node_Id; - Obj : out Entity_Id; - Deref : out Boolean); - -- Set the root object Obj, and whether the path contains a dereference, - -- from a path Path. - - --------------------- - -- Set_Root_Object -- - --------------------- - - procedure Set_Root_Object - (Path : Node_Id; - Obj : out Entity_Id; - Deref : out Boolean) - is - begin - case Nkind (Path) is - when N_Identifier - | N_Expanded_Name - => - Obj := Entity (Path); - Deref := False; - - when N_Type_Conversion - | N_Unchecked_Type_Conversion - | N_Qualified_Expression - => - Set_Root_Object (Expression (Path), Obj, Deref); - - when N_Indexed_Component - | N_Selected_Component - | N_Slice - => - Set_Root_Object (Prefix (Path), Obj, Deref); - - when N_Explicit_Dereference => - Set_Root_Object (Prefix (Path), Obj, Deref); - Deref := True; - - when others => - raise Program_Error; - end case; - end Set_Root_Object; - -- Local variables - - Root : Entity_Id; - Is_Deref : Boolean; - - -- Start of processing for Perm_Error - - begin - Set_Root_Object (N, Root, Is_Deref); - - if Emit_Messages then - if Is_Deref then - Error_Msg_NE - ("insufficient permission on dereference from &", N, Root); - else - Error_Msg_NE ("insufficient permission for &", N, Root); - end if; - - Perm_Mismatch (N, Perm, Found_Perm, Expl, Forbidden_Perm); - end if; - end Perm_Error; - - ------------------------------- - -- Perm_Error_Subprogram_End -- - ------------------------------- - - procedure Perm_Error_Subprogram_End - (E : Entity_Id; - Subp : Entity_Id; - Perm : Perm_Kind; - Found_Perm : Perm_Kind; - Expl : Node_Id) - is - begin - if Emit_Messages then - Error_Msg_Node_2 := Subp; - Error_Msg_NE ("insufficient permission for & when returning from &", - Subp, E); - Perm_Mismatch (Subp, Perm, Found_Perm, Expl); - end if; - end Perm_Error_Subprogram_End; - - ------------------ - -- Process_Path -- - ------------------ - - procedure Process_Path (Expr : Node_Id; Mode : Checking_Mode) is - - procedure Check_Not_Borrowed (Expr : Node_Id; Root : Entity_Id); - -- Check expression Expr originating in Root was not borrowed - - procedure Check_Not_Observed (Expr : Node_Id; Root : Entity_Id); - -- Check expression Expr originating in Root was not observed - - ------------------------ - -- Check_Not_Borrowed -- - ------------------------ - - procedure Check_Not_Borrowed (Expr : Node_Id; Root : Entity_Id) is - begin - -- An expression without root object cannot be borrowed - - if No (Root) then - return; - end if; - - -- Otherwise, try to match the expression with one of the borrowed - -- expressions. - - declare - Key : Variable_Maps.Key_Option := - Get_First_Key (Current_Borrowers); - Var : Entity_Id; - Borrowed : Node_Id; - B_Pledge : Entity_Id := Empty; - - begin - -- Search for a call to a pledge function or a global pragma in - -- the parents of Expr. - - declare - Call : Node_Id := Expr; - begin - while Present (Call) - and then - (Nkind (Call) /= N_Function_Call - or else not Is_Pledge_Function (Get_Called_Entity (Call))) - loop - -- Do not check for borrowed objects in global contracts - -- ??? However we should keep these objects in the borrowed - -- state when verifying the subprogram so that we can make - -- sure that they are only read inside pledges. - -- ??? There is probably a better way to disable checking of - -- borrows inside global contracts. - - if Nkind (Call) = N_Pragma - and then Get_Pragma_Id (Pragma_Name (Call)) = Pragma_Global - then - return; - end if; - - Call := Parent (Call); - end loop; - - if Present (Call) - and then Nkind (First_Actual (Call)) in N_Has_Entity - then - B_Pledge := Entity (First_Actual (Call)); - end if; - end; - - while Key.Present loop - Var := Key.K; - Borrowed := Get (Current_Borrowers, Var); - - if Is_Prefix_Or_Almost (Pref => Borrowed, Expr => Expr) - and then Var /= B_Pledge - and then Emit_Messages - then - Error_Msg_Sloc := Sloc (Borrowed); - Error_Msg_N ("object was borrowed #", Expr); - end if; - - Key := Get_Next_Key (Current_Borrowers); - end loop; - end; - end Check_Not_Borrowed; - - ------------------------ - -- Check_Not_Observed -- - ------------------------ - - procedure Check_Not_Observed (Expr : Node_Id; Root : Entity_Id) is - begin - -- An expression without root object cannot be observed - - if No (Root) then - return; - end if; - - -- Otherwise, try to match the expression with one of the observed - -- expressions. - - declare - Key : Variable_Maps.Key_Option := - Get_First_Key (Current_Observers); - Var : Entity_Id; - Observed : Node_Id; - - begin - while Key.Present loop - Var := Key.K; - Observed := Get (Current_Observers, Var); - - if Is_Prefix_Or_Almost (Pref => Observed, Expr => Expr) - and then Emit_Messages - then - Error_Msg_Sloc := Sloc (Observed); - Error_Msg_N ("object was observed #", Expr); - end if; - - Key := Get_Next_Key (Current_Observers); - end loop; - end; - end Check_Not_Observed; - - -- Local variables - - Expr_Type : constant Entity_Id := Etype (Expr); - Root : Entity_Id := Get_Root_Object (Expr); - Perm : Perm_Kind_Option; - - -- Start of processing for Process_Path - - begin - -- Nothing to do if the root type is not deep, or the path is not rooted - -- in an object. - - if not Present (Root) - or else not Is_Object (Root) - or else not Is_Deep (Etype (Root)) - then - return; - end if; - - -- Identify the root type for the path - - Root := Unique_Entity (Root); - - -- Except during elaboration, the root object should have been declared - -- and entered into the current permission environment. - - if not Inside_Elaboration - and then Get (Current_Perm_Env, Root) = null - then - Illegal_Global_Usage (Expr, Root); - end if; - - -- During elaboration, only the validity of operations is checked, no - -- need to compute the permission of Expr. - - if Inside_Elaboration then - Perm := None; - else - Perm := Get_Perm (Expr); - end if; - - -- Check permissions - - case Mode is - - when Read => - - -- No checking needed during elaboration - - if Inside_Elaboration then - return; - end if; - - -- Check path is readable - - if Perm not in Read_Perm then - Perm_Error (Expr, Read_Only, Perm, Expl => Get_Expl (Expr)); - return; - end if; - - when Move => - - -- Forbidden on deep path during elaboration, otherwise no - -- checking needed. - - if Inside_Elaboration then - if Is_Deep (Expr_Type) - and then not Inside_Procedure_Call - and then Present (Get_Root_Object (Expr)) - and then Emit_Messages - then - Error_Msg_N ("illegal move during elaboration", Expr); - end if; - - return; - end if; - - -- For deep path, check RW permission, otherwise R permission - - if not Is_Deep (Expr_Type) then - if Perm not in Read_Perm then - Perm_Error (Expr, Read_Only, Perm, Expl => Get_Expl (Expr)); - end if; - return; - end if; - - -- SPARK RM 3.10(1): At the point of a move operation the state of - -- the source object (if any) shall be Unrestricted. - - if Perm /= Read_Write then - Perm_Error (Expr, Read_Write, Perm, Expl => Get_Expl (Expr)); - return; - end if; - - when Assign => - - -- No checking needed during elaboration - - if Inside_Elaboration then - return; - end if; - - -- For assignment, check W permission - - if Perm not in Write_Perm then - Perm_Error (Expr, Write_Only, Perm, Expl => Get_Expl (Expr)); - return; - end if; - - when Borrow => - - -- Forbidden during elaboration, an error is already issued in - -- Check_Declaration, just return. - - if Inside_Elaboration then - return; - end if; - - -- For borrowing, check RW permission - - if Perm /= Read_Write then - Perm_Error (Expr, Read_Write, Perm, Expl => Get_Expl (Expr)); - return; - end if; - - when Observe => - - -- Forbidden during elaboration, an error is already issued in - -- Check_Declaration, just return. - - if Inside_Elaboration then - return; - end if; - - -- For borrowing, check R permission - - if Perm not in Read_Perm then - Perm_Error (Expr, Read_Only, Perm, Expl => Get_Expl (Expr)); - return; - end if; - end case; - - -- Check path was not borrowed - - Check_Not_Borrowed (Expr, Root); - - -- For modes that require W permission, check path was not observed - - case Mode is - when Read | Observe => - null; - when Assign | Move | Borrow => - Check_Not_Observed (Expr, Root); - end case; - - -- Do not update permission environment when handling calls - - if Inside_Procedure_Call then - return; - end if; - - -- Update the permissions - - case Mode is - - when Read => - null; - - when Move => - - -- SPARK RM 3.10(1): After a move operation, the state of the - -- source object (if any) becomes Moved. - - if Present (Get_Root_Object (Expr)) then - declare - Tree : constant Perm_Tree_Access := - Set_Perm_Prefixes (Expr, Write_Only, Expl => Expr); - begin - pragma Assert (Tree /= null); - Set_Perm_Extensions_Move (Tree, Etype (Expr), Expl => Expr); - end; - end if; - - when Assign => - - -- If there is no root object, or the tree has an array component, - -- then the permissions do not get modified by the assignment. - - if No (Get_Root_Object (Expr)) - or else Has_Array_Component (Expr) - then - return; - end if; - - -- Set permission RW for the path and its extensions - - declare - Tree : constant Perm_Tree_Access := Get_Perm_Tree (Expr); - begin - Tree.all.Tree.Permission := Read_Write; - Set_Perm_Extensions (Tree, Read_Write, Expl => Expr); - - -- Normalize the permission tree - - Set_Perm_Prefixes_Assign (Expr); - end; - - -- Borrowing and observing of paths is handled by the variables - -- Current_Borrowers and Current_Observers. - - when Borrow | Observe => - null; - end case; - end Process_Path; - - -------------------- - -- Return_Globals -- - -------------------- - - procedure Return_Globals (Subp : Entity_Id) is - - procedure Return_Global - (Expr : Node_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean); - -- Proxy procedure to return globals, to adjust for the type of first - -- parameter expected by Return_Parameter_Or_Global. - - ------------------- - -- Return_Global -- - ------------------- - - procedure Return_Global - (Expr : Node_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean) - is - begin - Return_Parameter_Or_Global - (Id => Entity (Expr), - Typ => Typ, - Kind => Kind, - Subp => Subp, - Global_Var => Global_Var); - end Return_Global; - - procedure Return_Globals_Inst is new Handle_Globals (Return_Global); - - -- Start of processing for Return_Globals - - begin - Return_Globals_Inst (Subp); - end Return_Globals; - - -------------------------------- - -- Return_Parameter_Or_Global -- - -------------------------------- - - procedure Return_Parameter_Or_Global - (Id : Entity_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean) - is - begin - -- Shallow parameters and globals need not be considered - - if not Is_Deep (Typ) then - return; - - elsif Kind = E_In_Parameter then - - -- Input global variables are observed only - - if Global_Var then - return; - - -- Anonymous access to constant is an observe - - elsif Is_Anonymous_Access_Type (Typ) - and then Is_Access_Constant (Typ) - then - return; - - -- Deep types other than access types define an observe - - elsif not Is_Access_Type (Typ) then - return; - end if; - end if; - - -- All other parameters and globals should return with mode RW to the - -- caller. - - declare - Tree : constant Perm_Tree_Access := Get (Current_Perm_Env, Id); - begin - if Permission (Tree) /= Read_Write then - Perm_Error_Subprogram_End - (E => Id, - Subp => Subp, - Perm => Read_Write, - Found_Perm => Permission (Tree), - Expl => Explanation (Tree)); - end if; - end; - end Return_Parameter_Or_Global; - - ----------------------- - -- Return_Parameters -- - ----------------------- - - procedure Return_Parameters (Subp : Entity_Id) is - Formal : Entity_Id; - begin - Formal := First_Formal (Subp); - while Present (Formal) loop - Return_Parameter_Or_Global - (Id => Formal, - Typ => Retysp (Etype (Formal)), - Kind => Ekind (Formal), - Subp => Subp, - Global_Var => False); - Next_Formal (Formal); - end loop; - end Return_Parameters; - - ------------------------- - -- Set_Perm_Extensions -- - ------------------------- - - procedure Set_Perm_Extensions - (T : Perm_Tree_Access; - P : Perm_Kind; - Expl : Node_Id) is - - procedure Free_Perm_Tree_Children (T : Perm_Tree_Access); - -- Free the permission tree of children if any, prio to replacing T - - ----------------------------- - -- Free_Perm_Tree_Children -- - ----------------------------- - - procedure Free_Perm_Tree_Children (T : Perm_Tree_Access) is - begin - case Kind (T) is - when Entire_Object => - null; - - when Reference => - Free_Tree (T.all.Tree.Get_All); - - when Array_Component => - Free_Tree (T.all.Tree.Get_Elem); - - when Record_Component => - declare - Hashtbl : Perm_Tree_Maps.Instance := Component (T); - Comp : Perm_Tree_Access; - - begin - Comp := Perm_Tree_Maps.Get_First (Hashtbl); - while Comp /= null loop - Free_Tree (Comp); - Comp := Perm_Tree_Maps.Get_Next (Hashtbl); - end loop; - - Perm_Tree_Maps.Reset (Hashtbl); - end; - end case; - end Free_Perm_Tree_Children; - - -- Start of processing for Set_Perm_Extensions - - begin - Free_Perm_Tree_Children (T); - T.all.Tree := Perm_Tree'(Kind => Entire_Object, - Is_Node_Deep => Is_Node_Deep (T), - Explanation => Expl, - Permission => Permission (T), - Children_Permission => P); - end Set_Perm_Extensions; - - ------------------------------ - -- Set_Perm_Extensions_Move -- - ------------------------------ - - procedure Set_Perm_Extensions_Move - (T : Perm_Tree_Access; - E : Entity_Id; - Expl : Node_Id) - is - Check_Ty : constant Entity_Id := Retysp (E); - begin - -- Shallow extensions are set to RW - - if not Is_Node_Deep (T) then - Set_Perm_Extensions (T, Read_Write, Expl => Expl); - return; - end if; - - -- Deep extensions are set to W before .all and NO afterwards - - T.all.Tree.Permission := Write_Only; - - case T.all.Tree.Kind is - - -- For a folded tree of composite type, unfold the tree for better - -- precision. - - when Entire_Object => - case Ekind (Check_Ty) is - when E_Array_Type - | E_Array_Subtype - => - declare - C : constant Perm_Tree_Access := - new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => Is_Node_Deep (T), - Explanation => Expl, - Permission => Read_Write, - Children_Permission => Read_Write)); - begin - Set_Perm_Extensions_Move - (C, Component_Type (Check_Ty), Expl); - T.all.Tree := (Kind => Array_Component, - Is_Node_Deep => Is_Node_Deep (T), - Explanation => Expl, - Permission => Write_Only, - Get_Elem => C); - end; - - when Record_Kind => - declare - C : Perm_Tree_Access; - Comp : Entity_Id; - Hashtbl : Perm_Tree_Maps.Instance; - - begin - Comp := First_Component_Or_Discriminant (Check_Ty); - while Present (Comp) loop - - -- Unfold components which are visible in SPARK - - if Component_Is_Visible_In_SPARK (Comp) then - C := new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => Is_Deep (Etype (Comp)), - Explanation => Expl, - Permission => Read_Write, - Children_Permission => Read_Write)); - Set_Perm_Extensions_Move (C, Etype (Comp), Expl); - - -- Hidden components are never deep - - else - C := new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => False, - Explanation => Expl, - Permission => Read_Write, - Children_Permission => Read_Write)); - Set_Perm_Extensions (C, Read_Write, Expl => Expl); - end if; - - Perm_Tree_Maps.Set - (Hashtbl, Original_Record_Component (Comp), C); - Next_Component_Or_Discriminant (Comp); - end loop; - - T.all.Tree := - (Kind => Record_Component, - Is_Node_Deep => Is_Node_Deep (T), - Explanation => Expl, - Permission => Write_Only, - Component => Hashtbl); - end; - - -- Otherwise, extensions are set to NO - - when others => - Set_Perm_Extensions (T, No_Access, Expl); - end case; - - when Reference => - Set_Perm_Extensions (T, No_Access, Expl); - - when Array_Component => - Set_Perm_Extensions_Move - (Get_Elem (T), Component_Type (Check_Ty), Expl); - - when Record_Component => - declare - C : Perm_Tree_Access; - Comp : Entity_Id; - - begin - Comp := First_Component_Or_Discriminant (Check_Ty); - while Present (Comp) loop - C := Perm_Tree_Maps.Get - (Component (T), Original_Record_Component (Comp)); - pragma Assert (C /= null); - - -- Move visible components - - if Component_Is_Visible_In_SPARK (Comp) then - Set_Perm_Extensions_Move (C, Etype (Comp), Expl); - - -- Hidden components are never deep - - else - Set_Perm_Extensions (C, Read_Write, Expl => Expl); - end if; - - Next_Component_Or_Discriminant (Comp); - end loop; - end; - end case; - end Set_Perm_Extensions_Move; - - ----------------------- - -- Set_Perm_Prefixes -- - ----------------------- - - function Set_Perm_Prefixes - (N : Node_Id; - Perm : Perm_Kind_Option; - Expl : Node_Id) return Perm_Tree_Access - is - begin - case Nkind (N) is - when N_Expanded_Name - | N_Identifier - => - declare - E : constant Entity_Id := Unique_Entity (Entity (N)); - C : constant Perm_Tree_Access := Get (Current_Perm_Env, E); - pragma Assert (C /= null); - - begin - if Perm /= None then - C.all.Tree.Permission := Glb (Perm, Permission (C)); - end if; - - return C; - end; - - -- For a nonterminal path, we set the permission tree of its prefix, - -- and then we extract from the returned pointer the subtree and - -- assign an adequate permission to it, if unfolded. If folded, - -- we unroll the tree one level. - - when N_Explicit_Dereference => - declare - C : constant Perm_Tree_Access := - Set_Perm_Prefixes (Prefix (N), Perm, Expl); - pragma Assert (C /= null); - pragma Assert (Kind (C) = Entire_Object - or else Kind (C) = Reference); - begin - -- The tree is already unfolded. Replace the permission of the - -- dereference. - - if Kind (C) = Reference then - declare - D : constant Perm_Tree_Access := Get_All (C); - pragma Assert (D /= null); - - begin - if Perm /= None then - D.all.Tree.Permission := Glb (Perm, Permission (D)); - end if; - - return D; - end; - - -- The tree is folded. Expand it. - - else - declare - pragma Assert (Kind (C) = Entire_Object); - - Child_P : constant Perm_Kind := Children_Permission (C); - D : constant Perm_Tree_Access := - new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => Is_Deep (Etype (N)), - Explanation => Expl, - Permission => Child_P, - Children_Permission => Child_P)); - begin - if Perm /= None then - D.all.Tree.Permission := Perm; - end if; - - C.all.Tree := (Kind => Reference, - Is_Node_Deep => Is_Node_Deep (C), - Explanation => Expl, - Permission => Permission (C), - Get_All => D); - return D; - end; - end if; - end; - - when N_Selected_Component => - declare - C : constant Perm_Tree_Access := - Set_Perm_Prefixes (Prefix (N), Perm, Expl); - pragma Assert (C /= null); - pragma Assert (Kind (C) = Entire_Object - or else Kind (C) = Record_Component); - begin - -- The tree is already unfolded. Replace the permission of the - -- component. - - if Kind (C) = Record_Component then - declare - Comp : constant Entity_Id := - Original_Record_Component - (Entity (Selector_Name (N))); - D : constant Perm_Tree_Access := - Perm_Tree_Maps.Get (Component (C), Comp); - pragma Assert (D /= null); - - begin - if Perm /= None then - D.all.Tree.Permission := Glb (Perm, Permission (D)); - end if; - - return D; - end; - - -- The tree is folded. Expand it. - - else - declare - pragma Assert (Kind (C) = Entire_Object); - - D : Perm_Tree_Access; - D_This : Perm_Tree_Access; - Comp : Node_Id; - P : Perm_Kind; - Child_P : constant Perm_Kind := Children_Permission (C); - Hashtbl : Perm_Tree_Maps.Instance; - -- Create an empty hash table - - begin - Comp := - First_Component_Or_Discriminant - (Retysp (Etype (Prefix (N)))); - - while Present (Comp) loop - if Perm /= None - and then Original_Record_Component (Comp) = - Original_Record_Component - (Entity (Selector_Name (N))) - then - P := Perm; - else - P := Child_P; - end if; - - D := new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => - -- Hidden components are never deep - Component_Is_Visible_In_SPARK (Comp) - and then Is_Deep (Etype (Comp)), - Explanation => Expl, - Permission => P, - Children_Permission => Child_P)); - Perm_Tree_Maps.Set - (Hashtbl, Original_Record_Component (Comp), D); - - -- Store the tree to return for this component - - if Original_Record_Component (Comp) = - Original_Record_Component - (Entity (Selector_Name (N))) - then - D_This := D; - end if; - - Next_Component_Or_Discriminant (Comp); - end loop; - - C.all.Tree := (Kind => Record_Component, - Is_Node_Deep => Is_Node_Deep (C), - Explanation => Expl, - Permission => Permission (C), - Component => Hashtbl); - return D_This; - end; - end if; - end; - - when N_Indexed_Component - | N_Slice - => - declare - C : constant Perm_Tree_Access := - Set_Perm_Prefixes (Prefix (N), Perm, Expl); - pragma Assert (C /= null); - pragma Assert (Kind (C) = Entire_Object - or else Kind (C) = Array_Component); - begin - -- The tree is already unfolded. Replace the permission of the - -- component. - - if Kind (C) = Array_Component then - declare - D : constant Perm_Tree_Access := Get_Elem (C); - pragma Assert (D /= null); - - begin - if Perm /= None then - D.all.Tree.Permission := Glb (Perm, Permission (D)); - end if; - - return D; - end; - - -- The tree is folded. Expand it. - - else - declare - pragma Assert (Kind (C) = Entire_Object); - - Child_P : constant Perm_Kind := Children_Permission (C); - D : constant Perm_Tree_Access := - new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => Is_Node_Deep (C), - Explanation => Expl, - Permission => Child_P, - Children_Permission => Child_P)); - begin - if Perm /= None then - D.all.Tree.Permission := Perm; - end if; - - C.all.Tree := (Kind => Array_Component, - Is_Node_Deep => Is_Node_Deep (C), - Explanation => Expl, - Permission => Permission (C), - Get_Elem => D); - return D; - end; - end if; - end; - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - return Set_Perm_Prefixes (Expression (N), Perm, Expl); - - when others => - raise Program_Error; - end case; - end Set_Perm_Prefixes; - - ------------------------------ - -- Set_Perm_Prefixes_Assign -- - ------------------------------ - - procedure Set_Perm_Prefixes_Assign (N : Node_Id) is - C : constant Perm_Tree_Access := Get_Perm_Tree (N); - - begin - case Kind (C) is - when Entire_Object => - pragma Assert (Children_Permission (C) = Read_Write); - C.all.Tree.Permission := Read_Write; - - when Reference => - C.all.Tree.Permission := - Lub (Permission (C), Permission (Get_All (C))); - - when Array_Component => - null; - - when Record_Component => - declare - Comp : Perm_Tree_Access; - Perm : Perm_Kind := Read_Write; - - begin - -- We take the Glb of all the descendants, and then update the - -- permission of the node with it. - - Comp := Perm_Tree_Maps.Get_First (Component (C)); - while Comp /= null loop - Perm := Glb (Perm, Permission (Comp)); - Comp := Perm_Tree_Maps.Get_Next (Component (C)); - end loop; - - C.all.Tree.Permission := Lub (Permission (C), Perm); - end; - end case; - - case Nkind (N) is - - -- Base identifier end recursion - - when N_Expanded_Name - | N_Identifier - => - null; - - when N_Explicit_Dereference - | N_Indexed_Component - | N_Selected_Component - | N_Slice - => - Set_Perm_Prefixes_Assign (Prefix (N)); - - when N_Qualified_Expression - | N_Type_Conversion - | N_Unchecked_Type_Conversion - => - Set_Perm_Prefixes_Assign (Expression (N)); - - when others => - raise Program_Error; - end case; - end Set_Perm_Prefixes_Assign; - - ------------------- - -- Setup_Globals -- - ------------------- - - procedure Setup_Globals (Subp : Entity_Id) is - - procedure Setup_Global - (Expr : Node_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean); - -- Proxy procedure to set up globals, to adjust for the type of first - -- parameter expected by Setup_Parameter_Or_Global. - - ------------------ - -- Setup_Global -- - ------------------ - - procedure Setup_Global - (Expr : Node_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean) - is - begin - Setup_Parameter_Or_Global - (Id => Entity (Expr), - Typ => Typ, - Kind => Kind, - Subp => Subp, - Global_Var => Global_Var, - Expl => Expr); - end Setup_Global; - - procedure Setup_Globals_Inst is new Handle_Globals (Setup_Global); - - -- Start of processing for Setup_Globals - - begin - Setup_Globals_Inst (Subp); - end Setup_Globals; - - ------------------------------- - -- Setup_Parameter_Or_Global -- - ------------------------------- - - procedure Setup_Parameter_Or_Global - (Id : Entity_Id; - Typ : Entity_Id; - Kind : Formal_Kind; - Subp : Entity_Id; - Global_Var : Boolean; - Expl : Node_Id) - is - Perm : Perm_Kind_Option; - - begin - case Kind is - when E_In_Parameter => - - -- Shallow parameters and globals need not be considered - - if not Is_Deep (Typ) then - Perm := None; - - -- Inputs of functions have R permission only - - elsif Ekind (Subp) = E_Function then - Perm := Read_Only; - - -- Input global variables have R permission only - - elsif Global_Var then - Perm := Read_Only; - - -- Anonymous access to constant is an observe - - elsif Is_Anonymous_Access_Type (Typ) - and then Is_Access_Constant (Typ) - then - Perm := Read_Only; - - -- Other access types are a borrow - - elsif Is_Access_Type (Typ) then - Perm := Read_Write; - - -- Deep types other than access types define an observe - - else - Perm := Read_Only; - end if; - - when E_Out_Parameter - | E_In_Out_Parameter - => - -- Shallow parameters and globals need not be considered - - if not Is_Deep (Typ) then - Perm := None; - - -- Functions cannot have outputs in SPARK - - elsif Ekind (Subp) = E_Function then - return; - - -- Deep types define a borrow or a move - - else - Perm := Read_Write; - end if; - end case; - - if Perm /= None then - declare - Tree : constant Perm_Tree_Access := - new Perm_Tree_Wrapper' - (Tree => - (Kind => Entire_Object, - Is_Node_Deep => Is_Deep (Etype (Id)), - Explanation => Expl, - Permission => Perm, - Children_Permission => Perm)); - begin - Set (Current_Perm_Env, Id, Tree); - end; - end if; - end Setup_Parameter_Or_Global; - - ---------------------- - -- Setup_Parameters -- - ---------------------- - - procedure Setup_Parameters (Subp : Entity_Id) is - Formal : Entity_Id; - begin - Formal := First_Formal (Subp); - while Present (Formal) loop - Setup_Parameter_Or_Global - (Id => Formal, - Typ => Retysp (Etype (Formal)), - Kind => Ekind (Formal), - Subp => Subp, - Global_Var => False, - Expl => Formal); - Next_Formal (Formal); - end loop; - end Setup_Parameters; - - -------------------------------- - -- Setup_Protected_Components -- - -------------------------------- - - procedure Setup_Protected_Components (Subp : Entity_Id) is - Typ : constant Entity_Id := Scope (Subp); - Comp : Entity_Id; - Kind : Formal_Kind; - - begin - Comp := First_Component_Or_Discriminant (Typ); - - -- The protected object is an implicit input of protected functions, and - -- an implicit input-output of protected procedures and entries. - - if Ekind (Subp) = E_Function then - Kind := E_In_Parameter; - else - Kind := E_In_Out_Parameter; - end if; - - while Present (Comp) loop - Setup_Parameter_Or_Global - (Id => Comp, - Typ => Retysp (Etype (Comp)), - Kind => Kind, - Subp => Subp, - Global_Var => False, - Expl => Comp); - - Next_Component_Or_Discriminant (Comp); - end loop; - end Setup_Protected_Components; - -end Sem_SPARK; diff --git a/gcc/ada/sem_spark.ads b/gcc/ada/sem_spark.ads deleted file mode 100644 index ff9aa63..0000000 --- a/gcc/ada/sem_spark.ads +++ /dev/null @@ -1,177 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT COMPILER COMPONENTS -- --- -- --- S E M _ S P A R K -- --- -- --- S p e c -- --- -- --- Copyright (C) 2017-2019, Free Software Foundation, Inc. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT 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 distributed with GNAT; see file COPYING3. If not, go to -- --- http://www.gnu.org/licenses for a complete copy of the license. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - --- This package implements an ownership analysis for access types. The rules --- that are enforced are defined in section 3.10 of the SPARK Reference --- Manual. --- --- Check_Safe_Pointers is called by Gnat1drv, when GNATprove mode is --- activated. It does an analysis of the source code, looking for code that is --- considered as SPARK and launches another function called Analyze_Node that --- will do the whole analysis. --- --- A path is an abstraction of a name, of which all indices, slices (for --- indexed components) and function calls have been abstracted and all --- dereferences are made explicit. A path is the atomic element viewed by the --- analysis, with the notion of prefixes and extensions of different paths. --- --- The analysis explores the AST, and looks for different constructs --- that may involve aliasing. These main constructs are assignments --- (N_Assignment_Statement, N_Object_Declaration, ...), or calls --- (N_Procedure_Call_Statement, N_Entry_Call_Statement, N_Function_Call). --- The analysis checks the permissions of each construct and updates them --- according to the SPARK RM. This can follow three main different types --- of operations: move, borrow, and observe. - ----------------------------- --- Deep and shallow types -- ----------------------------- - --- The analysis focuses on objects that can cause problems in terms of pointer --- aliasing. These objects have types that are called deep. Deep types are --- defined as being either types with an access part or class-wide types --- (which may have an access part in a derived type). Non-deep types are --- called shallow. Some objects of shallow type may cause pointer aliasing --- problems when they are explicitely marked as aliased (and then the aliasing --- occurs when we take the Access to this object and store it in a pointer). - ----------- --- Move -- ----------- - --- Moves can happen at several points in the program: during assignment (and --- any similar statement such as object declaration with initial value), or --- during return statements. --- --- The underlying concept consists of transferring the ownership of any path --- on the right-hand side to the left-hand side. There are some details that --- should be taken into account so as not to transfer paths that appear only --- as intermediate results of a more complex expression. - --- More specifically, the SPARK RM defines moved expressions, and any moved --- expression that points directly to a path is then checked and sees its --- permissions updated accordingly. - ------------- --- Borrow -- ------------- - --- Borrows can happen in subprogram calls. They consist of a temporary --- transfer of ownership from a caller to a callee. Expressions that can be --- borrowed can be found in either procedure or entry actual parameters, and --- consist of parameters of mode either "out" or "in out", or parameters of --- mode "in" that are of type nonconstant access-to-variable. We consider --- global variables as implicit parameters to subprograms, with their mode --- given by the Global contract associated to the subprogram. Note that the --- analysis looks for such a Global contract mentioning any global variable --- of deep type accessed directly in the subprogram, and it raises an error if --- there is no Global contract, or if the Global contract does not mention the --- variable. --- --- A borrow of a parameter X is equivalent in terms of aliasing to moving --- X'Access to the callee, and then assigning back X at the end of the call. --- --- Borrowed parameters should have read-write permission (or write-only for --- "out" parameters), and should all have read-write permission at the end --- of the call (this guarantee is ensured by the callee). - -------------- --- Observe -- -------------- - --- Observed parameters are all the other parameters that are not borrowed and --- that may cause problems with aliasing. They are considered as being sent to --- the callee with Read-Only permission, so that they can be aliased safely. --- This is the only construct that allows aliasing that does not prevent --- accessing the old path that is being aliased. However, this comes with --- the restriction that those aliased path cannot be written in the callee. - --------------------- --- Implementation -- --------------------- - --- The implementation is based on trees that represent the possible paths --- in the source code. Those trees can be unbounded in depth, hence they are --- represented using lazy data structures, whose laziness is handled manually. --- Each time an identifier is declared, its path is added to the permission --- environment as a tree with only one node, the declared identifier. Each --- time a path is checked or updated, we look in the tree at the adequate --- node, unfolding the tree whenever needed. - --- For this, each node has several variables that indicate whether it is --- deep (Is_Node_Deep), what permission it has (Permission), and what is --- the lowest permission of all its descendants (Children_Permission). After --- unfolding the tree, we update the permissions of each node, deleting the --- Children_Permission, and specifying new ones for the leaves of the unfolded --- tree. - --- After assigning a path, the descendants of the assigned path are dumped --- (and hence the tree is folded back), given that all descendants directly --- get read-write permission, which can be specified using the node's --- Children_Permission field. - --- The implementation is done as a generic, so that GNATprove can instantiate --- it with suitable formal arguments that depend on the SPARK_Mode boundary --- as well as the two-phase architecture of GNATprove (which runs the GNAT --- front end twice, once for global generation and once for analysis). - -with Types; use Types; - -generic - with function Retysp (X : Entity_Id) return Entity_Id; - -- Return the representative type in SPARK for a type. - - with function Component_Is_Visible_In_SPARK (C : Entity_Id) return Boolean; - -- Return whether a component is visible in SPARK. No aliasing check is - -- performed for a component that is visible. - - with function Emit_Messages return Boolean; - -- Return True when error messages should be emitted. - - with function Is_Pledge_Function (E : Entity_Id) return Boolean; - -- Return True if E is annotated with a pledge annotation - -package Sem_SPARK is - - function Is_Legal (N : Node_Id) return Boolean; - -- Test the legality of a node wrt ownership-checking rules. This does not - -- check rules related to the validity of permissions associated with paths - -- from objects, so that it can be called from GNATprove on code of library - -- units analyzed in SPARK_Mode Auto. - - procedure Check_Safe_Pointers (N : Node_Id); - -- The entry point of this package. It analyzes a node and reports errors - -- when there are violations of ownership rules. - - function Is_Deep (Typ : Entity_Id) return Boolean; - -- Returns True if the type passed as argument is deep - - function Is_Traversal_Function (E : Entity_Id) return Boolean; - - function Is_Local_Context (Scop : Entity_Id) return Boolean; - -- Return if a given scope defines a local context where it is legal to - -- declare a variable of anonymous access type. - -end Sem_SPARK; -- cgit v1.1 From 46a500a5cc81138ada165e97e63aed7bea4103e2 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:13:48 +0000 Subject: [Ada] Fix run-time segfault with derived access-to-subprogram type This fixes a segfault at run time for the call to a local subprogram through an access value if the type of this access value is derived from an initial access-to-subprogram type and the access value was originally obtained with the initial type. 2019-09-19 Eric Botcazou gcc/ada/ * sem_ch3.adb (Build_Derived_Access_Type): If this is an access- to-subprogram type, copy Can_Use_Internal_Rep from the parent. gcc/testsuite/ * gnat.dg/access9.adb: New testcase. From-SVN: r275945 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/sem_ch3.adb | 5 +++++ gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gnat.dg/access9.adb | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 gcc/testsuite/gnat.dg/access9.adb (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 6fa4edf..9b05d3e 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Eric Botcazou + + * sem_ch3.adb (Build_Derived_Access_Type): If this is an access- + to-subprogram type, copy Can_Use_Internal_Rep from the parent. + 2019-09-19 Yannick Moy * gcc-interface/Make-lang.in: Remove references to sem_spark. diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index 35be35a..e304e72 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -6723,6 +6723,11 @@ package body Sem_Ch3 is Has_Private_Component (Derived_Type)); Conditional_Delay (Derived_Type, Subt); + if Is_Access_Subprogram_Type (Derived_Type) then + Set_Can_Use_Internal_Rep + (Derived_Type, Can_Use_Internal_Rep (Parent_Type)); + end if; + -- Ada 2005 (AI-231): Set the null-exclusion attribute, and verify -- that it is not redundant. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7cde63d..a927297 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Eric Botcazou + + * gnat.dg/access9.adb: New testcase. + 2019-09-19 Ed Schonberg * gnat.dg/predicate14.adb, gnat.dg/predicate14.ads: New diff --git a/gcc/testsuite/gnat.dg/access9.adb b/gcc/testsuite/gnat.dg/access9.adb new file mode 100644 index 0000000..d2028c9 --- /dev/null +++ b/gcc/testsuite/gnat.dg/access9.adb @@ -0,0 +1,20 @@ +-- { dg-do run } + +procedure Access9 is + + type A_Type is access procedure; + + type B_Type is new A_Type; + + procedure Invoke (B : B_Type) is + begin + B.all; + end; + + procedure Nested is begin null; end; + + A : A_Type := Nested'Access; + +begin + Invoke (B_Type (A)); +end; \ No newline at end of file -- cgit v1.1 From 7005758ce72896e478245ed2de0aa146427a2ec9 Mon Sep 17 00:00:00 2001 From: Arnaud Charlet Date: Thu, 19 Sep 2019 08:13:52 +0000 Subject: [Ada] Exp_Attr: remove obsolete comment 2019-09-19 Arnaud Charlet gcc/ada/ * exp_attr.adb: Remove obsolete comment. From-SVN: r275946 --- gcc/ada/ChangeLog | 4 ++++ gcc/ada/exp_attr.adb | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 9b05d3e..b4bfc00 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Arnaud Charlet + + * exp_attr.adb: Remove obsolete comment. + 2019-09-19 Eric Botcazou * sem_ch3.adb (Build_Derived_Access_Type): If this is an access- diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index 817e7ef..1459cfc 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -2381,9 +2381,6 @@ package body Exp_Attr is -- generate a call to a run-time subprogram that returns the base -- address of the object. - -- This processing is not needed in the VM case, where dispatching - -- issues are taken care of by the virtual machine. - elsif Is_Class_Wide_Type (Ptyp) and then Is_Interface (Underlying_Type (Ptyp)) and then Tagged_Type_Expansion -- cgit v1.1 From 09709b4781192f7724e2bb2977d3610ae727260f Mon Sep 17 00:00:00 2001 From: Yannick Moy Date: Thu, 19 Sep 2019 08:13:58 +0000 Subject: [Ada] Allow constants of access type in Global contracts Now that SPARK supports access types, global constants of access type may appear as outputs of a subprogram, with the meaning that the underlying memory can be modified (see SPARK RM 3.10). 2019-09-19 Yannick Moy gcc/ada/ * sem_prag.adb (Analyze_Global_In_Decl_Part): Do not issue an error when a constant of an access type is used as output in a Global contract. (Analyze_Depends_In_Decl_Part): Do not issue an error when a constant of an access type is used as output in a Depends contract. gcc/testsuite/ * gnat.dg/global2.adb, gnat.dg/global2.ads: New testcase. From-SVN: r275947 --- gcc/ada/ChangeLog | 9 +++++++++ gcc/ada/sem_prag.adb | 35 ++++++++++++++++++++++++++++++----- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gnat.dg/global2.adb | 12 ++++++++++++ gcc/testsuite/gnat.dg/global2.ads | 6 ++++++ 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/global2.adb create mode 100644 gcc/testsuite/gnat.dg/global2.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index b4bfc00..070b8a1 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,12 @@ +2019-09-19 Yannick Moy + + * sem_prag.adb (Analyze_Global_In_Decl_Part): Do not issue an + error when a constant of an access type is used as output in a + Global contract. + (Analyze_Depends_In_Decl_Part): Do not issue an error when a + constant of an access type is used as output in a Depends + contract. + 2019-09-19 Arnaud Charlet * exp_attr.adb: Remove obsolete comment. diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 5a561ea..4367383 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -1262,8 +1262,28 @@ package body Sem_Prag is (Item_Is_Input : out Boolean; Item_Is_Output : out Boolean) is + -- A constant or IN parameter of access type should be handled + -- like a variable, as the underlying memory pointed-to can be + -- modified. Use Adjusted_Kind to do this adjustment. + + Adjusted_Kind : Entity_Kind := Ekind (Item_Id); + begin - case Ekind (Item_Id) is + if Ekind_In (Item_Id, E_Constant, + E_Generic_In_Parameter, + E_In_Parameter) + + -- If Item_Id is of a private type whose completion has not been + -- analyzed yet, its Underlying_Type is empty and we handle it + -- as a constant. + + and then Present (Underlying_Type (Etype (Item_Id))) + and then Is_Access_Type (Underlying_Type (Etype (Item_Id))) + then + Adjusted_Kind := E_Variable; + end if; + + case Adjusted_Kind is -- Abstract states @@ -1303,7 +1323,9 @@ package body Sem_Prag is Item_Is_Output := False; - -- Variables and IN OUT parameters + -- Variables and IN OUT parameters, as well as constants and + -- IN parameters of access type which are handled like + -- variables. when E_Generic_In_Out_Parameter | E_In_Out_Parameter @@ -2412,10 +2434,13 @@ package body Sem_Prag is -- Constant related checks - elsif Ekind (Item_Id) = E_Constant then + elsif Ekind (Item_Id) = E_Constant + and then + not Is_Access_Type (Underlying_Type (Etype (Item_Id))) + then - -- A constant is a read-only item, therefore it cannot act - -- as an output. + -- Unless it is of an access type, a constant is a read-only + -- item, therefore it cannot act as an output. if Nam_In (Global_Mode, Name_In_Out, Name_Output) then SPARK_Msg_NE diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a927297..da23e2c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Yannick Moy + + * gnat.dg/global2.adb, gnat.dg/global2.ads: New testcase. + 2019-09-19 Eric Botcazou * gnat.dg/access9.adb: New testcase. diff --git a/gcc/testsuite/gnat.dg/global2.adb b/gcc/testsuite/gnat.dg/global2.adb new file mode 100644 index 0000000..b18d9ac --- /dev/null +++ b/gcc/testsuite/gnat.dg/global2.adb @@ -0,0 +1,12 @@ +-- { dg-do compile } + +package body Global2 is + procedure Change_X is + begin + X.all := 1; + end Change_X; + procedure Change2_X is + begin + X.all := 1; + end Change2_X; +end Global2; \ No newline at end of file diff --git a/gcc/testsuite/gnat.dg/global2.ads b/gcc/testsuite/gnat.dg/global2.ads new file mode 100644 index 0000000..4de3158 --- /dev/null +++ b/gcc/testsuite/gnat.dg/global2.ads @@ -0,0 +1,6 @@ +package Global2 is + type Int_Acc is access Integer; + X : constant Int_Acc := new Integer'(34); + procedure Change_X with Global => (In_Out => X); + procedure Change2_X with Depends => (X => X); +end Global2; -- cgit v1.1 From 231ef54b96d6022bc844107f50490ba5c96f4a50 Mon Sep 17 00:00:00 2001 From: Yannick Moy Date: Thu, 19 Sep 2019 08:14:03 +0000 Subject: [Ada] Disable inlining of traversal function in GNATprove Traversal functions as defined in SPARK RM 3.10 should not be inlined for analysis in GNATprove, as this changes the ownership behavior. Disable the inlining performed in GNATprove on functions which could be interpreted as such. There is no impact on compilation and thus no test. 2019-09-19 Yannick Moy gcc/ada/ * inline.adb (Can_Be_Inlined_In_GNATprove_Mode): Add special case for traversal functions. From-SVN: r275948 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/inline.adb | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 070b8a1..8c88e90 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,10 @@ 2019-09-19 Yannick Moy + * inline.adb (Can_Be_Inlined_In_GNATprove_Mode): Add special + case for traversal functions. + +2019-09-19 Yannick Moy + * sem_prag.adb (Analyze_Global_In_Decl_Part): Do not issue an error when a constant of an access type is used as output in a Global contract. diff --git a/gcc/ada/inline.adb b/gcc/ada/inline.adb index 6e345d6..dab2275 100644 --- a/gcc/ada/inline.adb +++ b/gcc/ada/inline.adb @@ -1512,6 +1512,12 @@ package body Inline is -- Return True if subprogram Id is defined in the package specification, -- either its visible or private part. + function Maybe_Traversal_Function (Id : Entity_Id) return Boolean; + -- Return True if subprogram Id could be a traversal function, as + -- defined in SPARK RM 3.10. This is only a safe approximation, as the + -- knowledge of the SPARK boundary is needed to determine exactly + -- traversal functions. + --------------------------------------------------- -- Has_Formal_With_Discriminant_Dependent_Fields -- --------------------------------------------------- @@ -1635,6 +1641,20 @@ package body Inline is return Nkind (Parent (Decl)) = N_Compilation_Unit; end Is_Unit_Subprogram; + ------------------------------ + -- Maybe_Traversal_Function -- + ------------------------------ + + function Maybe_Traversal_Function (Id : Entity_Id) return Boolean is + begin + return Ekind (Id) = E_Function + + -- Only traversal functions return an anonymous access-to-object + -- type in SPARK. + + and then Is_Anonymous_Access_Type (Etype (Id)); + end Maybe_Traversal_Function; + -- Local declarations Id : Entity_Id; @@ -1757,6 +1777,15 @@ package body Inline is elsif Has_Formal_With_Discriminant_Dependent_Fields (Id) then return False; + -- Do not inline subprograms which may be traversal functions. Such + -- inlining introduces temporary variables of named access type for + -- which assignments are move instead of borrow/observe, possibly + -- leading to spurious errors when checking SPARK rules related to + -- pointer usage. + + elsif Maybe_Traversal_Function (Id) then + return False; + -- Otherwise, this is a subprogram declared inside the private part of a -- package, or inside a package body, or locally in a subprogram, and it -- does not have any contract. Inline it. -- cgit v1.1 From 46fa6b050e81504aab992d58b693aa81dd45eeb9 Mon Sep 17 00:00:00 2001 From: Ed Schonberg Date: Thu, 19 Sep 2019 08:14:08 +0000 Subject: [Ada] Spurious visibility error in generic child unit 2019-09-19 Ed Schonberg gcc/ada/ * sem_ch7.adb (Install_Parent_Private_Declarations): If a generic child unit is instantiated within a sibling child unit, the analysis of its private part requires that the private part of the ancestor be available, as is done when the context includes an instance of the ancestor. gcc/testsuite/ * gnat.dg/generic2-child.ads, gnat.dg/generic2-io_any.adb, gnat.dg/generic2-io_any.ads, gnat.dg/generic2.ads: New testcase. From-SVN: r275949 --- gcc/ada/ChangeLog | 8 ++++++++ gcc/ada/sem_ch7.adb | 18 +++++++++++++++--- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gnat.dg/generic2-child.ads | 5 +++++ gcc/testsuite/gnat.dg/generic2-io_any.adb | 5 +++++ gcc/testsuite/gnat.dg/generic2-io_any.ads | 6 ++++++ gcc/testsuite/gnat.dg/generic2.ads | 5 +++++ 7 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/generic2-child.ads create mode 100644 gcc/testsuite/gnat.dg/generic2-io_any.adb create mode 100644 gcc/testsuite/gnat.dg/generic2-io_any.ads create mode 100644 gcc/testsuite/gnat.dg/generic2.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 8c88e90..e761f70 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,11 @@ +2019-09-19 Ed Schonberg + + * sem_ch7.adb (Install_Parent_Private_Declarations): If a + generic child unit is instantiated within a sibling child unit, + the analysis of its private part requires that the private part + of the ancestor be available, as is done when the context + includes an instance of the ancestor. + 2019-09-19 Yannick Moy * inline.adb (Can_Be_Inlined_In_GNATprove_Mode): Add special diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb index f7998c0..db6bffd 100644 --- a/gcc/ada/sem_ch7.adb +++ b/gcc/ada/sem_ch7.adb @@ -1508,9 +1508,21 @@ package body Sem_Ch7 is Inst_Par := Renamed_Entity (Inst_Par); end if; - Gen_Par := - Generic_Parent - (Specification (Unit_Declaration_Node (Inst_Par))); + -- The instance may appear in a sibling generic unit, in + -- which case the prefix must include the common (generic) + -- ancestor, which is treated as a current instance. + + if Inside_A_Generic + and then Ekind (Inst_Par) = E_Generic_Package + then + Gen_Par := Inst_Par; + pragma Assert (In_Open_Scopes (Gen_Par)); + + else + Gen_Par := + Generic_Parent + (Specification (Unit_Declaration_Node (Inst_Par))); + end if; -- Install the private declarations and private use clauses -- of a parent instance of the child instance, unless the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index da23e2c..a3534f1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Ed Schonberg + + * gnat.dg/generic2-child.ads, gnat.dg/generic2-io_any.adb, + gnat.dg/generic2-io_any.ads, gnat.dg/generic2.ads: New testcase. + 2019-09-19 Yannick Moy * gnat.dg/global2.adb, gnat.dg/global2.ads: New testcase. diff --git a/gcc/testsuite/gnat.dg/generic2-child.ads b/gcc/testsuite/gnat.dg/generic2-child.ads new file mode 100644 index 0000000..291cb23 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic2-child.ads @@ -0,0 +1,5 @@ +generic +package Generic2.Child is +private + type My_Int is new Int; +end Generic2.Child; diff --git a/gcc/testsuite/gnat.dg/generic2-io_any.adb b/gcc/testsuite/gnat.dg/generic2-io_any.adb new file mode 100644 index 0000000..f077ad6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic2-io_any.adb @@ -0,0 +1,5 @@ +-- { dg-do compile } + +package body Generic2.IO_Any is + procedure Dummy is null; +end Generic2.IO_Any; \ No newline at end of file diff --git a/gcc/testsuite/gnat.dg/generic2-io_any.ads b/gcc/testsuite/gnat.dg/generic2-io_any.ads new file mode 100644 index 0000000..e56e229 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic2-io_any.ads @@ -0,0 +1,6 @@ +with Generic2.Child; +generic +package Generic2.IO_Any is + package V1 is new Generic2.Child; + procedure Dummy; +end Generic2.IO_Any; diff --git a/gcc/testsuite/gnat.dg/generic2.ads b/gcc/testsuite/gnat.dg/generic2.ads new file mode 100644 index 0000000..295d6b2 --- /dev/null +++ b/gcc/testsuite/gnat.dg/generic2.ads @@ -0,0 +1,5 @@ +generic +package Generic2 is +private + type Int is new Integer; +end Generic2; -- cgit v1.1 From 4fe56329e05e3e77c424929fdb102f2df075f74a Mon Sep 17 00:00:00 2001 From: Yannick Moy Date: Thu, 19 Sep 2019 08:14:13 +0000 Subject: [Ada] Use declared type for deciding on SPARK pointer rules A constant of pointer type is considered as mutable in SPARK, according to SPARK RM 3.10, but this should be based on the declared type of the constant instead of its underlying type. There is no impact on compilation hence no test. 2019-09-19 Yannick Moy gcc/ada/ * sem_prag.adb (Analyze_Depends_In_Decl_Part): Simplify previous test. From-SVN: r275950 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/sem_prag.adb | 8 +------- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index e761f70..54e48af 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Yannick Moy + + * sem_prag.adb (Analyze_Depends_In_Decl_Part): Simplify previous + test. + 2019-09-19 Ed Schonberg * sem_ch7.adb (Install_Parent_Private_Declarations): If a diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 4367383..b54604d 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -1272,13 +1272,7 @@ package body Sem_Prag is if Ekind_In (Item_Id, E_Constant, E_Generic_In_Parameter, E_In_Parameter) - - -- If Item_Id is of a private type whose completion has not been - -- analyzed yet, its Underlying_Type is empty and we handle it - -- as a constant. - - and then Present (Underlying_Type (Etype (Item_Id))) - and then Is_Access_Type (Underlying_Type (Etype (Item_Id))) + and then Is_Access_Type (Etype (Item_Id)) then Adjusted_Kind := E_Variable; end if; -- cgit v1.1 From fd0d7b4e3be10508119636f06807f23d5691088b Mon Sep 17 00:00:00 2001 From: Dmitriy Anisimkov Date: Thu, 19 Sep 2019 08:14:18 +0000 Subject: [Ada] New routine GNAT.Sockets.Create_Socket_Pair New routine to create 2 connected sockets. This routine is analog of the UNIX system call socketpair. On UNIX platforms it is implemented on the base of socketpair. On other platforms it is implemented by conecting network sockets over loopback interface. 2019-09-19 Dmitriy Anisimkov gcc/ada/ * libgnat/g-socket.ads, libgnat/g-socket.adb (Create_Socket_Pair): New routine. * libgnat/g-socthi.ads (OS_Has_Socketpair): Boolean constant. (C_Socketpair): New imported routine. * libgnat/g-socthi__mingw.ads, libgnat/g-socthi__vxworks.ads (Default_Socket_Pair_Family): New constant. (C_Socketpair): New routine. * libgnat/g-socthi__mingw.adb, libgnat/g-socthi__vxworks.adb (C_Socketpair): Is separated in anouther file. * libgnat/g-sthcso.adb (C_Socketpair): Non UNIX implementation. * libgnat/g-stsifd__sockets.adb: Reuse C_Socketpair. From-SVN: r275951 --- gcc/ada/ChangeLog | 14 +++ gcc/ada/libgnat/g-socket.adb | 28 +++++ gcc/ada/libgnat/g-socket.ads | 12 +- gcc/ada/libgnat/g-socthi.ads | 11 ++ gcc/ada/libgnat/g-socthi__mingw.adb | 10 ++ gcc/ada/libgnat/g-socthi__mingw.ads | 11 ++ gcc/ada/libgnat/g-socthi__vxworks.adb | 10 ++ gcc/ada/libgnat/g-socthi__vxworks.ads | 11 ++ gcc/ada/libgnat/g-sthcso.adb | 213 ++++++++++++++++++++++++++++++++++ gcc/ada/libgnat/g-stsifd__sockets.adb | 156 ++----------------------- 10 files changed, 330 insertions(+), 146 deletions(-) create mode 100644 gcc/ada/libgnat/g-sthcso.adb (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 54e48af..a204c28 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,17 @@ +2019-09-19 Dmitriy Anisimkov + + * libgnat/g-socket.ads, libgnat/g-socket.adb + (Create_Socket_Pair): New routine. + * libgnat/g-socthi.ads (OS_Has_Socketpair): Boolean constant. + (C_Socketpair): New imported routine. + * libgnat/g-socthi__mingw.ads, libgnat/g-socthi__vxworks.ads + (Default_Socket_Pair_Family): New constant. + (C_Socketpair): New routine. + * libgnat/g-socthi__mingw.adb, libgnat/g-socthi__vxworks.adb + (C_Socketpair): Is separated in anouther file. + * libgnat/g-sthcso.adb (C_Socketpair): Non UNIX implementation. + * libgnat/g-stsifd__sockets.adb: Reuse C_Socketpair. + 2019-09-19 Yannick Moy * sem_prag.adb (Analyze_Depends_In_Decl_Part): Simplify previous diff --git a/gcc/ada/libgnat/g-socket.adb b/gcc/ada/libgnat/g-socket.adb index 8565ccf..6c65424 100644 --- a/gcc/ada/libgnat/g-socket.adb +++ b/gcc/ada/libgnat/g-socket.adb @@ -867,6 +867,34 @@ package body GNAT.Sockets is Socket := Socket_Type (Res); end Create_Socket; + ------------------------ + -- Create_Socket_Pair -- + ------------------------ + + procedure Create_Socket_Pair + (Left : out Socket_Type; + Right : out Socket_Type; + Family : Family_Type := Family_Unspec; + Mode : Mode_Type := Socket_Stream; + Level : Level_Type := IP_Protocol_For_IP_Level) + is + Res : C.int; + Pair : aliased Thin_Common.Fd_Pair; + + begin + Res := C_Socketpair + ((if Family = Family_Unspec then Default_Socket_Pair_Family + else Families (Family)), + Modes (Mode), Levels (Level), Pair'Access); + + if Res = Failure then + Raise_Socket_Error (Socket_Errno); + end if; + + Left := Socket_Type (Pair (Pair'First)); + Right := Socket_Type (Pair (Pair'Last)); + end Create_Socket_Pair; + ----------- -- Empty -- ----------- diff --git a/gcc/ada/libgnat/g-socket.ads b/gcc/ada/libgnat/g-socket.ads index 38d1078..3962cc0 100644 --- a/gcc/ada/libgnat/g-socket.ads +++ b/gcc/ada/libgnat/g-socket.ads @@ -1104,7 +1104,17 @@ package GNAT.Sockets is Family : Family_Type := Family_Inet; Mode : Mode_Type := Socket_Stream; Level : Level_Type := IP_Protocol_For_IP_Level); - -- Create an endpoint for communication. Raises Socket_Error on error + -- Create an endpoint for communication. Raises Socket_Error on error. + + procedure Create_Socket_Pair + (Left : out Socket_Type; + Right : out Socket_Type; + Family : Family_Type := Family_Unspec; + Mode : Mode_Type := Socket_Stream; + Level : Level_Type := IP_Protocol_For_IP_Level); + -- Create two connected sockets. Raises Socket_Error on error. + -- If Family is unspecified, it creates Family_Unix sockets on UNIX and + -- Family_Inet sockets on non UNIX platforms. procedure Accept_Socket (Server : Socket_Type; diff --git a/gcc/ada/libgnat/g-socthi.ads b/gcc/ada/libgnat/g-socthi.ads index 2f22860..56b31ac 100644 --- a/gcc/ada/libgnat/g-socthi.ads +++ b/gcc/ada/libgnat/g-socthi.ads @@ -184,6 +184,16 @@ package GNAT.Sockets.Thin is function C_System (Command : System.Address) return C.int; + Default_Socket_Pair_Family : constant := SOSC.AF_UNIX; + -- UNIX has socketpair system call and AF_UNIX family is widely supported + + function C_Socketpair + (Domain : C.int; + Typ : C.int; + Protocol : C.int; + Fds : not null access Fd_Pair) return C.int; + -- Creates pair of connected sockets + ------------------------------------------------------- -- Signalling file descriptors for selector abortion -- ------------------------------------------------------- @@ -249,6 +259,7 @@ private pragma Import (C, C_Select, "select"); pragma Import (C, C_Setsockopt, "setsockopt"); pragma Import (C, C_Shutdown, "shutdown"); + pragma Import (C, C_Socketpair, "socketpair"); pragma Import (C, C_System, "system"); pragma Import (C, Nonreentrant_Gethostbyname, "gethostbyname"); diff --git a/gcc/ada/libgnat/g-socthi__mingw.adb b/gcc/ada/libgnat/g-socthi__mingw.adb index 9347d3b..5ad292d 100644 --- a/gcc/ada/libgnat/g-socthi__mingw.adb +++ b/gcc/ada/libgnat/g-socthi__mingw.adb @@ -511,6 +511,16 @@ package body GNAT.Sockets.Thin is return System.CRTL.ssize_t (Count); end C_Sendmsg; + ------------------ + -- C_Socketpair -- + ------------------ + + function C_Socketpair + (Domain : C.int; + Typ : C.int; + Protocol : C.int; + Fds : not null access Fd_Pair) return C.int is separate; + -------------- -- Finalize -- -------------- diff --git a/gcc/ada/libgnat/g-socthi__mingw.ads b/gcc/ada/libgnat/g-socthi__mingw.ads index 6908759..a5aa67e 100644 --- a/gcc/ada/libgnat/g-socthi__mingw.ads +++ b/gcc/ada/libgnat/g-socthi__mingw.ads @@ -177,6 +177,17 @@ package GNAT.Sockets.Thin is Typ : C.int; Protocol : C.int) return C.int; + Default_Socket_Pair_Family : constant := SOSC.AF_INET; + -- Windows has not socketpair system call, and C_Socketpair below is + -- implemented on loopback connected network sockets. + + function C_Socketpair + (Domain : C.int; + Typ : C.int; + Protocol : C.int; + Fds : not null access Fd_Pair) return C.int; + -- Creates pair of connected sockets + function C_System (Command : System.Address) return C.int; diff --git a/gcc/ada/libgnat/g-socthi__vxworks.adb b/gcc/ada/libgnat/g-socthi__vxworks.adb index 75b0790..a2bbed6 100644 --- a/gcc/ada/libgnat/g-socthi__vxworks.adb +++ b/gcc/ada/libgnat/g-socthi__vxworks.adb @@ -419,6 +419,16 @@ package body GNAT.Sockets.Thin is return R; end C_Socket; + ------------------ + -- C_Socketpair -- + ------------------ + + function C_Socketpair + (Domain : C.int; + Typ : C.int; + Protocol : C.int; + Fds : not null access Fd_Pair) return C.int is separate; + -------------- -- Finalize -- -------------- diff --git a/gcc/ada/libgnat/g-socthi__vxworks.ads b/gcc/ada/libgnat/g-socthi__vxworks.ads index e0ba92f..664218d 100644 --- a/gcc/ada/libgnat/g-socthi__vxworks.ads +++ b/gcc/ada/libgnat/g-socthi__vxworks.ads @@ -178,6 +178,17 @@ package GNAT.Sockets.Thin is Typ : C.int; Protocol : C.int) return C.int; + Default_Socket_Pair_Family : constant := SOSC.AF_INET; + -- VxWorks has not socketpair system call, and C_Socketpair below is + -- implemented on loopback connected network sockets. + + function C_Socketpair + (Domain : C.int; + Typ : C.int; + Protocol : C.int; + Fds : not null access Fd_Pair) return C.int; + -- Creates pair of connected sockets + function C_System (Command : System.Address) return C.int; diff --git a/gcc/ada/libgnat/g-sthcso.adb b/gcc/ada/libgnat/g-sthcso.adb new file mode 100644 index 0000000..49c55f2 --- /dev/null +++ b/gcc/ada/libgnat/g-sthcso.adb @@ -0,0 +1,213 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- G N A T . S O C K E T S . T H I N . C _ S O C K E T P A I R -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2001-2019, AdaCore -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- Portable sockets-based implementation of the C_Socketpair used for +-- platforms that do not support UNIX socketpair system call. + +-- Note: this code is only for non-UNIX platforms. + +separate (GNAT.Sockets.Thin) +function C_Socketpair + (Domain : C.int; + Typ : C.int; + Protocol : C.int; + Fds : not null access Fd_Pair) return C.int +is + use type C.char_array; + + L_Sock, C_Sock, P_Sock : C.int := Failure; + -- Listening socket, client socket and peer socket + + Family : constant Family_Type := + (case Domain is + when SOSC.AF_INET => Family_Inet, + when SOSC.AF_INET6 => Family_Inet6, + when others => Family_Unspec); + + Len : aliased C.int := C.int (Lengths (Family)); + + C_Sin : aliased Sockaddr; + C_Bin : aliased C.char_array (1 .. C.size_t (Len)); + for C_Bin'Address use C_Sin'Address; + -- Address of listening and client socket and it's binary representation. + -- We need binary representation because Ada does not allow to compare + -- unchecked union if either of the operands lacks inferable discriminants. + -- RM-B-3-3 23/2. + + P_Sin : aliased Sockaddr; + P_Bin : aliased C.char_array (1 .. C.size_t (Len)); + for P_Bin'Address use P_Sin'Address; + -- Address of peer socket and it's binary representation + + T_Sin : aliased Sockaddr; + T_Bin : aliased C.char_array (1 .. C.size_t (Len)); + for T_Bin'Address use T_Sin'Address; + -- Temporary address to compare and check that address and port of the + -- socket equal to peer address and port of the opposite connected socket. + + Res : C.int with Warnings => Off; + +begin + Set_Family (C_Sin.Sin_Family, Family); + + case Family is + when Family_Inet => + C_Sin.Sin_Addr.S_B1 := 127; + C_Sin.Sin_Addr.S_B4 := 1; + + when Family_Inet6 => + C_Sin.Sin6_Addr (C_Sin.Sin6_Addr'Last) := 1; + + when others => + Set_Socket_Errno (SOSC.EAFNOSUPPORT); + return Failure; + end case; + + for J in 1 .. 10 loop + -- Retry loop, in case the C_Connect below fails + + C_Sin.Sin_Port := 0; + + -- Create a listening socket + + L_Sock := C_Socket (Domain, Typ, Protocol); + exit when L_Sock = Failure; + + -- Bind the socket to an available port on localhost + + Res := C_Bind (L_Sock, C_Sin'Address, Len); + exit when Res = Failure; + + -- Get assigned port + + Res := C_Getsockname (L_Sock, C_Sin'Address, Len'Access); + exit when Res = Failure; + + -- Set socket to listen mode, with a backlog of 1 to guarantee that + -- exactly one call to connect(2) succeeds. + + Res := C_Listen (L_Sock, 1); + exit when Res = Failure; + + -- Create read end (client) socket + + C_Sock := C_Socket (Domain, Typ, Protocol); + exit when C_Sock = Failure; + + -- Connect listening socket + + Res := C_Connect (C_Sock, C_Sin'Address, Len); + + if Res = Failure then + -- In rare cases, the above C_Bind chooses a port that is still + -- marked "in use", even though it has been closed (perhaps by some + -- other process that has already exited). This causes the above + -- C_Connect to fail with EADDRINUSE. In this case, we close the + -- ports, and loop back to try again. This mysterious Windows + -- behavior is documented. See, for example: + -- http://msdn2.microsoft.com/en-us/library/ms737625.aspx + -- In an experiment with 2000 calls, 21 required exactly one retry, 7 + -- required two, and none required three or more. Note that no delay + -- is needed between retries; retrying C_Bind will typically produce + -- a different port. + + exit when Socket_Errno /= SOSC.EADDRINUSE; + + goto Repeat; + end if; + + -- Since the call to connect(2) has succeeded and the backlog limit + -- on the listening socket is 1, we know that there is now exactly + -- one pending connection on L_Sock, which is the one from R_Sock. + + P_Sin.Sun_Path := (others => C.nul); + + P_Sock := C_Accept (L_Sock, P_Sin'Address, Len'Access); + exit when P_Sock = Failure; + + -- Address and port of the socket equal to peer address and port of the + -- opposite connected socket. + + Res := C_Getsockname (P_Sock, T_Sin'Address, Len'Access); + exit when Res = Failure; + + if T_Bin /= C_Bin then + goto Repeat; + end if; + + -- Address and port of the socket equal to peer address and port of the + -- opposite connected socket. + + Res := C_Getsockname (C_Sock, T_Sin'Address, Len'Access); + exit when Res = Failure; + + if T_Bin /= P_Bin then + goto Repeat; + end if; + + -- Close listening socket (ignore exit status) + + Res := C_Close (L_Sock); + + Fds.all := (Read_End => C_Sock, Write_End => P_Sock); + + return Thin_Common.Success; + + <> + Res := C_Close (C_Sock); + C_Sock := Failure; + Res := C_Close (P_Sock); + P_Sock := Failure; + Res := C_Close (L_Sock); + L_Sock := Failure; + end loop; + + declare + Saved_Errno : constant Integer := Socket_Errno; + + begin + if P_Sock /= Failure then + Res := C_Close (P_Sock); + end if; + + if C_Sock /= Failure then + Res := C_Close (C_Sock); + end if; + + if L_Sock /= Failure then + Res := C_Close (L_Sock); + end if; + + Set_Socket_Errno (Saved_Errno); + end; + + return Failure; +end C_Socketpair; diff --git a/gcc/ada/libgnat/g-stsifd__sockets.adb b/gcc/ada/libgnat/g-stsifd__sockets.adb index 909e58c..90c98b7 100644 --- a/gcc/ada/libgnat/g-stsifd__sockets.adb +++ b/gcc/ada/libgnat/g-stsifd__sockets.adb @@ -57,154 +57,20 @@ package body Signalling_Fds is ------------ function Create (Fds : not null access Fd_Pair) return C.int is - L_Sock, R_Sock, W_Sock : C.int := Failure; - -- Listening socket, read socket and write socket - - Sin : aliased Sockaddr; - Len : aliased C.int; - -- Address of listening socket - - Res : C.int; - pragma Warnings (Off, Res); - -- Return status of system calls (usually ignored, hence warnings off) - + Res : constant C.int := + C_Socketpair (SOSC.AF_INET, SOSC.SOCK_STREAM, 0, Fds); begin - Fds.all := (Read_End | Write_End => Failure); - - -- We open two signalling sockets. One of them is used to send data - -- to the other, which is included in a C_Select socket set. The - -- communication is used to force the call to C_Select to complete, - -- and the waiting task to resume its execution. - - loop - -- Retry loop, in case the C_Connect below fails - - -- Create a listening socket - - L_Sock := C_Socket (SOSC.AF_INET, SOSC.SOCK_STREAM, 0); - - if L_Sock = Failure then - goto Fail; - end if; - - -- Bind the socket to an available port on localhost - - Set_Family (Sin.Sin_Family, Family_Inet); - Sin.Sin_Addr.S_B1 := 127; - Sin.Sin_Addr.S_B2 := 0; - Sin.Sin_Addr.S_B3 := 0; - Sin.Sin_Addr.S_B4 := 1; - Sin.Sin_Port := 0; - - Len := C.int (Lengths (Family_Inet)); - Res := C_Bind (L_Sock, Sin'Address, Len); - - if Res = Failure then - goto Fail; - end if; - - -- Get assigned port - - Res := C_Getsockname (L_Sock, Sin'Address, Len'Access); - if Res = Failure then - goto Fail; - end if; - - -- Set socket to listen mode, with a backlog of 1 to guarantee that - -- exactly one call to connect(2) succeeds. - - Res := C_Listen (L_Sock, 1); - - if Res = Failure then - goto Fail; - end if; - - -- Create read end (client) socket - - R_Sock := C_Socket (SOSC.AF_INET, SOSC.SOCK_STREAM, 0); - - if R_Sock = Failure then - goto Fail; - end if; - - -- Connect listening socket - - Res := C_Connect (R_Sock, Sin'Address, Len); - - exit when Res /= Failure; - - if Socket_Errno /= SOSC.EADDRINUSE then - goto Fail; - end if; - - -- In rare cases, the above C_Bind chooses a port that is still - -- marked "in use", even though it has been closed (perhaps by some - -- other process that has already exited). This causes the above - -- C_Connect to fail with EADDRINUSE. In this case, we close the - -- ports, and loop back to try again. This mysterious Windows - -- behavior is documented. See, for example: - -- http://msdn2.microsoft.com/en-us/library/ms737625.aspx - -- In an experiment with 2000 calls, 21 required exactly one retry, 7 - -- required two, and none required three or more. Note that no delay - -- is needed between retries; retrying C_Bind will typically produce - -- a different port. - - pragma Assert (Res = Failure - and then - Socket_Errno = SOSC.EADDRINUSE); - Res := C_Close (W_Sock); - W_Sock := Failure; - Res := C_Close (R_Sock); - R_Sock := Failure; - end loop; - - -- Since the call to connect(2) has succeeded and the backlog limit on - -- the listening socket is 1, we know that there is now exactly one - -- pending connection on L_Sock, which is the one from R_Sock. - - W_Sock := C_Accept (L_Sock, Sin'Address, Len'Access); - - if W_Sock = Failure then - goto Fail; + if Res /= Failure then + -- Set TCP_NODELAY on Fds (Write_End), since we always want to send + -- the data out immediately. + + Set_Socket_Option + (Socket => Socket_Type (Fds (Write_End)), + Level => IP_Protocol_For_TCP_Level, + Option => (Name => No_Delay, Enabled => True)); end if; - -- Set TCP_NODELAY on W_Sock, since we always want to send the data out - -- immediately. - - Set_Socket_Option - (Socket => Socket_Type (W_Sock), - Level => IP_Protocol_For_TCP_Level, - Option => (Name => No_Delay, Enabled => True)); - - -- Close listening socket (ignore exit status) - - Res := C_Close (L_Sock); - - Fds.all := (Read_End => R_Sock, Write_End => W_Sock); - - return Thin_Common.Success; - - <> - declare - Saved_Errno : constant Integer := Socket_Errno; - - begin - if W_Sock /= Failure then - Res := C_Close (W_Sock); - end if; - - if R_Sock /= Failure then - Res := C_Close (R_Sock); - end if; - - if L_Sock /= Failure then - Res := C_Close (L_Sock); - end if; - - Set_Socket_Errno (Saved_Errno); - end; - - return Failure; + return Res; end Create; ---------- -- cgit v1.1 From 9e0746fcd5bb14d164d3686b0940ae7129d05231 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:14:23 +0000 Subject: [Ada] Fix bogus visibility error with nested generics and inlining This prevents the compiler from issuing a bogus error about the visibility of an operator in an instantiation of a nested generic package which is itself used as an actual of an instantiation of another generic package, when the instantiations are done in a unit withed from the main unit and containing an inlined subprogram, and cross-unit inlining is enabled. In most cases, the compiler does not check the visibility of operators in an instantiation context because this has already been done when the generic package has been analyzed. However, there are exceptions like the actuals of an instantiation of a generic child unit which is done as a compilation unit and the In_Instance predicate has a special check for these cases. This check would incorrectly trigger here and needs to be tightened. 2019-09-19 Eric Botcazou gcc/ada/ * sem_util.adb (In_Instance): Test whether the current unit has been analyzed instead of being on the scope stack to detect the case of actuals of an instantiation of a generic child unit done as a compilation unit. gcc/testsuite/ * gnat.dg/inline20.adb, gnat.dg/inline20_g.adb, gnat.dg/inline20_g.ads, gnat.dg/inline20_h.ads, gnat.dg/inline20_i.ads, gnat.dg/inline20_q-io.ads, gnat.dg/inline20_q.ads, gnat.dg/inline20_r.ads: New testcase. From-SVN: r275952 --- gcc/ada/ChangeLog | 7 +++++++ gcc/ada/sem_util.adb | 6 +++--- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/gnat.dg/inline20.adb | 9 +++++++++ gcc/testsuite/gnat.dg/inline20_g.adb | 18 ++++++++++++++++++ gcc/testsuite/gnat.dg/inline20_g.ads | 18 ++++++++++++++++++ gcc/testsuite/gnat.dg/inline20_h.ads | 15 +++++++++++++++ gcc/testsuite/gnat.dg/inline20_i.ads | 19 +++++++++++++++++++ gcc/testsuite/gnat.dg/inline20_q-io.ads | 1 + gcc/testsuite/gnat.dg/inline20_q.ads | 3 +++ gcc/testsuite/gnat.dg/inline20_r.ads | 12 ++++++++++++ 11 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/inline20.adb create mode 100644 gcc/testsuite/gnat.dg/inline20_g.adb create mode 100644 gcc/testsuite/gnat.dg/inline20_g.ads create mode 100644 gcc/testsuite/gnat.dg/inline20_h.ads create mode 100644 gcc/testsuite/gnat.dg/inline20_i.ads create mode 100644 gcc/testsuite/gnat.dg/inline20_q-io.ads create mode 100644 gcc/testsuite/gnat.dg/inline20_q.ads create mode 100644 gcc/testsuite/gnat.dg/inline20_r.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index a204c28..3d348b4 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Eric Botcazou + + * sem_util.adb (In_Instance): Test whether the current unit has + been analyzed instead of being on the scope stack to detect the + case of actuals of an instantiation of a generic child unit done + as a compilation unit. + 2019-09-19 Dmitriy Anisimkov * libgnat/g-socket.ads, libgnat/g-socket.adb diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index b276fd2..9569919 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -12380,15 +12380,15 @@ package body Sem_Util is if Is_Generic_Instance (S) then -- A child instance is always compiled in the context of a parent - -- instance. Nevertheless, the actuals are not analyzed in an + -- instance. Nevertheless, its actuals must not be analyzed in an -- instance context. We detect this case by examining the current -- compilation unit, which must be a child instance, and checking - -- that it is not currently on the scope stack. + -- that it has not been analyzed yet. if Is_Child_Unit (Curr_Unit) and then Nkind (Unit (Cunit (Current_Sem_Unit))) = N_Package_Instantiation - and then not In_Open_Scopes (Curr_Unit) + and then Ekind (Curr_Unit) = E_Void then return False; else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a3534f1..f667897 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Eric Botcazou + + * gnat.dg/inline20.adb, gnat.dg/inline20_g.adb, + gnat.dg/inline20_g.ads, gnat.dg/inline20_h.ads, + gnat.dg/inline20_i.ads, gnat.dg/inline20_q-io.ads, + gnat.dg/inline20_q.ads, gnat.dg/inline20_r.ads: New testcase. + 2019-09-19 Ed Schonberg * gnat.dg/generic2-child.ads, gnat.dg/generic2-io_any.adb, diff --git a/gcc/testsuite/gnat.dg/inline20.adb b/gcc/testsuite/gnat.dg/inline20.adb new file mode 100644 index 0000000..dde9a53 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20.adb @@ -0,0 +1,9 @@ +-- { dg-do compile } +-- { dg-options "-O -gnatn2" } +with Inline20_Q.IO; +with Inline20_R; + +procedure Inline20 is +begin + Inline20_R.Log (Inline20_Q.IO.F); +end; diff --git a/gcc/testsuite/gnat.dg/inline20_g.adb b/gcc/testsuite/gnat.dg/inline20_g.adb new file mode 100644 index 0000000..dbae596 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_g.adb @@ -0,0 +1,18 @@ +with Ada.Streams; use Ada.Streams; + +package body Inline20_G is + + package body Nested_G is + + procedure Get (Data : T; Into : out Offset_Type) is + begin + Into := (T'Descriptor_Size + Data'Size) / Standard'Storage_Unit; + end; + + function F return Integer is + begin + return 0; + end; + end Nested_G; + +end Inline20_G; diff --git a/gcc/testsuite/gnat.dg/inline20_g.ads b/gcc/testsuite/gnat.dg/inline20_g.ads new file mode 100644 index 0000000..adf2df6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_g.ads @@ -0,0 +1,18 @@ +with Ada.Streams; + +generic +package Inline20_G is + + subtype Offset_Type is Ada.Streams.Stream_Element_Offset; + + generic + type T is private; + package Nested_G is + + procedure Get (Data : T; Into : out Offset_Type); + + function F return Integer with Inline; + + end Nested_G; + +end Inline20_G; diff --git a/gcc/testsuite/gnat.dg/inline20_h.ads b/gcc/testsuite/gnat.dg/inline20_h.ads new file mode 100644 index 0000000..5937798 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_h.ads @@ -0,0 +1,15 @@ +with Inline20_G; + +generic + with package Msg is new Inline20_G (<>); +package Inline20_H is + + generic + type T is private; + with function Image (Data : T) return String; + package Nested_H is + package My_Nested_G is new Msg.Nested_G (T); + function F return Integer renames My_Nested_G.F; + end Nested_H; + +end Inline20_H; diff --git a/gcc/testsuite/gnat.dg/inline20_i.ads b/gcc/testsuite/gnat.dg/inline20_i.ads new file mode 100644 index 0000000..d946375 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_i.ads @@ -0,0 +1,19 @@ +with Inline20_R; + +generic +package Inline20_I is + + type Rec is null record; + + generic + package Generic_IO is + + function Image (Quote : Rec) return String; + + package My_Nested_H is new Inline20_R.My_H.Nested_H (Rec, Image); + + function F return Integer renames My_Nested_H.F; + + end Generic_IO; + +end Inline20_I; \ No newline at end of file diff --git a/gcc/testsuite/gnat.dg/inline20_q-io.ads b/gcc/testsuite/gnat.dg/inline20_q-io.ads new file mode 100644 index 0000000..8e81887 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_q-io.ads @@ -0,0 +1 @@ +package Inline20_Q.IO is new Inline20_Q.Generic_IO; diff --git a/gcc/testsuite/gnat.dg/inline20_q.ads b/gcc/testsuite/gnat.dg/inline20_q.ads new file mode 100644 index 0000000..08c81cd --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_q.ads @@ -0,0 +1,3 @@ +with Inline20_I; + +package Inline20_Q is new Inline20_I; diff --git a/gcc/testsuite/gnat.dg/inline20_r.ads b/gcc/testsuite/gnat.dg/inline20_r.ads new file mode 100644 index 0000000..4b96f75 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline20_r.ads @@ -0,0 +1,12 @@ +with Inline20_G; +with Inline20_H; + +package Inline20_R is + + package My_G is new Inline20_G; + + package My_H is new Inline20_H (My_G); + + procedure Log (I : Integer); + +end Inline20_R; -- cgit v1.1 From d53301c91fe9cfffaa06880ea1e32a9fc9246709 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:14:28 +0000 Subject: [Ada] Fix bogus "too late" error with nested generics and inlining This prevents the compiler from issuing a bogus error about a constant whose full declaration appears too late, if it is declared in a nested generic package and instantiated in another nested instantiation, when the instantiations are done in a unit withed from the main unit and containing an inlined subprogram, and cross-unit inlining is enabled. It turns out that, under these very peculiar conditions, the compiler ends up instantiating the body of the generic package twice, which leads to various semantic errors, in particular for declarations of constants. 2019-09-19 Eric Botcazou gcc/ada/ * sem_ch12.adb (Instantiate_Package_Body): Check that the body has not already been instantiated when the body of the parent was being loaded. gcc/testsuite/ * gnat.dg/inline21.adb, gnat.dg/inline21_g.ads, gnat.dg/inline21_h.adb, gnat.dg/inline21_h.ads, gnat.dg/inline21_q.ads: New testcase. From-SVN: r275953 --- gcc/ada/ChangeLog | 6 ++++ gcc/ada/sem_ch12.adb | 62 ++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/gnat.dg/inline21.adb | 9 ++++++ gcc/testsuite/gnat.dg/inline21_g.ads | 8 +++++ gcc/testsuite/gnat.dg/inline21_h.adb | 14 ++++++++ gcc/testsuite/gnat.dg/inline21_h.ads | 10 ++++++ gcc/testsuite/gnat.dg/inline21_q.ads | 9 ++++++ 8 files changed, 124 insertions(+) create mode 100644 gcc/testsuite/gnat.dg/inline21.adb create mode 100644 gcc/testsuite/gnat.dg/inline21_g.ads create mode 100644 gcc/testsuite/gnat.dg/inline21_h.adb create mode 100644 gcc/testsuite/gnat.dg/inline21_h.ads create mode 100644 gcc/testsuite/gnat.dg/inline21_q.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 3d348b4..c10f7ff 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,11 @@ 2019-09-19 Eric Botcazou + * sem_ch12.adb (Instantiate_Package_Body): Check that the body + has not already been instantiated when the body of the parent + was being loaded. + +2019-09-19 Eric Botcazou + * sem_util.adb (In_Instance): Test whether the current unit has been analyzed instead of being on the scope stack to detect the case of actuals of an instantiation of a generic child unit done diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 61a40eb..280c925 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -11442,6 +11442,68 @@ package body Sem_Ch12 is else Load_Parent_Of_Generic (Inst_Node, Specification (Gen_Decl), Body_Optional); + + -- Surprisingly enough, loading the body of the parent can cause + -- the body to be instantiated and the double instantiation needs + -- to be prevented in order to avoid giving bogus semantic errors. + + -- This case can occur because of the Collect_Previous_Instances + -- machinery of Load_Parent_Of_Generic, which will instantiate + -- bodies that are deemed to be ahead of the body of the parent + -- in the compilation unit. But the relative position of these + -- bodies is computed using the mere comparison of their Sloc. + + -- Now suppose that you have two generic packages G and H, with + -- G containing a mere instantiation of H: + + -- generic + -- package H is + + -- generic + -- package Nested_G is + -- ... + -- end Nested_G; + + -- end H; + + -- with H; + + -- generic + -- package G is + + -- package My_H is new H; + + -- end G; + + -- and a third package Q instantiating G and Nested_G: + + -- with G; + + -- package Q is + + -- package My_G is new G; + + -- package My_Nested_G is new My_G.My_H.Nested_G; + + -- end Q; + + -- The body to be instantiated is that of My_Nested_G and its + -- parent is the instance My_G.My_H. This latter instantiation + -- is done when My_G is analyzed, i.e. after the declarations + -- of My_G and My_Nested_G have been parsed; as a result, the + -- Sloc of My_G.My_H is greater than the Sloc of My_Nested_G. + + -- Therefore loading the body of My_G.My_H will cause the body + -- of My_Nested_G to be instantiated because it is deemed to be + -- ahead of My_G.My_H. This means that Load_Parent_Of_Generic + -- will again be invoked on My_G.My_H, but this time with the + -- Collect_Previous_Instances machinery disabled, so there is + -- no endless mutual recursion and things are done in order. + + if Present (Corresponding_Body (Instance_Spec (Inst_Node))) then + goto Leave; + end if; + Gen_Body_Id := Corresponding_Body (Gen_Decl); end if; end if; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f667897..c8eea78 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2019-09-19 Eric Botcazou + * gnat.dg/inline21.adb, gnat.dg/inline21_g.ads, + gnat.dg/inline21_h.adb, gnat.dg/inline21_h.ads, + gnat.dg/inline21_q.ads: New testcase. + +2019-09-19 Eric Botcazou + * gnat.dg/inline20.adb, gnat.dg/inline20_g.adb, gnat.dg/inline20_g.ads, gnat.dg/inline20_h.ads, gnat.dg/inline20_i.ads, gnat.dg/inline20_q-io.ads, diff --git a/gcc/testsuite/gnat.dg/inline21.adb b/gcc/testsuite/gnat.dg/inline21.adb new file mode 100644 index 0000000..5df5691 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline21.adb @@ -0,0 +1,9 @@ +-- { dg-compile } +-- { dg-options "-O -gnatn" } + +with Inline21_Q; + +procedure Inline21 is +begin + Inline21_Q.My_Nested_G.Proc; +end; diff --git a/gcc/testsuite/gnat.dg/inline21_g.ads b/gcc/testsuite/gnat.dg/inline21_g.ads new file mode 100644 index 0000000..b4faf01 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline21_g.ads @@ -0,0 +1,8 @@ +with Inline21_H; + +generic +package Inline21_G is + + package My_H is new Inline21_H; + +end Inline21_G; diff --git a/gcc/testsuite/gnat.dg/inline21_h.adb b/gcc/testsuite/gnat.dg/inline21_h.adb new file mode 100644 index 0000000..c6cf063 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline21_h.adb @@ -0,0 +1,14 @@ +package body Inline21_H is + + package body Nested_G is + + C : constant Integer := 0; + + procedure Proc is + begin + null; + end; + + end Nested_G; + +end Inline21_H; \ No newline at end of file diff --git a/gcc/testsuite/gnat.dg/inline21_h.ads b/gcc/testsuite/gnat.dg/inline21_h.ads new file mode 100644 index 0000000..494c544 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline21_h.ads @@ -0,0 +1,10 @@ +generic +package Inline21_H is + + generic + package Nested_G is + procedure Proc; + pragma Inline (Proc); + end Nested_G; + +end Inline21_H; diff --git a/gcc/testsuite/gnat.dg/inline21_q.ads b/gcc/testsuite/gnat.dg/inline21_q.ads new file mode 100644 index 0000000..d3c2001 --- /dev/null +++ b/gcc/testsuite/gnat.dg/inline21_q.ads @@ -0,0 +1,9 @@ +with Inline21_G; + +package Inline21_Q is + + package My_G is new Inline21_G; + + package My_Nested_G is new My_G.My_H.Nested_G; + +end Inline21_Q; -- cgit v1.1 From bee475e2e059ef30d5dae7eea0cb0e09c97a3f18 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:14:38 +0000 Subject: [Ada] Fix copy operation with private discriminated record type This prevents the object code from reading too many bytes from the source for a copy operation involving a private discriminated record type with default discriminants and generated for the assignment of an aggregate to a variable or the initialization of a constant. The front-end already knows that it needs to convert the operation involving the aggregate into individual assignments if the type of the aggregate has mutable components, but it would not do so if this type is private, which does not change anything for code generation. Running these commands: gnatmake -q p -g -fsanitize=address p On the following sources: with Q; use Q; procedure P is type Rec is record A : T; end record; C : constant Rec := Rec'(A => Default_T); begin null; end; package Q is type T is private; Default_T : constant T; private A : constant := 170; B : constant := 8192; type A_Index is range 1 .. A; type B_Index is range 1 .. B; type A_Array is array (A_Index) of Boolean; type B_Array is array (B_Index) of Boolean; type Data_Type is (A_Type, B_Type); type T (Discriminant : Data_Type := A_Type) is record case Discriminant is when A_Type => Field_A : A_Array; when B_Type => Field_B : B_Array; end case; end record; Default_T : constant T := T'(Discriminant => A_Type, Field_A => (others => True)); end Q; Should execute silently. 2019-09-19 Eric Botcazou gcc/ada/ * exp_aggr.adb (Has_Mutable_Components): Look at the underlying type of components to find out whether they are mutable. From-SVN: r275954 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/exp_aggr.adb | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index c10f7ff..ff66682 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,10 @@ 2019-09-19 Eric Botcazou + * exp_aggr.adb (Has_Mutable_Components): Look at the underlying + type of components to find out whether they are mutable. + +2019-09-19 Eric Botcazou + * sem_ch12.adb (Instantiate_Package_Body): Check that the body has not already been instantiated when the body of the parent was being loaded. diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index 63f9d1a..3d3dd1b 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -8162,13 +8162,15 @@ package body Exp_Aggr is function Has_Mutable_Components (Typ : Entity_Id) return Boolean is Comp : Entity_Id; + Ctyp : Entity_Id; begin Comp := First_Component (Typ); while Present (Comp) loop - if Is_Record_Type (Etype (Comp)) - and then Has_Discriminants (Etype (Comp)) - and then not Is_Constrained (Etype (Comp)) + Ctyp := Underlying_Type (Etype (Comp)); + if Is_Record_Type (Ctyp) + and then Has_Discriminants (Ctyp) + and then not Is_Constrained (Ctyp) then return True; end if; -- cgit v1.1 From 87cd385fa5dad3a0e5d144e08670c7fdd85fe2ef Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:14:42 +0000 Subject: [Ada] Sem_Ch12: add a comment to indicate future work 2019-09-19 Eric Botcazou gcc/ada/ * sem_ch12.adb (Check_Private_View): Add a comment to indicate future work. From-SVN: r275955 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/sem_ch12.adb | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index ff66682..8a87274 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,10 @@ 2019-09-19 Eric Botcazou + * sem_ch12.adb (Check_Private_View): Add a comment to indicate + future work. + +2019-09-19 Eric Botcazou + * exp_aggr.adb (Has_Mutable_Components): Look at the underlying type of components to find out whether they are mutable. diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 280c925..4e74f9a 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -7478,6 +7478,11 @@ package body Sem_Ch12 is end loop; end; + -- The following case does not test Has_Private_View (N) so it may + -- end up switching views when they are not supposed to be switched. + -- This might be in keeping with Set_Global_Type setting the flag + -- for an array type even if it is not private ??? + elsif Is_Private_Type (T) and then Present (Full_View (T)) and then Is_Array_Type (Full_View (T)) -- cgit v1.1 From c3a75a09b8424c192b32a39fa273d27db5b9c039 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 19 Sep 2019 08:14:47 +0000 Subject: [Ada] Get rid of useless temporary for slice in overaligned record type This fixes a recent code quality regression for targets that do not require the strict alignment of memory accesses: the compiler would generate a useless temporary for a slice of an array component in an overaligned record type. Running these commands: gcc -c p.adb -gnatws -gnatD grep loop p.adb.dg On the following sources: procedure P (N : Positive) is type Rec1 is record I : Integer; end record; type Arr is array (Positive range <>) of Rec1; type Rec2 is record A : Arr (1 .. 128); end record; for Rec2'Alignment use 8; procedure Proc (A : Arr) is begin null; end; R : Rec2; begin Proc (R.A (1 .. N)); end; Should execute silently. 2019-09-19 Eric Botcazou gcc/ada/ * exp_util.adb (Is_Possibly_Unaligned_Slice): Do not return true on pure alignment considerations if the target does not require the strict alignment of memory accesses. From-SVN: r275956 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/exp_util.adb | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 8a87274..5808008 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,11 @@ 2019-09-19 Eric Botcazou + * exp_util.adb (Is_Possibly_Unaligned_Slice): Do not return true + on pure alignment considerations if the target does not require + the strict alignment of memory accesses. + +2019-09-19 Eric Botcazou + * sem_ch12.adb (Check_Private_View): Add a comment to indicate future work. diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 905e3f4..6306320 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -8692,9 +8692,11 @@ package body Exp_Util is -- We are definitely in trouble if the record in question -- has an alignment, and either we know this alignment is -- inconsistent with the alignment of the slice, or we don't - -- know what the alignment of the slice should be. + -- know what the alignment of the slice should be. But this + -- really matters only if the target has strict alignment. - if Known_Alignment (Ptyp) + if Target_Strict_Alignment + and then Known_Alignment (Ptyp) and then (Unknown_Alignment (Styp) or else Alignment (Styp) > Alignment (Ptyp)) then -- cgit v1.1 From 0c27222c60b26cd21588576f140abd04f1d8a853 Mon Sep 17 00:00:00 2001 From: Steve Baird Date: Thu, 19 Sep 2019 08:14:52 +0000 Subject: [Ada] Accept concatentation arguments to pragma Annotate In cases where pragma Annotate accepts a string literal as an argument, we now also accept a concatenation of string literals. 2019-09-19 Steve Baird gcc/ada/ * sem_prag.adb (Preferred_String_Type): A new function. Given an expression, determines whether the preference rules defined for the third-and-later arguments of pragma Annotate suffice to determine the type of the expression. If so, then the preferred type is returned; if not then Empty is returned. Handles concatenations. (Analyze_Pragma): Replace previous code, which dealt only with string literals, with calls to the new Preferred_String_Type function, which also handles concatenations. * doc/gnat_rm/implementation_defined_pragmas.rst: Update documentation for pragma Annotate. * gnat_rm.texi: Regenerate. gcc/testsuite/ * gnat.dg/annotation1.adb: New testcase. From-SVN: r275957 --- gcc/ada/ChangeLog | 15 +++++ .../doc/gnat_rm/implementation_defined_pragmas.rst | 3 +- gcc/ada/gnat_rm.texi | 6 +- gcc/ada/sem_prag.adb | 66 ++++++++++++++++++---- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gnat.dg/annotation1.adb | 7 +++ 6 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/annotation1.adb (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 5808008..4208f95 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,18 @@ +2019-09-19 Steve Baird + + * sem_prag.adb (Preferred_String_Type): A new function. Given an + expression, determines whether the preference rules defined for + the third-and-later arguments of pragma Annotate suffice to + determine the type of the expression. If so, then the preferred + type is returned; if not then Empty is returned. Handles + concatenations. + (Analyze_Pragma): Replace previous code, which dealt only with + string literals, with calls to the new Preferred_String_Type + function, which also handles concatenations. + * doc/gnat_rm/implementation_defined_pragmas.rst: Update + documentation for pragma Annotate. + * gnat_rm.texi: Regenerate. + 2019-09-19 Eric Botcazou * exp_util.adb (Is_Possibly_Unaligned_Slice): Do not return true diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst index 126aaf8..bf0a9d4 100644 --- a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst +++ b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst @@ -455,7 +455,8 @@ not otherwise analyze it. The second optional identifier is also left unanalyzed, and by convention is used to control the action of the tool to which the annotation is addressed. The remaining ARG arguments can be either string literals or more generally expressions. -String literals are assumed to be either of type +String literals (and concatenations of string literals) are assumed to be +either of type ``Standard.String`` or else ``Wide_String`` or ``Wide_Wide_String`` depending on the character literals they contain. All other kinds of arguments are analyzed as expressions, and must be diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index 1f5616f..2a4ad37 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -1836,7 +1836,8 @@ not otherwise analyze it. The second optional identifier is also left unanalyzed, and by convention is used to control the action of the tool to which the annotation is addressed. The remaining ARG arguments can be either string literals or more generally expressions. -String literals are assumed to be either of type +String literals (and concatenations of string literals) are assumed to be +either of type @code{Standard.String} or else @code{Wide_String} or @code{Wide_Wide_String} depending on the character literals they contain. All other kinds of arguments are analyzed as expressions, and must be @@ -7706,7 +7707,8 @@ usually supplied automatically by the project manager. A pragma Source_File_Name cannot appear after a @ref{ec,,Pragma Source_File_Name_Project}. For more details on the use of the @code{Source_File_Name} pragma, see the -sections on @code{Using Other File Names} and @cite{Alternative File Naming Schemes' in the :title:`GNAT User's Guide}. +sections on @cite{Using Other File Names} and @cite{Alternative File Naming Schemes} +in the @cite{GNAT User's Guide}. @node Pragma Source_File_Name_Project,Pragma Source_Reference,Pragma Source_File_Name,Implementation Defined Pragmas @anchor{gnat_rm/implementation_defined_pragmas pragma-source-file-name-project}@anchor{ec}@anchor{gnat_rm/implementation_defined_pragmas id41}@anchor{ed} diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index b54604d..5f7e6e5 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -13085,6 +13085,56 @@ package body Sem_Prag is Expr : Node_Id; Nam_Arg : Node_Id; + -------------------------- + -- Inferred_String_Type -- + -------------------------- + + function Preferred_String_Type (Expr : Node_Id) return Entity_Id; + -- Infer the type to use for a string literal or a concatentation + -- of operands whose types can be inferred. For such expressions, + -- returns the "narrowest" of the three predefined string types + -- that can represent the characters occuring in the expression. + -- For other expressions, returns Empty. + + function Preferred_String_Type (Expr : Node_Id) return Entity_Id is + begin + case Nkind (Expr) is + when N_String_Literal => + if Has_Wide_Wide_Character (Expr) then + return Standard_Wide_Wide_String; + elsif Has_Wide_Character (Expr) then + return Standard_Wide_String; + else + return Standard_String; + end if; + + when N_Op_Concat => + declare + L_Type : constant Entity_Id + := Preferred_String_Type (Left_Opnd (Expr)); + R_Type : constant Entity_Id + := Preferred_String_Type (Right_Opnd (Expr)); + + Type_Table : constant array (1 .. 4) of Entity_Id + := (Empty, + Standard_Wide_Wide_String, + Standard_Wide_String, + Standard_String); + begin + for Idx in Type_Table'Range loop + if (L_Type = Type_Table (Idx)) or + (R_Type = Type_Table (Idx)) + then + return Type_Table (Idx); + end if; + end loop; + raise Program_Error; + end; + + when others => + return Empty; + end case; + end Preferred_String_Type; begin GNAT_Pragma; Check_At_Least_N_Arguments (1); @@ -13144,18 +13194,12 @@ package body Sem_Prag is if Is_Entity_Name (Expr) then null; - -- For string literals, we assume Standard_String as the - -- type, unless the string contains wide or wide_wide - -- characters. + -- For string literals and concatenations of string literals + -- we assume Standard_String as the type, unless the string + -- contains wide or wide_wide characters. - elsif Nkind (Expr) = N_String_Literal then - if Has_Wide_Wide_Character (Expr) then - Resolve (Expr, Standard_Wide_Wide_String); - elsif Has_Wide_Character (Expr) then - Resolve (Expr, Standard_Wide_String); - else - Resolve (Expr, Standard_String); - end if; + elsif Present (Preferred_String_Type (Expr)) then + Resolve (Expr, Preferred_String_Type (Expr)); elsif Is_Overloaded (Expr) then Error_Pragma_Arg ("ambiguous argument for pragma%", Expr); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c8eea78..cac70e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Steve Baird + + * gnat.dg/annotation1.adb: New testcase. + 2019-09-19 Eric Botcazou * gnat.dg/inline21.adb, gnat.dg/inline21_g.ads, diff --git a/gcc/testsuite/gnat.dg/annotation1.adb b/gcc/testsuite/gnat.dg/annotation1.adb new file mode 100644 index 0000000..6ed14da --- /dev/null +++ b/gcc/testsuite/gnat.dg/annotation1.adb @@ -0,0 +1,7 @@ +-- { dg-do compile } + +procedure Annotation1 is + pragma Annotate (Some_Tool, Some_Action, "abc" & "def"); +begin + null; +end Annotation1; \ No newline at end of file -- cgit v1.1 From 4736041b5aa5681c44cbb9c183b11bbb781492fc Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 19 Sep 2019 08:14:57 +0000 Subject: [Ada] Emit DW_AT_GNU_bias with -fgnat-encodings=gdb Emit DW_AT_GNU_bias with -fgnat-encodings=gdb. gdb implements this, but not the encoded variant. 2019-09-19 Tom Tromey gcc/ada/ * gcc-interface/misc.c (gnat_get_type_bias): Return the bias when -fgnat-encodings=gdb. gcc/testsuite/ * gnat.dg/bias1.adb: New testcase. From-SVN: r275958 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/gcc-interface/misc.c | 2 +- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gnat.dg/bias1.adb | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gnat.dg/bias1.adb (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 4208f95..94b32fb 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Tom Tromey + + * gcc-interface/misc.c (gnat_get_type_bias): Return the bias + when -fgnat-encodings=gdb. + 2019-09-19 Steve Baird * sem_prag.adb (Preferred_String_Type): A new function. Given an diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c index a576b7e..4abd4d5 100644 --- a/gcc/ada/gcc-interface/misc.c +++ b/gcc/ada/gcc-interface/misc.c @@ -1111,7 +1111,7 @@ gnat_get_type_bias (const_tree gnu_type) { if (TREE_CODE (gnu_type) == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (gnu_type) - && gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + && gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) return TYPE_RM_MIN_VALUE (gnu_type); return NULL_TREE; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cac70e2..07adb11 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-19 Tom Tromey + + * gnat.dg/bias1.adb: New testcase. + 2019-09-19 Steve Baird * gnat.dg/annotation1.adb: New testcase. diff --git a/gcc/testsuite/gnat.dg/bias1.adb b/gcc/testsuite/gnat.dg/bias1.adb new file mode 100644 index 0000000..016a159 --- /dev/null +++ b/gcc/testsuite/gnat.dg/bias1.adb @@ -0,0 +1,34 @@ +-- { dg-do compile } +-- { dg-options "-cargs -g -dA -gnatws -fgnat-encodings=gdb -margs" } +-- { dg-final { scan-assembler "DW_AT_GNU_bias" } } + +procedure Bias1 is + type Small is range -7 .. -4; + for Small'Size use 2; + Y : Small := -5; + Y1 : Small := -7; + + type Byte is mod 256; + type Repeat_Count_T is new Byte range 1 .. 2 ** 6; + for Repeat_Count_T'Size use 6; + X : Repeat_Count_T := 64; + X1 : Repeat_Count_T := 1; + + type Char_Range is range 65 .. 68; + for Char_Range'Size use 2; + Cval : Char_Range := 65; + + type SomePackedRecord is record + R: Small; + S: Small; + end record; + pragma Pack (SomePackedRecord); + SPR : SomePackedRecord := (R => -4, S => -5); + + type Packed_Array is array (1 .. 3) of Small; + pragma pack (Packed_Array); + A : Packed_Array := (-7, -5, -4); + +begin + null; +end Bias1; \ No newline at end of file -- cgit v1.1 From f24f4c15884bf1ee65a10e2f959842eec4198876 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 19 Sep 2019 09:04:28 +0000 Subject: Rework constant subreg folds and handle more variable-length cases This patch rewrites the way simplify_subreg handles constants. It uses similar native_encode/native_decode routines to the tree-level handling of VIEW_CONVERT_EXPR, meaning that we can move between rtx constants and the target memory image of them. The main point of this patch is to support subregs of constant-length vectors for VLA vectors, beyond the very simple cases that were already handled. Many of the new tests failed before the patch for variable- length vectors. The boolean side is tested more by the upcoming SVE ACLE work. 2019-09-19 Richard Sandiford gcc/ * defaults.h (TARGET_UNIT): New macro. (target_unit): New type. * rtl.h (native_encode_rtx, native_decode_rtx) (native_decode_vector_rtx, subreg_size_lsb): Declare. (subreg_lsb_1): Turn into an inline wrapper around subreg_size_lsb. * rtlanal.c (subreg_lsb_1): Delete. (subreg_size_lsb): New function. * simplify-rtx.c: Include rtx-vector-builder.h (simplify_immed_subreg): Delete. (native_encode_rtx, native_decode_vector_rtx, native_decode_rtx) (simplify_const_vector_byte_offset, simplify_const_vector_subreg): New functions. (simplify_subreg): Use them. (test_vector_subregs_modes, test_vector_subregs_repeating) (test_vector_subregs_fore_back, test_vector_subregs_stepped) (test_vector_subregs): New functions. (test_vector_ops): Call test_vector_subregs for integer vector modes with at least 2 elements. From-SVN: r275959 --- gcc/ChangeLog | 21 ++ gcc/defaults.h | 14 + gcc/rtl.h | 20 +- gcc/rtlanal.c | 28 +- gcc/simplify-rtx.c | 902 +++++++++++++++++++++++++++++++++++------------------ 5 files changed, 663 insertions(+), 322 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 92fdc63..c51b6f6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2019-09-19 Richard Sandiford + + * defaults.h (TARGET_UNIT): New macro. + (target_unit): New type. + * rtl.h (native_encode_rtx, native_decode_rtx) + (native_decode_vector_rtx, subreg_size_lsb): Declare. + (subreg_lsb_1): Turn into an inline wrapper around subreg_size_lsb. + * rtlanal.c (subreg_lsb_1): Delete. + (subreg_size_lsb): New function. + * simplify-rtx.c: Include rtx-vector-builder.h + (simplify_immed_subreg): Delete. + (native_encode_rtx, native_decode_vector_rtx, native_decode_rtx) + (simplify_const_vector_byte_offset, simplify_const_vector_subreg): New + functions. + (simplify_subreg): Use them. + (test_vector_subregs_modes, test_vector_subregs_repeating) + (test_vector_subregs_fore_back, test_vector_subregs_stepped) + (test_vector_subregs): New functions. + (test_vector_ops): Call test_vector_subregs for integer vector + modes with at least 2 elements. + 2019-09-19 Richard Biener * tree-parloops.c (parloops_is_slp_reduction): Do not set diff --git a/gcc/defaults.h b/gcc/defaults.h index af7ea18..72d4fba 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -1459,4 +1459,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define DWARF_GNAT_ENCODINGS_DEFAULT DWARF_GNAT_ENCODINGS_GDB #endif +#ifndef USED_FOR_TARGET +/* Done this way to keep gengtype happy. */ +#if BITS_PER_UNIT == 8 +#define TARGET_UNIT uint8_t +#elif BITS_PER_UNIT == 16 +#define TARGET_UNIT uint16_t +#elif BITS_PER_UNIT == 32 +#define TARGET_UNIT uint32_t +#else +#error Unknown BITS_PER_UNIT +#endif +typedef TARGET_UNIT target_unit; +#endif + #endif /* ! GCC_DEFAULTS_H */ diff --git a/gcc/rtl.h b/gcc/rtl.h index c054861..9cadac7 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2406,12 +2406,30 @@ extern int rtx_cost (rtx, machine_mode, enum rtx_code, int, bool); extern int address_cost (rtx, machine_mode, addr_space_t, bool); extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int, struct full_rtx_costs *); +extern bool native_encode_rtx (machine_mode, rtx, vec &, + unsigned int, unsigned int); +extern rtx native_decode_rtx (machine_mode, vec, + unsigned int); +extern rtx native_decode_vector_rtx (machine_mode, vec, + unsigned int, unsigned int, unsigned int); extern poly_uint64 subreg_lsb (const_rtx); -extern poly_uint64 subreg_lsb_1 (machine_mode, machine_mode, poly_uint64); +extern poly_uint64 subreg_size_lsb (poly_uint64, poly_uint64, poly_uint64); extern poly_uint64 subreg_size_offset_from_lsb (poly_uint64, poly_uint64, poly_uint64); extern bool read_modify_subreg_p (const_rtx); +/* Given a subreg's OUTER_MODE, INNER_MODE, and SUBREG_BYTE, return the + bit offset at which the subreg begins (counting from the least significant + bit of the operand). */ + +inline poly_uint64 +subreg_lsb_1 (machine_mode outer_mode, machine_mode inner_mode, + poly_uint64 subreg_byte) +{ + return subreg_size_lsb (GET_MODE_SIZE (outer_mode), + GET_MODE_SIZE (inner_mode), subreg_byte); +} + /* Return the subreg byte offset for a subreg whose outer mode is OUTER_MODE, whose inner mode is INNER_MODE, and where there are LSB_SHIFT *bits* between the lsb of the outer value and the lsb of diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 3a72db7..28b399c 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3637,23 +3637,31 @@ loc_mentioned_in_p (rtx *loc, const_rtx in) return 0; } -/* Helper function for subreg_lsb. Given a subreg's OUTER_MODE, INNER_MODE, - and SUBREG_BYTE, return the bit offset where the subreg begins - (counting from the least significant bit of the operand). */ +/* Reinterpret a subreg as a bit extraction from an integer and return + the position of the least significant bit of the extracted value. + In other words, if the extraction were performed as a shift right + and mask, return the number of bits to shift right. + + The outer value of the subreg has OUTER_BYTES bytes and starts at + byte offset SUBREG_BYTE within an inner value of INNER_BYTES bytes. */ poly_uint64 -subreg_lsb_1 (machine_mode outer_mode, - machine_mode inner_mode, - poly_uint64 subreg_byte) +subreg_size_lsb (poly_uint64 outer_bytes, + poly_uint64 inner_bytes, + poly_uint64 subreg_byte) { poly_uint64 subreg_end, trailing_bytes, byte_pos; /* A paradoxical subreg begins at bit position 0. */ - if (paradoxical_subreg_p (outer_mode, inner_mode)) - return 0; + gcc_checking_assert (ordered_p (outer_bytes, inner_bytes)); + if (maybe_gt (outer_bytes, inner_bytes)) + { + gcc_checking_assert (known_eq (subreg_byte, 0U)); + return 0; + } - subreg_end = subreg_byte + GET_MODE_SIZE (outer_mode); - trailing_bytes = GET_MODE_SIZE (inner_mode) - subreg_end; + subreg_end = subreg_byte + outer_bytes; + trailing_bytes = inner_bytes - subreg_end; if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN) byte_pos = trailing_bytes; else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN) diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 9359a3c..87ba337 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -6130,342 +6130,466 @@ simplify_ternary_operation (enum rtx_code code, machine_mode mode, return 0; } -/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE - or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or - CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR. +/* Try to calculate NUM_BYTES bytes of the target memory image of X, + starting at byte FIRST_BYTE. Return true on success and add the + bytes to BYTES, such that each byte has BITS_PER_UNIT bits and such + that the bytes follow target memory order. Leave BYTES unmodified + on failure. - Works by unpacking INNER_BYTES bytes of OP into a collection of 8-bit values - represented as a little-endian array of 'unsigned char', selecting by BYTE, - and then repacking them again for OUTERMODE. If OP is a CONST_VECTOR, - FIRST_ELEM is the number of the first element to extract, otherwise - FIRST_ELEM is ignored. */ + MODE is the mode of X. The caller must reserve NUM_BYTES bytes in + BYTES before calling this function. */ -static rtx -simplify_immed_subreg (fixed_size_mode outermode, rtx op, - machine_mode innermode, unsigned int byte, - unsigned int first_elem, unsigned int inner_bytes) +bool +native_encode_rtx (machine_mode mode, rtx x, vec &bytes, + unsigned int first_byte, unsigned int num_bytes) { - enum { - value_bit = 8, - value_mask = (1 << value_bit) - 1 - }; - unsigned char value[MAX_BITSIZE_MODE_ANY_MODE / value_bit]; - int value_start; - int i; - int elem; - - int num_elem; - rtx * elems; - int elem_bitsize; - rtx result_s = NULL; - rtvec result_v = NULL; - enum mode_class outer_class; - scalar_mode outer_submode; - int max_bitsize; + /* Check the mode is sensible. */ + gcc_assert (GET_MODE (x) == VOIDmode + ? is_a (mode) + : mode == GET_MODE (x)); - /* Some ports misuse CCmode. */ - if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op)) - return op; + if (GET_CODE (x) == CONST_VECTOR) + { + /* CONST_VECTOR_ELT follows target memory order, so no shuffling + is necessary. The only complication is that MODE_VECTOR_BOOL + vectors can have several elements per byte. */ + unsigned int elt_bits = vector_element_size (GET_MODE_BITSIZE (mode), + GET_MODE_NUNITS (mode)); + unsigned int elt = first_byte * BITS_PER_UNIT / elt_bits; + if (elt_bits < BITS_PER_UNIT) + { + /* This is the only case in which elements can be smaller than + a byte. */ + gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL); + for (unsigned int i = 0; i < num_bytes; ++i) + { + target_unit value = 0; + for (unsigned int j = 0; j < BITS_PER_UNIT; j += elt_bits) + { + value |= (INTVAL (CONST_VECTOR_ELT (x, elt)) & 1) << j; + elt += 1; + } + bytes.quick_push (value); + } + return true; + } - /* We have no way to represent a complex constant at the rtl level. */ - if (COMPLEX_MODE_P (outermode)) - return NULL_RTX; + unsigned int start = bytes.length (); + unsigned int elt_bytes = GET_MODE_UNIT_SIZE (mode); + /* Make FIRST_BYTE relative to ELT. */ + first_byte %= elt_bytes; + while (num_bytes > 0) + { + /* Work out how many bytes we want from element ELT. */ + unsigned int chunk_bytes = MIN (num_bytes, elt_bytes - first_byte); + if (!native_encode_rtx (GET_MODE_INNER (mode), + CONST_VECTOR_ELT (x, elt), bytes, + first_byte, chunk_bytes)) + { + bytes.truncate (start); + return false; + } + elt += 1; + first_byte = 0; + num_bytes -= chunk_bytes; + } + return true; + } - /* We support any size mode. */ - max_bitsize = MAX (GET_MODE_BITSIZE (outermode), - inner_bytes * BITS_PER_UNIT); + /* All subsequent cases are limited to scalars. */ + scalar_mode smode; + if (!is_a (mode, &smode)) + return false; - /* Unpack the value. */ + /* Make sure that the region is in range. */ + unsigned int end_byte = first_byte + num_bytes; + unsigned int mode_bytes = GET_MODE_SIZE (smode); + gcc_assert (end_byte <= mode_bytes); - if (GET_CODE (op) == CONST_VECTOR) + if (CONST_SCALAR_INT_P (x)) { - num_elem = CEIL (inner_bytes, GET_MODE_UNIT_SIZE (innermode)); - elem_bitsize = GET_MODE_UNIT_BITSIZE (innermode); + /* The target memory layout is affected by both BYTES_BIG_ENDIAN + and WORDS_BIG_ENDIAN. Use the subreg machinery to get the lsb + position of each byte. */ + rtx_mode_t value (x, smode); + wide_int_ref value_wi (value); + for (unsigned int byte = first_byte; byte < end_byte; ++byte) + { + /* Always constant because the inputs are. */ + unsigned int lsb + = subreg_size_lsb (1, mode_bytes, byte).to_constant (); + /* Operate directly on the encoding rather than using + wi::extract_uhwi, so that we preserve the sign or zero + extension for modes that are not a whole number of bits in + size. (Zero extension is only used for the combination of + innermode == BImode && STORE_FLAG_VALUE == 1). */ + unsigned int elt = lsb / HOST_BITS_PER_WIDE_INT; + unsigned int shift = lsb % HOST_BITS_PER_WIDE_INT; + unsigned HOST_WIDE_INT uhwi = value_wi.elt (elt); + bytes.quick_push (uhwi >> shift); + } + return true; } - else + + if (CONST_DOUBLE_P (x)) { - num_elem = 1; - elem_bitsize = max_bitsize; + /* real_to_target produces an array of integers in target memory order. + All integers before the last one have 32 bits; the last one may + have 32 bits or fewer, depending on whether the mode bitsize + is divisible by 32. Each of these integers is then laid out + in target memory as any other integer would be. */ + long el32[MAX_BITSIZE_MODE_ANY_MODE / 32]; + real_to_target (el32, CONST_DOUBLE_REAL_VALUE (x), smode); + + /* The (maximum) number of target bytes per element of el32. */ + unsigned int bytes_per_el32 = 32 / BITS_PER_UNIT; + gcc_assert (bytes_per_el32 != 0); + + /* Build up the integers in a similar way to the CONST_SCALAR_INT_P + handling above. */ + for (unsigned int byte = first_byte; byte < end_byte; ++byte) + { + unsigned int index = byte / bytes_per_el32; + unsigned int subbyte = byte % bytes_per_el32; + unsigned int int_bytes = MIN (bytes_per_el32, + mode_bytes - index * bytes_per_el32); + /* Always constant because the inputs are. */ + unsigned int lsb + = subreg_size_lsb (1, int_bytes, subbyte).to_constant (); + bytes.quick_push ((unsigned long) el32[index] >> lsb); + } + return true; } - /* If this asserts, it is too complicated; reducing value_bit may help. */ - gcc_assert (BITS_PER_UNIT % value_bit == 0); - /* I don't know how to handle endianness of sub-units. */ - gcc_assert (elem_bitsize % BITS_PER_UNIT == 0); - for (elem = 0; elem < num_elem; elem++) + if (GET_CODE (x) == CONST_FIXED) { - unsigned char * vp; - rtx el = (GET_CODE (op) == CONST_VECTOR - ? CONST_VECTOR_ELT (op, first_elem + elem) - : op); + for (unsigned int byte = first_byte; byte < end_byte; ++byte) + { + /* Always constant because the inputs are. */ + unsigned int lsb + = subreg_size_lsb (1, mode_bytes, byte).to_constant (); + unsigned HOST_WIDE_INT piece = CONST_FIXED_VALUE_LOW (x); + if (lsb >= HOST_BITS_PER_WIDE_INT) + { + lsb -= HOST_BITS_PER_WIDE_INT; + piece = CONST_FIXED_VALUE_HIGH (x); + } + bytes.quick_push (piece >> lsb); + } + return true; + } - /* Vectors are kept in target memory order. (This is probably - a mistake.) */ - { - unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT; - unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize) - / BITS_PER_UNIT); - unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte; - unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte; - unsigned bytele = (subword_byte % UNITS_PER_WORD - + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD); - vp = value + (bytele * BITS_PER_UNIT) / value_bit; - } + return false; +} - switch (GET_CODE (el)) - { - case CONST_INT: - for (i = 0; - i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize; - i += value_bit) - *vp++ = INTVAL (el) >> i; - /* CONST_INTs are always logically sign-extended. */ - for (; i < elem_bitsize; i += value_bit) - *vp++ = INTVAL (el) < 0 ? -1 : 0; - break; +/* Read a vector of mode MODE from the target memory image given by BYTES, + starting at byte FIRST_BYTE. The vector is known to be encodable using + NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements each, + and BYTES is known to have enough bytes to supply NPATTERNS * + NELTS_PER_PATTERN vector elements. Each element of BYTES contains + BITS_PER_UNIT bits and the bytes are in target memory order. - case CONST_WIDE_INT: - { - rtx_mode_t val = rtx_mode_t (el, GET_MODE_INNER (innermode)); - unsigned char extend = wi::sign_mask (val); - int prec = wi::get_precision (val); - - for (i = 0; i < prec && i < elem_bitsize; i += value_bit) - *vp++ = wi::extract_uhwi (val, i, value_bit); - for (; i < elem_bitsize; i += value_bit) - *vp++ = extend; - } - break; + Return the vector on success, otherwise return NULL_RTX. */ - case CONST_DOUBLE: - if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode) - { - unsigned char extend = 0; - /* If this triggers, someone should have generated a - CONST_INT instead. */ - gcc_assert (elem_bitsize > HOST_BITS_PER_WIDE_INT); - - for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit) - *vp++ = CONST_DOUBLE_LOW (el) >> i; - while (i < HOST_BITS_PER_DOUBLE_INT && i < elem_bitsize) - { - *vp++ - = CONST_DOUBLE_HIGH (el) >> (i - HOST_BITS_PER_WIDE_INT); - i += value_bit; - } +rtx +native_decode_vector_rtx (machine_mode mode, vec bytes, + unsigned int first_byte, unsigned int npatterns, + unsigned int nelts_per_pattern) +{ + rtx_vector_builder builder (mode, npatterns, nelts_per_pattern); - if (CONST_DOUBLE_HIGH (el) >> (HOST_BITS_PER_WIDE_INT - 1)) - extend = -1; - for (; i < elem_bitsize; i += value_bit) - *vp++ = extend; - } - else - { - /* This is big enough for anything on the platform. */ - long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32]; - scalar_float_mode el_mode; + unsigned int elt_bits = vector_element_size (GET_MODE_BITSIZE (mode), + GET_MODE_NUNITS (mode)); + if (elt_bits < BITS_PER_UNIT) + { + /* This is the only case in which elements can be smaller than a byte. + Element 0 is always in the lsb of the containing byte. */ + gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL); + for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) + { + unsigned int bit_index = first_byte * BITS_PER_UNIT + i * elt_bits; + unsigned int byte_index = bit_index / BITS_PER_UNIT; + unsigned int lsb = bit_index % BITS_PER_UNIT; + builder.quick_push (bytes[byte_index] & (1 << lsb) + ? CONST1_RTX (BImode) + : CONST0_RTX (BImode)); + } + } + else + { + for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) + { + rtx x = native_decode_rtx (GET_MODE_INNER (mode), bytes, first_byte); + if (!x) + return NULL_RTX; + builder.quick_push (x); + first_byte += elt_bits / BITS_PER_UNIT; + } + } + return builder.build (); +} - el_mode = as_a (GET_MODE (el)); - int bitsize = GET_MODE_BITSIZE (el_mode); +/* Read an rtx of mode MODE from the target memory image given by BYTES, + starting at byte FIRST_BYTE. Each element of BYTES contains BITS_PER_UNIT + bits and the bytes are in target memory order. The image has enough + values to specify all bytes of MODE. - gcc_assert (bitsize <= elem_bitsize); - gcc_assert (bitsize % value_bit == 0); + Return the rtx on success, otherwise return NULL_RTX. */ - real_to_target (tmp, CONST_DOUBLE_REAL_VALUE (el), - GET_MODE (el)); +rtx +native_decode_rtx (machine_mode mode, vec bytes, + unsigned int first_byte) +{ + if (VECTOR_MODE_P (mode)) + { + /* If we know at compile time how many elements there are, + pull each element directly from BYTES. */ + unsigned int nelts; + if (GET_MODE_NUNITS (mode).is_constant (&nelts)) + return native_decode_vector_rtx (mode, bytes, first_byte, nelts, 1); + return NULL_RTX; + } - /* real_to_target produces its result in words affected by - FLOAT_WORDS_BIG_ENDIAN. However, we ignore this, - and use WORDS_BIG_ENDIAN instead; see the documentation - of SUBREG in rtl.texi. */ - for (i = 0; i < bitsize; i += value_bit) - { - int ibase; - if (WORDS_BIG_ENDIAN) - ibase = bitsize - 1 - i; - else - ibase = i; - *vp++ = tmp[ibase / 32] >> i % 32; - } + scalar_int_mode imode; + if (is_a (mode, &imode) + && GET_MODE_PRECISION (imode) <= MAX_BITSIZE_MODE_ANY_INT) + { + /* Pull the bytes msb first, so that we can use simple + shift-and-insert wide_int operations. */ + unsigned int size = GET_MODE_SIZE (imode); + wide_int result (wi::zero (GET_MODE_PRECISION (imode))); + for (unsigned int i = 0; i < size; ++i) + { + unsigned int lsb = (size - i - 1) * BITS_PER_UNIT; + /* Always constant because the inputs are. */ + unsigned int subbyte + = subreg_size_offset_from_lsb (1, size, lsb).to_constant (); + result <<= BITS_PER_UNIT; + result |= bytes[first_byte + subbyte]; + } + return immed_wide_int_const (result, imode); + } - /* It shouldn't matter what's done here, so fill it with - zero. */ - for (; i < elem_bitsize; i += value_bit) - *vp++ = 0; - } - break; + scalar_float_mode fmode; + if (is_a (mode, &fmode)) + { + /* We need to build an array of integers in target memory order. + All integers before the last one have 32 bits; the last one may + have 32 bits or fewer, depending on whether the mode bitsize + is divisible by 32. */ + long el32[MAX_BITSIZE_MODE_ANY_MODE / 32]; + unsigned int num_el32 = CEIL (GET_MODE_BITSIZE (fmode), 32); + memset (el32, 0, num_el32 * sizeof (long)); + + /* The (maximum) number of target bytes per element of el32. */ + unsigned int bytes_per_el32 = 32 / BITS_PER_UNIT; + gcc_assert (bytes_per_el32 != 0); + + unsigned int mode_bytes = GET_MODE_SIZE (fmode); + for (unsigned int byte = 0; byte < mode_bytes; ++byte) + { + unsigned int index = byte / bytes_per_el32; + unsigned int subbyte = byte % bytes_per_el32; + unsigned int int_bytes = MIN (bytes_per_el32, + mode_bytes - index * bytes_per_el32); + /* Always constant because the inputs are. */ + unsigned int lsb + = subreg_size_lsb (1, int_bytes, subbyte).to_constant (); + el32[index] |= (unsigned long) bytes[first_byte + byte] << lsb; + } + REAL_VALUE_TYPE r; + real_from_target (&r, el32, fmode); + return const_double_from_real_value (r, fmode); + } - case CONST_FIXED: - if (elem_bitsize <= HOST_BITS_PER_WIDE_INT) - { - for (i = 0; i < elem_bitsize; i += value_bit) - *vp++ = CONST_FIXED_VALUE_LOW (el) >> i; - } + if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) + { + scalar_mode smode = as_a (mode); + FIXED_VALUE_TYPE f; + f.data.low = 0; + f.data.high = 0; + f.mode = smode; + + unsigned int mode_bytes = GET_MODE_SIZE (smode); + for (unsigned int byte = 0; byte < mode_bytes; ++byte) + { + /* Always constant because the inputs are. */ + unsigned int lsb + = subreg_size_lsb (1, mode_bytes, byte).to_constant (); + unsigned HOST_WIDE_INT unit = bytes[first_byte + byte]; + if (lsb >= HOST_BITS_PER_WIDE_INT) + f.data.high |= unit << (lsb - HOST_BITS_PER_WIDE_INT); else - { - for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit) - *vp++ = CONST_FIXED_VALUE_LOW (el) >> i; - for (; i < HOST_BITS_PER_DOUBLE_INT && i < elem_bitsize; - i += value_bit) - *vp++ = CONST_FIXED_VALUE_HIGH (el) - >> (i - HOST_BITS_PER_WIDE_INT); - for (; i < elem_bitsize; i += value_bit) - *vp++ = 0; - } - break; - - default: - gcc_unreachable (); + f.data.low |= unit << lsb; } + return CONST_FIXED_FROM_FIXED_VALUE (f, mode); } - /* Now, pick the right byte to start with. */ - /* Renumber BYTE so that the least-significant byte is byte 0. A special - case is paradoxical SUBREGs, which shouldn't be adjusted since they - will already have offset 0. */ - if (inner_bytes >= GET_MODE_SIZE (outermode)) + return NULL_RTX; +} + +/* Simplify a byte offset BYTE into CONST_VECTOR X. The main purpose + is to convert a runtime BYTE value into a constant one. */ + +static poly_uint64 +simplify_const_vector_byte_offset (rtx x, poly_uint64 byte) +{ + /* Cope with MODE_VECTOR_BOOL by operating on bits rather than bytes. */ + machine_mode mode = GET_MODE (x); + unsigned int elt_bits = vector_element_size (GET_MODE_BITSIZE (mode), + GET_MODE_NUNITS (mode)); + /* The number of bits needed to encode one element from each pattern. */ + unsigned int sequence_bits = CONST_VECTOR_NPATTERNS (x) * elt_bits; + + /* Identify the start point in terms of a sequence number and a byte offset + within that sequence. */ + poly_uint64 first_sequence; + unsigned HOST_WIDE_INT subbit; + if (can_div_trunc_p (byte * BITS_PER_UNIT, sequence_bits, + &first_sequence, &subbit)) { - unsigned ibyte = inner_bytes - GET_MODE_SIZE (outermode) - byte; - unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte; - unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte; - byte = (subword_byte % UNITS_PER_WORD - + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD); + unsigned int nelts_per_pattern = CONST_VECTOR_NELTS_PER_PATTERN (x); + if (nelts_per_pattern == 1) + /* This is a duplicated vector, so the value of FIRST_SEQUENCE + doesn't matter. */ + byte = subbit / BITS_PER_UNIT; + else if (nelts_per_pattern == 2 && known_gt (first_sequence, 0U)) + { + /* The subreg drops the first element from each pattern and + only uses the second element. Find the first sequence + that starts on a byte boundary. */ + subbit += least_common_multiple (sequence_bits, BITS_PER_UNIT); + byte = subbit / BITS_PER_UNIT; + } } + return byte; +} + +/* Subroutine of simplify_subreg in which: + + - X is known to be a CONST_VECTOR + - OUTERMODE is known to be a vector mode - /* BYTE should still be inside OP. (Note that BYTE is unsigned, - so if it's become negative it will instead be very large.) */ - gcc_assert (byte < inner_bytes); + Try to handle the subreg by operating on the CONST_VECTOR encoding + rather than on each individual element of the CONST_VECTOR. - /* Convert from bytes to chunks of size value_bit. */ - value_start = byte * (BITS_PER_UNIT / value_bit); + Return the simplified subreg on success, otherwise return NULL_RTX. */ + +static rtx +simplify_const_vector_subreg (machine_mode outermode, rtx x, + machine_mode innermode, unsigned int first_byte) +{ + /* Paradoxical subregs of vectors have dubious semantics. */ + if (paradoxical_subreg_p (outermode, innermode)) + return NULL_RTX; - /* Re-pack the value. */ - num_elem = GET_MODE_NUNITS (outermode); + /* We can only preserve the semantics of a stepped pattern if the new + vector element is the same as the original one. */ + if (CONST_VECTOR_STEPPED_P (x) + && GET_MODE_INNER (outermode) != GET_MODE_INNER (innermode)) + return NULL_RTX; - if (VECTOR_MODE_P (outermode)) + /* Cope with MODE_VECTOR_BOOL by operating on bits rather than bytes. */ + unsigned int x_elt_bits + = vector_element_size (GET_MODE_BITSIZE (innermode), + GET_MODE_NUNITS (innermode)); + unsigned int out_elt_bits + = vector_element_size (GET_MODE_BITSIZE (outermode), + GET_MODE_NUNITS (outermode)); + + /* The number of bits needed to encode one element from every pattern + of the original vector. */ + unsigned int x_sequence_bits = CONST_VECTOR_NPATTERNS (x) * x_elt_bits; + + /* The number of bits needed to encode one element from every pattern + of the result. */ + unsigned int out_sequence_bits + = least_common_multiple (x_sequence_bits, out_elt_bits); + + /* Work out the number of interleaved patterns in the output vector + and the number of encoded elements per pattern. */ + unsigned int out_npatterns = out_sequence_bits / out_elt_bits; + unsigned int nelts_per_pattern = CONST_VECTOR_NELTS_PER_PATTERN (x); + + /* The encoding scheme requires the number of elements to be a multiple + of the number of patterns, so that each pattern appears at least once + and so that the same number of elements appear from each pattern. */ + bool ok_p = multiple_p (GET_MODE_NUNITS (outermode), out_npatterns); + unsigned int const_nunits; + if (GET_MODE_NUNITS (outermode).is_constant (&const_nunits) + && (!ok_p || out_npatterns * nelts_per_pattern > const_nunits)) { - result_v = rtvec_alloc (num_elem); - elems = &RTVEC_ELT (result_v, 0); + /* Either the encoding is invalid, or applying it would give us + more elements than we need. Just encode each element directly. */ + out_npatterns = const_nunits; + nelts_per_pattern = 1; } - else - elems = &result_s; + else if (!ok_p) + return NULL_RTX; - outer_submode = GET_MODE_INNER (outermode); - outer_class = GET_MODE_CLASS (outer_submode); - elem_bitsize = GET_MODE_BITSIZE (outer_submode); + /* Get enough bytes of X to form the new encoding. */ + unsigned int buffer_bits = out_npatterns * nelts_per_pattern * out_elt_bits; + unsigned int buffer_bytes = CEIL (buffer_bits, BITS_PER_UNIT); + auto_vec buffer (buffer_bytes); + if (!native_encode_rtx (innermode, x, buffer, first_byte, buffer_bytes)) + return NULL_RTX; - gcc_assert (elem_bitsize % value_bit == 0); - gcc_assert (elem_bitsize + value_start * value_bit <= max_bitsize); + /* Reencode the bytes as OUTERMODE. */ + return native_decode_vector_rtx (outermode, buffer, 0, out_npatterns, + nelts_per_pattern); +} - for (elem = 0; elem < num_elem; elem++) - { - unsigned char *vp; +/* Try to simplify a subreg of a constant by encoding the subreg region + as a sequence of target bytes and reading them back in the new mode. + Return the new value on success, otherwise return null. - /* Vectors are stored in target memory order. (This is probably - a mistake.) */ - { - unsigned byte = (elem * elem_bitsize) / BITS_PER_UNIT; - unsigned ibyte = (((num_elem - 1 - elem) * elem_bitsize) - / BITS_PER_UNIT); - unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte; - unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte; - unsigned bytele = (subword_byte % UNITS_PER_WORD - + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD); - vp = value + value_start + (bytele * BITS_PER_UNIT) / value_bit; - } + The subreg has outer mode OUTERMODE, inner mode INNERMODE, inner value X + and byte offset FIRST_BYTE. */ - switch (outer_class) - { - case MODE_INT: - case MODE_PARTIAL_INT: - { - int u; - int base = 0; - int units - = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1) - / HOST_BITS_PER_WIDE_INT; - HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; - wide_int r; - - if (GET_MODE_PRECISION (outer_submode) > MAX_BITSIZE_MODE_ANY_INT) - return NULL_RTX; - for (u = 0; u < units; u++) - { - unsigned HOST_WIDE_INT buf = 0; - for (i = 0; - i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize; - i += value_bit) - buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i; - - tmp[u] = buf; - base += HOST_BITS_PER_WIDE_INT; - } - r = wide_int::from_array (tmp, units, - GET_MODE_PRECISION (outer_submode)); -#if TARGET_SUPPORTS_WIDE_INT == 0 - /* Make sure r will fit into CONST_INT or CONST_DOUBLE. */ - if (wi::min_precision (r, SIGNED) > HOST_BITS_PER_DOUBLE_INT) - return NULL_RTX; -#endif - elems[elem] = immed_wide_int_const (r, outer_submode); - } - break; +static rtx +simplify_immed_subreg (fixed_size_mode outermode, rtx x, + machine_mode innermode, unsigned int first_byte) +{ + unsigned int buffer_bytes = GET_MODE_SIZE (outermode); + auto_vec buffer (buffer_bytes); - case MODE_FLOAT: - case MODE_DECIMAL_FLOAT: - { - REAL_VALUE_TYPE r; - long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32] = { 0 }; - - /* real_from_target wants its input in words affected by - FLOAT_WORDS_BIG_ENDIAN. However, we ignore this, - and use WORDS_BIG_ENDIAN instead; see the documentation - of SUBREG in rtl.texi. */ - for (i = 0; i < elem_bitsize; i += value_bit) - { - int ibase; - if (WORDS_BIG_ENDIAN) - ibase = elem_bitsize - 1 - i; - else - ibase = i; - tmp[ibase / 32] |= (*vp++ & value_mask) << i % 32; - } + /* Some ports misuse CCmode. */ + if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (x)) + return x; - real_from_target (&r, tmp, outer_submode); - elems[elem] = const_double_from_real_value (r, outer_submode); - } - break; + /* Paradoxical subregs read undefined values for bytes outside of the + inner value. However, we have traditionally always sign-extended + integer constants and zero-extended others. */ + unsigned int inner_bytes = buffer_bytes; + if (paradoxical_subreg_p (outermode, innermode)) + { + if (!GET_MODE_SIZE (innermode).is_constant (&inner_bytes)) + return NULL_RTX; - case MODE_FRACT: - case MODE_UFRACT: - case MODE_ACCUM: - case MODE_UACCUM: - { - FIXED_VALUE_TYPE f; - f.data.low = 0; - f.data.high = 0; - f.mode = outer_submode; - - for (i = 0; - i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize; - i += value_bit) - f.data.low |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i; - for (; i < elem_bitsize; i += value_bit) - f.data.high |= ((unsigned HOST_WIDE_INT)(*vp++ & value_mask) - << (i - HOST_BITS_PER_WIDE_INT)); - - elems[elem] = CONST_FIXED_FROM_FIXED_VALUE (f, outer_submode); - } - break; + target_unit filler = 0; + if (CONST_SCALAR_INT_P (x) && wi::neg_p (rtx_mode_t (x, innermode))) + filler = -1; - default: - gcc_unreachable (); - } + /* Add any leading bytes due to big-endian layout. The number of + bytes must be constant because both modes have constant size. */ + unsigned int leading_bytes + = -byte_lowpart_offset (outermode, innermode).to_constant (); + for (unsigned int i = 0; i < leading_bytes; ++i) + buffer.quick_push (filler); + + if (!native_encode_rtx (innermode, x, buffer, first_byte, inner_bytes)) + return NULL_RTX; + + /* Add any trailing bytes due to little-endian layout. */ + while (buffer.length () < buffer_bytes) + buffer.quick_push (filler); } - if (VECTOR_MODE_P (outermode)) - return gen_rtx_CONST_VECTOR (outermode, result_v); else - return result_s; + { + if (!native_encode_rtx (innermode, x, buffer, first_byte, inner_bytes)) + return NULL_RTX; + } + return native_decode_rtx (outermode, buffer, 0); } /* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE) @@ -6494,6 +6618,9 @@ simplify_subreg (machine_mode outermode, rtx op, if (outermode == innermode && known_eq (byte, 0U)) return op; + if (GET_CODE (op) == CONST_VECTOR) + byte = simplify_const_vector_byte_offset (op, byte); + if (multiple_p (byte, GET_MODE_UNIT_SIZE (innermode))) { rtx elt; @@ -6513,30 +6640,21 @@ simplify_subreg (machine_mode outermode, rtx op, || CONST_FIXED_P (op) || GET_CODE (op) == CONST_VECTOR) { - /* simplify_immed_subreg deconstructs OP into bytes and constructs - the result from bytes, so it only works if the sizes of the modes - and the value of the offset are known at compile time. Cases that - that apply to general modes and offsets should be handled here - before calling simplify_immed_subreg. */ - fixed_size_mode fs_outermode, fs_innermode; unsigned HOST_WIDE_INT cbyte; - if (is_a (outermode, &fs_outermode) - && is_a (innermode, &fs_innermode) - && byte.is_constant (&cbyte)) - return simplify_immed_subreg (fs_outermode, op, fs_innermode, cbyte, - 0, GET_MODE_SIZE (fs_innermode)); - - /* Handle constant-sized outer modes and variable-sized inner modes. */ - unsigned HOST_WIDE_INT first_elem; - if (GET_CODE (op) == CONST_VECTOR - && is_a (outermode, &fs_outermode) - && constant_multiple_p (byte, GET_MODE_UNIT_SIZE (innermode), - &first_elem)) - return simplify_immed_subreg (fs_outermode, op, innermode, 0, - first_elem, - GET_MODE_SIZE (fs_outermode)); + if (byte.is_constant (&cbyte)) + { + if (GET_CODE (op) == CONST_VECTOR && VECTOR_MODE_P (outermode)) + { + rtx tmp = simplify_const_vector_subreg (outermode, op, + innermode, cbyte); + if (tmp) + return tmp; + } - return NULL_RTX; + fixed_size_mode fs_outermode; + if (is_a (outermode, &fs_outermode)) + return simplify_immed_subreg (fs_outermode, op, innermode, cbyte); + } } /* Changing mode twice with SUBREG => just change it once, @@ -7179,6 +7297,165 @@ test_vec_merge (machine_mode mode) simplify_rtx (nvm)); } +/* Test subregs of integer vector constant X, trying elements in + the range [ELT_BIAS, ELT_BIAS + constant_lower_bound (NELTS)), + where NELTS is the number of elements in X. Subregs involving + elements [ELT_BIAS, ELT_BIAS + FIRST_VALID) are expected to fail. */ + +static void +test_vector_subregs_modes (rtx x, poly_uint64 elt_bias = 0, + unsigned int first_valid = 0) +{ + machine_mode inner_mode = GET_MODE (x); + scalar_mode int_mode = GET_MODE_INNER (inner_mode); + + for (unsigned int modei = 0; modei < NUM_MACHINE_MODES; ++modei) + { + machine_mode outer_mode = (machine_mode) modei; + if (!VECTOR_MODE_P (outer_mode)) + continue; + + unsigned int outer_nunits; + if (GET_MODE_INNER (outer_mode) == int_mode + && GET_MODE_NUNITS (outer_mode).is_constant (&outer_nunits) + && multiple_p (GET_MODE_NUNITS (inner_mode), outer_nunits)) + { + /* Test subregs in which the outer mode is a smaller, + constant-sized vector of the same element type. */ + unsigned int limit + = constant_lower_bound (GET_MODE_NUNITS (inner_mode)); + for (unsigned int elt = 0; elt < limit; elt += outer_nunits) + { + rtx expected = NULL_RTX; + if (elt >= first_valid) + { + rtx_vector_builder builder (outer_mode, outer_nunits, 1); + for (unsigned int i = 0; i < outer_nunits; ++i) + builder.quick_push (CONST_VECTOR_ELT (x, elt + i)); + expected = builder.build (); + } + poly_uint64 byte = (elt_bias + elt) * GET_MODE_SIZE (int_mode); + ASSERT_RTX_EQ (expected, + simplify_subreg (outer_mode, x, + inner_mode, byte)); + } + } + else if (known_eq (GET_MODE_SIZE (outer_mode), + GET_MODE_SIZE (inner_mode)) + && known_eq (elt_bias, 0U) + && (GET_MODE_CLASS (outer_mode) != MODE_VECTOR_BOOL + || known_eq (GET_MODE_BITSIZE (outer_mode), + GET_MODE_NUNITS (outer_mode))) + && (!FLOAT_MODE_P (outer_mode) + || (FLOAT_MODE_FORMAT (outer_mode)->ieee_bits + == GET_MODE_UNIT_PRECISION (outer_mode))) + && (GET_MODE_SIZE (inner_mode).is_constant () + || !CONST_VECTOR_STEPPED_P (x))) + { + /* Try converting to OUTER_MODE and back. */ + rtx outer_x = simplify_subreg (outer_mode, x, inner_mode, 0); + ASSERT_TRUE (outer_x != NULL_RTX); + ASSERT_RTX_EQ (x, simplify_subreg (inner_mode, outer_x, + outer_mode, 0)); + } + } + + if (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN) + { + /* Test each byte in the element range. */ + unsigned int limit + = constant_lower_bound (GET_MODE_SIZE (inner_mode)); + for (unsigned int i = 0; i < limit; ++i) + { + unsigned int elt = i / GET_MODE_SIZE (int_mode); + rtx expected = NULL_RTX; + if (elt >= first_valid) + { + unsigned int byte_shift = i % GET_MODE_SIZE (int_mode); + if (BYTES_BIG_ENDIAN) + byte_shift = GET_MODE_SIZE (int_mode) - byte_shift - 1; + rtx_mode_t vec_elt (CONST_VECTOR_ELT (x, elt), int_mode); + wide_int shifted_elt + = wi::lrshift (vec_elt, byte_shift * BITS_PER_UNIT); + expected = immed_wide_int_const (shifted_elt, QImode); + } + poly_uint64 byte = elt_bias * GET_MODE_SIZE (int_mode) + i; + ASSERT_RTX_EQ (expected, + simplify_subreg (QImode, x, inner_mode, byte)); + } + } +} + +/* Test constant subregs of integer vector mode INNER_MODE, using 1 + element per pattern. */ + +static void +test_vector_subregs_repeating (machine_mode inner_mode) +{ + poly_uint64 nunits = GET_MODE_NUNITS (inner_mode); + unsigned int min_nunits = constant_lower_bound (nunits); + scalar_mode int_mode = GET_MODE_INNER (inner_mode); + unsigned int count = gcd (min_nunits, 8); + + rtx_vector_builder builder (inner_mode, count, 1); + for (unsigned int i = 0; i < count; ++i) + builder.quick_push (gen_int_mode (8 - i, int_mode)); + rtx x = builder.build (); + + test_vector_subregs_modes (x); + if (!nunits.is_constant ()) + test_vector_subregs_modes (x, nunits - min_nunits); +} + +/* Test constant subregs of integer vector mode INNER_MODE, using 2 + elements per pattern. */ + +static void +test_vector_subregs_fore_back (machine_mode inner_mode) +{ + poly_uint64 nunits = GET_MODE_NUNITS (inner_mode); + unsigned int min_nunits = constant_lower_bound (nunits); + scalar_mode int_mode = GET_MODE_INNER (inner_mode); + unsigned int count = gcd (min_nunits, 4); + + rtx_vector_builder builder (inner_mode, count, 2); + for (unsigned int i = 0; i < count; ++i) + builder.quick_push (gen_int_mode (i, int_mode)); + for (unsigned int i = 0; i < count; ++i) + builder.quick_push (gen_int_mode (-(int) i, int_mode)); + rtx x = builder.build (); + + test_vector_subregs_modes (x); + if (!nunits.is_constant ()) + test_vector_subregs_modes (x, nunits - min_nunits, count); +} + +/* Test constant subregs of integer vector mode INNER_MODE, using 3 + elements per pattern. */ + +static void +test_vector_subregs_stepped (machine_mode inner_mode) +{ + /* Build { 0, 1, 2, 3, ... }. */ + scalar_mode int_mode = GET_MODE_INNER (inner_mode); + rtx_vector_builder builder (inner_mode, 1, 3); + for (unsigned int i = 0; i < 3; ++i) + builder.quick_push (gen_int_mode (i, int_mode)); + rtx x = builder.build (); + + test_vector_subregs_modes (x); +} + +/* Test constant subregs of integer vector mode INNER_MODE. */ + +static void +test_vector_subregs (machine_mode inner_mode) +{ + test_vector_subregs_repeating (inner_mode); + test_vector_subregs_fore_back (inner_mode); + test_vector_subregs_stepped (inner_mode); +} + /* Verify some simplifications involving vectors. */ static void @@ -7193,7 +7470,10 @@ test_vector_ops () test_vector_ops_duplicate (mode, scalar_reg); if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT && maybe_gt (GET_MODE_NUNITS (mode), 2)) - test_vector_ops_series (mode, scalar_reg); + { + test_vector_ops_series (mode, scalar_reg); + test_vector_subregs (mode); + } test_vec_merge (mode); } } -- cgit v1.1 From d9e736e7194b524c3624172b896d5ace9cb459aa Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 19 Sep 2019 12:49:45 +0000 Subject: re PR tree-optimization/91812 (GCC ignores volatile modifier) 2019-09-19 Richard Biener PR tree-optimization/91812 * tree-ssa-phiprop.c (propagate_with_phi): Do not replace volatile loads. * gcc.dg/torture/pr91812.c: New testcase. From-SVN: r275960 --- gcc/ChangeLog | 6 ++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/torture/pr91812.c | 26 ++++++++++++++++++++++++++ gcc/tree-ssa-phiprop.c | 11 +++++++++-- 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr91812.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c51b6f6..1810fe9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Richard Biener + + PR tree-optimization/91812 + * tree-ssa-phiprop.c (propagate_with_phi): Do not replace + volatile loads. + 2019-09-19 Richard Sandiford * defaults.h (TARGET_UNIT): New macro. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 07adb11..c5854bd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Richard Biener + + PR tree-optimization/91812 + * gcc.dg/torture/pr91812.c: New testcase. + 2019-09-19 Tom Tromey * gnat.dg/bias1.adb: New testcase. diff --git a/gcc/testsuite/gcc.dg/torture/pr91812.c b/gcc/testsuite/gcc.dg/torture/pr91812.c new file mode 100644 index 0000000..ebc67a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr91812.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ +/* { dg-options "-fdump-tree-optimized-blocks" } */ + +unsigned register1; +unsigned register2; + +void busy_wait_for_register (int x) +{ + volatile unsigned* ptr; + switch(x) { + case 0x1111: + ptr = ®ister1; + break; + + case 0x2222: + ptr = ®ister2; + break; + + default: + return; + } + while (*ptr) {} +} + +/* { dg-final { scan-tree-dump "loop depth 1" "optimized" } } */ diff --git a/gcc/tree-ssa-phiprop.c b/gcc/tree-ssa-phiprop.c index d710582..e90ae6a 100644 --- a/gcc/tree-ssa-phiprop.c +++ b/gcc/tree-ssa-phiprop.c @@ -338,8 +338,15 @@ propagate_with_phi (basic_block bb, gphi *phi, struct phiprop_d *phivn, && (!type || types_compatible_p (TREE_TYPE (gimple_assign_lhs (use_stmt)), type)) - /* We cannot replace a load that may throw or is volatile. */ - && !stmt_can_throw_internal (cfun, use_stmt))) + /* We cannot replace a load that may throw or is volatile. + For volatiles the transform can change the number of + executions if the load is inside a loop but the address + computations outside (PR91812). We could relax this + if we guard against that appropriately. For loads that can + throw we could relax things if the moved loads all are + known to not throw. */ + && !stmt_can_throw_internal (cfun, use_stmt) + && !gimple_has_volatile_ops (use_stmt))) continue; /* Check if we can move the loads. The def stmt of the virtual use -- cgit v1.1 From 37bc3aa0474f21b7a678b09951634de3205d014e Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 19 Sep 2019 15:13:21 +0200 Subject: Speed up qsort in IPA ICF. 2019-09-19 Martin Liska * ipa-icf.c (sort_sem_items_by_decl_uid): Simplify comparator. (sort_congruence_classes_by_decl_uid): Likewise. (sort_congruence_class_groups_by_decl_uid): Use std::pair for easier sorting. (sem_item_optimizer::merge_classes): Likewise. From-SVN: r275961 --- gcc/ChangeLog | 8 ++++++++ gcc/ipa-icf.c | 49 ++++++++++++++++--------------------------------- 2 files changed, 24 insertions(+), 33 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1810fe9..cbddb90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-19 Martin Liska + + * ipa-icf.c (sort_sem_items_by_decl_uid): Simplify comparator. + (sort_congruence_classes_by_decl_uid): Likewise. + (sort_congruence_class_groups_by_decl_uid): Use std::pair for + easier sorting. + (sem_item_optimizer::merge_classes): Likewise. + 2019-09-19 Richard Biener PR tree-optimization/91812 diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c index c9c3cb4..59b7f8b 100644 --- a/gcc/ipa-icf.c +++ b/gcc/ipa-icf.c @@ -3350,13 +3350,7 @@ sort_sem_items_by_decl_uid (const void *a, const void *b) int uid1 = DECL_UID (i1->decl); int uid2 = DECL_UID (i2->decl); - - if (uid1 < uid2) - return -1; - else if (uid1 > uid2) - return 1; - else - return 0; + return uid1 - uid2; } /* Sort pair of congruence_classes A and B by DECL_UID of the first member. */ @@ -3369,13 +3363,7 @@ sort_congruence_classes_by_decl_uid (const void *a, const void *b) int uid1 = DECL_UID (c1->members[0]->decl); int uid2 = DECL_UID (c2->members[0]->decl); - - if (uid1 < uid2) - return -1; - else if (uid1 > uid2) - return 1; - else - return 0; + return uid1 - uid2; } /* Sort pair of congruence_class_groups A and B by @@ -3384,20 +3372,11 @@ sort_congruence_classes_by_decl_uid (const void *a, const void *b) static int sort_congruence_class_groups_by_decl_uid (const void *a, const void *b) { - const congruence_class_group *g1 - = *(const congruence_class_group * const *)a; - const congruence_class_group *g2 - = *(const congruence_class_group * const *)b; - - int uid1 = DECL_UID (g1->classes[0]->members[0]->decl); - int uid2 = DECL_UID (g2->classes[0]->members[0]->decl); - - if (uid1 < uid2) - return -1; - else if (uid1 > uid2) - return 1; - else - return 0; + const std::pair *g1 + = *(const std::pair *const *) a; + const std::pair *g2 + = *(const std::pair *const *) b; + return g1->second - g2->second; } /* After reduction is done, we can declare all items in a group @@ -3445,10 +3424,14 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count) } } - auto_vec classes (m_classes.elements ()); + auto_vec > classes ( + m_classes.elements ()); for (hash_table::iterator it = m_classes.begin (); it != m_classes.end (); ++it) - classes.quick_push (*it); + { + int uid = DECL_UID ((*it)->classes[0]->members[0]->decl); + classes.quick_push (std::pair (*it, uid)); + } classes.qsort (sort_congruence_class_groups_by_decl_uid); @@ -3470,11 +3453,11 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count) } unsigned int l; - congruence_class_group *it; + std::pair *it; FOR_EACH_VEC_ELT (classes, l, it) - for (unsigned int i = 0; i < it->classes.length (); i++) + for (unsigned int i = 0; i < it->first->classes.length (); i++) { - congruence_class *c = it->classes[i]; + congruence_class *c = it->first->classes[i]; if (c->members.length () == 1) continue; -- cgit v1.1 From c449d3ae28ff4e133114fb67dbf7dcc7a95ca5d5 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 19 Sep 2019 13:33:55 +0000 Subject: Enforce correct COND_EXPR order for EXTRACT_LAST_REDUCTION For conditional reductions, the "then" value needs to be the candidate value calculated by this iteration while the "else" value needs to be the result carried over from previous iterations. If the COND_EXPR is the other way around, we need to swap it. 2019-09-19 Richard Sandiford gcc/ * tree-vectorizer.h (vectorizable_condition): Take an int reduction index instead of a boolean flag. * tree-vect-stmts.c (vectorizable_condition): Likewise. Swap the "then" and "else" values for EXTRACT_LAST_REDUCTION reductions if the reduction accumulator is the "then" rather than the "else" value. (vect_analyze_stmt): Update call accordingly. (vect_transform_stmt): Likewise. * tree-vect-loop.c (vectorizable_reduction): Likewise, asserting that the index is > 0. From-SVN: r275962 --- gcc/ChangeLog | 13 +++++++++++++ gcc/tree-vect-loop.c | 11 ++++++----- gcc/tree-vect-stmts.c | 41 +++++++++++++++++++++++++++++++++++++---- gcc/tree-vectorizer.h | 2 +- 4 files changed, 57 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cbddb90..506e93d7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-09-19 Richard Sandiford + + * tree-vectorizer.h (vectorizable_condition): Take an int + reduction index instead of a boolean flag. + * tree-vect-stmts.c (vectorizable_condition): Likewise. + Swap the "then" and "else" values for EXTRACT_LAST_REDUCTION + reductions if the reduction accumulator is the "then" rather + than the "else" value. + (vect_analyze_stmt): Update call accordingly. + (vect_transform_stmt): Likewise. + * tree-vect-loop.c (vectorizable_reduction): Likewise, + asserting that the index is > 0. + 2019-09-19 Martin Liska * ipa-icf.c (sort_sem_items_by_decl_uid): Simplify comparator. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 5ee4ee3..aec4462 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -6659,8 +6659,9 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, { /* Only call during the analysis stage, otherwise we'll lose STMT_VINFO_TYPE. */ + gcc_assert (reduc_index > 0); if (!vec_stmt && !vectorizable_condition (stmt_info, gsi, NULL, - true, NULL, cost_vec)) + reduc_index, NULL, cost_vec)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -7113,9 +7114,9 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, if (reduction_type == EXTRACT_LAST_REDUCTION) { - gcc_assert (!slp_node); + gcc_assert (!slp_node && reduc_index > 0); return vectorizable_condition (stmt_info, gsi, vec_stmt, - true, NULL, NULL); + reduc_index, NULL, NULL); } /* Create the destination vector */ @@ -7145,9 +7146,9 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, { if (code == COND_EXPR) { - gcc_assert (!slp_node); + gcc_assert (!slp_node && reduc_index > 0); vectorizable_condition (stmt_info, gsi, vec_stmt, - true, NULL, NULL); + reduc_index, NULL, NULL); break; } if (code == LSHIFT_EXPR diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 7f5f1c3..0636e5c 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -9778,7 +9778,7 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, bool vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, - stmt_vec_info *vec_stmt, bool for_reduction, + stmt_vec_info *vec_stmt, int reduc_index, slp_tree slp_node, stmt_vector_for_cost *cost_vec) { vec_info *vinfo = stmt_info->vinfo; @@ -9807,6 +9807,7 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vec vec_oprnds3 = vNULL; tree vec_cmp_type; bool masked = false; + bool for_reduction = (reduc_index > 0); if (for_reduction && STMT_SLP_TYPE (stmt_info)) return false; @@ -9888,6 +9889,29 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, cond_expr1 = TREE_OPERAND (cond_expr, 1); } + /* For conditional reductions, the "then" value needs to be the candidate + value calculated by this iteration while the "else" value needs to be + the result carried over from previous iterations. If the COND_EXPR + is the other way around, we need to swap it. */ + bool must_invert_cmp_result = false; + if (reduction_type == EXTRACT_LAST_REDUCTION && reduc_index == 1) + { + if (masked) + must_invert_cmp_result = true; + else + { + bool honor_nans = HONOR_NANS (TREE_TYPE (cond_expr0)); + tree_code new_code = invert_tree_comparison (cond_code, honor_nans); + if (new_code == ERROR_MARK) + must_invert_cmp_result = true; + else + cond_code = new_code; + } + /* Make sure we don't accidentally use the old condition. */ + cond_expr = NULL_TREE; + std::swap (then_clause, else_clause); + } + if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype)) { /* Boolean values may have another representation in vectors @@ -10102,6 +10126,15 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vect_finish_stmt_generation (stmt_info, new_stmt, gsi); vec_compare = vec_compare_name; } + if (must_invert_cmp_result) + { + tree vec_compare_name = make_ssa_name (vec_cmp_type); + gassign *new_stmt = gimple_build_assign (vec_compare_name, + BIT_NOT_EXPR, + vec_compare); + vect_finish_stmt_generation (stmt_info, new_stmt, gsi); + vec_compare = vec_compare_name; + } gcall *new_stmt = gimple_build_call_internal (IFN_FOLD_EXTRACT_LAST, 3, else_clause, vec_compare, vec_then_clause); @@ -10635,7 +10668,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize, node_instance, cost_vec) || vectorizable_induction (stmt_info, NULL, NULL, node, cost_vec) || vectorizable_shift (stmt_info, NULL, NULL, node, cost_vec) - || vectorizable_condition (stmt_info, NULL, NULL, false, node, + || vectorizable_condition (stmt_info, NULL, NULL, 0, node, cost_vec) || vectorizable_comparison (stmt_info, NULL, NULL, node, cost_vec)); @@ -10654,7 +10687,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize, || vectorizable_load (stmt_info, NULL, NULL, node, node_instance, cost_vec) || vectorizable_store (stmt_info, NULL, NULL, node, cost_vec) - || vectorizable_condition (stmt_info, NULL, NULL, false, node, + || vectorizable_condition (stmt_info, NULL, NULL, 0, node, cost_vec) || vectorizable_comparison (stmt_info, NULL, NULL, node, cost_vec)); @@ -10759,7 +10792,7 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, break; case condition_vec_info_type: - done = vectorizable_condition (stmt_info, gsi, &vec_stmt, false, + done = vectorizable_condition (stmt_info, gsi, &vec_stmt, 0, slp_node, NULL); gcc_assert (done); break; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index ac6e899..aef0ff8 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1534,7 +1534,7 @@ extern void vect_remove_stores (stmt_vec_info); extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree, slp_instance, stmt_vector_for_cost *); extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *, - stmt_vec_info *, bool, slp_tree, + stmt_vec_info *, int, slp_tree, stmt_vector_for_cost *); extern bool vectorizable_shift (stmt_vec_info, gimple_stmt_iterator *, stmt_vec_info *, slp_tree, -- cgit v1.1 From efe126563bb8d28cb3958423a735d0021e75702f Mon Sep 17 00:00:00 2001 From: Feng Xue Date: Thu, 19 Sep 2019 14:16:01 +0000 Subject: Use post-dom info to update if/switch predicate 2019-09-19 Feng Xue * ipa-fnsummary.c (set_cond_stmt_execution_predicate): Do not compute trivial predicate for condition branch. (set_switch_stmt_execution_predicate): Do not compute trivial predicate for switch case. (compute_bb_predicates): Update predicate based on post-dominating relationship. (analyze_function_body): Calculate post-dominating information. 2019-09-19 Feng Xue * gcc.dg/ipa/pr91089.c: Add a new function and pattern. From-SVN: r275963 --- gcc/ChangeLog | 10 +++++ gcc/ipa-fnsummary.c | 78 ++++++++++++++++++++++++++++++++------ gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.dg/ipa/pr91089.c | 47 +++++++++++++++++++++++ 4 files changed, 128 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 506e93d7..279974c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-09-19 Feng Xue + + * ipa-fnsummary.c (set_cond_stmt_execution_predicate): Do not compute + trivial predicate for condition branch. + (set_switch_stmt_execution_predicate): Do not compute trivial predicate + for switch case. + (compute_bb_predicates): Update predicate based on post-dominating + relationship. + (analyze_function_body): Calculate post-dominating information. + 2019-09-19 Richard Sandiford * tree-vectorizer.h (vectorizable_condition): Take an int diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 1bf1806..6de060a 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -1197,8 +1197,14 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi, ? code : inverted_code); /* invert_tree_comparison will return ERROR_MARK on FP comparsions that are not EQ/NE instead of returning proper - unordered one. Be sure it is not confused with NON_CONSTANT. */ - if (this_code != ERROR_MARK) + unordered one. Be sure it is not confused with NON_CONSTANT. + + And if the edge's target is the final block of diamond CFG graph + of this conditional statement, we do not need to compute + predicate for the edge because the final block's predicate must + be at least as that of the first block of the statement. */ + if (this_code != ERROR_MARK + && !dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest)) { predicate p = add_condition (summary, index, size, &aggpos, this_code, @@ -1282,18 +1288,38 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi, *(predicate *) e->aux = false; } + e = gimple_switch_edge (cfun, last, 0); + /* Set BOUND_COUNT to maximum count to bypass computing predicate for + default case if its target basic block is in convergence point of all + switch cases, which can be determined by checking whether it + post-dominates the switch statement. */ + if (dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest)) + bound_count = INT_MAX; + n = gimple_switch_num_labels (last); for (case_idx = 1; case_idx < n; ++case_idx) { tree cl = gimple_switch_label (last, case_idx); - tree min, max; + tree min = CASE_LOW (cl); + tree max = CASE_HIGH (cl); predicate p; - e = gimple_switch_edge (cfun, last, case_idx); - min = CASE_LOW (cl); - max = CASE_HIGH (cl); + /* The case value might not have same type as switch expression, + extend the value based on the expression type. */ + if (TREE_TYPE (min) != type) + min = wide_int_to_tree (type, wi::to_wide (min)); if (!max) + max = min; + else if (TREE_TYPE (max) != type) + max = wide_int_to_tree (type, wi::to_wide (max)); + + /* The case's target basic block is in convergence point of all switch + cases, its predicate should be at least as that of the switch + statement. */ + if (dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest)) + p = true; + else if (min == max) p = add_condition (summary, index, size, &aggpos, EQ_EXPR, unshare_expr_without_location (min)); else @@ -1305,6 +1331,7 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi, unshare_expr_without_location (max)); p = p1 & p2; } + e = gimple_switch_edge (cfun, last, case_idx); *(class predicate *) e->aux = p.or_with (summary->conds, *(class predicate *) e->aux); @@ -1334,9 +1361,6 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi, } } - if (!max) - max = min; - /* Create/extend a case range. And we count endpoints of range set, this number nearly equals to number of conditions that we will create for predicate of default case. */ @@ -1463,10 +1487,10 @@ compute_bb_predicates (struct ipa_func_body_info *fbi, break; } } - if (p == false) - gcc_checking_assert (!bb->aux); - else + if (p != false) { + basic_block pdom_bb; + if (!bb->aux) { done = false; @@ -1485,6 +1509,34 @@ compute_bb_predicates (struct ipa_func_body_info *fbi, *((predicate *) bb->aux) = p; } } + + /* For switch/if statement, we can OR-combine predicates of all + its cases/branches to get predicate for basic block in their + convergence point, but sometimes this will generate very + complicated predicate. Actually, we can get simplified + predicate in another way by using the fact that predicate + for a basic block must also hold true for its post dominators. + To be specific, basic block in convergence point of + conditional statement should include predicate of the + statement. */ + pdom_bb = get_immediate_dominator (CDI_POST_DOMINATORS, bb); + if (pdom_bb == EXIT_BLOCK_PTR_FOR_FN (my_function) || !pdom_bb) + ; + else if (!pdom_bb->aux) + { + done = false; + pdom_bb->aux = edge_predicate_pool.allocate (); + *((predicate *) pdom_bb->aux) = p; + } + else if (p != *(predicate *) pdom_bb->aux) + { + p = p.or_with (summary->conds, *(predicate *)pdom_bb->aux); + if (p != *(predicate *) pdom_bb->aux) + { + done = false; + *((predicate *) pdom_bb->aux) = p; + } + } } } } @@ -2089,6 +2141,7 @@ analyze_function_body (struct cgraph_node *node, bool early) if (opt_for_fn (node->decl, optimize)) { calculate_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_POST_DOMINATORS); if (!early) loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); else @@ -2469,6 +2522,7 @@ analyze_function_body (struct cgraph_node *node, bool early) else if (!ipa_edge_args_sum) ipa_free_all_node_params (); free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); } if (dump_file) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c5854bd..79de33c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,8 +1,13 @@ +2019-09-19 Feng Xue + + * gcc.dg/ipa/pr91089.c: Add a new function and pattern. + 2019-09-19 Richard Biener PR tree-optimization/91812 * gcc.dg/torture/pr91812.c: New testcase. +>>>>>>> .r275960 2019-09-19 Tom Tromey * gnat.dg/bias1.adb: New testcase. diff --git a/gcc/testsuite/gcc.dg/ipa/pr91089.c b/gcc/testsuite/gcc.dg/ipa/pr91089.c index e9e206f..7509c62 100644 --- a/gcc/testsuite/gcc.dg/ipa/pr91089.c +++ b/gcc/testsuite/gcc.dg/ipa/pr91089.c @@ -41,6 +41,52 @@ int callee (int i) return data += i; } +int fn2 (); + +int callee_complex_predicate (int i) +{ + switch (i ) + { + case 0: + fn (); + fn (); + fn (); + case 1: + fn (); + fn (); + case -1: + fn (); + case -2: + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + fn (); + data += i; + break; + } + + if (i == 1000) + { + int j; + + for (j = 0; j < 100; j++) + fn2 (); + } + return i + 3; +} + int caller () { return callee (-127) + @@ -60,3 +106,4 @@ int caller () /* { dg-final { scan-ipa-dump "op0 != 0" "fnsummary" } } */ /* { dg-final { scan-ipa-dump "op0 < 5" "fnsummary" } } */ /* { dg-final { scan-ipa-dump "op0 > 7" "fnsummary" } } */ +/* { dg-final { scan-ipa-dump "loop depth: 1 .+ time:\[ \]*\[0-9\]+ predicate: \\(op0 == 1000\\)\[\r\n]+" "fnsummary" } } */ -- cgit v1.1 From e3f15286d1129de2cceee6acd5d5584cb5422db6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Sep 2019 14:36:24 +0000 Subject: aarch64: Extend %R for integer registers * config/aarch64/aarch64.c (aarch64_print_operand): Allow integer registers with %R. From-SVN: r275964 --- gcc/ChangeLog | 5 +++++ gcc/config/aarch64/aarch64.c | 15 ++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 279974c..3081b8b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Richard Henderson + + * config/aarch64/aarch64.c (aarch64_print_operand): Allow integer + registers with %R. + 2019-09-19 Feng Xue * ipa-fnsummary.c (set_cond_stmt_execution_predicate): Do not compute diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 232317d..99d51e2 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -8420,7 +8420,7 @@ sizetochar (int size) 'S/T/U/V': Print a FP/SIMD register name for a register list. The register printed is the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V. - 'R': Print a scalar FP/SIMD register name + 1. + 'R': Print a scalar Integer/FP/SIMD register name + 1. 'X': Print bottom 16 bits of integer constant in hex. 'w/x': Print a general register name or the zero register (32-bit or 64-bit). @@ -8623,12 +8623,13 @@ aarch64_print_operand (FILE *f, rtx x, int code) break; case 'R': - if (!REG_P (x) || !FP_REGNUM_P (REGNO (x))) - { - output_operand_lossage ("incompatible floating point / vector register operand for '%%%c'", code); - return; - } - asm_fprintf (f, "q%d", REGNO (x) - V0_REGNUM + 1); + if (REG_P (x) && FP_REGNUM_P (REGNO (x))) + asm_fprintf (f, "q%d", REGNO (x) - V0_REGNUM + 1); + else if (REG_P (x) && GP_REGNUM_P (REGNO (x))) + asm_fprintf (f, "x%d", REGNO (x) - R0_REGNUM + 1); + else + output_operand_lossage ("incompatible register operand for '%%%c'", + code); break; case 'X': -- cgit v1.1 From 4a2095ebace8534038ce2adf4ae94bfc854066c4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Sep 2019 14:36:29 +0000 Subject: aarch64: Implement TImode compare-and-swap This pattern will only be used with the __sync functions, because we do not yet have a bare TImode atomic load. * config/aarch64/aarch64.c (aarch64_gen_compare_reg): Add support for NE comparison of TImode values. (aarch64_emit_load_exclusive): Add support for TImode. (aarch64_emit_store_exclusive): Likewise. (aarch64_split_compare_and_swap): Disable strong_zero_p for TImode. * config/aarch64/atomics.md (@atomic_compare_and_swap): Change iterator from ALLI to ALLI_TI. (@atomic_compare_and_swap): New. (@atomic_compare_and_swap_lse): New. (aarch64_load_exclusive_pair): New. (aarch64_store_exclusive_pair): New. * config/aarch64/iterators.md (JUST_TI): New. From-SVN: r275965 --- gcc/ChangeLog | 13 ++++++ gcc/config/aarch64/aarch64.c | 48 +++++++++++++++++---- gcc/config/aarch64/atomics.md | 93 ++++++++++++++++++++++++++++++++++++++--- gcc/config/aarch64/iterators.md | 3 ++ 4 files changed, 144 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3081b8b..d8749b9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -3,6 +3,19 @@ * config/aarch64/aarch64.c (aarch64_print_operand): Allow integer registers with %R. + * config/aarch64/aarch64.c (aarch64_gen_compare_reg): Add support + for NE comparison of TImode values. + (aarch64_emit_load_exclusive): Add support for TImode. + (aarch64_emit_store_exclusive): Likewise. + (aarch64_split_compare_and_swap): Disable strong_zero_p for TImode. + * config/aarch64/atomics.md (@atomic_compare_and_swap): + Change iterator from ALLI to ALLI_TI. + (@atomic_compare_and_swap): New. + (@atomic_compare_and_swap_lse): New. + (aarch64_load_exclusive_pair): New. + (aarch64_store_exclusive_pair): New. + * config/aarch64/iterators.md (JUST_TI): New. + 2019-09-19 Feng Xue * ipa-fnsummary.c (set_cond_stmt_execution_predicate): Do not compute diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 99d51e2..a5c4f55627 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -2039,10 +2039,33 @@ emit_set_insn (rtx x, rtx y) rtx aarch64_gen_compare_reg (RTX_CODE code, rtx x, rtx y) { - machine_mode mode = SELECT_CC_MODE (code, x, y); - rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM); + machine_mode cmp_mode = GET_MODE (x); + machine_mode cc_mode; + rtx cc_reg; - emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y)); + if (cmp_mode == TImode) + { + gcc_assert (code == NE); + + cc_mode = CCmode; + cc_reg = gen_rtx_REG (cc_mode, CC_REGNUM); + + rtx x_lo = operand_subword (x, 0, 0, TImode); + rtx y_lo = operand_subword (y, 0, 0, TImode); + emit_set_insn (cc_reg, gen_rtx_COMPARE (cc_mode, x_lo, y_lo)); + + rtx x_hi = operand_subword (x, 1, 0, TImode); + rtx y_hi = operand_subword (y, 1, 0, TImode); + emit_insn (gen_ccmpdi (cc_reg, cc_reg, x_hi, y_hi, + gen_rtx_EQ (cc_mode, cc_reg, const0_rtx), + GEN_INT (AARCH64_EQ))); + } + else + { + cc_mode = SELECT_CC_MODE (code, x, y); + cc_reg = gen_rtx_REG (cc_mode, CC_REGNUM); + emit_set_insn (cc_reg, gen_rtx_COMPARE (cc_mode, x, y)); + } return cc_reg; } @@ -2593,7 +2616,6 @@ aarch64_zero_extend_const_eq (machine_mode xmode, rtx x, gcc_assert (r != NULL); return rtx_equal_p (x, r); } - /* Return TARGET if it is nonnull and a register of mode MODE. Otherwise, return a fresh register of mode MODE if we can, @@ -16814,16 +16836,26 @@ static void aarch64_emit_load_exclusive (machine_mode mode, rtx rval, rtx mem, rtx model_rtx) { - emit_insn (gen_aarch64_load_exclusive (mode, rval, mem, model_rtx)); + if (mode == TImode) + emit_insn (gen_aarch64_load_exclusive_pair (gen_lowpart (DImode, rval), + gen_highpart (DImode, rval), + mem, model_rtx)); + else + emit_insn (gen_aarch64_load_exclusive (mode, rval, mem, model_rtx)); } /* Emit store exclusive. */ static void aarch64_emit_store_exclusive (machine_mode mode, rtx bval, - rtx rval, rtx mem, rtx model_rtx) + rtx mem, rtx rval, rtx model_rtx) { - emit_insn (gen_aarch64_store_exclusive (mode, bval, rval, mem, model_rtx)); + if (mode == TImode) + emit_insn (gen_aarch64_store_exclusive_pair + (bval, mem, operand_subword (rval, 0, 0, TImode), + operand_subword (rval, 1, 0, TImode), model_rtx)); + else + emit_insn (gen_aarch64_store_exclusive (mode, bval, mem, rval, model_rtx)); } /* Mark the previous jump instruction as unlikely. */ @@ -16950,7 +16982,7 @@ aarch64_split_compare_and_swap (rtx operands[]) CBNZ scratch, .label1 .label2: CMP rval, 0. */ - bool strong_zero_p = !is_weak && oldval == const0_rtx; + bool strong_zero_p = !is_weak && oldval == const0_rtx && mode != TImode; label1 = NULL; if (!is_weak) diff --git a/gcc/config/aarch64/atomics.md b/gcc/config/aarch64/atomics.md index a679270..f8bdd04 100644 --- a/gcc/config/aarch64/atomics.md +++ b/gcc/config/aarch64/atomics.md @@ -21,11 +21,11 @@ ;; Instruction patterns. (define_expand "@atomic_compare_and_swap" - [(match_operand:SI 0 "register_operand") ;; bool out - (match_operand:ALLI 1 "register_operand") ;; val out - (match_operand:ALLI 2 "aarch64_sync_memory_operand") ;; memory - (match_operand:ALLI 3 "nonmemory_operand") ;; expected - (match_operand:ALLI 4 "aarch64_reg_or_zero") ;; desired + [(match_operand:SI 0 "register_operand" "") ;; bool out + (match_operand:ALLI_TI 1 "register_operand" "") ;; val out + (match_operand:ALLI_TI 2 "aarch64_sync_memory_operand" "") ;; memory + (match_operand:ALLI_TI 3 "nonmemory_operand" "") ;; expected + (match_operand:ALLI_TI 4 "aarch64_reg_or_zero" "") ;; desired (match_operand:SI 5 "const_int_operand") ;; is_weak (match_operand:SI 6 "const_int_operand") ;; mod_s (match_operand:SI 7 "const_int_operand")] ;; mod_f @@ -88,6 +88,30 @@ } ) +(define_insn_and_split "@aarch64_compare_and_swap" + [(set (reg:CC CC_REGNUM) ;; bool out + (unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW)) + (set (match_operand:JUST_TI 0 "register_operand" "=&r") ;; val out + (match_operand:JUST_TI 1 "aarch64_sync_memory_operand" "+Q")) ;; memory + (set (match_dup 1) + (unspec_volatile:JUST_TI + [(match_operand:JUST_TI 2 "aarch64_reg_or_zero" "rZ") ;; expect + (match_operand:JUST_TI 3 "aarch64_reg_or_zero" "rZ") ;; desired + (match_operand:SI 4 "const_int_operand") ;; is_weak + (match_operand:SI 5 "const_int_operand") ;; mod_s + (match_operand:SI 6 "const_int_operand")] ;; mod_f + UNSPECV_ATOMIC_CMPSW)) + (clobber (match_scratch:SI 7 "=&r"))] + "" + "#" + "&& reload_completed" + [(const_int 0)] + { + aarch64_split_compare_and_swap (operands); + DONE; + } +) + (define_insn "@aarch64_compare_and_swap_lse" [(set (match_operand:SI 0 "register_operand" "+r") ;; val out (zero_extend:SI @@ -133,6 +157,28 @@ return "casal\t%0, %2, %1"; }) +(define_insn "@aarch64_compare_and_swap_lse" + [(set (match_operand:JUST_TI 0 "register_operand" "+r") ;; val out + (match_operand:JUST_TI 1 "aarch64_sync_memory_operand" "+Q")) ;; memory + (set (match_dup 1) + (unspec_volatile:JUST_TI + [(match_dup 0) ;; expect + (match_operand:JUST_TI 2 "register_operand" "r") ;; desired + (match_operand:SI 3 "const_int_operand")] ;; mod_s + UNSPECV_ATOMIC_CMPSW))] + "TARGET_LSE" +{ + enum memmodel model = memmodel_from_int (INTVAL (operands[3])); + if (is_mm_relaxed (model)) + return "casp\t%0, %R0, %2, %R2, %1"; + else if (is_mm_acquire (model) || is_mm_consume (model)) + return "caspa\t%0, %R0, %2, %R2, %1"; + else if (is_mm_release (model)) + return "caspl\t%0, %R0, %2, %R2, %1"; + else + return "caspal\t%0, %R0, %2, %R2, %1"; +}) + (define_expand "atomic_exchange" [(match_operand:ALLI 0 "register_operand") (match_operand:ALLI 1 "aarch64_sync_memory_operand") @@ -581,6 +627,24 @@ } ) +(define_insn "aarch64_load_exclusive_pair" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI + [(match_operand:TI 2 "aarch64_sync_memory_operand" "Q") + (match_operand:SI 3 "const_int_operand")] + UNSPECV_LX)) + (set (match_operand:DI 1 "register_operand" "=r") + (unspec_volatile:DI [(match_dup 2) (match_dup 3)] UNSPECV_LX))] + "" + { + enum memmodel model = memmodel_from_int (INTVAL (operands[3])); + if (is_mm_relaxed (model) || is_mm_consume (model) || is_mm_release (model)) + return "ldxp\t%0, %1, %2"; + else + return "ldaxp\t%0, %1, %2"; + } +) + (define_insn "@aarch64_store_exclusive" [(set (match_operand:SI 0 "register_operand" "=&r") (unspec_volatile:SI [(const_int 0)] UNSPECV_SX)) @@ -599,6 +663,25 @@ } ) +(define_insn "aarch64_store_exclusive_pair" + [(set (match_operand:SI 0 "register_operand" "=&r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_SX)) + (set (match_operand:TI 1 "aarch64_sync_memory_operand" "=Q") + (unspec_volatile:TI + [(match_operand:DI 2 "aarch64_reg_or_zero" "rZ") + (match_operand:DI 3 "aarch64_reg_or_zero" "rZ") + (match_operand:SI 4 "const_int_operand")] + UNSPECV_SX))] + "" + { + enum memmodel model = memmodel_from_int (INTVAL (operands[3])); + if (is_mm_relaxed (model) || is_mm_consume (model) || is_mm_acquire (model)) + return "stxp\t%w0, %x2, %x3, %1"; + else + return "stlxp\t%w0, %x2, %x3, %1"; + } +) + (define_expand "mem_thread_fence" [(match_operand:SI 0 "const_int_operand")] "" diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index d23f0fc..03b3ce3 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -29,6 +29,9 @@ ;; Iterator for HI, SI, DI, some instructions can only work on these modes. (define_mode_iterator GPI_I16 [(HI "AARCH64_ISA_F16") SI DI]) +;; "Iterator" for just TI -- features like @pattern only work with iterators. +(define_mode_iterator JUST_TI [TI]) + ;; Iterator for QI and HI modes (define_mode_iterator SHORT [QI HI]) -- cgit v1.1 From b7e560deb37e38fb224a0cf108e15df4a717167a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Sep 2019 14:36:33 +0000 Subject: aarch64: Tidy aarch64_split_compare_and_swap With aarch64_track_speculation, we had extra code to do exactly what the !strong_zero_p path already did. The rest is reducing code duplication. * config/aarch64/aarch64 (aarch64_split_compare_and_swap): Disable strong_zero_p for aarch64_track_speculation; unify some code paths; use aarch64_gen_compare_reg instead of open-coding. From-SVN: r275966 --- gcc/ChangeLog | 4 ++++ gcc/config/aarch64/aarch64.c | 50 +++++++++++++------------------------------- 2 files changed, 18 insertions(+), 36 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d8749b9..cef3a6e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -16,6 +16,10 @@ (aarch64_store_exclusive_pair): New. * config/aarch64/iterators.md (JUST_TI): New. + * config/aarch64/aarch64 (aarch64_split_compare_and_swap): Disable + strong_zero_p for aarch64_track_speculation; unify some code paths; + use aarch64_gen_compare_reg instead of open-coding. + 2019-09-19 Feng Xue * ipa-fnsummary.c (set_cond_stmt_execution_predicate): Do not compute diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index a5c4f55627..b937514 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -16955,13 +16955,11 @@ aarch64_emit_post_barrier (enum memmodel model) void aarch64_split_compare_and_swap (rtx operands[]) { - rtx rval, mem, oldval, newval, scratch; + rtx rval, mem, oldval, newval, scratch, x, model_rtx; machine_mode mode; bool is_weak; rtx_code_label *label1, *label2; - rtx x, cond; enum memmodel model; - rtx model_rtx; rval = operands[0]; mem = operands[1]; @@ -16982,7 +16980,8 @@ aarch64_split_compare_and_swap (rtx operands[]) CBNZ scratch, .label1 .label2: CMP rval, 0. */ - bool strong_zero_p = !is_weak && oldval == const0_rtx && mode != TImode; + bool strong_zero_p = (!is_weak && !aarch64_track_speculation && + oldval == const0_rtx && mode != TImode); label1 = NULL; if (!is_weak) @@ -16995,35 +16994,20 @@ aarch64_split_compare_and_swap (rtx operands[]) /* The initial load can be relaxed for a __sync operation since a final barrier will be emitted to stop code hoisting. */ if (is_mm_sync (model)) - aarch64_emit_load_exclusive (mode, rval, mem, - GEN_INT (MEMMODEL_RELAXED)); + aarch64_emit_load_exclusive (mode, rval, mem, GEN_INT (MEMMODEL_RELAXED)); else aarch64_emit_load_exclusive (mode, rval, mem, model_rtx); if (strong_zero_p) - { - if (aarch64_track_speculation) - { - /* Emit an explicit compare instruction, so that we can correctly - track the condition codes. */ - rtx cc_reg = aarch64_gen_compare_reg (NE, rval, const0_rtx); - x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx); - } - else - x = gen_rtx_NE (VOIDmode, rval, const0_rtx); - - x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, - gen_rtx_LABEL_REF (Pmode, label2), pc_rtx); - aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); - } + x = gen_rtx_NE (VOIDmode, rval, const0_rtx); else { - cond = aarch64_gen_compare_reg_maybe_ze (NE, rval, oldval, mode); - x = gen_rtx_NE (VOIDmode, cond, const0_rtx); - x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, - gen_rtx_LABEL_REF (Pmode, label2), pc_rtx); - aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); + rtx cc_reg = aarch64_gen_compare_reg_maybe_ze (NE, rval, oldval, mode); + x = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx); } + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, + gen_rtx_LABEL_REF (Pmode, label2), pc_rtx); + aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); aarch64_emit_store_exclusive (mode, scratch, mem, newval, model_rtx); @@ -17044,22 +17028,16 @@ aarch64_split_compare_and_swap (rtx operands[]) aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); } else - { - cond = gen_rtx_REG (CCmode, CC_REGNUM); - x = gen_rtx_COMPARE (CCmode, scratch, const0_rtx); - emit_insn (gen_rtx_SET (cond, x)); - } + aarch64_gen_compare_reg (NE, scratch, const0_rtx); emit_label (label2); + /* If we used a CBNZ in the exchange loop emit an explicit compare with RVAL to set the condition flags. If this is not used it will be removed by later passes. */ if (strong_zero_p) - { - cond = gen_rtx_REG (CCmode, CC_REGNUM); - x = gen_rtx_COMPARE (CCmode, rval, const0_rtx); - emit_insn (gen_rtx_SET (cond, x)); - } + aarch64_gen_compare_reg (NE, rval, const0_rtx); + /* Emit any final barrier needed for a __sync operation. */ if (is_mm_sync (model)) aarch64_emit_post_barrier (model); -- cgit v1.1 From 3950b229a5ed6710f30241c2ddc3c74909bf4740 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Sep 2019 14:36:43 +0000 Subject: aarch64: Implement -moutline-atomics * config/aarch64/aarch64.opt (-moutline-atomics): New. * config/aarch64/aarch64.c (aarch64_atomic_ool_func): New. (aarch64_ool_cas_names, aarch64_ool_swp_names): New. (aarch64_ool_ldadd_names, aarch64_ool_ldset_names): New. (aarch64_ool_ldclr_names, aarch64_ool_ldeor_names): New. (aarch64_expand_compare_and_swap): Honor TARGET_OUTLINE_ATOMICS. * config/aarch64/atomics.md (atomic_exchange): Likewise. (atomic_): Likewise. (atomic_fetch_): Likewise. (atomic__fetch): Likewise. * doc/invoke.texi: Document -moutline-atomics. testsuite/ * gcc.target/aarch64/atomic-op-acq_rel.c: Use -mno-outline-atomics. * gcc.target/aarch64/atomic-comp-swap-release-acquire.c: Likewise. * gcc.target/aarch64/atomic-op-acquire.c: Likewise. * gcc.target/aarch64/atomic-op-char.c: Likewise. * gcc.target/aarch64/atomic-op-consume.c: Likewise. * gcc.target/aarch64/atomic-op-imm.c: Likewise. * gcc.target/aarch64/atomic-op-int.c: Likewise. * gcc.target/aarch64/atomic-op-long.c: Likewise. * gcc.target/aarch64/atomic-op-relaxed.c: Likewise. * gcc.target/aarch64/atomic-op-release.c: Likewise. * gcc.target/aarch64/atomic-op-seq_cst.c: Likewise. * gcc.target/aarch64/atomic-op-short.c: Likewise. * gcc.target/aarch64/atomic_cmp_exchange_zero_reg_1.c: Likewise. * gcc.target/aarch64/atomic_cmp_exchange_zero_strong_1.c: Likewise. * gcc.target/aarch64/sync-comp-swap.c: Likewise. * gcc.target/aarch64/sync-op-acquire.c: Likewise. * gcc.target/aarch64/sync-op-full.c: Likewise. From-SVN: r275968 --- gcc/ChangeLog | 12 +++ gcc/config/aarch64/aarch64-protos.h | 13 +++ gcc/config/aarch64/aarch64.c | 87 ++++++++++++++++++++ gcc/config/aarch64/aarch64.opt | 3 + gcc/config/aarch64/atomics.md | 94 ++++++++++++++++++++-- gcc/doc/invoke.texi | 16 +++- gcc/testsuite/ChangeLog | 21 ++++- .../aarch64/atomic-comp-swap-release-acquire.c | 2 +- .../gcc.target/aarch64/atomic-op-acq_rel.c | 2 +- .../gcc.target/aarch64/atomic-op-acquire.c | 2 +- gcc/testsuite/gcc.target/aarch64/atomic-op-char.c | 2 +- .../gcc.target/aarch64/atomic-op-consume.c | 2 +- gcc/testsuite/gcc.target/aarch64/atomic-op-imm.c | 2 +- gcc/testsuite/gcc.target/aarch64/atomic-op-int.c | 2 +- gcc/testsuite/gcc.target/aarch64/atomic-op-long.c | 2 +- .../gcc.target/aarch64/atomic-op-relaxed.c | 2 +- .../gcc.target/aarch64/atomic-op-release.c | 2 +- .../gcc.target/aarch64/atomic-op-seq_cst.c | 2 +- gcc/testsuite/gcc.target/aarch64/atomic-op-short.c | 2 +- .../aarch64/atomic_cmp_exchange_zero_reg_1.c | 2 +- .../aarch64/atomic_cmp_exchange_zero_strong_1.c | 2 +- gcc/testsuite/gcc.target/aarch64/sync-comp-swap.c | 2 +- gcc/testsuite/gcc.target/aarch64/sync-op-acquire.c | 2 +- gcc/testsuite/gcc.target/aarch64/sync-op-full.c | 2 +- 24 files changed, 253 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cef3a6e..06faf82 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -20,6 +20,18 @@ strong_zero_p for aarch64_track_speculation; unify some code paths; use aarch64_gen_compare_reg instead of open-coding. + * config/aarch64/aarch64.opt (-moutline-atomics): New. + * config/aarch64/aarch64.c (aarch64_atomic_ool_func): New. + (aarch64_ool_cas_names, aarch64_ool_swp_names): New. + (aarch64_ool_ldadd_names, aarch64_ool_ldset_names): New. + (aarch64_ool_ldclr_names, aarch64_ool_ldeor_names): New. + (aarch64_expand_compare_and_swap): Honor TARGET_OUTLINE_ATOMICS. + * config/aarch64/atomics.md (atomic_exchange): Likewise. + (atomic_): Likewise. + (atomic_fetch_): Likewise. + (atomic__fetch): Likewise. + * doc/invoke.texi: Document -moutline-atomics. + 2019-09-19 Feng Xue * ipa-fnsummary.c (set_cond_stmt_execution_predicate): Do not compute diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index c4b73d2..1c1aac7 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -696,4 +696,17 @@ poly_uint64 aarch64_regmode_natural_size (machine_mode); bool aarch64_high_bits_all_ones_p (HOST_WIDE_INT); +struct atomic_ool_names +{ + const char *str[5][4]; +}; + +rtx aarch64_atomic_ool_func(machine_mode mode, rtx model_rtx, + const atomic_ool_names *names); +extern const atomic_ool_names aarch64_ool_swp_names; +extern const atomic_ool_names aarch64_ool_ldadd_names; +extern const atomic_ool_names aarch64_ool_ldset_names; +extern const atomic_ool_names aarch64_ool_ldclr_names; +extern const atomic_ool_names aarch64_ool_ldeor_names; + #endif /* GCC_AARCH64_PROTOS_H */ diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index b937514..56a4a47d 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -16867,6 +16867,82 @@ aarch64_emit_unlikely_jump (rtx insn) add_reg_br_prob_note (jump, profile_probability::very_unlikely ()); } +/* We store the names of the various atomic helpers in a 5x4 array. + Return the libcall function given MODE, MODEL and NAMES. */ + +rtx +aarch64_atomic_ool_func(machine_mode mode, rtx model_rtx, + const atomic_ool_names *names) +{ + memmodel model = memmodel_base (INTVAL (model_rtx)); + int mode_idx, model_idx; + + switch (mode) + { + case E_QImode: + mode_idx = 0; + break; + case E_HImode: + mode_idx = 1; + break; + case E_SImode: + mode_idx = 2; + break; + case E_DImode: + mode_idx = 3; + break; + case E_TImode: + mode_idx = 4; + break; + default: + gcc_unreachable (); + } + + switch (model) + { + case MEMMODEL_RELAXED: + model_idx = 0; + break; + case MEMMODEL_CONSUME: + case MEMMODEL_ACQUIRE: + model_idx = 1; + break; + case MEMMODEL_RELEASE: + model_idx = 2; + break; + case MEMMODEL_ACQ_REL: + case MEMMODEL_SEQ_CST: + model_idx = 3; + break; + default: + gcc_unreachable (); + } + + return init_one_libfunc_visibility (names->str[mode_idx][model_idx], + VISIBILITY_HIDDEN); +} + +#define DEF0(B, N) \ + { "__aarch64_" #B #N "_relax", \ + "__aarch64_" #B #N "_acq", \ + "__aarch64_" #B #N "_rel", \ + "__aarch64_" #B #N "_acq_rel" } + +#define DEF4(B) DEF0(B, 1), DEF0(B, 2), DEF0(B, 4), DEF0(B, 8), \ + { NULL, NULL, NULL, NULL } +#define DEF5(B) DEF0(B, 1), DEF0(B, 2), DEF0(B, 4), DEF0(B, 8), DEF0(B, 16) + +static const atomic_ool_names aarch64_ool_cas_names = { { DEF5(cas) } }; +const atomic_ool_names aarch64_ool_swp_names = { { DEF4(swp) } }; +const atomic_ool_names aarch64_ool_ldadd_names = { { DEF4(ldadd) } }; +const atomic_ool_names aarch64_ool_ldset_names = { { DEF4(ldset) } }; +const atomic_ool_names aarch64_ool_ldclr_names = { { DEF4(ldclr) } }; +const atomic_ool_names aarch64_ool_ldeor_names = { { DEF4(ldeor) } }; + +#undef DEF0 +#undef DEF4 +#undef DEF5 + /* Expand a compare and swap pattern. */ void @@ -16913,6 +16989,17 @@ aarch64_expand_compare_and_swap (rtx operands[]) newval, mod_s)); cc_reg = aarch64_gen_compare_reg_maybe_ze (NE, rval, oldval, mode); } + else if (TARGET_OUTLINE_ATOMICS) + { + /* Oldval must satisfy compare afterward. */ + if (!aarch64_plus_operand (oldval, mode)) + oldval = force_reg (mode, oldval); + rtx func = aarch64_atomic_ool_func (mode, mod_s, &aarch64_ool_cas_names); + rval = emit_library_call_value (func, NULL_RTX, LCT_NORMAL, r_mode, + oldval, mode, newval, mode, + XEXP (mem, 0), Pmode); + cc_reg = aarch64_gen_compare_reg_maybe_ze (NE, rval, oldval, mode); + } else { /* The oldval predicate varies by mode. Test it and force to reg. */ diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 55d4660..865b6a6 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -255,3 +255,6 @@ user-land code. TargetVariable long aarch64_stack_protector_guard_offset = 0 +moutline-atomics +Target Report Mask(OUTLINE_ATOMICS) Save +Generate local calls to out-of-line atomic operations. diff --git a/gcc/config/aarch64/atomics.md b/gcc/config/aarch64/atomics.md index f8bdd04..2e59b86 100644 --- a/gcc/config/aarch64/atomics.md +++ b/gcc/config/aarch64/atomics.md @@ -186,16 +186,27 @@ (match_operand:SI 3 "const_int_operand")] "" { - rtx (*gen) (rtx, rtx, rtx, rtx); - /* Use an atomic SWP when available. */ if (TARGET_LSE) - gen = gen_aarch64_atomic_exchange_lse; + { + emit_insn (gen_aarch64_atomic_exchange_lse + (operands[0], operands[1], operands[2], operands[3])); + } + else if (TARGET_OUTLINE_ATOMICS) + { + machine_mode mode = mode; + rtx func = aarch64_atomic_ool_func (mode, operands[3], + &aarch64_ool_swp_names); + rtx rval = emit_library_call_value (func, operands[0], LCT_NORMAL, + mode, operands[2], mode, + XEXP (operands[1], 0), Pmode); + emit_move_insn (operands[0], rval); + } else - gen = gen_aarch64_atomic_exchange; - - emit_insn (gen (operands[0], operands[1], operands[2], operands[3])); - + { + emit_insn (gen_aarch64_atomic_exchange + (operands[0], operands[1], operands[2], operands[3])); + } DONE; } ) @@ -280,6 +291,39 @@ } operands[1] = force_reg (mode, operands[1]); } + else if (TARGET_OUTLINE_ATOMICS) + { + const atomic_ool_names *names; + switch () + { + case MINUS: + operands[1] = expand_simple_unop (mode, NEG, operands[1], + NULL, 1); + /* fallthru */ + case PLUS: + names = &aarch64_ool_ldadd_names; + break; + case IOR: + names = &aarch64_ool_ldset_names; + break; + case XOR: + names = &aarch64_ool_ldeor_names; + break; + case AND: + operands[1] = expand_simple_unop (mode, NOT, operands[1], + NULL, 1); + names = &aarch64_ool_ldclr_names; + break; + default: + gcc_unreachable (); + } + machine_mode mode = mode; + rtx func = aarch64_atomic_ool_func (mode, operands[2], names); + emit_library_call_value (func, NULL_RTX, LCT_NORMAL, mode, + operands[1], mode, + XEXP (operands[0], 0), Pmode); + DONE; + } else gen = gen_aarch64_atomic_; @@ -405,6 +449,40 @@ } operands[2] = force_reg (mode, operands[2]); } + else if (TARGET_OUTLINE_ATOMICS) + { + const atomic_ool_names *names; + switch () + { + case MINUS: + operands[2] = expand_simple_unop (mode, NEG, operands[2], + NULL, 1); + /* fallthru */ + case PLUS: + names = &aarch64_ool_ldadd_names; + break; + case IOR: + names = &aarch64_ool_ldset_names; + break; + case XOR: + names = &aarch64_ool_ldeor_names; + break; + case AND: + operands[2] = expand_simple_unop (mode, NOT, operands[2], + NULL, 1); + names = &aarch64_ool_ldclr_names; + break; + default: + gcc_unreachable (); + } + machine_mode mode = mode; + rtx func = aarch64_atomic_ool_func (mode, operands[3], names); + rtx rval = emit_library_call_value (func, operands[0], LCT_NORMAL, mode, + operands[2], mode, + XEXP (operands[1], 0), Pmode); + emit_move_insn (operands[0], rval); + DONE; + } else gen = gen_aarch64_atomic_fetch_; @@ -494,7 +572,7 @@ { /* Use an atomic load-operate instruction when possible. In this case we will re-compute the result from the original mem value. */ - if (TARGET_LSE) + if (TARGET_LSE || TARGET_OUTLINE_ATOMICS) { rtx tmp = gen_reg_rtx (mode); operands[2] = force_reg (mode, operands[2]); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0e36935..6d67c12 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -643,7 +643,8 @@ Objective-C and Objective-C++ Dialects}. -march=@var{name} -mcpu=@var{name} -mtune=@var{name} @gol -moverride=@var{string} -mverbose-cost-dump @gol -mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{sysreg} @gol --mstack-protector-guard-offset=@var{offset} -mtrack-speculation } +-mstack-protector-guard-offset=@var{offset} -mtrack-speculation @gol +-moutline-atomics } @emph{Adapteva Epiphany Options} @gccoptlist{-mhalf-reg-file -mprefer-short-insn-regs @gol @@ -15874,6 +15875,19 @@ be used by the compiler when expanding calls to @code{__builtin_speculation_safe_copy} to permit a more efficient code sequence to be generated. +@item -moutline-atomics +@itemx -mno-outline-atomics +Enable or disable calls to out-of-line helpers to implement atomic operations. +These helpers will, at runtime, determine if the LSE instructions from +ARMv8.1-A can be used; if not, they will use the load/store-exclusive +instructions that are present in the base ARMv8.0 ISA. + +This option is only applicable when compiling for the base ARMv8.0 +instruction set. If using a later revision, e.g. @option{-march=armv8.1-a} +or @option{-march=armv8-a+lse}, the ARMv8.1-Atomics instructions will be +used directly. The same applies when using @option{-mcpu=} when the +selected cpu supports the @samp{lse} feature. + @item -march=@var{name} @opindex march Specify the name of the target architecture and, optionally, one or diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 79de33c..9d6d983 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,23 @@ +2019-09-19 Richard Henderson + + * gcc.target/aarch64/atomic-op-acq_rel.c: Use -mno-outline-atomics. + * gcc.target/aarch64/atomic-comp-swap-release-acquire.c: Likewise. + * gcc.target/aarch64/atomic-op-acquire.c: Likewise. + * gcc.target/aarch64/atomic-op-char.c: Likewise. + * gcc.target/aarch64/atomic-op-consume.c: Likewise. + * gcc.target/aarch64/atomic-op-imm.c: Likewise. + * gcc.target/aarch64/atomic-op-int.c: Likewise. + * gcc.target/aarch64/atomic-op-long.c: Likewise. + * gcc.target/aarch64/atomic-op-relaxed.c: Likewise. + * gcc.target/aarch64/atomic-op-release.c: Likewise. + * gcc.target/aarch64/atomic-op-seq_cst.c: Likewise. + * gcc.target/aarch64/atomic-op-short.c: Likewise. + * gcc.target/aarch64/atomic_cmp_exchange_zero_reg_1.c: Likewise. + * gcc.target/aarch64/atomic_cmp_exchange_zero_strong_1.c: Likewise. + * gcc.target/aarch64/sync-comp-swap.c: Likewise. + * gcc.target/aarch64/sync-op-acquire.c: Likewise. + * gcc.target/aarch64/sync-op-full.c: Likewise. + 2019-09-19 Feng Xue * gcc.dg/ipa/pr91089.c: Add a new function and pattern. @@ -7,7 +27,6 @@ PR tree-optimization/91812 * gcc.dg/torture/pr91812.c: New testcase. ->>>>>>> .r275960 2019-09-19 Tom Tromey * gnat.dg/bias1.adb: New testcase. diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-comp-swap-release-acquire.c b/gcc/testsuite/gcc.target/aarch64/atomic-comp-swap-release-acquire.c index 49ca5d0..a828a72 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-comp-swap-release-acquire.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-comp-swap-release-acquire.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2 -fno-ipa-icf" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -fno-ipa-icf -mno-outline-atomics" } */ #include "atomic-comp-swap-release-acquire.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-acq_rel.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-acq_rel.c index 74f2634..6823ce3 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-acq_rel.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-acq_rel.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-acq_rel.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-acquire.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-acquire.c index 66c1b1e..87937de 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-acquire.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-acquire.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-acquire.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-char.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-char.c index c09d043..60955e5 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-char.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-char.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-char.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-consume.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-consume.c index 5783ab8..16cb11a 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-consume.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-consume.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-consume.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-imm.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-imm.c index 18b8f0b..bcab4e4 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-imm.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-imm.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ int v = 0; diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-int.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-int.c index 8520f08..040e4a8 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-int.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-int.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-int.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-long.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-long.c index d011f8c..fc88b92 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-long.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-long.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ long v = 0; diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-relaxed.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-relaxed.c index ed96bfd..503d62b 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-relaxed.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-relaxed.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-relaxed.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-release.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-release.c index fc4be17..efe14ae 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-release.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-release.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-release.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-seq_cst.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-seq_cst.c index 613000f..09973bf 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-seq_cst.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-seq_cst.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-seq_cst.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-op-short.c b/gcc/testsuite/gcc.target/aarch64/atomic-op-short.c index e82c811..e1dcebb 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic-op-short.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic-op-short.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "atomic-op-short.x" diff --git a/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_reg_1.c b/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_reg_1.c index f2a21dd..2924697 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_reg_1.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_reg_1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -march=armv8-a+nolse" } */ +/* { dg-options "-O2 -march=armv8-a+nolse -mno-outline-atomics" } */ /* { dg-skip-if "" { *-*-* } { "-mcpu=*" } { "" } } */ int diff --git a/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_strong_1.c b/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_strong_1.c index 8d2ae67..6daf9b0 100644 --- a/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_strong_1.c +++ b/gcc/testsuite/gcc.target/aarch64/atomic_cmp_exchange_zero_strong_1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -march=armv8-a+nolse" } */ +/* { dg-options "-O2 -march=armv8-a+nolse -mno-outline-atomics" } */ /* { dg-skip-if "" { *-*-* } { "-mcpu=*" } { "" } } */ int diff --git a/gcc/testsuite/gcc.target/aarch64/sync-comp-swap.c b/gcc/testsuite/gcc.target/aarch64/sync-comp-swap.c index e571b2f..f56415f 100644 --- a/gcc/testsuite/gcc.target/aarch64/sync-comp-swap.c +++ b/gcc/testsuite/gcc.target/aarch64/sync-comp-swap.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2 -fno-ipa-icf" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -fno-ipa-icf -mno-outline-atomics" } */ #include "sync-comp-swap.x" diff --git a/gcc/testsuite/gcc.target/aarch64/sync-op-acquire.c b/gcc/testsuite/gcc.target/aarch64/sync-op-acquire.c index 357bf1b..39b3144 100644 --- a/gcc/testsuite/gcc.target/aarch64/sync-op-acquire.c +++ b/gcc/testsuite/gcc.target/aarch64/sync-op-acquire.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "sync-op-acquire.x" diff --git a/gcc/testsuite/gcc.target/aarch64/sync-op-full.c b/gcc/testsuite/gcc.target/aarch64/sync-op-full.c index c6ba162..6b8b204 100644 --- a/gcc/testsuite/gcc.target/aarch64/sync-op-full.c +++ b/gcc/testsuite/gcc.target/aarch64/sync-op-full.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=armv8-a+nolse -O2" } */ +/* { dg-options "-march=armv8-a+nolse -O2 -mno-outline-atomics" } */ #include "sync-op-full.x" -- cgit v1.1 From 9f576d304d65c184572a6f8ce7541196e5da5c1c Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 19 Sep 2019 17:16:15 +0200 Subject: Fix cast in sort_congruence_class_groups_by_decl_uid. 2019-09-19 Martin Liska * ipa-icf.c (sort_congruence_class_groups_by_decl_uid): Use proper casting. From-SVN: r275969 --- gcc/ChangeLog | 5 +++++ gcc/ipa-icf.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 06faf82..ac055ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Martin Liska + + * ipa-icf.c (sort_congruence_class_groups_by_decl_uid): + Use proper casting. + 2019-09-19 Richard Henderson * config/aarch64/aarch64.c (aarch64_print_operand): Allow integer diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c index 59b7f8b..009aeb4 100644 --- a/gcc/ipa-icf.c +++ b/gcc/ipa-icf.c @@ -3373,9 +3373,9 @@ static int sort_congruence_class_groups_by_decl_uid (const void *a, const void *b) { const std::pair *g1 - = *(const std::pair *const *) a; + = (const std::pair *) a; const std::pair *g2 - = *(const std::pair *const *) b; + = (const std::pair *) b; return g1->second - g2->second; } -- cgit v1.1 From 40858b9dfb72960bff5978b1441d0f2d21ae55ba Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Thu, 19 Sep 2019 16:51:08 +0000 Subject: [ARM] Simplify logical DImode iterators Further simplify the logical DImode expander using code iterator and obtab attributes. This avoids adding unnecessary code_attr entries. gcc/ * config/arm/arm.md (di3): Use and . * config/arm/iterators.md (optab): Add and, ior, xor entries. (logical_op): Remove code attribute. (logical_OP): Likewise. From-SVN: r275970 --- gcc/ChangeLog | 7 +++++++ gcc/config/arm/arm.md | 8 ++++---- gcc/config/arm/iterators.md | 12 ++++++++---- 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ac055ef..3be2b55 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Wilco Dijkstra + + * config/arm/arm.md (di3): Use and . + * config/arm/iterators.md (optab): Add and, ior, xor entries. + (logical_op): Remove code attribute. + (logical_OP): Likewise. + 2019-09-19 Martin Liska * ipa-icf.c (sort_congruence_class_groups_by_decl_uid): diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index d54082b..d607f88 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -2039,16 +2039,16 @@ ; operands or complex immediates, which leads to fewer LDRD/STRD instructions. ; So an explicit expander is needed to generate better code. -(define_expand "di3" +(define_expand "di3" [(set (match_operand:DI 0 "s_register_operand") (LOGICAL:DI (match_operand:DI 1 "s_register_operand") - (match_operand:DI 2 "arm_di_operand")))] + (match_operand:DI 2 "arm_di_operand")))] "TARGET_32BIT" { - rtx low = simplify_gen_binary (, SImode, + rtx low = simplify_gen_binary (, SImode, gen_lowpart (SImode, operands[1]), gen_lowpart (SImode, operands[2])); - rtx high = simplify_gen_binary (, SImode, + rtx high = simplify_gen_binary (, SImode, gen_highpart (SImode, operands[1]), gen_highpart_mode (SImode, DImode, operands[2])); diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 5e3299e..2d8ef3f 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -287,9 +287,6 @@ (define_code_attr vfml_op [(plus "a") (minus "s")]) -(define_code_attr logical_op [(ior "ior") (xor "xor") (and "and")]) -(define_code_attr logical_OP [(ior "IOR") (xor "XOR") (and "AND")]) - ;;---------------------------------------------------------------------------- ;; Int iterators ;;---------------------------------------------------------------------------- @@ -797,7 +794,14 @@ (umax "u")]) (define_code_attr cnb [(ltu "CC_C") (geu "CC")]) -(define_code_attr optab [(ltu "ltu") (geu "geu")]) + +;; Map rtl operator codes to optab names +(define_code_attr optab + [(ltu "ltu") + (geu "geu") + (and "and") + (ior "ior") + (xor "xor")]) ;; Assembler mnemonics for signedness of widening operations. (define_code_attr US [(sign_extend "s") (zero_extend "u")]) -- cgit v1.1 From 54dc857754b64ae1e56191d983ae2c4434d96fb2 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 19 Sep 2019 17:05:51 +0000 Subject: re PR target/91814 (ICE in elimination_costs_in_insn, at reload1.c:3549 since r274926) 2019-09-19 Richard Biener PR target/91814 * config/i386/i386-features.c (gen_gpr_to_xmm_move_src): Force operand to a register if it isn't nonimmediate_operand. From-SVN: r275971 --- gcc/ChangeLog | 6 ++++++ gcc/config/i386/i386-features.c | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3be2b55..9010eae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-19 Richard Biener + + PR target/91814 + * config/i386/i386-features.c (gen_gpr_to_xmm_move_src): + Force operand to a register if it isn't nonimmediate_operand. + 2019-09-19 Wilco Dijkstra * config/arm/arm.md (di3): Use and . diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index 454eeae..f57a555 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -668,10 +668,13 @@ scalar_chain::emit_conversion_insns (rtx insns, rtx_insn *after) static rtx gen_gpr_to_xmm_move_src (enum machine_mode vmode, rtx gpr) { + if (!nonimmediate_operand (gpr, GET_MODE_INNER (vmode))) + gpr = force_reg (GET_MODE_INNER (vmode), gpr); switch (GET_MODE_NUNITS (vmode)) { case 1: - return gen_rtx_SUBREG (vmode, gpr, 0); + /* We are not using this case currently. */ + gcc_unreachable (); case 2: return gen_rtx_VEC_CONCAT (vmode, gpr, CONST0_RTX (GET_MODE_INNER (vmode))); -- cgit v1.1 From b3c4d0dd309b7027f6e0f0b9a84829fcd53f7d64 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 19 Sep 2019 17:19:31 +0000 Subject: tree-vect-loop.c (vect_is_slp_reduction): Remove. 2019-09-19 Richard Biener * tree-vect-loop.c (vect_is_slp_reduction): Remove. (check_reduction_path): New overload having the path as result. (vect_is_simple_reduction): From the detected reduction path build a SLP reduction chain if possible. From-SVN: r275972 --- gcc/ChangeLog | 7 ++ gcc/tree-vect-loop.c | 219 +++++++++++---------------------------------------- 2 files changed, 54 insertions(+), 172 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9010eae..e7feded 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-19 Richard Biener + * tree-vect-loop.c (vect_is_slp_reduction): Remove. + (check_reduction_path): New overload having the path as result. + (vect_is_simple_reduction): From the detected reduction + path build a SLP reduction chain if possible. + +2019-09-19 Richard Biener + PR target/91814 * config/i386/i386-features.c (gen_gpr_to_xmm_move_src): Force operand to a register if it isn't nonimmediate_operand. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index aec4462..9a4d960d 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -2541,163 +2541,6 @@ vect_valid_reduction_input_p (stmt_vec_info def_stmt_info) && !is_loop_header_bb_p (gimple_bb (def_stmt_info->stmt)))); } -/* Detect SLP reduction of the form: - - #a1 = phi - a2 = operation (a1) - a3 = operation (a2) - a4 = operation (a3) - a5 = operation (a4) - - #a = phi - - PHI is the reduction phi node (#a1 = phi above) - FIRST_STMT is the first reduction stmt in the chain - (a2 = operation (a1)). - - Return TRUE if a reduction chain was detected. */ - -static bool -vect_is_slp_reduction (loop_vec_info loop_info, gimple *phi, - gimple *first_stmt) -{ - class loop *loop = (gimple_bb (phi))->loop_father; - class loop *vect_loop = LOOP_VINFO_LOOP (loop_info); - enum tree_code code; - gimple *loop_use_stmt = NULL; - stmt_vec_info use_stmt_info; - tree lhs; - imm_use_iterator imm_iter; - use_operand_p use_p; - int nloop_uses, size = 0, n_out_of_loop_uses; - bool found = false; - - if (loop != vect_loop) - return false; - - auto_vec reduc_chain; - lhs = PHI_RESULT (phi); - code = gimple_assign_rhs_code (first_stmt); - while (1) - { - nloop_uses = 0; - n_out_of_loop_uses = 0; - FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) - { - gimple *use_stmt = USE_STMT (use_p); - if (is_gimple_debug (use_stmt)) - continue; - - /* Check if we got back to the reduction phi. */ - if (use_stmt == phi) - { - loop_use_stmt = use_stmt; - found = true; - break; - } - - if (flow_bb_inside_loop_p (loop, gimple_bb (use_stmt))) - { - loop_use_stmt = use_stmt; - nloop_uses++; - } - else - n_out_of_loop_uses++; - - /* There are can be either a single use in the loop or two uses in - phi nodes. */ - if (nloop_uses > 1 || (n_out_of_loop_uses && nloop_uses)) - return false; - } - - if (found) - break; - - /* We reached a statement with no loop uses. */ - if (nloop_uses == 0) - return false; - - /* This is a loop exit phi, and we haven't reached the reduction phi. */ - if (gimple_code (loop_use_stmt) == GIMPLE_PHI) - return false; - - if (!is_gimple_assign (loop_use_stmt) - || code != gimple_assign_rhs_code (loop_use_stmt) - || !flow_bb_inside_loop_p (loop, gimple_bb (loop_use_stmt))) - return false; - - /* Insert USE_STMT into reduction chain. */ - use_stmt_info = loop_info->lookup_stmt (loop_use_stmt); - reduc_chain.safe_push (use_stmt_info); - - lhs = gimple_assign_lhs (loop_use_stmt); - size++; - } - - if (!found || loop_use_stmt != phi || size < 2) - return false; - - /* Swap the operands, if needed, to make the reduction operand be the second - operand. */ - lhs = PHI_RESULT (phi); - for (unsigned i = 0; i < reduc_chain.length (); ++i) - { - gassign *next_stmt = as_a (reduc_chain[i]->stmt); - if (gimple_assign_rhs2 (next_stmt) == lhs) - { - tree op = gimple_assign_rhs1 (next_stmt); - stmt_vec_info def_stmt_info = loop_info->lookup_def (op); - - /* Check that the other def is either defined in the loop - ("vect_internal_def"), or it's an induction (defined by a - loop-header phi-node). */ - if (def_stmt_info - && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt)) - && vect_valid_reduction_input_p (def_stmt_info)) - { - lhs = gimple_assign_lhs (next_stmt); - continue; - } - - return false; - } - else - { - gcc_assert (gimple_assign_rhs1 (next_stmt) == lhs); - tree op = gimple_assign_rhs2 (next_stmt); - stmt_vec_info def_stmt_info = loop_info->lookup_def (op); - - /* Check that the other def is either defined in the loop - ("vect_internal_def"), or it's an induction (defined by a - loop-header phi-node). */ - if (def_stmt_info - && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt_info->stmt)) - && vect_valid_reduction_input_p (def_stmt_info)) - { - lhs = gimple_assign_lhs (next_stmt); - continue; - } - - return false; - } - } - - /* Build up the actual chain. */ - for (unsigned i = 0; i < reduc_chain.length () - 1; ++i) - { - REDUC_GROUP_FIRST_ELEMENT (reduc_chain[i]) = reduc_chain[0]; - REDUC_GROUP_NEXT_ELEMENT (reduc_chain[i]) = reduc_chain[i+1]; - } - REDUC_GROUP_FIRST_ELEMENT (reduc_chain.last ()) = reduc_chain[0]; - REDUC_GROUP_NEXT_ELEMENT (reduc_chain.last ()) = NULL; - - /* Save the chain for further analysis in SLP detection. */ - LOOP_VINFO_REDUCTION_CHAINS (loop_info).safe_push (reduc_chain[0]); - REDUC_GROUP_SIZE (reduc_chain[0]) = size; - - return true; -} - /* Return true if we need an in-order reduction for operation CODE on type TYPE. NEED_WRAPPING_INTEGRAL_OVERFLOW is true if integer overflow must wrap. */ @@ -2738,11 +2581,11 @@ needs_fold_left_reduction_p (tree type, tree_code code, /* Return true if the reduction PHI in LOOP with latch arg LOOP_ARG and reduction operation CODE has a handled computation expression. */ -bool +static bool check_reduction_path (dump_user_location_t loc, loop_p loop, gphi *phi, - tree loop_arg, enum tree_code code) + tree loop_arg, enum tree_code code, + vec > &path) { - auto_vec > path; auto_bitmap visited; tree lookfor = PHI_RESULT (phi); ssa_op_iter curri; @@ -2839,6 +2682,15 @@ pop: return ! fail && ! neg; } +bool +check_reduction_path (dump_user_location_t loc, loop_p loop, gphi *phi, + tree loop_arg, enum tree_code code) +{ + auto_vec > path; + return check_reduction_path (loc, loop, phi, loop_arg, code, path); +} + + /* Function vect_is_simple_reduction @@ -3223,23 +3075,46 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, return def_stmt_info; } - /* Try to find SLP reduction chain. */ - if (! nested_in_vect_loop - && code != COND_EXPR - && orig_code != MINUS_EXPR - && vect_is_slp_reduction (loop_info, phi, def_stmt)) + /* Look for the expression computing loop_arg from loop PHI result. */ + auto_vec > path; + if (check_reduction_path (vect_location, loop, phi, loop_arg, code, + path)) { - if (dump_enabled_p ()) - report_vect_op (MSG_NOTE, def_stmt, - "reduction: detected reduction chain: "); + /* Try building an SLP reduction chain for which the additional + restriction is that all operations in the chain are the same. */ + auto_vec reduc_chain; + unsigned i; + for (i = path.length () - 1; i >= 1; --i) + { + gimple *stmt = USE_STMT (path[i].second); + if (gimple_assign_rhs_code (stmt) != code) + break; + reduc_chain.safe_push (loop_info->lookup_stmt (stmt)); + } + if (i == 0 + && ! nested_in_vect_loop + && code != COND_EXPR) + { + for (unsigned i = 0; i < reduc_chain.length () - 1; ++i) + { + REDUC_GROUP_FIRST_ELEMENT (reduc_chain[i]) = reduc_chain[0]; + REDUC_GROUP_NEXT_ELEMENT (reduc_chain[i]) = reduc_chain[i+1]; + } + REDUC_GROUP_FIRST_ELEMENT (reduc_chain.last ()) = reduc_chain[0]; + REDUC_GROUP_NEXT_ELEMENT (reduc_chain.last ()) = NULL; + + /* Save the chain for further analysis in SLP detection. */ + LOOP_VINFO_REDUCTION_CHAINS (loop_info).safe_push (reduc_chain[0]); + REDUC_GROUP_SIZE (reduc_chain[0]) = reduc_chain.length (); + + if (dump_enabled_p ()) + report_vect_op (MSG_NOTE, def_stmt, + "reduction: detected reduction chain: "); + } return def_stmt_info; } - /* Look for the expression computing loop_arg from loop PHI result. */ - if (check_reduction_path (vect_location, loop, phi, loop_arg, code)) - return def_stmt_info; - if (dump_enabled_p ()) { report_vect_op (MSG_MISSED_OPTIMIZATION, def_stmt, -- cgit v1.1 From e564cf98de47f843a21e98c4cb18bf644f4bb604 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 19 Sep 2019 15:39:22 -0400 Subject: Revert "Fix conversions for built-in operator overloading candidates." This reverts commit 948d5b831affef14a49f56804b01e3f1ba00cdb3. From-SVN: r275976 --- gcc/cp/ChangeLog | 8 ++++++++ gcc/cp/call.c | 51 ++++++++++++++++++++++++++------------------------- gcc/cp/typeck.c | 4 ++-- 3 files changed, 36 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index efa1686..de1677f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-09-19 Jason Merrill + + Revert: + * call.c (build_new_op_1): Don't apply any standard conversions to + the operands of a built-in operator. Don't suppress conversions in + cp_build_unary_op. + * typeck.c (cp_build_unary_op): Do integral promotions for enums. + 2019-09-16 Paolo Carlini * decl.c (grokdeclarator): Use declspecs->locations and diff --git a/gcc/cp/call.c b/gcc/cp/call.c index b780b0a..e613d8a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6142,40 +6142,41 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, break; } - /* "If a built-in candidate is selected by overload resolution, the - operands of class type are converted to the types of the - corresponding parameters of the selected operation function, - except that the second standard conversion sequence of a - user-defined conversion sequence (12.3.3.1.2) is not applied." */ + /* We need to strip any leading REF_BIND so that bitfields + don't cause errors. This should not remove any important + conversions, because builtins don't apply to class + objects directly. */ conv = cand->convs[0]; - if (conv->user_conv_p) - { - while (conv->kind != ck_user) - conv = next_conversion (conv); - arg1 = convert_like (conv, arg1, complain); - } + if (conv->kind == ck_ref_bind) + conv = next_conversion (conv); + arg1 = convert_like (conv, arg1, complain); if (arg2) { conv = cand->convs[1]; - if (conv->user_conv_p) - { - while (conv->kind != ck_user) - conv = next_conversion (conv); - arg2 = convert_like (conv, arg2, complain); - } - } + if (conv->kind == ck_ref_bind) + conv = next_conversion (conv); + else + arg2 = decay_conversion (arg2, complain); + /* We need to call warn_logical_operator before + converting arg2 to a boolean_type, but after + decaying an enumerator to its value. */ + if (complain & tf_warning) + warn_logical_operator (loc, code, boolean_type_node, + code_orig_arg1, arg1, + code_orig_arg2, arg2); + + arg2 = convert_like (conv, arg2, complain); + } if (arg3) { conv = cand->convs[2]; - if (conv->user_conv_p) - { - while (conv->kind != ck_user) - conv = next_conversion (conv); - arg3 = convert_like (conv, arg3, complain); - } + if (conv->kind == ck_ref_bind) + conv = next_conversion (conv); + convert_like (conv, arg3, complain); } + } } @@ -6243,7 +6244,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, case REALPART_EXPR: case IMAGPART_EXPR: case ABS_EXPR: - return cp_build_unary_op (code, arg1, false, complain); + return cp_build_unary_op (code, arg1, candidates != 0, complain); case ARRAY_REF: return cp_build_array_ref (input_location, arg1, arg2, complain); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index c6bf41e..d85e547 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6249,7 +6249,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, : _("wrong type argument to unary plus")); else { - if (!noconvert && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg))) + if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg))) arg = cp_perform_integral_promotions (arg, complain); /* Make sure the result is not an lvalue: a unary plus or minus @@ -6274,7 +6274,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, | WANT_VECTOR_OR_COMPLEX, arg, true))) errstring = _("wrong type argument to bit-complement"); - else if (!noconvert && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg))) + else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg))) { /* Warn if the expression has boolean value. */ if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE -- cgit v1.1 From a519efbef81fbd8ae9c4766f878e64ed7a0d8f7d Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 19 Sep 2019 19:39:30 +0000 Subject: [Darwin, PPC, testsuite] Fix pr89313.c fail. Darwin defines '__POWERPC__' rather than '__powerpc__' so check for the upper case version too in order to select the correct register name. gcc/testsuite: 2019-09-19 Iain Sandoe * gcc.dg/pr89313.c: Test for __POWERPC__ in addition to __powerpc__ in register name selection. From-SVN: r275977 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/pr89313.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9d6d983..7efdac9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-19 Iain Sandoe + + * gcc.dg/pr89313.c: Test for __POWERPC__ in addition to + __powerpc__ in register name selection. + 2019-09-19 Richard Henderson * gcc.target/aarch64/atomic-op-acq_rel.c: Use -mno-outline-atomics. diff --git a/gcc/testsuite/gcc.dg/pr89313.c b/gcc/testsuite/gcc.dg/pr89313.c index 6688323..76cb091 100644 --- a/gcc/testsuite/gcc.dg/pr89313.c +++ b/gcc/testsuite/gcc.dg/pr89313.c @@ -8,7 +8,7 @@ # define REG "r0" #elif defined (__i386__) # define REG "%eax" -#elif defined (__powerpc__) +#elif defined (__powerpc__) || defined (__POWERPC__) # define REG "r3" #elif defined (__s390__) # define REG "0" -- cgit v1.1 From e0710fcf7dc70054a9a20ab1b8d77f4fef26ef2c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 19 Sep 2019 15:41:17 -0400 Subject: Handle [[likely]] on compound-statement. I overlooked this case when adding [[likely]] handling to cp_parser_statement. * parser.c (cp_parser_statement): Handle [[likely]] on compound-statement. From-SVN: r275978 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/parser.c | 5 ++++- gcc/testsuite/g++.dg/cpp2a/attr-likely5.C | 9 +++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/attr-likely5.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index de1677f..3015d68 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-09-17 Jason Merrill + + * parser.c (cp_parser_statement): Handle [[likely]] on + compound-statement. + 2019-09-19 Jason Merrill Revert: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 165039e..da0ffac 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11297,7 +11297,10 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, } /* Anything that starts with a `{' must be a compound-statement. */ else if (token->type == CPP_OPEN_BRACE) - statement = cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false); + { + std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); + statement = cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false); + } /* CPP_PRAGMA is a #pragma inside a function body, which constitutes a statement all its own. */ else if (token->type == CPP_PRAGMA) diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely5.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely5.C new file mode 100644 index 0000000..1662148 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely5.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } + +void f(int i) +{ + if (i) [[likely]] + { + ++i; + } +} -- cgit v1.1 From 7d112d6670a0e0e662f8a7e64c33686e475832c8 Mon Sep 17 00:00:00 2001 From: Lewis Hyatt Date: Thu, 19 Sep 2019 19:56:11 +0000 Subject: Support extended characters in C/C++ identifiers (PR c/67224) libcpp/ChangeLog 2019-09-19 Lewis Hyatt PR c/67224 * charset.c (_cpp_valid_utf8): New function to help lex UTF-8 tokens. * internal.h (_cpp_valid_utf8): Declare. * lex.c (forms_identifier_p): Use it to recognize UTF-8 identifiers. (_cpp_lex_direct): Handle UTF-8 in identifiers and CPP_OTHER tokens. Do all work in "default" case to avoid slowing down typical code paths. Also handle $ and UCN in the default case for consistency. gcc/Changelog 2019-09-19 Lewis Hyatt PR c/67224 * doc/cpp.texi: Document support for extended characters in identifiers. * doc/cppopts.texi: Likewise. gcc/testsuite/ChangeLog 2019-09-19 Lewis Hyatt PR c/67224 * c-c++-common/cpp/ucnid-2011-1-utf8.c: New test. * g++.dg/cpp/ucnid-1-utf8.C: New test. * g++.dg/cpp/ucnid-2-utf8.C: New test. * g++.dg/cpp/ucnid-3-utf8.C: New test. * g++.dg/cpp/ucnid-4-utf8.C: New test. * g++.dg/other/ucnid-1-utf8.C: New test. * gcc.dg/cpp/ucnid-1-utf8.c: New test. * gcc.dg/cpp/ucnid-10-utf8.c: New test. * gcc.dg/cpp/ucnid-11-utf8.c: New test. * gcc.dg/cpp/ucnid-12-utf8.c: New test. * gcc.dg/cpp/ucnid-13-utf8.c: New test. * gcc.dg/cpp/ucnid-14-utf8.c: New test. * gcc.dg/cpp/ucnid-15-utf8.c: New test. * gcc.dg/cpp/ucnid-2-utf8.c: New test. * gcc.dg/cpp/ucnid-3-utf8.c: New test. * gcc.dg/cpp/ucnid-4-utf8.c: New test. * gcc.dg/cpp/ucnid-6-utf8.c: New test. * gcc.dg/cpp/ucnid-7-utf8.c: New test. * gcc.dg/cpp/ucnid-9-utf8.c: New test. * gcc.dg/ucnid-1-utf8.c: New test. * gcc.dg/ucnid-10-utf8.c: New test. * gcc.dg/ucnid-11-utf8.c: New test. * gcc.dg/ucnid-12-utf8.c: New test. * gcc.dg/ucnid-13-utf8.c: New test. * gcc.dg/ucnid-14-utf8.c: New test. * gcc.dg/ucnid-15-utf8.c: New test. * gcc.dg/ucnid-16-utf8.c: New test. * gcc.dg/ucnid-2-utf8.c: New test. * gcc.dg/ucnid-3-utf8.c: New test. * gcc.dg/ucnid-4-utf8.c: New test. * gcc.dg/ucnid-5-utf8.c: New test. * gcc.dg/ucnid-6-utf8.c: New test. * gcc.dg/ucnid-7-utf8.c: New test. * gcc.dg/ucnid-8-utf8.c: New test. * gcc.dg/ucnid-9-utf8.c: New test. From-SVN: r275979 --- gcc/ChangeLog | 7 ++++ gcc/doc/cpp.texi | 32 +++++++++--------- gcc/doc/cppopts.texi | 5 +-- gcc/testsuite/ChangeLog | 39 ++++++++++++++++++++++ gcc/testsuite/c-c++-common/cpp/ucnid-2011-1-utf8.c | 15 +++++++++ gcc/testsuite/g++.dg/cpp/ucnid-1-utf8.C | 17 ++++++++++ gcc/testsuite/g++.dg/cpp/ucnid-2-utf8.C | 24 +++++++++++++ gcc/testsuite/g++.dg/cpp/ucnid-3-utf8.C | 23 +++++++++++++ gcc/testsuite/g++.dg/cpp/ucnid-4-utf8.C | 17 ++++++++++ gcc/testsuite/g++.dg/other/ucnid-1-utf8.C | 28 ++++++++++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-1-utf8.c | 26 +++++++++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-10-utf8.c | 8 +++++ gcc/testsuite/gcc.dg/cpp/ucnid-11-utf8.c | 30 +++++++++++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-12-utf8.c | 13 ++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-13-utf8.c | 5 +++ gcc/testsuite/gcc.dg/cpp/ucnid-14-utf8.c | 6 ++++ gcc/testsuite/gcc.dg/cpp/ucnid-15-utf8.c | 6 ++++ gcc/testsuite/gcc.dg/cpp/ucnid-2-utf8.c | 16 +++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-3-utf8.c | 7 ++++ gcc/testsuite/gcc.dg/cpp/ucnid-4-utf8.c | 17 ++++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-6-utf8.c | 5 +++ gcc/testsuite/gcc.dg/cpp/ucnid-7-utf8.c | 21 ++++++++++++ gcc/testsuite/gcc.dg/cpp/ucnid-9-utf8.c | 8 +++++ gcc/testsuite/gcc.dg/ucnid-1-utf8.c | 25 ++++++++++++++ gcc/testsuite/gcc.dg/ucnid-10-utf8.c | 11 ++++++ gcc/testsuite/gcc.dg/ucnid-11-utf8.c | 7 ++++ gcc/testsuite/gcc.dg/ucnid-12-utf8.c | 7 ++++ gcc/testsuite/gcc.dg/ucnid-13-utf8.c | 15 +++++++++ gcc/testsuite/gcc.dg/ucnid-14-utf8.c | 23 +++++++++++++ gcc/testsuite/gcc.dg/ucnid-15-utf8.c | 38 +++++++++++++++++++++ gcc/testsuite/gcc.dg/ucnid-16-utf8.c | 6 ++++ gcc/testsuite/gcc.dg/ucnid-2-utf8.c | 28 ++++++++++++++++ gcc/testsuite/gcc.dg/ucnid-3-utf8.c | 28 ++++++++++++++++ gcc/testsuite/gcc.dg/ucnid-4-utf8.c | 28 ++++++++++++++++ gcc/testsuite/gcc.dg/ucnid-5-utf8.c | 19 +++++++++++ gcc/testsuite/gcc.dg/ucnid-6-utf8.c | 28 ++++++++++++++++ gcc/testsuite/gcc.dg/ucnid-7-utf8.c | 9 +++++ gcc/testsuite/gcc.dg/ucnid-8-utf8.c | 16 +++++++++ gcc/testsuite/gcc.dg/ucnid-9-utf8.c | 25 ++++++++++++++ 39 files changed, 671 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/cpp/ucnid-2011-1-utf8.c create mode 100644 gcc/testsuite/g++.dg/cpp/ucnid-1-utf8.C create mode 100644 gcc/testsuite/g++.dg/cpp/ucnid-2-utf8.C create mode 100644 gcc/testsuite/g++.dg/cpp/ucnid-3-utf8.C create mode 100644 gcc/testsuite/g++.dg/cpp/ucnid-4-utf8.C create mode 100644 gcc/testsuite/g++.dg/other/ucnid-1-utf8.C create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-1-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-10-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-11-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-12-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-13-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-14-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-15-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-2-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-3-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-4-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-6-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-7-utf8.c create mode 100644 gcc/testsuite/gcc.dg/cpp/ucnid-9-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-1-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-10-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-11-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-12-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-13-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-14-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-15-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-16-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-2-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-3-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-4-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-5-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-6-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-7-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-8-utf8.c create mode 100644 gcc/testsuite/gcc.dg/ucnid-9-utf8.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e7feded..7f16c16 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-19 Lewis Hyatt + + PR c/67224 + * doc/cpp.texi: Document support for extended characters in + identifiers. + * doc/cppopts.texi: Likewise. + 2019-09-19 Richard Biener * tree-vect-loop.c (vect_is_slp_reduction): Remove. diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index e271f51..f2de39a 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -274,11 +274,11 @@ the character in the source character set that they represent, then converted to the execution character set, just like unescaped characters. -In identifiers, characters outside the ASCII range can only be -specified with the @samp{\u} and @samp{\U} escapes, not used -directly. If strict ISO C90 conformance is specified with an option +In identifiers, characters outside the ASCII range can be specified +with the @samp{\u} and @samp{\U} escapes or used directly in the input +encoding. If strict ISO C90 conformance is specified with an option such as @option{-std=c90}, or @option{-fno-extended-identifiers} is -used, then those escapes are not permitted in identifiers. +used, then those constructs are not permitted in identifiers. @node Initial processing @section Initial processing @@ -503,8 +503,7 @@ In the 1999 C standard, identifiers may contain letters which are not part of the ``basic source character set'', at the implementation's discretion (such as accented Latin letters, Greek letters, or Chinese ideograms). This may be done with an extended character set, or the -@samp{\u} and @samp{\U} escape sequences. GCC only accepts such -characters in the @samp{\u} and @samp{\U} forms. +@samp{\u} and @samp{\U} escape sequences. As an extension, GCC treats @samp{$} as a letter. This is for compatibility with some systems, such as VMS, where @samp{$} is commonly @@ -584,15 +583,15 @@ Punctuator: @{ @} [ ] # ## @end smallexample @cindex other tokens -Any other single character is considered ``other''. It is passed on to -the preprocessor's output unmolested. The C compiler will almost -certainly reject source code containing ``other'' tokens. In ASCII, the -only other characters are @samp{@@}, @samp{$}, @samp{`}, and control +Any other single byte is considered ``other'' and passed on to the +preprocessor's output unchanged. The C compiler will almost certainly +reject source code containing ``other'' tokens. In ASCII, the only +``other'' characters are @samp{@@}, @samp{$}, @samp{`}, and control characters other than NUL (all bits zero). (Note that @samp{$} is -normally considered a letter.) All characters with the high bit set -(numeric range 0x7F--0xFF) are also ``other'' in the present -implementation. This will change when proper support for international -character sets is added to GCC@. +normally considered a letter.) All bytes with the high bit set +(numeric range 0x7F--0xFF) that were not succesfully interpreted as +part of an extended character in the input encoding are also ``other'' +in the present implementation. NUL is a special case because of the high probability that its appearance is accidental, and because it may be invisible to the user @@ -4179,7 +4178,10 @@ be controlled using the @option{-fexec-charset} and The C and C++ standards allow identifiers to be composed of @samp{_} and the alphanumeric characters. C++ also allows universal character names. C99 and later C standards permit both universal character -names and implementation-defined characters. +names and implementation-defined characters. In both C and C++ modes, +GCC accepts in identifiers exactly those extended characters that +correspond to universal character names permitted by the chosen +standard. GCC allows the @samp{$} character in identifiers as an extension for most targets. This is true regardless of the @option{std=} switch, diff --git a/gcc/doc/cppopts.texi b/gcc/doc/cppopts.texi index 61e22cd..f4bc3f5 100644 --- a/gcc/doc/cppopts.texi +++ b/gcc/doc/cppopts.texi @@ -254,8 +254,9 @@ Accept @samp{$} in identifiers. @item -fextended-identifiers @opindex fextended-identifiers -Accept universal character names in identifiers. This option is -enabled by default for C99 (and later C standard versions) and C++. +Accept universal character names and extended characters in +identifiers. This option is enabled by default for C99 (and later C +standard versions) and C++. @item -fno-canonical-system-headers @opindex fno-canonical-system-headers diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7efdac9..1f9b5ac 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,42 @@ +2019-09-19 Lewis Hyatt + + PR c/67224 + * c-c++-common/cpp/ucnid-2011-1-utf8.c: New test. + * g++.dg/cpp/ucnid-1-utf8.C: New test. + * g++.dg/cpp/ucnid-2-utf8.C: New test. + * g++.dg/cpp/ucnid-3-utf8.C: New test. + * g++.dg/cpp/ucnid-4-utf8.C: New test. + * g++.dg/other/ucnid-1-utf8.C: New test. + * gcc.dg/cpp/ucnid-1-utf8.c: New test. + * gcc.dg/cpp/ucnid-10-utf8.c: New test. + * gcc.dg/cpp/ucnid-11-utf8.c: New test. + * gcc.dg/cpp/ucnid-12-utf8.c: New test. + * gcc.dg/cpp/ucnid-13-utf8.c: New test. + * gcc.dg/cpp/ucnid-14-utf8.c: New test. + * gcc.dg/cpp/ucnid-15-utf8.c: New test. + * gcc.dg/cpp/ucnid-2-utf8.c: New test. + * gcc.dg/cpp/ucnid-3-utf8.c: New test. + * gcc.dg/cpp/ucnid-4-utf8.c: New test. + * gcc.dg/cpp/ucnid-6-utf8.c: New test. + * gcc.dg/cpp/ucnid-7-utf8.c: New test. + * gcc.dg/cpp/ucnid-9-utf8.c: New test. + * gcc.dg/ucnid-1-utf8.c: New test. + * gcc.dg/ucnid-10-utf8.c: New test. + * gcc.dg/ucnid-11-utf8.c: New test. + * gcc.dg/ucnid-12-utf8.c: New test. + * gcc.dg/ucnid-13-utf8.c: New test. + * gcc.dg/ucnid-14-utf8.c: New test. + * gcc.dg/ucnid-15-utf8.c: New test. + * gcc.dg/ucnid-16-utf8.c: New test. + * gcc.dg/ucnid-2-utf8.c: New test. + * gcc.dg/ucnid-3-utf8.c: New test. + * gcc.dg/ucnid-4-utf8.c: New test. + * gcc.dg/ucnid-5-utf8.c: New test. + * gcc.dg/ucnid-6-utf8.c: New test. + * gcc.dg/ucnid-7-utf8.c: New test. + * gcc.dg/ucnid-8-utf8.c: New test. + * gcc.dg/ucnid-9-utf8.c: New test. + 2019-09-19 Iain Sandoe * gcc.dg/pr89313.c: Test for __POWERPC__ in addition to diff --git a/gcc/testsuite/c-c++-common/cpp/ucnid-2011-1-utf8.c b/gcc/testsuite/c-c++-common/cpp/ucnid-2011-1-utf8.c new file mode 100644 index 0000000..02c5fc0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/ucnid-2011-1-utf8.c @@ -0,0 +1,15 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=c11 -pedantic" { target c } } */ +/* { dg-options "-std=c++11 -pedantic" { target c++ } } */ + +¨ + +BÌ€ + +Ì€ /* { dg-error "not valid at the start of an identifier" } */ + +AÌ€ /* { dg-warning "not in NFC" } */ + +ð€€ +🿽 +󡈴 diff --git a/gcc/testsuite/g++.dg/cpp/ucnid-1-utf8.C b/gcc/testsuite/g++.dg/cpp/ucnid-1-utf8.C new file mode 100644 index 0000000..839b188 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp/ucnid-1-utf8.C @@ -0,0 +1,17 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu++98 -pedantic" } */ + +ª /* { dg-error "not valid in an identifier" } */ +« /* { dg-error "not valid in an identifier" } */ +¶ /* { dg-error "not valid in an identifier" } */ +º /* { dg-error "not valid in an identifier" } */ +À +Ö +΄ + +Ù© /* { dg-error "not valid in an identifier" } */ +AÙ© /* { dg-error "not valid in an identifier" } */ +0º /* { dg-error "not valid in an identifier" } */ +0Ù© /* { dg-error "not valid in an identifier" } */ +๙ +A๙ diff --git a/gcc/testsuite/g++.dg/cpp/ucnid-2-utf8.C b/gcc/testsuite/g++.dg/cpp/ucnid-2-utf8.C new file mode 100644 index 0000000..0381452 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp/ucnid-2-utf8.C @@ -0,0 +1,24 @@ +/* Test stringization of identifiers with extended characters works. */ + +/* Note: The results expected in these tests are what GCC currently +outputs, but they are not technically standard-conforming. If GCC is +changed in the future to produce the standard-conforming output, then +this test will fail and should be adjusted to check for UCNs in the +output rather than UTF-8. See PR 91755 for more details. */ + +/* { dg-do run } */ + +#include +#include + +#define h(s) #s +#define str(s) h(s) + +int +main () +{ + if (strcmp (str (str (Ã)), "\"Ã\"")) + abort (); + if (strcmp (str (str (Ã)), "\"Ã\"")) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp/ucnid-3-utf8.C b/gcc/testsuite/g++.dg/cpp/ucnid-3-utf8.C new file mode 100644 index 0000000..5c3044a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp/ucnid-3-utf8.C @@ -0,0 +1,23 @@ +/* Test pasting of identifiers with extended characters works. */ + +/* Note: The results expected in these tests are what GCC currently +outputs, but they are not technically standard-conforming. If GCC is +changed in the future to produce the standard-conforming output, then +this test will fail and should be adjusted to check for UCNs in the +output rather than UTF-8. See PR 91755 for more details. */ + +/* { dg-do run } */ + +#include +#include + +#define c(s1, s2) s1 ## s2 +#define h(s) #s +#define str(s) h(s) + +int +main () +{ + if (strcmp (str (str (c (Ã, Ã))), "\"ÃÃ\"")) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp/ucnid-4-utf8.C b/gcc/testsuite/g++.dg/cpp/ucnid-4-utf8.C new file mode 100644 index 0000000..de252e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp/ucnid-4-utf8.C @@ -0,0 +1,17 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu++98"} */ + +ª +« /* { dg-error "not valid in an identifier" } */ +¶ /* { dg-error "not valid in an identifier" } */ +º +À +Ö +΄ + +Ù© /* OK in C++ */ +AÙ© +0º +0Ù© +๙ /* OK in C++ */ +A๙ diff --git a/gcc/testsuite/g++.dg/other/ucnid-1-utf8.C b/gcc/testsuite/g++.dg/other/ucnid-1-utf8.C new file mode 100644 index 0000000..dab4152 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/ucnid-1-utf8.C @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "" } */ +/* { dg-xfail-if "" { powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ +#include + +int À(void) { return 1; } +int Ã(void) { return 2; } +int Â(void) { return 3; } +int whÿ(void) { return 4; } +int aÄbÑδe(void) { return 5; } + +int main (void) +{ + + if (À() != 1) + abort (); + if (Ã() != 2) + abort (); + if (Â() != 3) + abort (); + if (whÿ() != 4) + abort (); + if (aÄbÑδe() != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-1-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-1-utf8.c new file mode 100644 index 0000000..9100b98 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-1-utf8.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-std=c99 -g3" } */ +void abort (void); + +#define À 1 +#define à 2 +#define  3 +#define whÿ 4 +#define aÄbÑδe 5 + +int main (void) +{ + + if (À != 1) + abort (); + if (à != 2) + abort (); + if ( != 3) + abort (); + if (whÿ != 4) + abort (); + if (aÄbÑδe != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-10-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-10-utf8.c new file mode 100644 index 0000000..7eeb026 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-10-utf8.c @@ -0,0 +1,8 @@ +/* Test UTF-8 is allowed in preprocessing numbers. */ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#define a(x) b(x) +#define b(x) 0 +#define p ) +int c = a(0À.p); diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-11-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-11-utf8.c new file mode 100644 index 0000000..56b88f8b --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-11-utf8.c @@ -0,0 +1,30 @@ +/* Test spelling differences in UCNs are properly diagnosed for macro + redefinitions. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99 -pedantic-errors" } */ + +/* Different spelling of UCN in expansion. */ +#define m1 \u00c1 /* { dg-message "-:previous definition" } */ +#define m1 à /* { dg-error "-:redefined" } */ + +#define m1ok à +#define m1ok à + +/* Different spelling of UCN in argument name. */ +#define m2(\u00c1) /* { dg-message "-:previous definition" } */ +#define m2(Ã) /* { dg-error "-:redefined" } */ + +#define m2ok(Ã) +#define m2ok(Ã) + +/* Same spelling in argument name but different spelling when used in + expansion. */ +#define m3(\u00c1) \u00c1 /* { dg-message "-:previous definition" } */ +#define m3(\u00c1) à /* { dg-error "-:redefined" } */ + +#define m3ok(\u00c1) à +#define m3ok(\u00c1) à + +/* Different spelling of the macro name itself is OK. */ +#define m4ok\u00c1 +#define m4okà diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-12-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-12-utf8.c new file mode 100644 index 0000000..9b54249 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-12-utf8.c @@ -0,0 +1,13 @@ +/* Test spelling differences in UCNs in macro definitions still count + as the same identifier for macro expansion. */ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -pedantic-errors" } */ + +#define m1\u00c1 +#ifndef m1à +#error not defined +#endif + +#define m2(\u00c1) à + +int i = m2 (0); diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-13-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-13-utf8.c new file mode 100644 index 0000000..aff39b6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-13-utf8.c @@ -0,0 +1,5 @@ +/* Verify macros named with UTF-8 are output in -dD output with UCNs. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99 -dD" } */ +/* { dg-final { scan-file ucnid-13-utf8.i "\\\\U000000c1" } } */ +#define à 1 diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-14-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-14-utf8.c new file mode 100644 index 0000000..6ea14eb --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-14-utf8.c @@ -0,0 +1,6 @@ +/* Verify macro definitions with UTF-8 are output in -dD output with + the original spelling. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99 -dD" } */ +/* { dg-final { scan-file ucnid-14-utf8.i "Ã" } } */ +#define a à diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-15-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-15-utf8.c new file mode 100644 index 0000000..cf2289a --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-15-utf8.c @@ -0,0 +1,6 @@ +/* Verify macro definitions with UTF-8 in argument names are output in + -dD output with the original spelling. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99 -dD" } */ +/* { dg-final { scan-file ucnid-15-utf8.i "#define a\\(Ã\\) x:Ã:y:Ã:z" } } */ +#define a(Ã) x:Ã:y:Ã:z diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-2-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-2-utf8.c new file mode 100644 index 0000000..e3730f8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-2-utf8.c @@ -0,0 +1,16 @@ +/* { dg-do run } */ +/* { dg-options "-std=c99" } */ +#include +#include + +#define str(t) #t + +int main (void) +{ + const char s[] = str (ゲ); + + if (strcmp (s, "ゲ") != 0) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-3-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-3-utf8.c new file mode 100644 index 0000000..4c9ed25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-3-utf8.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#define paste(x, y) x ## y + +int paste(ª, Ô±) = 3; + diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-4-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-4-utf8.c new file mode 100644 index 0000000..ccc7a1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-4-utf8.c @@ -0,0 +1,17 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99" } */ + +ª +« /* not a preprocessing error because we lex it into its own token */ +¶ /* not a preprocessing error because we lex it into its own token */ +º +À +Ö +΄ + +Ù© /* { dg-error "not valid at the start of an identifier" } */ +AÙ© +0º +0Ù© +๙ /* { dg-error "not valid at the start of an identifier" } */ +A๙ diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-6-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-6-utf8.c new file mode 100644 index 0000000..b4dd094 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-6-utf8.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c89" } */ +#define a b( +#define b(x) q +int aª); diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-7-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-7-utf8.c new file mode 100644 index 0000000..22aff7e --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-7-utf8.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +/* When GCC reads UTF-8-encoded input into its internal UTF-8 +representation, it does not apply any transformation to the data, and +in particular it makes no attempt to verify that the encoding is valid +UTF-8. Historically, if any non-ASCII characters were found outside a +string or comment, they were treated as stray tokens and did not +necessarily produce an error, e.g. if, as in this test, they disappear +in the preprocessor. Now that UTF-8 is also supported in identifiers, +the basic structure of this process has not changed; GCC just treats +invalid UTF-8 as a stray token. This test verifies that the historical +behavior is unchanged. In the future, if GCC were changed, say, to +validate the UTF-8 on input, then this test would no longer be +appropriate. */ + + +#define a b( +#define b(x) q +/* The line below contains invalid UTF-8. */ +int aÏ); diff --git a/gcc/testsuite/gcc.dg/cpp/ucnid-9-utf8.c b/gcc/testsuite/gcc.dg/cpp/ucnid-9-utf8.c new file mode 100644 index 0000000..1558eca --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/ucnid-9-utf8.c @@ -0,0 +1,8 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99 -pedantic" } */ + +â…  +ↂ +〇 +〡 +〩 diff --git a/gcc/testsuite/gcc.dg/ucnid-1-utf8.c b/gcc/testsuite/gcc.dg/ucnid-1-utf8.c new file mode 100644 index 0000000..7213673 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-1-utf8.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-std=c99 -g" } */ +void abort (void); + +int main (void) +{ + int À = 1; + int à = 2; + int  = 3; + int whÿ = 4; + int aÄbÑδe = 5; + + if (À != 1) + abort (); + if (à != 2) + abort (); + if ( != 3) + abort (); + if (whÿ != 4) + abort (); + if (aÄbÑδe != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ucnid-10-utf8.c b/gcc/testsuite/gcc.dg/ucnid-10-utf8.c new file mode 100644 index 0000000..86830b8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-10-utf8.c @@ -0,0 +1,11 @@ +/* Verify diagnostics for extended identifiers refer to UCNs (in the C + locale). Test #pragma pack diagnostics. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99" } */ +/* { dg-require-ascii-locale "" } */ +/* { dg-skip-if "" { powerpc-ibm-aix* } } */ + +#pragma pack(push) +#pragma pack(pop, ó) /* { dg-warning "pop, \\\\U000000f3.*push, \\\\U000000f3" } */ +#pragma pack(ç) /* { dg-warning "unknown action '\\\\U000000e7'" } */ + diff --git a/gcc/testsuite/gcc.dg/ucnid-11-utf8.c b/gcc/testsuite/gcc.dg/ucnid-11-utf8.c new file mode 100644 index 0000000..c6a89ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-11-utf8.c @@ -0,0 +1,7 @@ +/* { dg-do run } */ +/* { dg-xfail-if "" { powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-skip-if "-fdata-sections not supported" { { hppa*-*-hpux* } && { ! lp64 } } } */ +/* { dg-options "-std=c99 -fdata-sections -g" } */ + +#include "ucnid-3-utf8.c" diff --git a/gcc/testsuite/gcc.dg/ucnid-12-utf8.c b/gcc/testsuite/gcc.dg/ucnid-12-utf8.c new file mode 100644 index 0000000..cfdffba --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-12-utf8.c @@ -0,0 +1,7 @@ +/* { dg-do run } */ +/* { dg-xfail-if "" { powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-skip-if "-ffunction-sections not supported" { { hppa*-*-hpux* } && { ! lp64 } } } */ +/* { dg-options "-std=c99 -ffunction-sections -g" } */ + +#include "ucnid-4-utf8.c" diff --git a/gcc/testsuite/gcc.dg/ucnid-13-utf8.c b/gcc/testsuite/gcc.dg/ucnid-13-utf8.c new file mode 100644 index 0000000..41536c3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-13-utf8.c @@ -0,0 +1,15 @@ +/* Verify diagnostics for extended identifiers refer to UCNs (in the C + locale). Miscellaneous diagnostics. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 -Wpacked" } */ +/* { dg-require-ascii-locale "" } */ +/* { dg-skip-if "" { powerpc-ibm-aix* } } */ + +int a __attribute__((À)); /* { dg-warning "'\\\\U000000c0' attribute directive ignored" } */ + +extern void à (void) __attribute__((deprecated)); +void g (void) { à (); } /* { dg-warning "'\\\\U000000c1' is deprecated" } */ + +struct  { char c; } __attribute__((packed)); /* { dg-warning "'\\\\U000000c2'" } */ + +void h (void) { asm ("%[Ã]" : : ); } /* { dg-error "undefined named operand '\\\\U000000c3'" } */ diff --git a/gcc/testsuite/gcc.dg/ucnid-14-utf8.c b/gcc/testsuite/gcc.dg/ucnid-14-utf8.c new file mode 100644 index 0000000..e781ed6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-14-utf8.c @@ -0,0 +1,23 @@ +/* Test miscellaneous uses of UTF-8 in identifiers compile and run OK, + with debug info enabled. */ +/* { dg-do run } */ +/* { dg-options "-std=c99 -g" } */ + +extern void abort (void); +extern void exit (int); + +int +main (void) +{ + struct À { int Ã; } x; + struct À *y = &x; + y->à = 1; + if (x.à != 1) + abort (); + goto ÿ; + ÿ: ; + enum e {  = 4 }; + if ( != 4) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/ucnid-15-utf8.c b/gcc/testsuite/gcc.dg/ucnid-15-utf8.c new file mode 100644 index 0000000..e233689 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-15-utf8.c @@ -0,0 +1,38 @@ +/* Test combinations of UTF-8 in various parts of identifiers. */ +/* { dg-do run } */ +/* { dg-xfail-if "" { "powerpc-ibm-aix*" } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-options "-std=c99" } */ + +extern void abort (void); + +int Ï€ = 3; +int π² = 9; +int Ï€p1 = 4; +int twoÏ€ = 6; +int four_plus_Ï€_ = 7; +int 😀ÀÃÂÃÄÅßàáâãäaÃ¥bæçèéêcëìígîïð7ñ9__òóô4õöÆ3ÇÈÉÊËabcÃŒÃÃŽÃÃÑÒÓÔÕÖ😄😅🤣😂_ÿ = 2; +int Ï€\u03C0 = 9; + +int main() { + if (Ï€ != 3) + abort (); + + if (π² != 9) + abort (); + + if (Ï€p1 != 4) + abort (); + + if (twoÏ€ != 6) + abort (); + + if (four_plus_Ï€_ != 7) + abort () ; + + if (😀ÀÃÂÃÄÅßàáâãäaÃ¥bæçèéêcëìígîïð7ñ9__òóô4õöÆ3ÇÈÉÊËabcÃŒÃÃŽÃÃÑÒÓÔÕÖ😄😅🤣😂_ÿ != 2) + abort (); + + if(ππ != π²) + abort (); +} diff --git a/gcc/testsuite/gcc.dg/ucnid-16-utf8.c b/gcc/testsuite/gcc.dg/ucnid-16-utf8.c new file mode 100644 index 0000000..5d000a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-16-utf8.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -g -finput-charset=latin1" } */ +/* { dg-final { scan-file ucnid-16-utf8.s "²" } } */ + +/* This superscript is encoded in latin1; verify that we still get UTF-8 in the output. */ +int x² = 9; diff --git a/gcc/testsuite/gcc.dg/ucnid-2-utf8.c b/gcc/testsuite/gcc.dg/ucnid-2-utf8.c new file mode 100644 index 0000000..70f9464 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-2-utf8.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-xfail-if "" { powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-options "-std=c99 -g" } */ +void abort (void); + +static int À = 1; +static int à = 2; +static int  = 3; +static int whÿ = 4; +static int aÄbÑδe = 5; + +int main (void) +{ + + if (À != 1) + abort (); + if (à != 2) + abort (); + if ( != 3) + abort (); + if (whÿ != 4) + abort (); + if (aÄbÑδe != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ucnid-3-utf8.c b/gcc/testsuite/gcc.dg/ucnid-3-utf8.c new file mode 100644 index 0000000..f8509a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-3-utf8.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-xfail-if "" { powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-options "-std=c99 -g" } */ +void abort (void); + +int À = 1; +int à = 2; +int  = 3; +int whÿ = 4; +int aÄbÑδe = 5; + +int main (void) +{ + + if (À != 1) + abort (); + if (à != 2) + abort (); + if ( != 3) + abort (); + if (whÿ != 4) + abort (); + if (aÄbÑδe != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ucnid-4-utf8.c b/gcc/testsuite/gcc.dg/ucnid-4-utf8.c new file mode 100644 index 0000000..bf1c403 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-4-utf8.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-xfail-if "" { powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-options "-std=c99 -g" } */ +void abort (void); + +int À(void) { return 1; } +int Ã(void) { return 2; } +int Â(void) { return 3; } +int whÿ(void) { return 4; } +int aÄbÑδe(void) { return 5; } + +int main (void) +{ + + if (À() != 1) + abort (); + if (Ã() != 2) + abort (); + if (Â() != 3) + abort (); + if (whÿ() != 4) + abort (); + if (aÄbÑδe() != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ucnid-5-utf8.c b/gcc/testsuite/gcc.dg/ucnid-5-utf8.c new file mode 100644 index 0000000..f4473e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-5-utf8.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-skip-if "No dollar in identfiers" { avr-*-* powerpc-ibm-aix* } } */ +/* { dg-options "-std=c99 -fdollars-in-identifiers -g" } */ +void abort (void); + +int a$b(void) { return 1; } +int a$b😀(void) { return 2; } + +int main (void) +{ + + if (a$b() != 1) + abort (); + + if (a$b😀() != 2) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ucnid-6-utf8.c b/gcc/testsuite/gcc.dg/ucnid-6-utf8.c new file mode 100644 index 0000000..36ce52b --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-6-utf8.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-xfail-if "" { "powerpc-ibm-aix*" } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-options "-std=c99 -save-temps -g" } */ +void abort (void); + +int À(void) { return 1; } +int Ã(void) { return 2; } +int Â(void) { return 3; } +int whÿ(void) { return 4; } +int aÄbÑδe(void) { return 5; } + +int main (void) +{ + + if (À() != 1) + abort (); + if (Ã() != 2) + abort (); + if (Â() != 3) + abort (); + if (whÿ() != 4) + abort (); + if (aÄbÑδe() != 5) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ucnid-7-utf8.c b/gcc/testsuite/gcc.dg/ucnid-7-utf8.c new file mode 100644 index 0000000..07f5ca0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-7-utf8.c @@ -0,0 +1,9 @@ +/* Verify diagnostics for extended identifiers refer to UCNs (in the C + locale). */ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ +/* { dg-require-ascii-locale "" } */ +/* { dg-skip-if "" { "powerpc-ibm-aix*" } } */ + +void *p = &é; /* { dg-error "'\\\\U000000e9' undeclared" } */ +void *q = &Ḁ; /* { dg-error "'\\\\U00001e00' undeclared" } */ diff --git a/gcc/testsuite/gcc.dg/ucnid-8-utf8.c b/gcc/testsuite/gcc.dg/ucnid-8-utf8.c new file mode 100644 index 0000000..e6c440d --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-8-utf8.c @@ -0,0 +1,16 @@ +/* Verify diagnostics for extended identifiers refer to UCNs (in the C + locale). Further tests of C front-end diagnostics. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 -Wvla" } */ +/* { dg-require-ascii-locale "" } */ +/* { dg-skip-if "" { powerpc-ibm-aix* } } */ + +int a __attribute__((__mode__(é))); /* { dg-error "unknown machine mode '\\\\U000000e9'" } */ +struct s1 { int é : 0; }; /* { dg-error "zero width for bit-field '\\\\U000000e9'" } */ + +void f (int b) { int é[b]; } /* { dg-warning "variable length array '\\\\U000000e9'" } */ + +void g (static int é); /* { dg-error "storage class specified for parameter '\\\\U000000e9'" } */ + +struct s2 { int á; } é = { { 0 } }; /* { dg-warning "braces around scalar initializer" } */ +/* { dg-message "near initialization for '\\\\U000000e9\\.\\\\U000000e1'" "UCN diag" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/gcc.dg/ucnid-9-utf8.c b/gcc/testsuite/gcc.dg/ucnid-9-utf8.c new file mode 100644 index 0000000..c937196 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ucnid-9-utf8.c @@ -0,0 +1,25 @@ +/* Test __func__ with extended identifiers and character set + conversions. */ +/* { dg-do run } */ +/* { dg-xfail-if "" { "powerpc-ibm-aix*" } } */ +/* { dg-skip-if "" { ! ucn } } */ +/* { dg-options "-std=c99 -fexec-charset=ISO-8859-1 -g" } */ +/* { dg-require-iconv "ISO-8859-1" } */ + +extern int strcmp (const char *, const char *); +extern void abort (void); +extern void exit (int); + +void +é (void) +{ + if (strcmp (__func__, "é") != 0) + abort (); +} + +int +main (void) +{ + é (); + exit (0); +} -- cgit v1.1 From 6889a3acfeed47265886676c6d43b04ef799fb82 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 19 Sep 2019 22:15:34 +0000 Subject: PR middle-end/91631 - buffer overflow into an array member of a declared object not detected gcc/ChangeLog: PR middle-end/91631 * builtins.c (component_size): Correct trailing array computation, rename to component_ref_size and move... (compute_objsize): Adjust. * gimple-ssa-warn-restrict.c (builtin_memref::refsize): New member. (builtin_access::strict): Do not consider mememmove. (builtin_access::write_off): New function. (builtin_memref::builtin_memref): Initialize refsize. (builtin_memref::set_base_and_offset): Adjust refoff and compute refsize. (builtin_memref::offset_out_of_bounds): Use ooboff input values. Handle refsize. (builtin_access::builtin_access): Intialize dstoff to destination refeence offset here instead of in maybe_diag_overlap. Adjust referencess even to unrelated objects. Adjust sizrange of bounded string functions to reflect bound. For strcat, adjust destination sizrange by that of source. (builtin_access::strcat_overlap): Adjust offsets and sizes to reflect the increase in destination sizrange above. (builtin_access::overlap): Do not set dstoff here but instead in builtin_access::builtin_access. (check_bounds_or_overlap): Use builtin_access::write_off. (maybe_diag_access_bounds): Add argument. Add informational notes. (dump_builtin_memref, dump_builtin_access): New functions. * tree.c (component_ref_size): ...to here. * tree.h (component_ref_size): Declare. * tree-ssa-strlen (handle_builtin_strcat): Include the terminating nul in the size of the source string. gcc/testsuite/ChangeLog: PR middle-end/91631 * /c-c++-common/Warray-bounds-3.c: Correct expected offsets. * /c-c++-common/Warray-bounds-4.c: Same. * gcc.dg/Warray-bounds-39.c: Remove xfails. * gcc.dg/Warray-bounds-45.c: New test. * gcc.dg/Warray-bounds-46.c: New test. From-SVN: r275981 --- gcc/ChangeLog | 31 +++ gcc/builtins.c | 50 +--- gcc/gimple-ssa-warn-restrict.c | 348 ++++++++++++++++++++------- gcc/testsuite/ChangeLog | 9 + gcc/testsuite/c-c++-common/Warray-bounds-3.c | 26 +- gcc/testsuite/c-c++-common/Warray-bounds-4.c | 6 +- gcc/testsuite/gcc.dg/Warray-bounds-39.c | 6 +- gcc/testsuite/gcc.dg/Warray-bounds-45.c | 330 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Warray-bounds-46.c | 249 +++++++++++++++++++ gcc/tree-ssa-strlen.c | 7 +- gcc/tree.c | 70 ++++++ gcc/tree.h | 7 + 12 files changed, 983 insertions(+), 156 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-45.c create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-46.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7f16c16..9dfb646 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2019-09-19 Martin Sebor + + PR middle-end/91631 + * builtins.c (component_size): Correct trailing array computation, + rename to component_ref_size and move... + (compute_objsize): Adjust. + * gimple-ssa-warn-restrict.c (builtin_memref::refsize): New member. + (builtin_access::strict): Do not consider memmove. + (builtin_access::write_off): New function. + (builtin_memref::builtin_memref): Initialize refsize. + (builtin_memref::set_base_and_offset): Adjust refoff and compute + refsize. + (builtin_memref::offset_out_of_bounds): Use ooboff input values. + Handle refsize. + (builtin_access::builtin_access): Initialize dstoff to destination + refeence offset here instead of in maybe_diag_overlap. Adjust + referencess even to unrelated objects. Adjust sizrange of bounded + string functions to reflect bound. For strcat, adjust destination + sizrange by that of source. + (builtin_access::strcat_overlap): Adjust offsets and sizes + to reflect the increase in destination sizrange above. + (builtin_access::overlap): Do not set dstoff here but instead + in builtin_access::builtin_access. + (check_bounds_or_overlap): Use builtin_access::write_off. + (maybe_diag_access_bounds): Add argument. Add informational notes. + (dump_builtin_memref, dump_builtin_access): New functions. + * tree.c (component_ref_size): ...to here. + * tree.h (component_ref_size): Declare. + * tree-ssa-strlen (handle_builtin_strcat): Include the terminating + nul in the size of the source string. + 2019-09-19 Lewis Hyatt PR c/67224 diff --git a/gcc/builtins.c b/gcc/builtins.c index f8063c1..1fd4b88 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3562,54 +3562,6 @@ check_access (tree exp, tree, tree, tree dstwrite, return true; } -/* Determines the size of the member referenced by the COMPONENT_REF - REF, using its initializer expression if necessary in order to - determine the size of an initialized flexible array member. - Returns the size (which might be zero for an object with - an uninitialized flexible array member) or null if the size - cannot be determined. */ - -static tree -component_size (tree ref) -{ - gcc_assert (TREE_CODE (ref) == COMPONENT_REF); - - tree member = TREE_OPERAND (ref, 1); - - /* If the member is not last or has a size greater than one, return - it. Otherwise it's either a flexible array member or a zero-length - array member, or an array of length one treated as such. */ - tree size = DECL_SIZE_UNIT (member); - if (size - && (!array_at_struct_end_p (ref) - || (!integer_zerop (size) - && !integer_onep (size)))) - return size; - - /* If the reference is to a declared object and the member a true - flexible array, try to determine its size from its initializer. */ - poly_int64 off = 0; - tree base = get_addr_base_and_unit_offset (ref, &off); - if (!base || !VAR_P (base)) - return NULL_TREE; - - /* The size of any member of a declared object other than a flexible - array member is that obtained above. */ - if (size) - return size; - - if (tree init = DECL_INITIAL (base)) - if (TREE_CODE (init) == CONSTRUCTOR) - { - off <<= LOG2_BITS_PER_UNIT; - init = fold_ctor_reference (NULL_TREE, init, off, 0, base); - if (init) - return TYPE_SIZE_UNIT (TREE_TYPE (init)); - } - - return DECL_EXTERNAL (base) ? NULL_TREE : integer_zero_node; -} - /* Helper to compute the size of the object referenced by the DEST expression which must have pointer type, using Object Size type OSTYPE (only the least significant 2 bits are used). Return @@ -3744,7 +3696,7 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) if (TREE_CODE (dest) == COMPONENT_REF) { *pdecl = TREE_OPERAND (dest, 1); - return component_size (dest); + return component_ref_size (dest); } if (TREE_CODE (dest) != ADDR_EXPR) diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index cbfc478..4f6e535 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -137,6 +137,8 @@ public: /* The size of the BASE object, PTRDIFF_MAX if indeterminate, and negative until (possibly lazily) initialized. */ offset_int basesize; + /* Same for the subobject. */ + offset_int refsize; /* The non-negative offset of the referenced subobject. Used to avoid warnings for (apparently) possibly but not definitively overlapping @@ -160,7 +162,7 @@ public: builtin_memref (tree, tree); - tree offset_out_of_bounds (int, offset_int[2]) const; + tree offset_out_of_bounds (int, offset_int[3]) const; private: @@ -192,7 +194,8 @@ class builtin_access and false for raw memory functions. */ bool strict () const { - return detect_overlap != &builtin_access::generic_overlap; + return (detect_overlap != &builtin_access::generic_overlap + && detect_overlap != &builtin_access::no_overlap); } builtin_access (gimple *, builtin_memref &, builtin_memref &); @@ -200,6 +203,10 @@ class builtin_access /* Entry point to determine overlap. */ bool overlap (); + offset_int write_off (tree) const; + + void dump (FILE *) const; + private: /* Implementation functions used to determine overlap. */ bool generic_overlap (); @@ -234,6 +241,7 @@ builtin_memref::builtin_memref (tree expr, tree size) ref (), base (), basesize (-1), + refsize (-1), refoff (HOST_WIDE_INT_MIN), offrange (), sizrange (), @@ -298,6 +306,19 @@ builtin_memref::builtin_memref (tree expr, tree size) } } +/* Based on the initial length of the destination STARTLEN, returns + the offset of the first write access from the beginning of + the destination. Nonzero only for strcat-type of calls. */ + +offset_int builtin_access::write_off (tree startlen) const +{ + if (detect_overlap != &builtin_access::strcat_overlap + || !startlen || TREE_CODE (startlen) != INTEGER_CST) + return 0; + + return wi::to_offset (startlen); +} + /* Ctor helper to set or extend OFFRANGE based on the OFFSET argument. Pointer offsets are represented as unsigned sizetype but must be treated as signed. */ @@ -483,33 +504,69 @@ builtin_memref::set_base_and_offset (tree expr) if (TREE_CODE (base) == MEM_REF) { - tree memrefoff = TREE_OPERAND (base, 1); + tree memrefoff = fold_convert (ptrdiff_type_node, TREE_OPERAND (base, 1)); extend_offset_range (memrefoff); base = TREE_OPERAND (base, 0); + + if (refoff != HOST_WIDE_INT_MIN + && TREE_CODE (expr) == COMPONENT_REF) + { + /* Bump up the offset of the referenced subobject to reflect + the offset to the enclosing object. For example, so that + in + struct S { char a, b[3]; } s[2]; + strcpy (s[1].b, "1234"); + REFOFF is set to s[1].b - (char*)s. */ + tree basetype = TREE_TYPE (TREE_TYPE (base)); + if (tree basesize = TYPE_SIZE_UNIT (basetype)) + if (TREE_CODE (basesize) == INTEGER_CST) + { + offset_int size = wi::to_offset (basesize); + offset_int off = tree_to_shwi (memrefoff); + refoff += size * (off / size); + } + } + + if (!integer_zerop (memrefoff)) + /* A non-zero offset into an array of struct with flexible array + members implies that the array is empty because there is no + way to initialize such a member when it belongs to an array. + This must be some sort of a bug. */ + refsize = 0; } + if (TREE_CODE (ref) == COMPONENT_REF) + if (tree size = component_ref_size (ref)) + if (TREE_CODE (size) == INTEGER_CST) + refsize = wi::to_offset (size); + if (TREE_CODE (base) == SSA_NAME) set_base_and_offset (base); } /* Return error_mark_node if the signed offset exceeds the bounds - of the address space (PTRDIFF_MAX). Otherwise, return either - BASE or REF when the offset exceeds the bounds of the BASE or - REF object, and set OOBOFF to the past-the-end offset formed - by the reference, including its size. When STRICT is non-zero - use REF size, when available, otherwise use BASE size. When - STRICT is greater than 1, use the size of the last array member - as the bound, otherwise treat such a member as a flexible array - member. Return NULL when the offset is in bounds. */ + of the address space (PTRDIFF_MAX). Otherwise, return either BASE + or REF when the offset exceeds the bounds of the BASE or REF object, + and set OOBOFF to the past-the-end offset formed by the reference, + including its size. OOBOFF is initially setto the range of offsets, + and OOBOFF[2] to the offset of the first write access (nonzero for + the strcat family). When STRICT is nonzero use REF size, when + available, otherwise use BASE size. When STRICT is greater than 1, + use the size of the last array member as the bound, otherwise treat + such a member as a flexible array member. Return NULL when the offset + is in bounds. */ tree -builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[2]) const +builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[3]) const { if (!ptr) return NULL_TREE; + /* The offset of the first write access or zero. */ + offset_int wroff = ooboff[2]; + /* A temporary, possibly adjusted, copy of the offset range. */ - offset_int offrng[2] = { offrange[0], offrange[1] }; + offset_int offrng[2] = { ooboff[0], ooboff[1] }; if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE) { @@ -527,9 +584,19 @@ builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[2]) const bool hib = wi::les_p (offrng[0], offrng[1]); bool lob = !hib; + /* Set to the size remaining in the object object after subtracting + REFOFF. It may become negative as a result of negative indices + into the enclosing object, such as in: + extern struct S { char a[4], b[3], c[1]; } *p; + strcpy (p[-3].b, "123"); */ + offset_int size = basesize; + tree obj = base; + + const bool decl_p = DECL_P (obj); + if (basesize < 0) { - endoff = offrng[lob] + sizrange[0]; + endoff = offrng[lob] + (sizrange[0] - wroff); /* For a reference through a pointer to an object of unknown size all initial offsets are considered valid, positive as well as @@ -539,41 +606,45 @@ builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[2]) const if (endoff > maxobjsize) return error_mark_node; - return NULL_TREE; + /* When the referenced subobject is known, the end offset must be + within its bounds. Otherwise there is nothing to do. */ + if (strict + && !decl_p + && ref + && refsize >= 0 + && TREE_CODE (ref) == COMPONENT_REF) + { + /* If REFOFF is negative, SIZE will become negative here. */ + size = refoff + refsize; + obj = ref; + } + else + return NULL_TREE; } /* A reference to an object of known size must be within the bounds - of the base object. */ - if (offrng[hib] < 0 || offrng[lob] > basesize) - return base; + of either the base object or the subobject (see above for when + a subobject can be used). */ + if ((decl_p && offrng[hib] < 0) || offrng[lob] > size) + return obj; /* The extent of the reference must also be within the bounds of - the base object (if known) or the maximum object size otherwise. */ - endoff = wi::smax (offrng[lob], 0) + sizrange[0]; + the base object (if known) or the subobject or the maximum object + size otherwise. */ + endoff = offrng[lob] + sizrange[0]; if (endoff > maxobjsize) return error_mark_node; - offset_int size = basesize; - tree obj = base; - if (strict - && DECL_P (obj) + && decl_p && ref - && refoff >= 0 - && TREE_CODE (ref) == COMPONENT_REF - && (strict > 1 - || !array_at_struct_end_p (ref))) + && refsize >= 0 + && TREE_CODE (ref) == COMPONENT_REF) { - /* If the reference is to a member subobject, the offset must - be within the bounds of the subobject. */ - tree field = TREE_OPERAND (ref, 1); - tree type = TREE_TYPE (field); - if (tree sz = TYPE_SIZE_UNIT (type)) - if (TREE_CODE (sz) == INTEGER_CST) - { - size = refoff + wi::to_offset (sz); - obj = ref; - } + /* If the reference is to a member subobject of a declared object, + the offset must be within the bounds of the subobject. */ + size = refoff + refsize; + obj = ref; } if (endoff <= size) @@ -581,12 +652,12 @@ builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[2]) const /* Set the out-of-bounds offset range to be one greater than that delimited by the reference including its size. */ - ooboff[lob] = size + 1; + ooboff[lob] = size; if (endoff > ooboff[lob]) - ooboff[hib] = endoff; + ooboff[hib] = endoff - 1; else - ooboff[hib] = wi::smax (offrng[lob], 0) + sizrange[1]; + ooboff[hib] = offrng[lob] + sizrange[1]; return obj; } @@ -599,8 +670,10 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst, : dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (), dstoff (), srcoff (), dstsiz (), srcsiz () { + dstoff[0] = dst.offrange[0]; + dstoff[1] = dst.offrange[1]; + /* Zero out since the offset_int ctors invoked above are no-op. */ - dstoff[0] = dstoff[1] = 0; srcoff[0] = srcoff[1] = 0; dstsiz[0] = dstsiz[1] = 0; srcsiz[0] = srcsiz[1] = 0; @@ -716,15 +789,9 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst, src.basesize = maxobjsize; } - /* If there is no dependency between the references or the base - objects of the two references aren't the same there's nothing - else to do. */ - if (depends_p && dstref->base != srcref->base) - return; - - /* ...otherwise, make adjustments for references to the same object - by string built-in functions to reflect the constraints imposed - by the function. */ + /* Make adjustments for references to the same object by string + built-in functions to reflect the constraints imposed by + the function. */ /* For bounded string functions determine the range of the bound on the access. For others, the range stays unbounded. */ @@ -755,6 +822,7 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst, } } + bool dstsize_set = false; /* The size range of one reference involving the same base object can be determined from the size range of the other reference. This makes it possible to compute accurate offsets for warnings @@ -766,6 +834,7 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst, the source. */ dstref->sizrange[0] = srcref->sizrange[0]; dstref->sizrange[1] = srcref->sizrange[1]; + dstsize_set = true; } else if (srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize) { @@ -778,11 +847,15 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst, { if (dstref->strbounded_p) { - /* Read access by strncpy is bounded. */ - if (bounds[0] < srcref->sizrange[0]) - srcref->sizrange[0] = bounds[0]; - if (bounds[1] < srcref->sizrange[1]) - srcref->sizrange[1] = bounds[1]; + /* Read access by strncpy is constrained by the third + argument but except for a zero bound is at least one. */ + offset_int size = wi::umax (srcref->basesize, 1); + offset_int bound = wi::umin (size, bounds[0]); + if (bound < srcref->sizrange[0]) + srcref->sizrange[0] = bound; + bound = wi::umin (srcref->basesize, bounds[1]); + if (bound < srcref->sizrange[1]) + srcref->sizrange[1] = bound; } /* For string functions, adjust the size range of the source @@ -834,6 +907,11 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst, } } } + else if (!dstsize_set && detect_overlap == &builtin_access::strcat_overlap) + { + dstref->sizrange[0] += srcref->sizrange[0] - 1; + dstref->sizrange[1] += srcref->sizrange[1] - 1; + } if (dstref->strbounded_p) { @@ -1108,10 +1186,11 @@ builtin_access::strcat_overlap () /* Adjust for strcat-like accesses. */ /* As a special case for strcat, set the DSTREF offsets to the length - of the source string since the function starts writing at the first - nul, and set the size to 1 for the length of the nul. */ - acs.dstoff[0] += acs.dstsiz[0]; - acs.dstoff[1] += acs.dstsiz[1]; + of the destination string since the function starts writing over + its terminating nul, and set the destination size to 1 for the length + of the nul. */ + acs.dstoff[0] += dstsiz[0] - srcref->sizrange[0]; + acs.dstoff[1] += dstsiz[1] - srcref->sizrange[1]; bool strfunc_unknown_args = acs.dstsiz[0] == 0 && acs.dstsiz[1] != 0; @@ -1189,7 +1268,8 @@ builtin_access::strcat_overlap () acs.ovlsiz[0] = dstref->sizrange[0] == dstref->sizrange[1] ? 1 : 0; acs.ovlsiz[1] = 1; - offset_int endoff = dstref->offrange[0] + dstref->sizrange[0]; + offset_int endoff + = dstref->offrange[0] + (dstref->sizrange[0] - srcref->sizrange[0]); if (endoff <= srcref->offrange[0]) acs.ovloff[0] = wi::smin (maxobjsize, srcref->offrange[0]).to_shwi (); else @@ -1261,10 +1341,6 @@ builtin_access::overlap () if (!dstref->base || !srcref->base) return false; - /* Set the access offsets. */ - acs.dstoff[0] = dstref->offrange[0]; - acs.dstoff[1] = dstref->offrange[1]; - /* If the base object is an array adjust the bounds of the offset to be non-negative and within the bounds of the array if possible. */ if (dstref->base @@ -1626,7 +1702,8 @@ maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs) static bool maybe_diag_access_bounds (location_t loc, gimple *call, tree func, int strict, - const builtin_memref &ref, bool do_warn) + const builtin_memref &ref, offset_int wroff, + bool do_warn) { const offset_int maxobjsize = ref.maxobjsize; @@ -1665,8 +1742,12 @@ maybe_diag_access_bounds (location_t loc, gimple *call, tree func, int strict, } /* Check for out-bounds pointers regardless of warning options since - the result is used to make codegen decisions. */ - offset_int ooboff[] = { ref.offrange[0], ref.offrange[1] }; + the result is used to make codegen decisions. An excessive WROFF + can only come up as a result of an invalid strncat bound and is + diagnosed separately using a more meaningful warning. */ + if (maxobjsize < wroff) + wroff = 0; + offset_int ooboff[] = { ref.offrange[0], ref.offrange[1], wroff }; tree oobref = ref.offset_out_of_bounds (strict, ooboff); if (!oobref) return false; @@ -1787,27 +1868,45 @@ maybe_diag_access_bounds (location_t loc, gimple *call, tree func, int strict, } else if (TREE_CODE (ref.ref) == MEM_REF) { - tree type = TREE_TYPE (TREE_OPERAND (ref.ref, 0)); + tree refop = TREE_OPERAND (ref.ref, 0); + tree type = TREE_TYPE (refop); if (POINTER_TYPE_P (type)) type = TREE_TYPE (type); type = TYPE_MAIN_VARIANT (type); - warned = warning_at (loc, OPT_Warray_bounds, - "%G%qD offset %s from the object at %qE is out " - "of the bounds of %qT", - call, func, rangestr[0], ref.base, type); + if (warning_at (loc, OPT_Warray_bounds, + "%G%qD offset %s from the object at %qE is out " + "of the bounds of %qT", + call, func, rangestr[0], ref.base, type)) + { + if (TREE_CODE (ref.ref) == COMPONENT_REF) + refop = TREE_OPERAND (ref.ref, 1); + if (DECL_P (refop)) + inform (DECL_SOURCE_LOCATION (refop), + "subobject %qD declared here", refop); + warned = true; + } } else { + tree refop = TREE_OPERAND (ref.ref, 0); tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref.ref)); - warned = warning_at (loc, OPT_Warray_bounds, - "%G%qD offset %s from the object at %qE is out " - "of the bounds of referenced subobject %qD with " - "type %qT at offset %wu", - call, func, rangestr[0], ref.base, - TREE_OPERAND (ref.ref, 1), type, - ref.refoff.to_uhwi ()); + if (warning_at (loc, OPT_Warray_bounds, + "%G%qD offset %s from the object at %qE is out " + "of the bounds of referenced subobject %qD with " + "type %qT at offset %wi", + call, func, rangestr[0], ref.base, + TREE_OPERAND (ref.ref, 1), type, + ref.refoff.to_shwi ())) + { + if (TREE_CODE (ref.ref) == COMPONENT_REF) + refop = TREE_OPERAND (ref.ref, 1); + if (DECL_P (refop)) + inform (DECL_SOURCE_LOCATION (refop), + "subobject %qD declared here", refop); + warned = true; + } } return warned; @@ -1936,17 +2035,23 @@ check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize, builtin_memref dstref (dst, dstsize); builtin_memref srcref (src, srcsize); + /* Create a descriptor of the access. This may adjust both DSTREF + and SRCREF based on one another and the kind of the access. */ builtin_access acs (call, dstref, srcref); /* Set STRICT to the value of the -Warray-bounds=N argument for string functions or when N > 1. */ int strict = (acs.strict () || warn_array_bounds > 1 ? warn_array_bounds : 0); - /* Validate offsets first to make sure they are within the bounds - of the destination object if its size is known, or PTRDIFF_MAX - otherwise. */ - if (maybe_diag_access_bounds (loc, call, func, strict, dstref, do_warn) - || maybe_diag_access_bounds (loc, call, func, strict, srcref, do_warn)) + /* The starting offset of the destination write access. Nonzero only + for the strcat family of functions. */ + offset_int wroff = acs.write_off (dstsize); + + /* Validate offsets to each reference before the access first to make + sure they are within the bounds of the destination object if its + size is known, or PTRDIFF_MAX otherwise. */ + if (maybe_diag_access_bounds (loc, call, func, strict, dstref, wroff, do_warn) + || maybe_diag_access_bounds (loc, call, func, strict, srcref, 0, do_warn)) { if (do_warn) gimple_set_no_warning (call, true); @@ -2003,3 +2108,76 @@ make_pass_warn_restrict (gcc::context *ctxt) { return new pass_wrestrict (ctxt); } + +DEBUG_FUNCTION void +dump_builtin_memref (FILE *fp, const builtin_memref &ref) +{ + fprintf (fp, "\n ptr = "); + print_generic_expr (fp, ref.ptr, TDF_LINENO); + fprintf (fp, "\n ref = "); + if (ref.ref) + print_generic_expr (fp, ref.ref, TDF_LINENO); + else + fputs ("null", fp); + fprintf (fp, "\n base = "); + print_generic_expr (fp, ref.base, TDF_LINENO); + fprintf (fp, + "\n basesize = %lli" + "\n refsize = %lli" + "\n refoff = %lli" + "\n offrange = [%lli, %lli]" + "\n sizrange = [%lli, %lli]" + "\n strbounded_p = %s\n", + (long long)ref.basesize.to_shwi (), + (long long)ref.refsize.to_shwi (), + (long long)ref.refoff.to_shwi (), + (long long)ref.offrange[0].to_shwi (), + (long long)ref.offrange[1].to_shwi (), + (long long)ref.sizrange[0].to_shwi (), + (long long)ref.sizrange[1].to_shwi (), + ref.strbounded_p ? "true" : "false"); +} + +void +builtin_access::dump (FILE *fp) const +{ + fprintf (fp, " dstref:"); + dump_builtin_memref (fp, *dstref); + fprintf (fp, "\n srcref:"); + dump_builtin_memref (fp, *srcref); + + fprintf (fp, + " sizrange = [%lli, %lli]\n" + " ovloff = [%lli, %lli]\n" + " ovlsiz = [%lli, %lli]\n" + " dstoff = [%lli, %lli]\n" + " dstsiz = [%lli, %lli]\n" + " srcoff = [%lli, %lli]\n" + " srcsiz = [%lli, %lli]\n", + (long long)sizrange[0], (long long)sizrange[1], + (long long)ovloff[0], (long long)ovloff[1], + (long long)ovlsiz[0], (long long)ovlsiz[1], + (long long)dstoff[0].to_shwi (), (long long)dstoff[1].to_shwi (), + (long long)dstsiz[0].to_shwi (), (long long)dstsiz[1].to_shwi (), + (long long)srcoff[0].to_shwi (), (long long)srcoff[1].to_shwi (), + (long long)srcsiz[0].to_shwi (), (long long)srcsiz[1].to_shwi ()); +} + +DEBUG_FUNCTION void +dump_builtin_access (FILE *fp, gimple *stmt, const builtin_access &acs) +{ + if (stmt) + { + fprintf (fp, "\nDumping builtin_access for "); + print_gimple_expr (fp, stmt, TDF_LINENO); + fputs (":\n", fp); + } + + acs.dump (fp); +} + +DEBUG_FUNCTION void +debug (gimple *stmt, const builtin_access &acs) +{ + dump_builtin_access (stdout, stmt, acs); +} diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1f9b5ac..c230b2a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-09-19 Martin Sebor + + PR middle-end/91631 + * /c-c++-common/Warray-bounds-3.c: Correct expected offsets. + * /c-c++-common/Warray-bounds-4.c: Same. + * gcc.dg/Warray-bounds-39.c: Remove xfails. + * gcc.dg/Warray-bounds-45.c: New test. + * gcc.dg/Warray-bounds-46.c: New test. + 2019-09-19 Lewis Hyatt PR c/67224 diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-3.c b/gcc/testsuite/c-c++-common/Warray-bounds-3.c index 7f2b33b..ab84c60 100644 --- a/gcc/testsuite/c-c++-common/Warray-bounds-3.c +++ b/gcc/testsuite/c-c++-common/Warray-bounds-3.c @@ -115,7 +115,7 @@ void test_memcpy_bounds_anti_range (char *d, const char *s, size_t n) offset, i.e., 7 + 3. Including the whole final range because would be confusing (the upper bound would either be negative or a very large positive number) so only the lower bound is included. */ - T (char, 9, a, a + SAR ( 0, 6), 3); /* { dg-warning "forming offset 10 is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a, a + SAR ( 0, 6), 3); /* { dg-warning "forming offset 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */ /* This fails because the offset isn't represented as an SSA_NAME but rather as a GIMPLE_PHI (offset, 0). With some effort it is @@ -129,18 +129,18 @@ void test_memcpy_bounds_anti_range (char *d, const char *s, size_t n) T (char, 9, a, a + SAR ( 2, 6), 3); T (char, 9, a, a + SAR ( 3, 6), 3); - T (char, 9, a, a + SAR (-1, 7), 3); /* { dg-warning "forming offset \\\[10, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */ - T (char, 9, a, a + SAR (-2, 8), 3); /* { dg-warning "forming offset \\\[10, 12] is out of the bounds \\\[0, 9] of object " "memcpy" } */ - T (char, 9, a, a + SAR (-3, 7), 5); /* { dg-warning "forming offset \\\[10, 13] is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a, a + SAR (-1, 7), 3); /* { dg-warning "forming offset \\\[9, 10] is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a, a + SAR (-2, 8), 3); /* { dg-warning "offset \\\[9, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a, a + SAR (-3, 7), 5); /* { dg-warning "forming offset \\\[9, 12] is out of the bounds \\\[0, 9] of object " "memcpy" } */ T (char, 9, a + SAR (-2, -1), a, 3); T (char, 9, a + SAR (-1, 1), a, 3); T (char, 9, a + SAR ( 0, 1), a, 3); T (char, 9, a + SAR ( 0, 2), a, 3); T (char, 9, a + SAR ( 0, 3), a, 3); - T (char, 9, a + SAR ( 0, 6), a, 3); /* { dg-warning "forming offset 10 is out of the bounds \\\[0, 9] of object " "memcpy" } */ - T (char, 9, a + SAR (-1, 7), a, 3); /* { dg-warning "forming offset \\\[10, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */ - T (char, 9, a + SAR (-2, 8), a, 3); /* { dg-warning "forming offset \\\[10, 12] is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a + SAR ( 0, 6), a, 3); /* { dg-warning "forming offset 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a + SAR (-1, 7), a, 3); /* { dg-warning "forming offset \\\[9, 10] is out of the bounds \\\[0, 9] of object " "memcpy" } */ + T (char, 9, a + SAR (-2, 8), a, 3); /* { dg-warning "offset \\\[9, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */ ptrdiff_t i = SAR (DIFF_MIN + 1, DIFF_MAX - 4); T (char, 1, d, d + SAR (DIFF_MIN + 3, DIFF_MAX - 1), 3); @@ -312,13 +312,13 @@ void test_strcpy_bounds (char *d, const char *s) it out of bounds (it isn't) but because the final source offset after the access has completed, is. It would be clearer if the warning mentioned the final offset. */ - TI (char, 2, "", a + SR (2, DIFF_MAX - 1), s); /* { dg-warning "forming offset 3 is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]." "strcpy" } */ + TI (char, 2, "", a + SR (2, DIFF_MAX - 1), s); /* { dg-warning "offset 2 is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]." "strcpy" } */ TI (char, 2, "", a + SR (3, DIFF_MAX - 1), s); /* { dg-warning "offset \\\[3, \[0-9\]+] is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]." "strcpy" } */ TI (char, 3, "", a + SR (0, DIFF_MAX - 1), s); TI (char, 3, "", a + SR (1, DIFF_MAX - 1), s); TI (char, 3, "", a + SR (2, DIFF_MAX - 1), s); - TI (char, 3, "", a + SR (3, DIFF_MAX - 1), s); /* { dg-warning "forming offset 4 is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]." "strcpy" } */ + TI (char, 3, "", a + SR (3, DIFF_MAX - 1), s); /* { dg-warning "offset 3 is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]." "strcpy" } */ TI (char, 3, "", a + SR (4, DIFF_MAX - 1), s); /* { dg-warning "offset \\\[4, \[0-9\]+] is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]." "strcpy" } */ TI (char, 4, "", a + SR (DIFF_MAX - 2, DIFF_MAX - 1), s); /* { dg-warning "offset \\\[\[0-9\]+, \[0-9\]+] is out of the bounds \\\[0, 4] of object \[^\n\r\]+ with type .char ?\\\[4\\\]." "strcpy" } */ @@ -364,15 +364,15 @@ void test_strcpy_bounds_memarray_range (void) TM (a5, "0", ma.a5 + i, ma.a5); TM (a5, "01", ma.a5 + i, ma.a5); TM (a5, "012", ma.a5 + i, ma.a5); - TM (a5, "0123", ma.a5 + i, ma.a5); /* { dg-warning "offset 10 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 4" "strcpy" } */ + TM (a5, "0123", ma.a5 + i, ma.a5); /* { dg-warning "offset 9 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 4" "strcpy" } */ TM (a11, "0", ma.a5, ma.a11); TM (a11, "01", ma.a5, ma.a11); TM (a11, "012", ma.a5, ma.a11); TM (a11, "0123", ma.a5, ma.a11); - TM (a11, "01234", ma.a5, ma.a11); /* { dg-warning "offset 10 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */ - TM (a11, "012345", ma.a5, ma.a11); /* { dg-warning "offset \\\[10, 11] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */ - TM (a11, "0123456", ma.a5, ma.a11); /* { dg-warning "offset \\\[10, 12] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */ + TM (a11, "01234", ma.a5, ma.a11); /* { dg-warning "offset 9 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */ + TM (a11, "012345", ma.a5, ma.a11); /* { dg-warning "offset \\\[9, 10] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */ + TM (a11, "0123456", ma.a5, ma.a11); /* { dg-warning "offset \\\[9, 11] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */ TM (a11, "0123456", ma.a11 + i, "789abcd"); } diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-4.c b/gcc/testsuite/c-c++-common/Warray-bounds-4.c index 7a39b23..961107a 100644 --- a/gcc/testsuite/c-c++-common/Warray-bounds-4.c +++ b/gcc/testsuite/c-c++-common/Warray-bounds-4.c @@ -44,8 +44,8 @@ void test_memcpy_bounds_memarray_range (void) TM (ma.a5, ma.a5 + j, ma.a5, 1); TM (ma.a5, ma.a5 + j, ma.a5, 3); TM (ma.a5, ma.a5 + j, ma.a5, 5); - TM (ma.a5, ma.a5 + j, ma.a5, 7); /* { dg-warning "offset \\\[6, 8] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 0" } */ - TM (ma.a5, ma.a5 + j, ma.a5, 9); /* { dg-warning "offset \\\[6, 10] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 0" } */ + TM (ma.a5, ma.a5 + j, ma.a5, 7); /* { dg-warning "offset \\\[5, 7] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 0" } */ + TM (ma.a5, ma.a5 + j, ma.a5, 9); /* { dg-warning "offset \\\[5, 9] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 0" } */ } void test_strcpy_bounds_memarray_range (void) @@ -67,7 +67,7 @@ void test_strcpy_bounds_memarray_range (void) #if __i386__ || __x86_64__ /* Disabled for non-x86 targets due to bug 83462. */ - TM ("", "012345", ma.a7 + i, ma.a7); /* { dg-warning "offset 13 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a7. with type .char ?\\\[7]. at offset 5" "strcpy" { xfail { ! { i?86-*-* x86_64-*-* } } } } */ + TM ("", "012345", ma.a7 + i, ma.a7); /* { dg-warning "offset 12 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a7. with type .char ?\\\[7]. at offset 5" "strcpy" { xfail { ! { i?86-*-* x86_64-*-* } } } } */ #endif } diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-39.c b/gcc/testsuite/gcc.dg/Warray-bounds-39.c index ca42af8..f10ffac 100644 --- a/gcc/testsuite/gcc.dg/Warray-bounds-39.c +++ b/gcc/testsuite/gcc.dg/Warray-bounds-39.c @@ -123,7 +123,7 @@ char* test_strcpy_s0 (char *d) char* test_strcpy_s0_0 (char *d) { - return strcpy (d, s0_0[0]); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr88991" { xfail *-*-* } } */ + return strcpy (d, s0_0[0]); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */ } @@ -139,10 +139,10 @@ char* test_strncpy_s0_2 (char *d) char* test_strncpy_s0_0_1 (char *d) { - return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr88991" { xfail *-*-* } } */ + return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */ } char* test_strncpy_s0_0_2 (char *d) { - return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr88991" { xfail *-*-* } } */ + return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */ } diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-45.c b/gcc/testsuite/gcc.dg/Warray-bounds-45.c new file mode 100644 index 0000000..e21452f --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-45.c @@ -0,0 +1,330 @@ +/* PR middle-end/91631 - buffer overflow into an array member of a declared + object not detected + Test to verify that past-the-end accesses by string functions to member + arrays by-reference objects are diagnosed. + { dg-do compile } + { dg-options "-O2 -Wall -Wno-unused-local-typedefs -ftrack-macro-expansion=0" } */ + +extern char* strcpy (char*, const char*); +extern char* strcat (char*, const char*); + +void sink (void*, ...); + +#define S36 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +#define S(N) (S36 + sizeof (S36) - N - 1) + +/* In the test macro, prevent the strcpy to memcpy transformation + by using a local array initialized with the string literal. Without + it, GCC transforms the strcpy call with memcpy which (unfortunately) + permits accesses that cross subobject boundaries. */ +#define T(dst, ncpy, ncat) \ + do { \ + const char a[] = S36; \ + strcpy (dst, a + sizeof a - ncpy - 1); \ + const char b[] = S36; \ + strcat (dst, b + sizeof b - ncat - 1); \ + sink (dst); \ + } while (0) + + +struct MemArrays +{ + char a7[7]; // { dg-message "'a7' declared here" } + char a4[4]; // { dg-message "'a4' declared here" } + char a3[3]; // { dg-message "'a3' declared here" } +}; + +struct MemArrays gma; + +void strcat_value (void) +{ + T (gma.a7, 1, 1); + T (gma.a7, 1, 5); + T (gma.a7, 1, 6); // { dg-warning "'strcat' offset 7 from the object at 'gma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + T (gma.a7, 1, 7); // { dg-warning "'strcat' offset \\\[7, 8] from the object at 'gma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + + T (gma.a7, 2, 1); + T (gma.a7, 2, 4); + T (gma.a7, 2, 5); // { dg-warning "'strcat' offset 7 from the object at 'gma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + T (gma.a7, 2, 6); // { dg-warning "'strcat' offset \\\[7, 8] from the object at 'gma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + + T (gma.a7, 5, 1); + T (gma.a7, 5, 2); // { dg-warning "'strcat' offset 7 from the object at 'gma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + + T (gma.a4, 1, 1); + T (gma.a4, 1, 2); + T (gma.a4, 1, 3); // { dg-warning "'strcat' offset 11 from the object at 'gma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 7" } + T (gma.a4, 1, 4); // { dg-warning "'strcat' offset \\\[11, 12] from the object at 'gma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 7" } + + T (gma.a4, 2, 3); // { dg-warning "'strcat' offset \\\[11, 12] from the object at 'gma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 7" } + + T (gma.a3, 1, 1); + T (gma.a3, 1, 2); // { dg-warning "'strcat' offset 14 from the object at 'gma' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 11" } +} + + +void strcat_ref (struct MemArrays *pma) +{ + T (pma->a7, 1, 1); + T (pma->a7, 1, 5); + T (pma->a7, 1, 6); // { dg-warning "'strcat' offset 7 from the object at 'pma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + T (pma->a7, 1, 7); // { dg-warning "'strcat' offset \\\[7, 8] from the object at 'pma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + + T (pma->a7, 2, 1); + T (pma->a7, 2, 4); + T (pma->a7, 2, 5); // { dg-warning "'strcat' offset 7 from the object at 'pma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + T (pma->a7, 2, 6); // { dg-warning "'strcat' offset \\\[7, 8] from the object at 'pma' is out of the bounds of referenced subobject 'a7' with type 'char\\\[7]' at offset 0" } + + T (pma->a4, 1, 1); + T (pma->a4, 1, 2); + T (pma->a4, 1, 3); // { dg-warning "'strcat' offset 11 from the object at 'pma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 7" } + T (pma->a4, 1, 4); // { dg-warning "'strcat' offset \\\[11, 12] from the object at 'pma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 7" } + + T (pma->a4, 2, 3); // { dg-warning "'strcat' offset \\\[11, 12] from the object at 'pma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 7" } + + T (pma->a3, 1, 1); + T (pma->a3, 1, 2); // { dg-warning "'strcat' offset 14 from the object at 'pma' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 11" } +} + + +#define T2(dst1, dst2, ncpy, ncat) \ + do { \ + const char a[] = S36; \ + strcpy (dst1, a + sizeof a - ncpy - 1); \ + const char b[] = S36; \ + strcat (dst2, b + sizeof b - ncat - 1); \ + sink (dst1, dst2); \ + } while (0) + +struct ArraysOfMemArrays +{ + struct MemArrays ma3[3]; +} a3[3]; + +void strcat_arrays_of_arrays_value (void) +{ + T2 (a3[0].ma3[0].a7, a3[0].ma3[0].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (a3[0].ma3[0].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[0].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[1].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[1].a7, a3[0].ma3[1].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (a3[0].ma3[1].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[2].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[2].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[2].a7, a3[0].ma3[2].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + + T2 (a3[0].ma3[0].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[0].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[0].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[1].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[1].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[1].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[2].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[2].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[2].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[0].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[0].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[0].a7, a3[2].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[1].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[1].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[1].a7, a3[2].ma3[2].a7, 6, 6); + + T2 (a3[0].ma3[2].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[0].ma3[2].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[0].ma3[2].a7, a3[2].ma3[2].a7, 6, 6); + + + T2 (a3[1].ma3[0].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[0].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[0].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[1].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[1].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[1].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[2].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[2].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[2].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[0].a7, a3[1].ma3[0].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (a3[1].ma3[0].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[0].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[1].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[1].a7, a3[1].ma3[1].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (a3[1].ma3[1].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[2].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[2].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[2].a7, a3[1].ma3[2].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + + T2 (a3[1].ma3[0].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[0].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[0].a7, a3[2].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[1].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[1].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[1].a7, a3[2].ma3[2].a7, 6, 6); + + T2 (a3[1].ma3[2].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[1].ma3[2].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[1].ma3[2].a7, a3[2].ma3[2].a7, 6, 6); + + + T2 (a3[2].ma3[0].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[0].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[0].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[1].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[1].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[1].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[2].a7, a3[0].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[2].a7, a3[0].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[2].a7, a3[0].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[0].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[0].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[0].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[1].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[1].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[1].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[2].a7, a3[1].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[2].a7, a3[1].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[2].a7, a3[1].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[0].a7, a3[2].ma3[0].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (a3[2].ma3[0].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[0].a7, a3[2].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[1].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[1].a7, a3[2].ma3[1].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (a3[2].ma3[1].a7, a3[2].ma3[2].a7, 6, 6); + + T2 (a3[2].ma3[2].a7, a3[2].ma3[0].a7, 6, 6); + T2 (a3[2].ma3[2].a7, a3[2].ma3[1].a7, 6, 6); + T2 (a3[2].ma3[2].a7, a3[2].ma3[2].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } +} + + +void strcat_arrays_of_arrays_ref (struct ArraysOfMemArrays *p) +{ + T2 (p[0].ma3[0].a7, p[0].ma3[0].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (p[0].ma3[0].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[0].ma3[0].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[1].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[0].ma3[1].a7, p[0].ma3[1].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (p[0].ma3[1].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[2].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[0].ma3[2].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[0].ma3[2].a7, p[0].ma3[2].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + + T2 (p[0].ma3[0].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[0].ma3[0].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[0].ma3[0].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[1].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[0].ma3[1].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[0].ma3[1].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[2].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[0].ma3[2].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[0].ma3[2].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[0].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[0].ma3[0].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[0].ma3[0].a7, p[2].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[1].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[0].ma3[1].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[0].ma3[1].a7, p[2].ma3[2].a7, 6, 6); + + T2 (p[0].ma3[2].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[0].ma3[2].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[0].ma3[2].a7, p[2].ma3[2].a7, 6, 6); + + + T2 (p[1].ma3[0].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[1].ma3[0].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[1].ma3[0].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[1].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[1].ma3[1].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[1].ma3[1].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[2].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[1].ma3[2].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[1].ma3[2].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[0].a7, p[1].ma3[0].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (p[1].ma3[0].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[1].ma3[0].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[1].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[1].ma3[1].a7, p[1].ma3[1].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (p[1].ma3[1].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[2].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[1].ma3[2].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[1].ma3[2].a7, p[1].ma3[2].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + + T2 (p[1].ma3[0].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[1].ma3[0].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[1].ma3[0].a7, p[2].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[1].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[1].ma3[1].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[1].ma3[1].a7, p[2].ma3[2].a7, 6, 6); + + T2 (p[1].ma3[2].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[1].ma3[2].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[1].ma3[2].a7, p[2].ma3[2].a7, 6, 6); + + + T2 (p[2].ma3[0].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[2].ma3[0].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[2].ma3[0].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[1].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[2].ma3[1].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[2].ma3[1].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[2].a7, p[0].ma3[0].a7, 6, 6); + T2 (p[2].ma3[2].a7, p[0].ma3[1].a7, 6, 6); + T2 (p[2].ma3[2].a7, p[0].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[0].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[2].ma3[0].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[2].ma3[0].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[1].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[2].ma3[1].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[2].ma3[1].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[2].a7, p[1].ma3[0].a7, 6, 6); + T2 (p[2].ma3[2].a7, p[1].ma3[1].a7, 6, 6); + T2 (p[2].ma3[2].a7, p[1].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[0].a7, p[2].ma3[0].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (p[2].ma3[0].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[2].ma3[0].a7, p[2].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[1].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[2].ma3[1].a7, p[2].ma3[1].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } + T2 (p[2].ma3[1].a7, p[2].ma3[2].a7, 6, 6); + + T2 (p[2].ma3[2].a7, p[2].ma3[0].a7, 6, 6); + T2 (p[2].ma3[2].a7, p[2].ma3[1].a7, 6, 6); + T2 (p[2].ma3[2].a7, p[2].ma3[2].a7, 6, 6); // { dg-warning "\\\[-Warray-bounds" } +} diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-46.c b/gcc/testsuite/gcc.dg/Warray-bounds-46.c new file mode 100644 index 0000000..09b577e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-46.c @@ -0,0 +1,249 @@ +/* PR middle-end/91631 - buffer overflow into an array member of a declared + object not detected + Test to verify that past-the-end accesses by string functions to member + arrays by-reference objects are diagnosed. + { dg-do compile } + { dg-options "-O2 -Wall -Wno-unused-local-typedefs -ftrack-macro-expansion=0" } */ + +#define SA(expr) typedef int StaticAssert [2 * !!(expr) - 1] + +typedef __SIZE_TYPE__ size_t; + +extern char* strcpy (char*, const char*); +extern char* strncpy (char*, const char*, size_t); + +void sink (void*); + +struct MA17 +{ + char pad[4]; + char a1[1], a2[2], a3[3], a4[4], a5[5], a6[6], a7[7], a8[8], a9[9], a10[10]; + char a11[11], a12[12], a13[13], a14[14], a15[15], a16[16], a17[17], ax[]; +}; + +extern struct MA17 gma; +extern struct MA17 gma2[2]; + +struct MA17 igma_3 = { .ax = { 1, 2, 3 } }; +struct MA17 igma2_[2]; + +#define S36 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +#define S(N) (S36 + sizeof (S36) - N - 1) + +/* In the test macro, prevent the strcpy to memcpy transformation + by using a local array initialized with the string literal. Without + it, GCC transforms the strcpy call with memcpy which (unfortunately) + permits accesses that cross subobject boundaries. */ +#define T(dst, n) \ + do { \ + const char a[] = S36; \ + strcpy (dst, a + sizeof a - n - 1); \ + sink (dst); \ + } while (0) + +void strcpy_global (void) +{ + T (gma.a1, 0); + T (gma.a1, 1); // { dg-warning "'strcpy' offset 5 from the object at 'gma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + T (gma.a1, 4); // { dg-warning "'strcpy' offset \\\[5, 8] from the object at 'gma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + + T (gma.a2, 1); + T (gma.a2, 2); // { dg-warning "'strcpy' offset 7 from the object at 'gma' is out of the bounds of referenced subobject 'a2' with type 'char\\\[2]' at offset 5" } + + T (gma.a3, 2); + T (gma.a3, 3); // { dg-warning "'strcpy' offset 10 from the object at 'gma' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 7" } + + T (gma.a4, 3); + T (gma.a4, 4); // { dg-warning "'strcpy' offset 14 from the object at 'gma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 10" } + + T (gma.a5, 4); + T (gma.a5, 5); // { dg-warning "'strcpy' offset 19 from the object at 'gma' is out of the bounds of referenced subobject 'a5' with type 'char\\\[5]' at offset 14" } + + SA (__builtin_offsetof (struct MA17, a17) == 140); + + T (gma.a17, 16); + T (gma.a17, 17); // { dg-warning "'strcpy' offset 157 from the object at 'gma' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 140" } + + SA (__builtin_offsetof (struct MA17, ax) == 157); + + T (gma.ax, 0); // { dg-warning "'strcpy' offset 157 is out of the bounds \\\[0, 157] of object 'gma' with type 'struct MA17'" } +} + + +void strcpy_global_array (void) +{ + T (gma2[0].a1, 0); + T (gma2[0].a1, 1); // { dg-warning "'strcpy' offset 5 from the object at 'gma2' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + T (gma2[0].a1, 4); // { dg-warning "'strcpy' offset \\\[5, 8] from the object at 'gma2' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + + T (gma2[0].a2, 1); + T (gma2[0].a2, 2); // { dg-warning "'strcpy' offset 7 from the object at 'gma2' is out of the bounds of referenced subobject 'a2' with type 'char\\\[2]' at offset 5" } + + T (gma2[0].a3, 2); + T (gma2[0].a3, 3); // { dg-warning "'strcpy' offset 10 from the object at 'gma2' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 7" } + + T (gma2[0].a4, 3); + T (gma2[0].a4, 4); // { dg-warning "'strcpy' offset 14 from the object at 'gma2' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 10" } + + T (gma2[0].a5, 4); + T (gma2[0].a5, 5); // { dg-warning "'strcpy' offset 19 from the object at 'gma2' is out of the bounds of referenced subobject 'a5' with type 'char\\\[5]' at offset 14" } + + T (gma2[0].a17, 16); + T (gma2[0].a17, 17); // { dg-warning "'strcpy' offset 157 from the object at 'gma2' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 140" } + + /* GMA2 is external buts because it's an array its definition in another + translation unit may not provide an initializer for the flexible array + member. Verify that a warning is issued for access to it. */ + T (gma2[0].ax, 1); // { dg-warning "'strcpy' offset \\\[157, 158] from the object at 'gma2' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" } + T (gma2[0].ax, 7); // { dg-warning "'strcpy' offset \\\[157, 164] from the object at 'gma2' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" } + + /* IGMA_ is internal and provides on definition for the flexible array + member. Verify that a warnin is issued for out-of-bounds accesses + to it. */ + T (igma2_[0].ax, 1); // { dg-warning "'strcpy' offset \\\[157, 158] from the object at 'igma2_' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" } + + T (igma_3.ax, 0); + T (igma_3.ax, 1); + T (igma_3.ax, 1); + T (igma_3.ax, 3); // { dg-warning " offset 160 " } + T (igma_3.ax, 9); // { dg-warning " offset \\\[160, 166] " } +} + + +void strcpy_local (void) +{ + struct MA17 lma; + + T (lma.a1, 0); + T (lma.a1, 1); // { dg-warning "'strcpy' offset 5 from the object at 'lma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + T (lma.a1, 4); // { dg-warning "'strcpy' offset \\\[5, 8] from the object at 'lma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + + T (lma.a2, 1); + T (lma.a2, 2); // { dg-warning "'strcpy' offset 7 from the object at 'lma' is out of the bounds of referenced subobject 'a2' with type 'char\\\[2]' at offset 5" } + + T (lma.a3, 2); + T (lma.a3, 3); // { dg-warning "'strcpy' offset 10 from the object at 'lma' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 7" } + + T (lma.a4, 3); + T (lma.a4, 4); // { dg-warning "'strcpy' offset 14 from the object at 'lma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 10" } + + T (lma.a5, 4); + T (lma.a5, 5); // { dg-warning "'strcpy' offset 19 from the object at 'lma' is out of the bounds of referenced subobject 'a5' with type 'char\\\[5]' at offset 14" } + + T (lma.a17, 16); + T (lma.a17, 17); // { dg-warning "'strcpy' offset 157 from the object at 'lma' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 140" } + + T (lma.ax, 0); // { dg-warning "'strcpy' offset 157 from the object at 'lma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" } +} + + +void strcpy_ref (struct MA17 *pma) +{ + T (pma->a1, 0); + T (pma->a1, 1); // { dg-warning "'strcpy' offset 5 from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + T (pma->a1, 4); // { dg-warning "'strcpy' offset \\\[5, 8] from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 4" } + + T (pma->a2, 1); + T (pma->a2, 2); // { dg-warning "'strcpy' offset 7 from the object at 'pma' is out of the bounds of referenced subobject 'a2' with type 'char\\\[2]' at offset 5" } + + T (pma->a3, 2); + T (pma->a3, 3); // { dg-warning "'strcpy' offset 10 from the object at 'pma' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 7" } + + T (pma->a4, 3); + T (pma->a4, 4); // { dg-warning "'strcpy' offset 14 from the object at 'pma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 10" } + + T (pma->a5, 4); + T (pma->a5, 5); // { dg-warning "'strcpy' offset 19 from the object at 'pma' is out of the bounds of referenced subobject 'a5' with type 'char\\\[5]' at offset 14" } + + T (pma->a17, 16); + T (pma->a17, 17); // { dg-warning "'strcpy' offset 157 from the object at 'pma' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 140" } + + T (pma->ax, 0); + T ((*pma).ax, 8); + T (pma[0].ax, 9); + + SA (__builtin_offsetof (struct MA17, a1) == 4 + && sizeof (struct MA17) == 157); + + T (pma[1].a1, 0); + T (pma[1].a1, 1); // { dg-warning "'strcpy' offset 162 from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 161" } + T (pma[1].a1, 4); // { dg-warning "'strcpy' offset \\\[162, 165] from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset 161" } + + T (pma[1].a2, 1); + T (pma[1].a2, 2); // { dg-warning "'strcpy' offset 164 from the object at 'pma' is out of the bounds of referenced subobject 'a2' with type 'char\\\[2]' at offset 162" } + + T (pma[1].a3, 2); + T (pma[1].a3, 3); // { dg-warning "'strcpy' offset 167 from the object at 'pma' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset 164" } + + T (pma[1].a4, 3); + T (pma[1].a4, 4); // { dg-warning "'strcpy' offset 171 from the object at 'pma' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset 167" } + + T (pma[1].a5, 4); + T (pma[1].a5, 5); // { dg-warning "'strcpy' offset 176 from the object at 'pma' is out of the bounds of referenced subobject 'a5' with type 'char\\\[5]' at offset 171" } + + T (pma[1].a17, 16); + T (pma[1].a17, 17); // { dg-warning "'strcpy' offset 314 from the object at 'pma' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 297" } + + /* Since PMA points to an array of structs, accessing the flexible + member of any of the elements of the array except for the last one + would necessarily access a part of the next element of the enclosing + array. The warning assumes that PMA doesn't point to the last element + of the array which could in theory have nonzero elements without + overlapping other objects. */ + T (pma[1].ax, 0); // { dg-warning "'strcpy' offset 314 from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 314" } + T ((pma + 1)->ax, 1); // { dg-warning "'strcpy' offset \\\[314, 315] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 314" } + T ((pma + 1)[1].ax, 2); // { dg-warning "'strcpy' offset \\\[471, 473] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 471" } + T ((*(pma + 2)).ax, 2); // { dg-warning "'strcpy' offset \\\[471, 473] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 471" } + T (pma[3].ax, 9); // { dg-warning "'strcpy' offset \\\[628, 637] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 628" } + + T (pma[-1].a1, 0); + T (pma[-1].a1, 1); // { dg-warning "'strcpy' offset -152 from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset -153" } + T (pma[-1].a1, 4); // { dg-warning "'strcpy' offset \\\[-152, -149] from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset -153" } +} + +struct MA3 +{ + char a4[4]; // { dg-message "'a4' declared here" } + char a3[3]; // { dg-message "'a3' declared here" } + char c; +}; + +void strcpy_ref_note (struct MA17 *pma, struct MA3 *pma3) +{ + T (pma3[-1].a4, 0); + T (pma3[-1].a4, 1); + T (pma3[-1].a4, 2); + T (pma3[-1].a4, 3); + T (pma3[-1].a4, 4); // { dg-warning "'strcpy' offset -4 from the object at 'pma3' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset -8" } + T (pma3[-1].a4, 5); // { dg-warning "'strcpy' offset \\\[-4, -3] from the object at 'pma3' is out of the bounds of referenced subobject 'a4' with type 'char\\\[4]' at offset -8" } + + T (pma3[-1].a3, 0); + T (pma3[-1].a3, 1); + T (pma3[-1].a3, 2); + T (pma3[-1].a3, 3); // { dg-warning "'strcpy' offset -1 from the object at 'pma3' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset -4" } + T (pma3[-1].a3, 4); // { dg-warning "'strcpy' offset \\\[-1, 0] from the object at 'pma3' is out of the bounds of referenced subobject 'a3' with type 'char\\\[3]' at offset -4" } +} + + +void strncpy_vla_member (unsigned n) +{ + struct VarLenStruct { + char a4[4], an[n], bn[n]; + } x; + + sink (&x); + + strncpy (x.bn, x.a4, sizeof x.bn); + sink (&x); + + strncpy (x.a4, x.bn, sizeof x.a4); + x.a4[sizeof x.a4 - 1] = '\0'; + sink (&x); + + strncpy (x.a4, x.bn, n); + sink (&x); + + strncpy (x.an, x.bn, sizeof x.bn); /* { dg-bogus "\\\[-Warray-bounds" } */ + sink (&x); +} diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index b979320..5e1054b 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -3057,11 +3057,12 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi) /* Compute the size of the source sequence, including the nul. */ tree srcsize = srclen ? srclen : size_zero_node; - srcsize = fold_build2 (PLUS_EXPR, type, srcsize, build_int_cst (type, 1)); - + tree one = build_int_cst (type, 1); + srcsize = fold_build2 (PLUS_EXPR, type, srcsize, one); + tree dstsize = fold_build2 (PLUS_EXPR, type, dstlen, one); tree sptr = si && si->ptr ? si->ptr : src; - if (check_bounds_or_overlap (stmt, dst, sptr, dstlen, srcsize)) + if (check_bounds_or_overlap (stmt, dst, sptr, dstsize, srcsize)) { gimple_set_no_warning (stmt, true); set_no_warning = true; diff --git a/gcc/tree.c b/gcc/tree.c index 6be756c..59ea6b9 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -67,6 +67,7 @@ along with GCC; see the file COPYING3. If not see #include "rtl.h" #include "regs.h" #include "tree-vector-builder.h" +#include "gimple-fold.h" /* Tree code classes. */ @@ -13850,6 +13851,75 @@ component_ref_field_offset (tree exp) return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp); } +/* Determines the size of the member referenced by the COMPONENT_REF + REF, using its initializer expression if necessary in order to + determine the size of an initialized flexible array member. + Returns the size (which might be zero for an object with + an uninitialized flexible array member) or null if the size + cannot be determined. */ + +tree +component_ref_size (tree ref) +{ + gcc_assert (TREE_CODE (ref) == COMPONENT_REF); + + tree member = TREE_OPERAND (ref, 1); + + /* If the member is not an array, or is not last, or is an array with + more than one element, return its size. Otherwise it's either + a bona fide flexible array member, or a zero-length array member, + or an array of length one treated as such. */ + tree size = DECL_SIZE_UNIT (member); + if (size) + { + tree memtype = TREE_TYPE (member); + if (TREE_CODE (memtype) != ARRAY_TYPE + || !array_at_struct_end_p (ref)) + return size; + + if (!integer_zerop (size)) + if (tree dom = TYPE_DOMAIN (memtype)) + if (tree min = TYPE_MIN_VALUE (dom)) + if (tree max = TYPE_MAX_VALUE (dom)) + if (TREE_CODE (min) == INTEGER_CST + && TREE_CODE (max) == INTEGER_CST) + { + offset_int minidx = wi::to_offset (min); + offset_int maxidx = wi::to_offset (max); + if (maxidx - minidx > 1) + return size; + } + } + + /* If the reference is to a declared object and the member a true + flexible array, try to determine its size from its initializer. */ + poly_int64 off = 0; + tree base = get_addr_base_and_unit_offset (ref, &off); + if (!base || !VAR_P (base)) + return NULL_TREE; + + /* The size of any member of a declared object other than a flexible + array member is that obtained above. */ + if (size) + return size; + + if (tree init = DECL_INITIAL (base)) + if (TREE_CODE (init) == CONSTRUCTOR) + { + off <<= LOG2_BITS_PER_UNIT; + init = fold_ctor_reference (NULL_TREE, init, off, 0, base); + if (init) + return TYPE_SIZE_UNIT (TREE_TYPE (init)); + } + + /* Return "don't know" for an external non-array object since its + flexible array member can be initialized to have any number of + elements. Otherwise, return zero because the flexible array + member has no elements. */ + return (DECL_EXTERNAL (base) && TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE + ? NULL_TREE : integer_zero_node); +} + /* Return the machine mode of T. For vectors, returns the mode of the inner type. The main use case is to feed the result to HONOR_NANS, avoiding the BLKmode that a direct TYPE_MODE (T) might return. */ diff --git a/gcc/tree.h b/gcc/tree.h index 3fc36a4..c825109 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5263,6 +5263,13 @@ extern bool array_at_struct_end_p (tree); by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */ extern tree component_ref_field_offset (tree); +/* Return the size of the member referenced by the COMPONENT_REF, using + its initializer expression if necessary in order to determine the size + of an initialized flexible array member. The size might be zero for + an object with an uninitialized flexible array member or null if it + cannot be determined. */ +extern tree component_ref_size (tree); + extern int tree_map_base_eq (const void *, const void *); extern unsigned int tree_map_base_hash (const void *); extern int tree_map_base_marked_p (const void *); -- cgit v1.1 From ff6686d2e5f797d6c6a36ad14a7084bc1dc350e4 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 20 Sep 2019 00:25:04 +0200 Subject: New IPA-SRA 2019-09-20 Martin Jambor * coretypes.h (cgraph_edge): Declare. * ipa-param-manipulation.c: Rewrite. * ipa-param-manipulation.h: Likewise. * Makefile.in (GTFILES): Added ipa-param-manipulation.h and ipa-sra.c. (OBJS): Added ipa-sra.o. * cgraph.h (ipa_replace_map): Removed fields old_tree, replace_p and ref_p, added fields param_adjustments and performed_splits. (struct cgraph_clone_info): Remove ags_to_skip and combined_args_to_skip, new field param_adjustments. (cgraph_node::create_clone): Changed parameters to use ipa_param_adjustments. (cgraph_node::create_virtual_clone): Likewise. (cgraph_node::create_virtual_clone_with_body): Likewise. (tree_function_versioning): Likewise. (cgraph_build_function_type_skip_args): Removed. * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Convert to using ipa_param_adjustments. (clone_of_p): Likewise. * cgraphclones.c (cgraph_build_function_type_skip_args): Removed. (build_function_decl_skip_args): Likewise. (duplicate_thunk_for_node): Adjust parameters using ipa_param_body_adjustments, copy param_adjustments instead of args_to_skip. (cgraph_node::create_clone): Convert to using ipa_param_adjustments. (cgraph_node::create_virtual_clone): Likewise. (cgraph_node::create_version_clone_with_body): Likewise. (cgraph_materialize_clone): Likewise. (symbol_table::materialize_all_clones): Likewise. * ipa-fnsummary.c (ipa_fn_summary_t::duplicate): Simplify ipa_replace_map check. * ipa-cp.c (get_replacement_map): Do not initialize removed fields. (initialize_node_lattices): Make aware that some parameters might have already been removed. (want_remove_some_param_p): New function. (create_specialized_node): Convert to using ipa_param_adjustments and deal with possibly pre-existing adjustments. * lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. (output_node_opt_summary): Do not stream removed fields. Stream parameter adjustments instead of argumetns to skip. (input_node_opt_summary): Likewise. (input_node_opt_summary): Likewise. * lto-section-in.c (lto_section_name): Added ipa-sra section. * lto-streamer.h (lto_section_type): Likewise. * tree-inline.h (copy_body_data): New fields killed_new_ssa_names and param_body_adjs. (copy_decl_to_var): Declare. * tree-inline.c (update_clone_info): Do not remap old_tree. (remap_gimple_stmt): Use ipa_param_body_adjustments to modify gimple statements, walk all extra generated statements and remap their operands. (redirect_all_calls): Add killed SSA names to a hash set. (remap_ssa_name): Do not remap killed SSA names. (copy_arguments_for_versioning): Renames to copy_arguments_nochange, half of functionality moved to ipa_param_body_adjustments. (copy_decl_to_var): Make exported. (copy_body): Destroy killed_new_ssa_names hash set. (expand_call_inline): Remap performed splits. (update_clone_info): Likewise. (tree_function_versioning): Simplify tree_map processing. Updated to accept ipa_param_adjustments and use ipa_param_body_adjustments. * omp-simd-clone.c (simd_clone_vector_of_formal_parm_types): Adjust for the new interface. (simd_clone_clauses_extract): Likewise, make args an auto_vec. (simd_clone_compute_base_data_type): Likewise. (simd_clone_init_simd_arrays): Adjust for the new interface. (simd_clone_adjust_argument_types): Likewise. (struct modify_stmt_info): Likewise. (ipa_simd_modify_stmt_ops): Likewise. (ipa_simd_modify_function_body): Likewise. (simd_clone_adjust): Likewise. * tree-sra.c: Removed IPA-SRA. Include tree-sra.h. (type_internals_preclude_sra_p): Make public. * tree-sra.h: New file. * ipa-inline-transform.c (save_inline_function_body): Update to refelct new tree_function_versioning signature. * ipa-prop.c (adjust_agg_replacement_values): Use a helper from ipa_param_adjustments to get current parameter indices. (ipcp_modif_dom_walker::before_dom_children): Likewise. (ipcp_update_bits): Likewise. (ipcp_update_vr): Likewise. * ipa-split.c (split_function): Convert to using ipa_param_adjustments. * ipa-sra.c: New file. * multiple_target.c (create_target_clone): Update to reflet new type of create_version_clone_with_body. * trans-mem.c (ipa_tm_create_version): Update to reflect new type of tree_function_versioning. (modify_function): Update to reflect new type of tree_function_versioning. * params.def (PARAM_IPA_SRA_MAX_REPLACEMENTS): New. * passes.def: Remove old IPA-SRA and add new one. * tree-pass.h (make_pass_early_ipa_sra): Remove declaration. (make_pass_ipa_sra): Declare. * dbgcnt.def: Remove eipa_sra. Added ipa_sra_params and ipa_sra_retvalues. * doc/invoke.texi (ipa-sra-max-replacements): New. testsuite/ * g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan. * gcc.dg/ipa/ipa-sra-1.c: Likewise. * gcc.dg/ipa/ipa-sra-10.c: Likewise. * gcc.dg/ipa/ipa-sra-11.c: Likewise. * gcc.dg/ipa/ipa-sra-3.c: Likewise. * gcc.dg/ipa/ipa-sra-4.c: Likewise. * gcc.dg/ipa/ipa-sra-5.c: Likewise. * gcc.dg/ipa/ipacost-2.c: Disable ipa-sra. * gcc.dg/ipa/ipcp-agg-9.c: Likewise. * gcc.dg/ipa/pr78121.c: Adjust scan pattern. * gcc.dg/ipa/vrp1.c: Likewise. * gcc.dg/ipa/vrp2.c: Likewise. * gcc.dg/ipa/vrp3.c: Likewise. * gcc.dg/ipa/vrp7.c: Likewise. * gcc.dg/ipa/vrp8.c: Likewise. * gcc.dg/noreorder.c: use noipa attribute instead of noinline. * gcc.dg/ipa/20040703-wpa.c: New test. * gcc.dg/ipa/ipa-sra-12.c: New test. * gcc.dg/ipa/ipa-sra-13.c: Likewise. * gcc.dg/ipa/ipa-sra-14.c: Likewise. * gcc.dg/ipa/ipa-sra-15.c: Likewise. * gcc.dg/ipa/ipa-sra-16.c: Likewise. * gcc.dg/ipa/ipa-sra-17.c: Likewise. * gcc.dg/ipa/ipa-sra-18.c: Likewise. * gcc.dg/ipa/ipa-sra-19.c: Likewise. * gcc.dg/ipa/ipa-sra-20.c: Likewise. * gcc.dg/ipa/ipa-sra-21.c: Likewise. * gcc.dg/ipa/ipa-sra-22.c: Likewise. * gcc.dg/sso/ipa-sra-1.c: Likewise. * g++.dg/ipa/ipa-sra-2.C: Likewise. * g++.dg/ipa/ipa-sra-3.C: Likewise. * gcc.dg/tree-ssa/ipa-cp-1.c: Make return value used. * g++.dg/ipa/devirt-19.C: Add missing return, add -fipa-cp-clone option. * g++.dg/lto/devirt-19_0.C: Add -fipa-cp-clone option. * gcc.dg/ipa/ipa-sra-2.c: Removed. * gcc.dg/ipa/ipa-sra-6.c: Likewise. From-SVN: r275982 --- gcc/ChangeLog | 98 + gcc/Makefile.in | 3 +- gcc/cgraph.c | 127 +- gcc/cgraph.h | 45 +- gcc/cgraphclones.c | 213 +- gcc/coretypes.h | 1 + gcc/dbgcnt.def | 3 +- gcc/doc/invoke.texi | 5 + gcc/ipa-cp.c | 172 +- gcc/ipa-fnsummary.c | 4 +- gcc/ipa-inline-transform.c | 3 +- gcc/ipa-param-manipulation.c | 2093 +++++++++++---- gcc/ipa-param-manipulation.h | 449 +++- gcc/ipa-prop.c | 103 +- gcc/ipa-split.c | 32 +- gcc/ipa-sra.c | 4049 ++++++++++++++++++++++++++++++ gcc/lto-cgraph.c | 121 +- gcc/lto-section-in.c | 3 +- gcc/lto-streamer.h | 1 + gcc/multiple_target.c | 5 +- gcc/omp-simd-clone.c | 229 +- gcc/params.def | 7 + gcc/passes.def | 2 +- gcc/testsuite/ChangeLog | 40 + gcc/testsuite/g++.dg/ipa/devirt-19.C | 5 +- gcc/testsuite/g++.dg/ipa/ipa-sra-1.C | 46 + gcc/testsuite/g++.dg/ipa/ipa-sra-2.C | 19 + gcc/testsuite/g++.dg/ipa/ipa-sra-3.C | 9 + gcc/testsuite/g++.dg/ipa/pr81248.C | 4 +- gcc/testsuite/g++.dg/lto/devirt-19_0.C | 2 +- gcc/testsuite/gcc.dg/ipa/20040703-wpa.c | 151 ++ gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c | 4 +- gcc/testsuite/gcc.dg/ipa/ipa-sra-10.c | 4 +- gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c | 6 +- gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c | 50 + gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c | 49 + gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c | 60 + gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c | 61 + gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c | 74 + gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c | 102 + gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c | 49 + gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c | 31 + gcc/testsuite/gcc.dg/ipa/ipa-sra-2.c | 51 - gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c | 38 + gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c | 33 + gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c | 56 + gcc/testsuite/gcc.dg/ipa/ipa-sra-3.c | 7 +- gcc/testsuite/gcc.dg/ipa/ipa-sra-4.c | 8 +- gcc/testsuite/gcc.dg/ipa/ipa-sra-5.c | 4 +- gcc/testsuite/gcc.dg/ipa/ipa-sra-6.c | 33 - gcc/testsuite/gcc.dg/ipa/ipacost-2.c | 4 +- gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c | 2 +- gcc/testsuite/gcc.dg/ipa/pr78121.c | 2 +- gcc/testsuite/gcc.dg/ipa/vrp1.c | 4 +- gcc/testsuite/gcc.dg/ipa/vrp2.c | 4 +- gcc/testsuite/gcc.dg/ipa/vrp3.c | 2 +- gcc/testsuite/gcc.dg/ipa/vrp7.c | 2 +- gcc/testsuite/gcc.dg/ipa/vrp8.c | 2 +- gcc/testsuite/gcc.dg/noreorder.c | 6 +- gcc/testsuite/gcc.dg/sso/ipa-sra-1.c | 57 + gcc/testsuite/gcc.dg/tree-ssa/ipa-cp-1.c | 2 +- gcc/trans-mem.c | 3 +- gcc/tree-inline.c | 385 ++- gcc/tree-inline.h | 10 + gcc/tree-pass.h | 2 +- gcc/tree-sra.c | 1859 +------------- gcc/tree-sra.h | 31 + 67 files changed, 7998 insertions(+), 3143 deletions(-) create mode 100644 gcc/ipa-sra.c create mode 100644 gcc/testsuite/g++.dg/ipa/ipa-sra-1.C create mode 100644 gcc/testsuite/g++.dg/ipa/ipa-sra-2.C create mode 100644 gcc/testsuite/g++.dg/ipa/ipa-sra-3.C create mode 100644 gcc/testsuite/gcc.dg/ipa/20040703-wpa.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c delete mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-2.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c delete mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-6.c create mode 100644 gcc/testsuite/gcc.dg/sso/ipa-sra-1.c create mode 100644 gcc/tree-sra.h (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9dfb646..6f34d1a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,101 @@ +2019-09-20 Martin Jambor + + * coretypes.h (cgraph_edge): Declare. + * ipa-param-manipulation.c: Rewrite. + * ipa-param-manipulation.h: Likewise. + * Makefile.in (GTFILES): Added ipa-param-manipulation.h and ipa-sra.c. + (OBJS): Added ipa-sra.o. + * cgraph.h (ipa_replace_map): Removed fields old_tree, replace_p + and ref_p, added fields param_adjustments and performed_splits. + (struct cgraph_clone_info): Remove ags_to_skip and + combined_args_to_skip, new field param_adjustments. + (cgraph_node::create_clone): Changed parameters to use + ipa_param_adjustments. + (cgraph_node::create_virtual_clone): Likewise. + (cgraph_node::create_virtual_clone_with_body): Likewise. + (tree_function_versioning): Likewise. + (cgraph_build_function_type_skip_args): Removed. + * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Convert to + using ipa_param_adjustments. + (clone_of_p): Likewise. + * cgraphclones.c (cgraph_build_function_type_skip_args): Removed. + (build_function_decl_skip_args): Likewise. + (duplicate_thunk_for_node): Adjust parameters using + ipa_param_body_adjustments, copy param_adjustments instead of + args_to_skip. + (cgraph_node::create_clone): Convert to using ipa_param_adjustments. + (cgraph_node::create_virtual_clone): Likewise. + (cgraph_node::create_version_clone_with_body): Likewise. + (cgraph_materialize_clone): Likewise. + (symbol_table::materialize_all_clones): Likewise. + * ipa-fnsummary.c (ipa_fn_summary_t::duplicate): Simplify + ipa_replace_map check. + * ipa-cp.c (get_replacement_map): Do not initialize removed fields. + (initialize_node_lattices): Make aware that some parameters might have + already been removed. + (want_remove_some_param_p): New function. + (create_specialized_node): Convert to using ipa_param_adjustments and + deal with possibly pre-existing adjustments. + * lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. + (output_node_opt_summary): Do not stream removed fields. Stream + parameter adjustments instead of argumetns to skip. + (input_node_opt_summary): Likewise. + (input_node_opt_summary): Likewise. + * lto-section-in.c (lto_section_name): Added ipa-sra section. + * lto-streamer.h (lto_section_type): Likewise. + * tree-inline.h (copy_body_data): New fields killed_new_ssa_names and + param_body_adjs. + (copy_decl_to_var): Declare. + * tree-inline.c (update_clone_info): Do not remap old_tree. + (remap_gimple_stmt): Use ipa_param_body_adjustments to modify gimple + statements, walk all extra generated statements and remap their + operands. + (redirect_all_calls): Add killed SSA names to a hash set. + (remap_ssa_name): Do not remap killed SSA names. + (copy_arguments_for_versioning): Renames to copy_arguments_nochange, + half of functionality moved to ipa_param_body_adjustments. + (copy_decl_to_var): Make exported. + (copy_body): Destroy killed_new_ssa_names hash set. + (expand_call_inline): Remap performed splits. + (update_clone_info): Likewise. + (tree_function_versioning): Simplify tree_map processing. Updated to + accept ipa_param_adjustments and use ipa_param_body_adjustments. + * omp-simd-clone.c (simd_clone_vector_of_formal_parm_types): Adjust + for the new interface. + (simd_clone_clauses_extract): Likewise, make args an auto_vec. + (simd_clone_compute_base_data_type): Likewise. + (simd_clone_init_simd_arrays): Adjust for the new interface. + (simd_clone_adjust_argument_types): Likewise. + (struct modify_stmt_info): Likewise. + (ipa_simd_modify_stmt_ops): Likewise. + (ipa_simd_modify_function_body): Likewise. + (simd_clone_adjust): Likewise. + * tree-sra.c: Removed IPA-SRA. Include tree-sra.h. + (type_internals_preclude_sra_p): Make public. + * tree-sra.h: New file. + * ipa-inline-transform.c (save_inline_function_body): Update to + refelct new tree_function_versioning signature. + * ipa-prop.c (adjust_agg_replacement_values): Use a helper from + ipa_param_adjustments to get current parameter indices. + (ipcp_modif_dom_walker::before_dom_children): Likewise. + (ipcp_update_bits): Likewise. + (ipcp_update_vr): Likewise. + * ipa-split.c (split_function): Convert to using ipa_param_adjustments. + * ipa-sra.c: New file. + * multiple_target.c (create_target_clone): Update to reflet new type + of create_version_clone_with_body. + * trans-mem.c (ipa_tm_create_version): Update to reflect new type of + tree_function_versioning. + (modify_function): Update to reflect new type of + tree_function_versioning. + * params.def (PARAM_IPA_SRA_MAX_REPLACEMENTS): New. + * passes.def: Remove old IPA-SRA and add new one. + * tree-pass.h (make_pass_early_ipa_sra): Remove declaration. + (make_pass_ipa_sra): Declare. + * dbgcnt.def: Remove eipa_sra. Added ipa_sra_params and + ipa_sra_retvalues. + * doc/invoke.texi (ipa-sra-max-replacements): New. + 2019-09-19 Martin Sebor PR middle-end/91631 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 152df9f..2cf0c79 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1368,6 +1368,7 @@ OBJS = \ init-regs.o \ internal-fn.o \ ipa-cp.o \ + ipa-sra.o \ ipa-devirt.o \ ipa-fnsummary.o \ ipa-polymorphic-call.o \ @@ -2527,7 +2528,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \ - $(srcdir)/dbxout.c \ + $(srcdir)/ipa-param-manipulation.h $(srcdir)/ipa-sra.c $(srcdir)/dbxout.c \ $(srcdir)/signop.h \ $(srcdir)/dwarf2out.h \ $(srcdir)/dwarf2asm.c \ diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 843891e..331b363 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1342,7 +1342,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void) if (flag_checking && decl) { cgraph_node *node = cgraph_node::get (decl); - gcc_assert (!node || !node->clone.combined_args_to_skip); + gcc_assert (!node || !node->clone.param_adjustments); } if (symtab->dump_file) @@ -1350,25 +1350,36 @@ cgraph_edge::redirect_call_stmt_to_callee (void) fprintf (symtab->dump_file, "updating call of %s -> %s: ", e->caller->dump_name (), e->callee->dump_name ()); print_gimple_stmt (symtab->dump_file, e->call_stmt, 0, dump_flags); - if (e->callee->clone.combined_args_to_skip) + if (e->callee->clone.param_adjustments) + e->callee->clone.param_adjustments->dump (symtab->dump_file); + unsigned performed_len + = vec_safe_length (e->caller->clone.performed_splits); + if (performed_len > 0) + fprintf (symtab->dump_file, "Performed splits records:\n"); + for (unsigned i = 0; i < performed_len; i++) { - fprintf (symtab->dump_file, " combined args to skip: "); - dump_bitmap (symtab->dump_file, - e->callee->clone.combined_args_to_skip); + ipa_param_performed_split *sm + = &(*e->caller->clone.performed_splits)[i]; + print_node_brief (symtab->dump_file, " dummy_decl: ", sm->dummy_decl, + TDF_UID); + fprintf (symtab->dump_file, ", unit_offset: %u\n", sm->unit_offset); } } - if (e->callee->clone.combined_args_to_skip) + if (ipa_param_adjustments *padjs = e->callee->clone.param_adjustments) { - int lp_nr; + /* We need to defer cleaning EH info on the new statement to + fixup-cfg. We may not have dominator information at this point + and thus would end up with unreachable blocks and have no way + to communicate that we need to run CFG cleanup then. */ + int lp_nr = lookup_stmt_eh_lp (e->call_stmt); + if (lp_nr != 0) + remove_stmt_from_eh_lp (e->call_stmt); - new_stmt = e->call_stmt; - if (e->callee->clone.combined_args_to_skip) - new_stmt - = gimple_call_copy_skip_args (new_stmt, - e->callee->clone.combined_args_to_skip); tree old_fntype = gimple_call_fntype (e->call_stmt); - gimple_call_set_fndecl (new_stmt, e->callee->decl); + new_stmt = padjs->modify_call (e->call_stmt, + e->caller->clone.performed_splits, + e->callee->decl, false); cgraph_node *origin = e->callee; while (origin->clone_of) origin = origin->clone_of; @@ -1379,92 +1390,12 @@ cgraph_edge::redirect_call_stmt_to_callee (void) gimple_call_set_fntype (new_stmt, TREE_TYPE (e->callee->decl)); else { - bitmap skip = e->callee->clone.combined_args_to_skip; - tree t = cgraph_build_function_type_skip_args (old_fntype, skip, - false); - gimple_call_set_fntype (new_stmt, t); - } - - if (gimple_vdef (new_stmt) - && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) - SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; - - gsi = gsi_for_stmt (e->call_stmt); - - /* For optimized away parameters, add on the caller side - before the call - DEBUG D#X => parm_Y(D) - stmts and associate D#X with parm in decl_debug_args_lookup - vector to say for debug info that if parameter parm had been passed, - it would have value parm_Y(D). */ - if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS) - { - vec **debug_args - = decl_debug_args_lookup (e->callee->decl); - tree old_decl = gimple_call_fndecl (e->call_stmt); - if (debug_args && old_decl) - { - tree parm; - unsigned i = 0, num; - unsigned len = vec_safe_length (*debug_args); - unsigned nargs = gimple_call_num_args (e->call_stmt); - for (parm = DECL_ARGUMENTS (old_decl), num = 0; - parm && num < nargs; - parm = DECL_CHAIN (parm), num++) - if (bitmap_bit_p (e->callee->clone.combined_args_to_skip, num) - && is_gimple_reg (parm)) - { - unsigned last = i; - - while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm)) - i += 2; - if (i >= len) - { - i = 0; - while (i < last - && (**debug_args)[i] != DECL_ORIGIN (parm)) - i += 2; - if (i >= last) - continue; - } - tree ddecl = (**debug_args)[i + 1]; - tree arg = gimple_call_arg (e->call_stmt, num); - if (!useless_type_conversion_p (TREE_TYPE (ddecl), - TREE_TYPE (arg))) - { - tree rhs1; - if (!fold_convertible_p (TREE_TYPE (ddecl), arg)) - continue; - if (TREE_CODE (arg) == SSA_NAME - && gimple_assign_cast_p (SSA_NAME_DEF_STMT (arg)) - && (rhs1 - = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (arg))) - && useless_type_conversion_p (TREE_TYPE (ddecl), - TREE_TYPE (rhs1))) - arg = rhs1; - else - arg = fold_convert (TREE_TYPE (ddecl), arg); - } - - gimple *def_temp - = gimple_build_debug_bind (ddecl, unshare_expr (arg), - e->call_stmt); - gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT); - } - } + tree new_fntype = padjs->build_new_function_type (old_fntype, true); + gimple_call_set_fntype (new_stmt, new_fntype); } - gsi_replace (&gsi, new_stmt, false); - /* We need to defer cleaning EH info on the new statement to - fixup-cfg. We may not have dominator information at this point - and thus would end up with unreachable blocks and have no way - to communicate that we need to run CFG cleanup then. */ - lp_nr = lookup_stmt_eh_lp (e->call_stmt); if (lp_nr != 0) - { - remove_stmt_from_eh_lp (e->call_stmt); - add_stmt_to_eh_lp (new_stmt, lp_nr); - } + add_stmt_to_eh_lp (new_stmt, lp_nr); } else { @@ -3014,8 +2945,8 @@ clone_of_p (cgraph_node *node, cgraph_node *node2) return true; node = node->callees->callee->ultimate_alias_target (); - if (!node2->clone.args_to_skip - || !bitmap_bit_p (node2->clone.args_to_skip, 0)) + if (!node2->clone.param_adjustments + || node2->clone.param_adjustments->first_param_intact_p ()) return false; if (node2->former_clone_of == node->decl) return true; diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 4c54210..1da6cab 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "profile-count.h" #include "ipa-ref.h" #include "plugin-api.h" +#include "ipa-param-manipulation.h" extern void debuginfo_early_init (void); extern void debuginfo_init (void); @@ -740,23 +741,31 @@ struct GTY(()) cgraph_global_info { will be replaced by another tree while versioning. */ struct GTY(()) ipa_replace_map { - /* The tree that will be replaced. */ - tree old_tree; /* The new (replacing) tree. */ tree new_tree; /* Parameter number to replace, when old_tree is NULL. */ int parm_num; - /* True when a substitution should be done, false otherwise. */ - bool replace_p; - /* True when we replace a reference to old_tree. */ - bool ref_p; }; struct GTY(()) cgraph_clone_info { + /* Constants discovered by IPA-CP, i.e. which parameter should be replaced + with what. */ vec *tree_map; - bitmap args_to_skip; - bitmap combined_args_to_skip; + /* Parameter modification that IPA-SRA decided to perform. */ + ipa_param_adjustments *param_adjustments; + /* Lists of dummy-decl and offset pairs representing split formal parameters + in the caller. Offsets of all new replacements are enumerated, those + coming from the same original parameter have the same dummy decl stored + along with them. + + Dummy decls sit in call statement arguments followed by new parameter + decls (or their SSA names) in between (caller) clone materialization and + call redirection. Redirection then recognizes the dummy variable and + together with the stored offsets can reconstruct what exactly the new + parameter decls represent and can leave in place only those that the + callee expects. */ + vec *performed_splits; }; enum cgraph_simd_clone_arg_type @@ -976,15 +985,16 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node vec redirect_callers, bool call_duplication_hook, cgraph_node *new_inlined_to, - bitmap args_to_skip, const char *suffix = NULL); + ipa_param_adjustments *param_adjustments, + const char *suffix = NULL); /* Create callgraph node clone with new declaration. The actual body will be copied later at compilation stage. The name of the new clone will be constructed from the name of the original node, SUFFIX and NUM_SUFFIX. */ cgraph_node *create_virtual_clone (vec redirect_callers, vec *tree_map, - bitmap args_to_skip, const char * suffix, - unsigned num_suffix); + ipa_param_adjustments *param_adjustments, + const char * suffix, unsigned num_suffix); /* cgraph node being removed from symbol table; see if its entry can be replaced by other inline clone. */ @@ -1033,9 +1043,10 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node Return the new version's cgraph node. */ cgraph_node *create_version_clone_with_body (vec redirect_callers, - vec *tree_map, bitmap args_to_skip, - bool skip_return, bitmap bbs_to_copy, basic_block new_entry_block, - const char *clone_name, tree target_attributes = NULL_TREE); + vec *tree_map, + ipa_param_adjustments *param_adjustments, + bitmap bbs_to_copy, basic_block new_entry_block, const char *clone_name, + tree target_attributes = NULL_TREE); /* Insert a new cgraph_function_version_info node into cgraph_fnver_htab corresponding to cgraph_node. */ @@ -2459,14 +2470,12 @@ tree clone_function_name (tree decl, const char *suffix, tree clone_function_name (tree decl, const char *suffix); void tree_function_versioning (tree, tree, vec *, - bool, bitmap, bool, bitmap, basic_block); + ipa_param_adjustments *, + bool, bitmap, basic_block); void dump_callgraph_transformation (const cgraph_node *original, const cgraph_node *clone, const char *suffix); -tree cgraph_build_function_type_skip_args (tree orig_type, bitmap args_to_skip, - bool skip_return); - /* In cgraphbuild.c */ int compute_call_stmt_bb_frequency (tree, basic_block bb); void record_references_in_initializer (tree, bool); diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index fa75369..909407b 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -142,96 +142,6 @@ cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid, return new_edge; } -/* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP and the - return value if SKIP_RETURN is true. */ - -tree -cgraph_build_function_type_skip_args (tree orig_type, bitmap args_to_skip, - bool skip_return) -{ - tree new_type = NULL; - tree args, new_args = NULL; - tree new_reversed; - int i = 0; - - for (args = TYPE_ARG_TYPES (orig_type); args && args != void_list_node; - args = TREE_CHAIN (args), i++) - if (!args_to_skip || !bitmap_bit_p (args_to_skip, i)) - new_args = tree_cons (NULL_TREE, TREE_VALUE (args), new_args); - - new_reversed = nreverse (new_args); - if (args) - { - if (new_reversed) - TREE_CHAIN (new_args) = void_list_node; - else - new_reversed = void_list_node; - } - - /* Use copy_node to preserve as much as possible from original type - (debug info, attribute lists etc.) - Exception is METHOD_TYPEs must have THIS argument. - When we are asked to remove it, we need to build new FUNCTION_TYPE - instead. */ - if (TREE_CODE (orig_type) != METHOD_TYPE - || !args_to_skip - || !bitmap_bit_p (args_to_skip, 0)) - { - new_type = build_distinct_type_copy (orig_type); - TYPE_ARG_TYPES (new_type) = new_reversed; - } - else - { - new_type - = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type), - new_reversed)); - TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type); - } - - if (skip_return) - TREE_TYPE (new_type) = void_type_node; - - return new_type; -} - -/* Build variant of function decl ORIG_DECL skipping ARGS_TO_SKIP and the - return value if SKIP_RETURN is true. - - Arguments from DECL_ARGUMENTS list can't be removed now, since they are - linked by TREE_CHAIN directly. The caller is responsible for eliminating - them when they are being duplicated (i.e. copy_arguments_for_versioning). */ - -static tree -build_function_decl_skip_args (tree orig_decl, bitmap args_to_skip, - bool skip_return) -{ - tree new_decl = copy_node (orig_decl); - tree new_type; - - new_type = TREE_TYPE (orig_decl); - if (prototype_p (new_type) - || (skip_return && !VOID_TYPE_P (TREE_TYPE (new_type)))) - new_type - = cgraph_build_function_type_skip_args (new_type, args_to_skip, - skip_return); - TREE_TYPE (new_decl) = new_type; - - /* For declarations setting DECL_VINDEX (i.e. methods) - we expect first argument to be THIS pointer. */ - if (args_to_skip && bitmap_bit_p (args_to_skip, 0)) - DECL_VINDEX (new_decl) = NULL_TREE; - - /* When signature changes, we need to clear builtin info. */ - if (fndecl_built_in_p (new_decl) - && args_to_skip - && !bitmap_empty_p (args_to_skip)) - set_decl_built_in_function (new_decl, NOT_BUILT_IN, 0); - /* The FE might have information and assumptions about the other - arguments. */ - DECL_LANG_SPECIFIC (new_decl) = NULL; - return new_decl; -} - /* Set flags of NEW_NODE and its decl. NEW_NODE is a newly created private clone or its thunk. */ @@ -281,35 +191,21 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node) return cs->caller; tree new_decl; - if (!node->clone.args_to_skip) - new_decl = copy_node (thunk->decl); - else + if (node->clone.param_adjustments) { /* We do not need to duplicate this_adjusting thunks if we have removed this. */ if (thunk->thunk.this_adjusting - && bitmap_bit_p (node->clone.args_to_skip, 0)) + && !node->clone.param_adjustments->first_param_intact_p ()) return node; - new_decl = build_function_decl_skip_args (thunk->decl, - node->clone.args_to_skip, - false); - } - - tree *link = &DECL_ARGUMENTS (new_decl); - int i = 0; - for (tree pd = DECL_ARGUMENTS (thunk->decl); pd; pd = DECL_CHAIN (pd), i++) - { - if (!node->clone.args_to_skip - || !bitmap_bit_p (node->clone.args_to_skip, i)) - { - tree nd = copy_node (pd); - DECL_CONTEXT (nd) = new_decl; - *link = nd; - link = &DECL_CHAIN (nd); - } + new_decl = copy_node (thunk->decl); + ipa_param_body_adjustments body_adj (node->clone.param_adjustments, + new_decl); + body_adj.modify_formal_parameters (); } - *link = NULL_TREE; + else + new_decl = copy_node (thunk->decl); gcc_checking_assert (!DECL_STRUCT_FUNCTION (new_decl)); gcc_checking_assert (!DECL_INITIAL (new_decl)); @@ -331,8 +227,7 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node) new_thunk->thunk = thunk->thunk; new_thunk->unique_name = in_lto_p; new_thunk->former_clone_of = thunk->decl; - new_thunk->clone.args_to_skip = node->clone.args_to_skip; - new_thunk->clone.combined_args_to_skip = node->clone.combined_args_to_skip; + new_thunk->clone.param_adjustments = node->clone.param_adjustments; cgraph_edge *e = new_thunk->create_edge (node, NULL, new_thunk->count); symtab->call_edge_duplication_hooks (thunk->callees, e); @@ -415,7 +310,11 @@ dump_callgraph_transformation (const cgraph_node *original, If the new node is being inlined into another one, NEW_INLINED_TO should be the outline function the new one is (even indirectly) inlined to. All hooks will see this in node's global.inlined_to, when invoked. Can be NULL if the - node is not inlined. */ + node is not inlined. + + If PARAM_ADJUSTMENTS is non-NULL, the parameter manipulation information + will be overwritten by the new structure. Otherwise the new node will + share parameter manipulation information with the original node. */ cgraph_node * cgraph_node::create_clone (tree new_decl, profile_count prof_count, @@ -423,7 +322,8 @@ cgraph_node::create_clone (tree new_decl, profile_count prof_count, vec redirect_callers, bool call_duplication_hook, cgraph_node *new_inlined_to, - bitmap args_to_skip, const char *suffix) + ipa_param_adjustments *param_adjustments, + const char *suffix) { cgraph_node *new_node = symtab->create_empty (); cgraph_edge *e; @@ -467,19 +367,13 @@ cgraph_node::create_clone (tree new_decl, profile_count prof_count, new_node->merged_comdat = merged_comdat; new_node->thunk = thunk; + if (param_adjustments) + new_node->clone.param_adjustments = param_adjustments; + else + new_node->clone.param_adjustments = clone.param_adjustments; new_node->clone.tree_map = NULL; - new_node->clone.args_to_skip = args_to_skip; + new_node->clone.performed_splits = vec_safe_copy (clone.performed_splits); new_node->split_part = split_part; - if (!args_to_skip) - new_node->clone.combined_args_to_skip = clone.combined_args_to_skip; - else if (clone.combined_args_to_skip) - { - new_node->clone.combined_args_to_skip = BITMAP_GGC_ALLOC (); - bitmap_ior (new_node->clone.combined_args_to_skip, - clone.combined_args_to_skip, args_to_skip); - } - else - new_node->clone.combined_args_to_skip = args_to_skip; FOR_EACH_VEC_ELT (redirect_callers, i, e) { @@ -621,8 +515,8 @@ clone_function_name (tree decl, const char *suffix) cgraph_node * cgraph_node::create_virtual_clone (vec redirect_callers, vec *tree_map, - bitmap args_to_skip, const char * suffix, - unsigned num_suffix) + ipa_param_adjustments *param_adjustments, + const char * suffix, unsigned num_suffix) { tree old_decl = decl; cgraph_node *new_node = NULL; @@ -632,13 +526,16 @@ cgraph_node::create_virtual_clone (vec redirect_callers, char *name; gcc_checking_assert (local.versionable); - gcc_assert (local.can_change_signature || !args_to_skip); + /* TODO: It would be nice if we could recognize that param_adjustments do not + actually perform any changes, but at the moment let's require it simply + does not exist. */ + gcc_assert (local.can_change_signature || !param_adjustments); /* Make a new FUNCTION_DECL tree node */ - if (!args_to_skip) + if (!param_adjustments) new_decl = copy_node (old_decl); else - new_decl = build_function_decl_skip_args (old_decl, args_to_skip, false); + new_decl = param_adjustments->adjust_decl (old_decl); /* These pointers represent function body and will be populated only when clone is materialized. */ @@ -662,7 +559,8 @@ cgraph_node::create_virtual_clone (vec redirect_callers, SET_DECL_RTL (new_decl, NULL); new_node = create_clone (new_decl, count, false, - redirect_callers, false, NULL, args_to_skip, suffix); + redirect_callers, false, NULL, param_adjustments, + suffix); /* Update the properties. Make clone visible only within this translation unit. Make sure @@ -1021,9 +919,10 @@ cgraph_node::create_version_clone (tree new_decl, cgraph_node * cgraph_node::create_version_clone_with_body (vec redirect_callers, - vec *tree_map, bitmap args_to_skip, - bool skip_return, bitmap bbs_to_copy, basic_block new_entry_block, - const char *suffix, tree target_attributes) + vec *tree_map, + ipa_param_adjustments *param_adjustments, + bitmap bbs_to_copy, basic_block new_entry_block, const char *suffix, + tree target_attributes) { tree old_decl = decl; cgraph_node *new_version_node = NULL; @@ -1032,14 +931,16 @@ cgraph_node::create_version_clone_with_body if (!tree_versionable_function_p (old_decl)) return NULL; - gcc_assert (local.can_change_signature || !args_to_skip); + /* TODO: Restore an assert that we do not change signature if + local.can_change_signature is false. We cannot just check that + param_adjustments is NULL because unfortunately ipa-split removes return + values from such functions. */ /* Make a new FUNCTION_DECL tree node for the new version. */ - if (!args_to_skip && !skip_return) - new_decl = copy_node (old_decl); + if (param_adjustments) + new_decl = param_adjustments->adjust_decl (old_decl); else - new_decl - = build_function_decl_skip_args (old_decl, args_to_skip, skip_return); + new_decl = copy_node (old_decl); /* Generate a new name for the new version. */ DECL_NAME (new_decl) = clone_function_name_numbered (old_decl, suffix); @@ -1076,8 +977,8 @@ cgraph_node::create_version_clone_with_body new_version_node->ipa_transforms_to_apply = ipa_transforms_to_apply.copy (); /* Copy the OLD_VERSION_NODE function tree to the new version. */ - tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip, - skip_return, bbs_to_copy, new_entry_block); + tree_function_versioning (old_decl, new_decl, tree_map, param_adjustments, + false, bbs_to_copy, new_entry_block); /* Update the new version's properties. Make The new version visible only within this translation unit. Make sure @@ -1117,9 +1018,8 @@ cgraph_materialize_clone (cgraph_node *node) node->former_clone_of = node->clone_of->former_clone_of; /* Copy the OLD_VERSION_NODE function tree to the new version. */ tree_function_versioning (node->clone_of->decl, node->decl, - node->clone.tree_map, true, - node->clone.args_to_skip, false, - NULL, NULL); + node->clone.tree_map, node->clone.param_adjustments, + true, NULL, NULL); if (symtab->dump_file) { dump_function_to_file (node->clone_of->decl, symtab->dump_file, @@ -1194,28 +1094,15 @@ symbol_table::materialize_all_clones (void) { ipa_replace_map *replace_info; replace_info = (*node->clone.tree_map)[i]; - print_generic_expr (symtab->dump_file, - replace_info->old_tree); - fprintf (symtab->dump_file, " -> "); + fprintf (symtab->dump_file, "%i -> ", + (*node->clone.tree_map)[i]->parm_num); print_generic_expr (symtab->dump_file, replace_info->new_tree); - fprintf (symtab->dump_file, "%s%s;", - replace_info->replace_p ? "(replace)":"", - replace_info->ref_p ? "(ref)":""); } fprintf (symtab->dump_file, "\n"); } - if (node->clone.args_to_skip) - { - fprintf (symtab->dump_file, " args_to_skip: "); - dump_bitmap (symtab->dump_file, - node->clone.args_to_skip); - } - if (node->clone.args_to_skip) - { - fprintf (symtab->dump_file, " combined_args_to_skip:"); - dump_bitmap (symtab->dump_file, node->clone.combined_args_to_skip); - } + if (node->clone.param_adjustments) + node->clone.param_adjustments->dump (symtab->dump_file); } cgraph_materialize_clone (node); stabilized = false; diff --git a/gcc/coretypes.h b/gcc/coretypes.h index fc0e09b..257de22 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -141,6 +141,7 @@ struct gomp_teams; struct symtab_node; struct cgraph_node; struct varpool_node; +struct cgraph_edge; union section; typedef union section section; diff --git a/gcc/dbgcnt.def b/gcc/dbgcnt.def index ef981aa..7c9daaf 100644 --- a/gcc/dbgcnt.def +++ b/gcc/dbgcnt.def @@ -156,7 +156,6 @@ DEBUG_COUNTER (df_byte_scan) DEBUG_COUNTER (dse) DEBUG_COUNTER (dse1) DEBUG_COUNTER (dse2) -DEBUG_COUNTER (eipa_sra) DEBUG_COUNTER (gcse2_delete) DEBUG_COUNTER (global_alloc_at_func) DEBUG_COUNTER (global_alloc_at_reg) @@ -168,6 +167,8 @@ DEBUG_COUNTER (if_after_combine) DEBUG_COUNTER (if_after_reload) DEBUG_COUNTER (if_conversion) DEBUG_COUNTER (if_conversion_tree) +DEBUG_COUNTER (ipa_sra_params) +DEBUG_COUNTER (ipa_sra_retvalues) DEBUG_COUNTER (ira_move) DEBUG_COUNTER (local_alloc_for_sched) DEBUG_COUNTER (merged_ipa_icf) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6d67c12..83016a5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -11870,6 +11870,11 @@ parameters only when their cumulative size is less or equal to @option{ipa-sra-ptr-growth-factor} times the size of the original pointer parameter. +@item ipa-sra-max-replacements +Maximum pieces of an aggregate that IPA-SRA tracks. As a +consequence, it is also the maximum number of replacements of a formal +parameter. + @item sra-max-scalarization-size-Ospeed @itemx sra-max-scalarization-size-Osize The two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 33d52fe..b4fb74e 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -1184,7 +1184,10 @@ initialize_node_lattices (struct cgraph_node *node) int i; gcc_checking_assert (node->has_gimple_body_p ()); - if (node->local.local) + + if (!ipa_get_param_count (info)) + disable = true; + else if (node->local.local) { int caller_count = 0; node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count, @@ -1206,32 +1209,72 @@ initialize_node_lattices (struct cgraph_node *node) disable = true; } - for (i = 0; i < ipa_get_param_count (info); i++) + if (dump_file && (dump_flags & TDF_DETAILS) + && !node->alias && !node->thunk.thunk_p) { - class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); - plats->m_value_range.init (); + fprintf (dump_file, "Initializing lattices of %s\n", + node->dump_name ()); + if (disable || variable) + fprintf (dump_file, " Marking all lattices as %s\n", + disable ? "BOTTOM" : "VARIABLE"); } - if (disable || variable) + auto_vec surviving_params; + bool pre_modified = false; + if (!disable && node->clone.param_adjustments) { - for (i = 0; i < ipa_get_param_count (info); i++) + /* At the moment all IPA optimizations should use the number of + parameters of the prevailing decl as the m_always_copy_start. + Handling any other value would complicate the code below, so for the + time bing let's only assert it is so. */ + gcc_assert ((node->clone.param_adjustments->m_always_copy_start + == ipa_get_param_count (info)) + || node->clone.param_adjustments->m_always_copy_start < 0); + + pre_modified = true; + node->clone.param_adjustments->get_surviving_params (&surviving_params); + + if (dump_file && (dump_flags & TDF_DETAILS) + && !node->alias && !node->thunk.thunk_p) { - class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); - if (disable) + bool first = true; + for (int j = 0; j < ipa_get_param_count (info); j++) { - plats->itself.set_to_bottom (); - plats->ctxlat.set_to_bottom (); - set_agg_lats_to_bottom (plats); - plats->bits_lattice.set_to_bottom (); - plats->m_value_range.set_to_bottom (); + if (j < (int) surviving_params.length () + && surviving_params[j]) + continue; + if (first) + { + fprintf (dump_file, + " The following parameters are dead on arrival:"); + first = false; + } + fprintf (dump_file, " %u", j); } - else + if (!first) + fprintf (dump_file, "\n"); + } + } + + for (i = 0; i < ipa_get_param_count (info); i++) + { + ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); + if (disable + || (pre_modified && (surviving_params.length () <= (unsigned) i + || !surviving_params[i]))) + { + plats->itself.set_to_bottom (); + plats->ctxlat.set_to_bottom (); + set_agg_lats_to_bottom (plats); + plats->bits_lattice.set_to_bottom (); + plats->m_value_range.set_to_bottom (); + } + else + { + plats->m_value_range.init (); + if (variable) set_all_contains_variable (plats); } - if (dump_file && (dump_flags & TDF_DETAILS) - && !node->alias && !node->thunk.thunk_p) - fprintf (dump_file, "Marking all lattices of %s as %s\n", - node->dump_name (), disable ? "BOTTOM" : "VARIABLE"); } for (ie = node->indirect_calls; ie; ie = ie->next_callee) @@ -3654,12 +3697,8 @@ get_replacement_map (class ipa_node_params *info, tree value, int parm_num) print_generic_expr (dump_file, value); fprintf (dump_file, "\n"); } - replace_map->old_tree = NULL; replace_map->parm_num = parm_num; replace_map->new_tree = value; - replace_map->replace_p = true; - replace_map->ref_p = false; - return replace_map; } @@ -3797,6 +3836,35 @@ update_specialized_profile (struct cgraph_node *new_node, dump_profile_updates (orig_node, new_node); } +/* Return true if we would like to remove a parameter from NODE when cloning it + with KNOWN_CSTS scalar constants. */ + +static bool +want_remove_some_param_p (cgraph_node *node, vec known_csts) +{ + auto_vec surviving; + bool filled_vec = false; + ipa_node_params *info = IPA_NODE_REF (node); + int i, count = ipa_get_param_count (info); + + for (i = 0; i < count; i++) + { + if (!known_csts[i] && ipa_is_param_used (info, i)) + continue; + + if (!filled_vec) + { + if (!node->clone.param_adjustments) + return true; + node->clone.param_adjustments->get_surviving_params (&surviving); + filled_vec = true; + } + if (surviving.length() < (unsigned) i && surviving[i]) + return true; + } + return false; +} + /* Create a specialized version of NODE with known constants in KNOWN_CSTS, known contexts in KNOWN_CONTEXTS and known aggregate values in AGGVALS and redirect all edges in CALLERS to it. */ @@ -3810,31 +3878,65 @@ create_specialized_node (struct cgraph_node *node, { class ipa_node_params *new_info, *info = IPA_NODE_REF (node); vec *replace_trees = NULL; + vec *new_params = NULL; struct ipa_agg_replacement_value *av; struct cgraph_node *new_node; int i, count = ipa_get_param_count (info); - bitmap args_to_skip; - + ipa_param_adjustments *old_adjustments = node->clone.param_adjustments; + ipa_param_adjustments *new_adjustments; gcc_assert (!info->ipcp_orig_node); + gcc_assert (node->local.can_change_signature + || !old_adjustments); - if (node->local.can_change_signature) + if (old_adjustments) { - args_to_skip = BITMAP_GGC_ALLOC (); - for (i = 0; i < count; i++) + /* At the moment all IPA optimizations should use the number of + parameters of the prevailing decl as the m_always_copy_start. + Handling any other value would complicate the code below, so for the + time bing let's only assert it is so. */ + gcc_assert (old_adjustments->m_always_copy_start == count + || old_adjustments->m_always_copy_start < 0); + int old_adj_count = vec_safe_length (old_adjustments->m_adj_params); + for (i = 0; i < old_adj_count; i++) { - tree t = known_csts[i]; + ipa_adjusted_param *old_adj = &(*old_adjustments->m_adj_params)[i]; + if (!node->local.can_change_signature + || old_adj->op != IPA_PARAM_OP_COPY + || (!known_csts[old_adj->base_index] + && ipa_is_param_used (info, old_adj->base_index))) + { + ipa_adjusted_param new_adj = *old_adj; - if (t || !ipa_is_param_used (info, i)) - bitmap_set_bit (args_to_skip, i); + new_adj.prev_clone_adjustment = true; + new_adj.prev_clone_index = i; + vec_safe_push (new_params, new_adj); + } } + bool skip_return = old_adjustments->m_skip_return; + new_adjustments = (new (ggc_alloc ()) + ipa_param_adjustments (new_params, count, + skip_return)); } - else + else if (node->local.can_change_signature + && want_remove_some_param_p (node, known_csts)) { - args_to_skip = NULL; - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " cannot change function signature\n"); + ipa_adjusted_param adj; + memset (&adj, 0, sizeof (adj)); + adj.op = IPA_PARAM_OP_COPY; + for (i = 0; i < count; i++) + if (!known_csts[i] && ipa_is_param_used (info, i)) + { + adj.base_index = i; + adj.prev_clone_index = i; + vec_safe_push (new_params, adj); + } + new_adjustments = (new (ggc_alloc ()) + ipa_param_adjustments (new_params, count, false)); } + else + new_adjustments = NULL; + replace_trees = vec_safe_copy (node->clone.tree_map); for (i = 0; i < count; i++) { tree t = known_csts[i]; @@ -3863,7 +3965,7 @@ create_specialized_node (struct cgraph_node *node, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME ( node->decl))); new_node = node->create_virtual_clone (callers, replace_trees, - args_to_skip, "constprop", + new_adjustments, "constprop", suffix_counter); suffix_counter++; diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 6de060a..a438679 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -616,9 +616,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, for (j = 0; vec_safe_iterate (dst->clone.tree_map, j, &r); j++) { - if (((!r->old_tree && r->parm_num == i) - || (r->old_tree && r->old_tree == ipa_get_param (parms_info, i))) - && r->replace_p && !r->ref_p) + if (r->parm_num == i) { known_vals[i] = r->new_tree; break; diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index 897c563..d229960 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -617,8 +617,7 @@ save_inline_function_body (struct cgraph_node *node) /* Copy the OLD_VERSION_NODE function tree to the new version. */ tree_function_versioning (node->decl, first_clone->decl, - NULL, true, NULL, false, - NULL, NULL); + NULL, NULL, true, NULL, NULL); /* The function will be short lived and removed after we inline all the clones, but make it internal so we won't confuse ourself. */ diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index 1af6d05..7f52e9c 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -22,170 +22,201 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "backend.h" -#include "rtl.h" #include "tree.h" #include "gimple.h" #include "ssa.h" #include "cgraph.h" #include "fold-const.h" +#include "tree-eh.h" #include "stor-layout.h" #include "gimplify.h" #include "gimple-iterator.h" #include "gimplify-me.h" +#include "tree-cfg.h" #include "tree-dfa.h" #include "ipa-param-manipulation.h" #include "print-tree.h" #include "gimple-pretty-print.h" #include "builtins.h" +#include "tree-ssa.h" +#include "tree-inline.h" -/* Return a heap allocated vector containing formal parameters of FNDECL. */ -vec -ipa_get_vector_of_formal_parms (tree fndecl) +/* Actual prefixes of different newly synthetized parameters. Keep in sync + with IPA_PARAM_PREFIX_* defines. */ + +static const char *ipa_param_prefixes[IPA_PARAM_PREFIX_COUNT] + = {"SYNTH", + "ISRA", + "simd", + "mask"}; + +/* Names of parameters for dumping. Keep in sync with enum ipa_parm_op. */ + +static const char *ipa_param_op_names[IPA_PARAM_PREFIX_COUNT] + = {"IPA_PARAM_OP_UNDEFINED", + "IPA_PARAM_OP_COPY", + "IPA_PARAM_OP_NEW", + "IPA_PARAM_OP_SPLIT"}; + +/* Fill an empty vector ARGS with PARM_DECLs representing formal parameters of + FNDECL. The function should not be called during LTO WPA phase except for + thunks (or functions with bodies streamed in). */ + +void +push_function_arg_decls (vec *args, tree fndecl) { - vec args; int count; tree parm; - gcc_assert (!flag_wpa); + /* Safety check that we do not attempt to use the function in WPA, except + when the function is a thunk and then we have DECL_ARGUMENTS or when we + have already explicitely loaded its body. */ + gcc_assert (!flag_wpa + || DECL_ARGUMENTS (fndecl) + || gimple_has_body_p (fndecl)); count = 0; for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) count++; - args.create (count); + args->reserve_exact (count); for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) - args.quick_push (parm); - - return args; + args->quick_push (parm); } -/* Return a heap allocated vector containing types of formal parameters of +/* Fill an empty vector TYPES with trees representing formal parameters of function type FNTYPE. */ -vec -ipa_get_vector_of_formal_parm_types (tree fntype) +void +push_function_arg_types (vec *types, tree fntype) { - vec types; int count = 0; tree t; for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) count++; - types.create (count); + types->reserve_exact (count); for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) - types.quick_push (TREE_VALUE (t)); - - return types; + types->quick_push (TREE_VALUE (t)); } -/* Modify the function declaration FNDECL and its type according to the plan in - ADJUSTMENTS. It also sets base fields of individual adjustments structures - to reflect the actual parameters being modified which are determined by the - base_index field. */ +/* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human + friendly way, assuming they are meant to be applied to FNDECL. */ void -ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments) -{ - vec oparms = ipa_get_vector_of_formal_parms (fndecl); - tree orig_type = TREE_TYPE (fndecl); - tree old_arg_types = TYPE_ARG_TYPES (orig_type); - - /* The following test is an ugly hack, some functions simply don't have any - arguments in their type. This is probably a bug but well... */ - bool care_for_types = (old_arg_types != NULL_TREE); - bool last_parm_void; - vec otypes; - if (care_for_types) - { - last_parm_void = (TREE_VALUE (tree_last (old_arg_types)) - == void_type_node); - otypes = ipa_get_vector_of_formal_parm_types (orig_type); - if (last_parm_void) - gcc_assert (oparms.length () + 1 == otypes.length ()); - else - gcc_assert (oparms.length () == otypes.length ()); - } - else - { - last_parm_void = false; - otypes.create (0); - } +ipa_dump_adjusted_parameters (FILE *f, + vec *adj_params) +{ + unsigned i, len = vec_safe_length (adj_params); + bool first = true; - int len = adjustments.length (); - tree *link = &DECL_ARGUMENTS (fndecl); - tree new_arg_types = NULL; - for (int i = 0; i < len; i++) + fprintf (f, " IPA adjusted parameters: "); + for (i = 0; i < len; i++) { - struct ipa_parm_adjustment *adj; - gcc_assert (link); + struct ipa_adjusted_param *apm; + apm = &(*adj_params)[i]; - adj = &adjustments[i]; - tree parm; - if (adj->op == IPA_PARM_OP_NEW) - parm = NULL; + if (!first) + fprintf (f, " "); else - parm = oparms[adj->base_index]; - adj->base = parm; + first = false; - if (adj->op == IPA_PARM_OP_COPY) - { - if (care_for_types) - new_arg_types = tree_cons (NULL_TREE, otypes[adj->base_index], - new_arg_types); - *link = parm; - link = &DECL_CHAIN (parm); - } - else if (adj->op != IPA_PARM_OP_REMOVE) + fprintf (f, "%i. %s %s", i, ipa_param_op_names[apm->op], + apm->prev_clone_adjustment ? "prev_clone_adjustment " : ""); + switch (apm->op) { - tree new_parm; - tree ptype; - - if (adj->by_ref) - ptype = build_pointer_type (adj->type); - else - { - ptype = adj->type; - if (is_gimple_reg_type (ptype) - && TYPE_MODE (ptype) != BLKmode) - { - unsigned malign = GET_MODE_ALIGNMENT (TYPE_MODE (ptype)); - if (TYPE_ALIGN (ptype) != malign) - ptype = build_aligned_type (ptype, malign); - } - } + case IPA_PARAM_OP_UNDEFINED: + break; - if (care_for_types) - new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types); + case IPA_PARAM_OP_COPY: + fprintf (f, ", base_index: %u", apm->base_index); + fprintf (f, ", prev_clone_index: %u", apm->prev_clone_index); + break; - new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE, - ptype); - const char *prefix = adj->arg_prefix ? adj->arg_prefix : "SYNTH"; - DECL_NAME (new_parm) = create_tmp_var_name (prefix); - DECL_ARTIFICIAL (new_parm) = 1; - DECL_ARG_TYPE (new_parm) = ptype; - DECL_CONTEXT (new_parm) = fndecl; - TREE_USED (new_parm) = 1; - DECL_IGNORED_P (new_parm) = 1; - layout_decl (new_parm, 0); + case IPA_PARAM_OP_SPLIT: + fprintf (f, ", offset: %u", apm->unit_offset); + /* fall-through */ + case IPA_PARAM_OP_NEW: + fprintf (f, ", base_index: %u", apm->base_index); + fprintf (f, ", prev_clone_index: %u", apm->prev_clone_index); + print_node_brief (f, ", type: ", apm->type, 0); + print_node_brief (f, ", alias type: ", apm->alias_ptr_type, 0); + fprintf (f, " prefix: %s", + ipa_param_prefixes[apm->param_prefix_index]); + if (apm->reverse) + fprintf (f, ", reverse-sso"); + break; + } + fprintf (f, "\n"); + } +} - if (adj->op == IPA_PARM_OP_NEW) - adj->base = NULL; - else - adj->base = parm; - adj->new_decl = new_parm; +/* Fill NEW_TYPES with types of a function after its current OTYPES have been + modified as described in ADJ_PARAMS. When USE_PREV_INDICES is true, use + prev_clone_index from ADJ_PARAMS as opposed to base_index when the parameter + is false. */ - *link = new_parm; - link = &DECL_CHAIN (new_parm); +static void +fill_vector_of_new_param_types (vec *new_types, vec *otypes, + vec *adj_params, + bool use_prev_indices) +{ + unsigned adj_len = vec_safe_length (adj_params); + new_types->reserve_exact (adj_len); + for (unsigned i = 0; i < adj_len ; i++) + { + ipa_adjusted_param *apm = &(*adj_params)[i]; + if (apm->op == IPA_PARAM_OP_COPY) + { + unsigned index + = use_prev_indices ? apm->prev_clone_index : apm->base_index; + /* The following needs to be handled gracefully because of type + mismatches. This happens with LTO but apparently also in Fortran + with -fcoarray=lib -O2 -lcaf_single -latomic. */ + if (index >= otypes->length ()) + continue; + new_types->quick_push ((*otypes)[index]); } + else if (apm->op == IPA_PARAM_OP_NEW + || apm->op == IPA_PARAM_OP_SPLIT) + { + tree ntype = apm->type; + if (is_gimple_reg_type (ntype) + && TYPE_MODE (ntype) != BLKmode) + { + unsigned malign = GET_MODE_ALIGNMENT (TYPE_MODE (ntype)); + if (TYPE_ALIGN (ntype) != malign) + ntype = build_aligned_type (ntype, malign); + } + new_types->quick_push (ntype); + } + else + gcc_unreachable (); } +} - *link = NULL_TREE; +/* Build and return a function type just like ORIG_TYPE but with parameter + types given in NEW_PARAM_TYPES - which can be NULL if, but only if, + ORIG_TYPE itself has NULL TREE_ARG_TYPEs. If METHOD2FUNC is true, also make + it a FUNCTION_TYPE instead of FUNCTION_TYPE. */ - tree new_reversed = NULL; - if (care_for_types) +static tree +build_adjusted_function_type (tree orig_type, vec *new_param_types, + bool method2func, bool skip_return) +{ + tree new_arg_types = NULL; + if (TYPE_ARG_TYPES (orig_type)) { - new_reversed = nreverse (new_arg_types); + gcc_checking_assert (new_param_types); + bool last_parm_void = (TREE_VALUE (tree_last (TYPE_ARG_TYPES (orig_type))) + == void_type_node); + unsigned len = new_param_types->length (); + for (unsigned i = 0; i < len; i++) + new_arg_types = tree_cons (NULL_TREE, (*new_param_types)[i], + new_arg_types); + + tree new_reversed = nreverse (new_arg_types); if (last_parm_void) { if (new_reversed) @@ -193,224 +224,568 @@ ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments) else new_reversed = void_list_node; } + new_arg_types = new_reversed; } - /* Use copy_node to preserve as much as possible from original type - (debug info, attribute lists etc.) - Exception is METHOD_TYPEs must have THIS argument. - When we are asked to remove it, we need to build new FUNCTION_TYPE - instead. */ + /* Use build_distinct_type_copy to preserve as much as possible from original + type (debug info, attribute lists etc.). The one exception is + METHOD_TYPEs which must have THIS argument and when we are asked to remove + it, we need to build new FUNCTION_TYPE instead. */ tree new_type = NULL; - if (TREE_CODE (orig_type) != METHOD_TYPE - || (adjustments[0].op == IPA_PARM_OP_COPY - && adjustments[0].base_index == 0)) + if (method2func) + { + tree ret_type; + if (skip_return) + ret_type = void_type_node; + else + ret_type = TREE_TYPE (orig_type); + + new_type + = build_distinct_type_copy (build_function_type (ret_type, + new_arg_types)); + TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type); + } + else { new_type = build_distinct_type_copy (orig_type); - TYPE_ARG_TYPES (new_type) = new_reversed; + TYPE_ARG_TYPES (new_type) = new_arg_types; + if (skip_return) + TREE_TYPE (new_type) = void_type_node; + } + + return new_type; +} + +/* Return the maximum index in any IPA_PARAM_OP_COPY adjustment or -1 if there + is none. */ + +int +ipa_param_adjustments::get_max_base_index () +{ + unsigned adj_len = vec_safe_length (m_adj_params); + int max_index = -1; + for (unsigned i = 0; i < adj_len ; i++) + { + ipa_adjusted_param *apm = &(*m_adj_params)[i]; + if (apm->op == IPA_PARAM_OP_COPY + && max_index < apm->base_index) + max_index = apm->base_index; + } + return max_index; +} + + +/* Fill SURVIVING_PARAMS with an array of bools where each one says whether a + parameter that originally was at that position still survives in the given + clone or is removed/replaced. If the final array is smaller than an index + of an original parameter, that parameter also did not survive. That a + parameter survives does not mean it has the same index as before. */ + +void +ipa_param_adjustments::get_surviving_params (vec *surviving_params) +{ + unsigned adj_len = vec_safe_length (m_adj_params); + int max_index = get_max_base_index (); + + if (max_index < 0) + return; + surviving_params->reserve_exact (max_index + 1); + surviving_params->quick_grow_cleared (max_index + 1); + for (unsigned i = 0; i < adj_len ; i++) + { + ipa_adjusted_param *apm = &(*m_adj_params)[i]; + if (apm->op == IPA_PARAM_OP_COPY) + (*surviving_params)[apm->base_index] = true; + } +} + +/* Fill NEW_INDICES with new indices of each surviving parameter or -1 for + those which do not survive. Any parameter outside of lenght of the vector + does not survive. There is currently no support for a parameter to be + copied to two distinct new parameters. */ + +void +ipa_param_adjustments::get_updated_indices (vec *new_indices) +{ + unsigned adj_len = vec_safe_length (m_adj_params); + int max_index = get_max_base_index (); + + if (max_index < 0) + return; + unsigned res_len = max_index + 1; + new_indices->reserve_exact (res_len); + for (unsigned i = 0; i < res_len ; i++) + new_indices->quick_push (-1); + for (unsigned i = 0; i < adj_len ; i++) + { + ipa_adjusted_param *apm = &(*m_adj_params)[i]; + if (apm->op == IPA_PARAM_OP_COPY) + (*new_indices)[apm->base_index] = i; + } +} + +/* Return true if the first parameter (assuming there was one) survives the + transformation intact and remains the first one. */ + +bool +ipa_param_adjustments::first_param_intact_p () +{ + return (!vec_safe_is_empty (m_adj_params) + && (*m_adj_params)[0].op == IPA_PARAM_OP_COPY + && (*m_adj_params)[0].base_index == 0); +} + +/* Return true if we have to change what has formerly been a method into a + function. */ + +bool +ipa_param_adjustments::method2func_p (tree orig_type) +{ + return ((TREE_CODE (orig_type) == METHOD_TYPE) && !first_param_intact_p ()); +} + +/* Given function type OLD_TYPE, return a new type derived from it after + performing all atored modifications. TYPE_ORIGINAL_P should be true when + OLD_TYPE refers to the type before any IPA transformations, as opposed to a + type that can be an intermediate one in between various IPA + transformations. */ + +tree +ipa_param_adjustments::build_new_function_type (tree old_type, + bool type_original_p) +{ + auto_vec new_param_types, *new_param_types_p; + if (prototype_p (old_type)) + { + auto_vec otypes; + push_function_arg_types (&otypes, old_type); + fill_vector_of_new_param_types (&new_param_types, &otypes, m_adj_params, + !type_original_p); + new_param_types_p = &new_param_types; } else + new_param_types_p = NULL; + + return build_adjusted_function_type (old_type, new_param_types_p, + method2func_p (old_type), m_skip_return); +} + +/* Build variant of function decl ORIG_DECL which has no return value if + M_SKIP_RETURN is true and, if ORIG_DECL's types or parameters is known, has + this type adjusted as indicated in M_ADJ_PARAMS. Arguments from + DECL_ARGUMENTS list are not processed now, since they are linked by + TREE_CHAIN directly and not accessible in LTO during WPA. The caller is + responsible for eliminating them when clones are properly materialized. */ + +tree +ipa_param_adjustments::adjust_decl (tree orig_decl) +{ + tree new_decl = copy_node (orig_decl); + tree orig_type = TREE_TYPE (orig_decl); + if (prototype_p (orig_type) + || (m_skip_return && !VOID_TYPE_P (TREE_TYPE (orig_type)))) { - new_type - = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type), - new_reversed)); - TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type); - DECL_VINDEX (fndecl) = NULL_TREE; + tree new_type = build_new_function_type (orig_type, false); + TREE_TYPE (new_decl) = new_type; } + if (method2func_p (orig_type)) + DECL_VINDEX (new_decl) = NULL_TREE; /* When signature changes, we need to clear builtin info. */ - if (fndecl_built_in_p (fndecl)) - set_decl_built_in_function (fndecl, NOT_BUILT_IN, 0); + if (fndecl_built_in_p (new_decl)) + set_decl_built_in_function (new_decl, NOT_BUILT_IN, 0); + + DECL_VIRTUAL_P (new_decl) = 0; + DECL_LANG_SPECIFIC (new_decl) = NULL; - TREE_TYPE (fndecl) = new_type; - DECL_VIRTUAL_P (fndecl) = 0; - DECL_LANG_SPECIFIC (fndecl) = NULL; - otypes.release (); - oparms.release (); + return new_decl; } -/* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS. - If this is a directly recursive call, CS must be NULL. Otherwise it must - contain the corresponding call graph edge. */ +/* Wrapper around get_base_ref_and_offset for cases interesting for IPA-SRA + transformations. Return true if EXPR has an interesting form and fill in + *BASE_P and *UNIT_OFFSET_P with the appropriate info. */ -void -ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt, - ipa_parm_adjustment_vec adjustments) -{ - struct cgraph_node *current_node = cgraph_node::get (current_function_decl); - vec vargs; - vec **debug_args = NULL; - gcall *new_stmt; - gimple_stmt_iterator gsi, prev_gsi; - tree callee_decl; - int i, len; +static bool +isra_get_ref_base_and_offset (tree expr, tree *base_p, unsigned *unit_offset_p) +{ + HOST_WIDE_INT offset, size; + bool reverse; + tree base + = get_ref_base_and_extent_hwi (expr, &offset, &size, &reverse); + if (!base || size < 0) + return false; - len = adjustments.length (); - vargs.create (len); - callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl; - current_node->remove_stmt_references (stmt); + if ((offset % BITS_PER_UNIT) != 0) + return false; - gsi = gsi_for_stmt (stmt); - prev_gsi = gsi; - gsi_prev (&prev_gsi); - for (i = 0; i < len; i++) + if (TREE_CODE (base) == MEM_REF) { - struct ipa_parm_adjustment *adj; + poly_int64 plmoff = mem_ref_offset (base).force_shwi (); + HOST_WIDE_INT moff; + bool is_cst = plmoff.is_constant (&moff); + if (!is_cst) + return false; + offset += moff * BITS_PER_UNIT; + base = TREE_OPERAND (base, 0); + } - adj = &adjustments[i]; + if (offset < 0 || (offset / BITS_PER_UNIT) > UINT_MAX) + return false; - if (adj->op == IPA_PARM_OP_COPY) - { - tree arg = gimple_call_arg (stmt, adj->base_index); + *base_p = base; + *unit_offset_p = offset / BITS_PER_UNIT; + return true; +} - vargs.quick_push (arg); +/* Return true if EXPR describes a transitive split (i.e. one that happened for + both the caller and the callee) as recorded in PERFORMED_SPLITS. In that + case, store index of the respective record in PERFORMED_SPLITS into + *SM_IDX_P and the unit offset from all handled components in EXPR into + *UNIT_OFFSET_P. */ + +static bool +transitive_split_p (vec *performed_splits, + tree expr, unsigned *sm_idx_p, unsigned *unit_offset_p) +{ + tree base; + if (!isra_get_ref_base_and_offset (expr, &base, unit_offset_p)) + return false; + + if (TREE_CODE (base) == SSA_NAME) + { + base = SSA_NAME_VAR (base); + if (!base) + return false; + } + + unsigned len = vec_safe_length (performed_splits); + for (unsigned i = 0 ; i < len; i++) + { + ipa_param_performed_split *sm = &(*performed_splits)[i]; + if (sm->dummy_decl == base) + { + *sm_idx_p = i; + return true; } - else if (adj->op != IPA_PARM_OP_REMOVE) + } + return false; +} + +/* Structure to hold declarations representing transitive IPA-SRA splits. In + essence, if we need to pass UNIT_OFFSET of a parameter which originally has + number BASE_INDEX, we should pass down REPL. */ + +struct transitive_split_map +{ + tree repl; + unsigned base_index; + unsigned unit_offset; +}; + +/* If call STMT contains any parameters representing transitive splits as + described by PERFORMED_SPLITS, return the number of extra parameters that + were addded during clone materialization and fill in INDEX_MAP with adjusted + indices of corresponding original parameters and TRANS_MAP with description + of all transitive replacement descriptions. Otherwise return zero. */ + +static unsigned +init_transitive_splits (vec *performed_splits, + gcall *stmt, vec *index_map, + auto_vec *trans_map) +{ + unsigned phony_arguments = 0; + unsigned stmt_idx = 0, base_index = 0; + unsigned nargs = gimple_call_num_args (stmt); + while (stmt_idx < nargs) + { + unsigned unit_offset_delta; + tree base_arg = gimple_call_arg (stmt, stmt_idx); + + if (phony_arguments > 0) + index_map->safe_push (stmt_idx); + + unsigned sm_idx; + stmt_idx++; + if (transitive_split_p (performed_splits, base_arg, &sm_idx, + &unit_offset_delta)) { - tree expr, base, off; - location_t loc; - unsigned int deref_align = 0; - bool deref_base = false; - - /* We create a new parameter out of the value of the old one, we can - do the following kind of transformations: - - - A scalar passed by reference is converted to a scalar passed by - value. (adj->by_ref is false and the type of the original - actual argument is a pointer to a scalar). - - - A part of an aggregate is passed instead of the whole aggregate. - The part can be passed either by value or by reference, this is - determined by value of adj->by_ref. Moreover, the code below - handles both situations when the original aggregate is passed by - value (its type is not a pointer) and when it is passed by - reference (it is a pointer to an aggregate). - - When the new argument is passed by reference (adj->by_ref is true) - it must be a part of an aggregate and therefore we form it by - simply taking the address of a reference inside the original - aggregate. */ - - poly_int64 byte_offset = exact_div (adj->offset, BITS_PER_UNIT); - base = gimple_call_arg (stmt, adj->base_index); - loc = gimple_location (stmt); - - if (TREE_CODE (base) != ADDR_EXPR - && POINTER_TYPE_P (TREE_TYPE (base))) - off = build_int_cst (adj->alias_ptr_type, byte_offset); - else + if (phony_arguments == 0) + /* We have optimistically avoided constructing index_map do far but + now it is clear it will be necessary, so let's create the easy + bit we skipped until now. */ + for (unsigned k = 0; k < stmt_idx; k++) + index_map->safe_push (k); + + tree dummy = (*performed_splits)[sm_idx].dummy_decl; + for (unsigned j = sm_idx; j < performed_splits->length (); j++) { - poly_int64 base_offset; - tree prev_base; - bool addrof; + ipa_param_performed_split *caller_split + = &(*performed_splits)[j]; + if (caller_split->dummy_decl != dummy) + break; - if (TREE_CODE (base) == ADDR_EXPR) - { - base = TREE_OPERAND (base, 0); - addrof = true; - } - else - addrof = false; - prev_base = base; - base = get_addr_base_and_unit_offset (base, &base_offset); - /* Aggregate arguments can have non-invariant addresses. */ - if (!base) - { - base = build_fold_addr_expr (prev_base); - off = build_int_cst (adj->alias_ptr_type, byte_offset); - } - else if (TREE_CODE (base) == MEM_REF) - { - if (!addrof) - { - deref_base = true; - deref_align = TYPE_ALIGN (TREE_TYPE (base)); - } - off = build_int_cst (adj->alias_ptr_type, - base_offset + byte_offset); - off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), - off); - base = TREE_OPERAND (base, 0); - } - else + tree arg = gimple_call_arg (stmt, stmt_idx); + struct transitive_split_map tsm; + tsm.repl = arg; + tsm.base_index = base_index; + if (caller_split->unit_offset >= unit_offset_delta) { - off = build_int_cst (adj->alias_ptr_type, - base_offset + byte_offset); - base = build_fold_addr_expr (base); + tsm.unit_offset + = (caller_split->unit_offset - unit_offset_delta); + trans_map->safe_push (tsm); } + + phony_arguments++; + stmt_idx++; } + } + base_index++; + } + return phony_arguments; +} - if (!adj->by_ref) +/* Modify actual arguments of a function call in statement STMT, assuming it + calls CALLEE_DECL. CALLER_ADJ must be the description of parameter + adjustments of the caller or NULL if there are none. Return the new + statement that replaced the old one. When invoked, cfun and + current_function_decl have to be set to the caller. */ + +gcall * +ipa_param_adjustments::modify_call (gcall *stmt, + vec *performed_splits, + tree callee_decl, bool update_references) +{ + unsigned len = vec_safe_length (m_adj_params); + auto_vec vargs (len); + tree old_decl = gimple_call_fndecl (stmt); + unsigned old_nargs = gimple_call_num_args (stmt); + auto_vec kept (old_nargs); + kept.quick_grow_cleared (old_nargs); + + auto_vec index_map; + auto_vec trans_map; + bool transitive_remapping = false; + + if (performed_splits) + { + unsigned removed = init_transitive_splits (performed_splits, + stmt, &index_map, &trans_map); + if (removed > 0) + { + transitive_remapping = true; + old_nargs -= removed; + } + } + + cgraph_node *current_node = cgraph_node::get (current_function_decl); + if (update_references) + current_node->remove_stmt_references (stmt); + + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + gimple_stmt_iterator prev_gsi = gsi; + gsi_prev (&prev_gsi); + for (unsigned i = 0; i < len; i++) + { + ipa_adjusted_param *apm = &(*m_adj_params)[i]; + if (apm->op == IPA_PARAM_OP_COPY) + { + unsigned index = apm->base_index; + if (index >= old_nargs) + /* Can happen if the original call has argument mismatch, + ignore. */ + continue; + if (transitive_remapping) + index = index_map[apm->base_index]; + + tree arg = gimple_call_arg (stmt, index); + + vargs.quick_push (arg); + kept[index] = true; + continue; + } + + /* At the moment the only user of IPA_PARAM_OP_NEW modifies calls itself. + If we ever want to support it during WPA IPA stage, we'll need a + mechanism to call into the IPA passes that introduced them. Currently + we simply mandate that IPA infrastructure understands all argument + modifications. Remember, edge redirection/modification is done only + once, not in steps for each pass modifying the callee like clone + materialization. */ + gcc_assert (apm->op == IPA_PARAM_OP_SPLIT); + + /* We have to handle transitive changes differently using the maps we + have created before. So look into them first. */ + tree repl = NULL_TREE; + for (unsigned j = 0; j < trans_map.length (); j++) + if (trans_map[j].base_index == apm->base_index + && trans_map[j].unit_offset == apm->unit_offset) + { + repl = trans_map[j].repl; + break; + } + if (repl) + { + vargs.quick_push (repl); + continue; + } + + unsigned index = apm->base_index; + if (index >= old_nargs) + /* Can happen if the original call has argument mismatch, ignore. */ + continue; + if (transitive_remapping) + index = index_map[apm->base_index]; + tree base = gimple_call_arg (stmt, index); + + /* We create a new parameter out of the value of the old one, we can + do the following kind of transformations: + + - A scalar passed by reference, potentially as a part of a larger + aggregate, is converted to a scalar passed by value. + + - A part of an aggregate is passed instead of the whole aggregate. */ + + location_t loc = gimple_location (stmt); + tree off; + bool deref_base = false; + unsigned int deref_align = 0; + if (TREE_CODE (base) != ADDR_EXPR + && POINTER_TYPE_P (TREE_TYPE (base))) + off = build_int_cst (apm->alias_ptr_type, apm->unit_offset); + else + { + bool addrof; + if (TREE_CODE (base) == ADDR_EXPR) { - tree type = adj->type; - unsigned int align; - unsigned HOST_WIDE_INT misalign; + base = TREE_OPERAND (base, 0); + addrof = true; + } + else + addrof = false; - if (deref_base) - { - align = deref_align; - misalign = 0; - } - else - { - get_pointer_alignment_1 (base, &align, &misalign); - if (TYPE_ALIGN (type) > align) - align = TYPE_ALIGN (type); - } - misalign += (offset_int::from (wi::to_wide (off), - SIGNED).to_short_addr () - * BITS_PER_UNIT); - misalign = misalign & (align - 1); - if (misalign != 0) - align = least_bit_hwi (misalign); - if (align < TYPE_ALIGN (type)) - type = build_aligned_type (type, align); - base = force_gimple_operand_gsi (&gsi, base, - true, NULL, true, GSI_SAME_STMT); - expr = fold_build2_loc (loc, MEM_REF, type, base, off); - REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse; - /* If expr is not a valid gimple call argument emit - a load into a temporary. */ - if (is_gimple_reg_type (TREE_TYPE (expr))) + tree prev_base = base; + poly_int64 base_offset; + base = get_addr_base_and_unit_offset (base, &base_offset); + + /* Aggregate arguments can have non-invariant addresses. */ + if (!base) + { + base = build_fold_addr_expr (prev_base); + off = build_int_cst (apm->alias_ptr_type, apm->unit_offset); + } + else if (TREE_CODE (base) == MEM_REF) + { + if (!addrof) { - gimple *tem = gimple_build_assign (NULL_TREE, expr); - if (gimple_in_ssa_p (cfun)) - { - gimple_set_vuse (tem, gimple_vuse (stmt)); - expr = make_ssa_name (TREE_TYPE (expr), tem); - } - else - expr = create_tmp_reg (TREE_TYPE (expr)); - gimple_assign_set_lhs (tem, expr); - gimple_set_location (tem, loc); - gsi_insert_before (&gsi, tem, GSI_SAME_STMT); + deref_base = true; + deref_align = TYPE_ALIGN (TREE_TYPE (base)); } + off = build_int_cst (apm->alias_ptr_type, + base_offset + apm->unit_offset); + off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), + off); + base = TREE_OPERAND (base, 0); } else { - expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off); - REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse; - expr = build_fold_addr_expr (expr); - expr = force_gimple_operand_gsi (&gsi, expr, - true, NULL, true, GSI_SAME_STMT); + off = build_int_cst (apm->alias_ptr_type, + base_offset + apm->unit_offset); + base = build_fold_addr_expr (base); } - vargs.quick_push (expr); } - if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS) + + tree type = apm->type; + unsigned int align; + unsigned HOST_WIDE_INT misalign; + + if (deref_base) { - unsigned int ix; - tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg; - gimple *def_temp; + align = deref_align; + misalign = 0; + } + else + { + get_pointer_alignment_1 (base, &align, &misalign); + /* All users must make sure that we can be optimistic when it + comes to alignment in this case (by inspecting the final users + of these new parameters). */ + if (TYPE_ALIGN (type) > align) + align = TYPE_ALIGN (type); + } + misalign + += (offset_int::from (wi::to_wide (off), SIGNED).to_short_addr () + * BITS_PER_UNIT); + misalign = misalign & (align - 1); + if (misalign != 0) + align = least_bit_hwi (misalign); + if (align < TYPE_ALIGN (type)) + type = build_aligned_type (type, align); + base = force_gimple_operand_gsi (&gsi, base, + true, NULL, true, GSI_SAME_STMT); + tree expr = fold_build2_loc (loc, MEM_REF, type, base, off); + REF_REVERSE_STORAGE_ORDER (expr) = apm->reverse; + /* If expr is not a valid gimple call argument emit + a load into a temporary. */ + if (is_gimple_reg_type (TREE_TYPE (expr))) + { + gimple *tem = gimple_build_assign (NULL_TREE, expr); + if (gimple_in_ssa_p (cfun)) + { + gimple_set_vuse (tem, gimple_vuse (stmt)); + expr = make_ssa_name (TREE_TYPE (expr), tem); + } + else + expr = create_tmp_reg (TREE_TYPE (expr)); + gimple_assign_set_lhs (tem, expr); + gsi_insert_before (&gsi, tem, GSI_SAME_STMT); + } + vargs.quick_push (expr); + } + + if (m_always_copy_start >= 0) + for (unsigned i = m_always_copy_start; i < old_nargs; i++) + vargs.safe_push (gimple_call_arg (stmt, i)); + + /* For optimized away parameters, add on the caller side + before the call + DEBUG D#X => parm_Y(D) + stmts and associate D#X with parm in decl_debug_args_lookup + vector to say for debug info that if parameter parm had been passed, + it would have value parm_Y(D). */ + if (MAY_HAVE_DEBUG_BIND_STMTS && old_decl && callee_decl) + { + vec **debug_args = NULL; + unsigned i = 0; + for (tree old_parm = DECL_ARGUMENTS (old_decl); + old_parm && i < old_nargs && ((int) i) < m_always_copy_start; + old_parm = DECL_CHAIN (old_parm), i++) + { + if (!is_gimple_reg (old_parm) || kept[i]) + continue; + tree origin = DECL_ORIGIN (old_parm); + tree arg = gimple_call_arg (stmt, i); - arg = gimple_call_arg (stmt, adj->base_index); if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE (arg))) { if (!fold_convertible_p (TREE_TYPE (origin), arg)) continue; - arg = fold_convert_loc (gimple_location (stmt), - TREE_TYPE (origin), arg); + tree rhs1; + if (TREE_CODE (arg) == SSA_NAME + && gimple_assign_cast_p (SSA_NAME_DEF_STMT (arg)) + && (rhs1 + = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (arg))) + && useless_type_conversion_p (TREE_TYPE (origin), + TREE_TYPE (rhs1))) + arg = rhs1; + else + arg = fold_convert_loc (gimple_location (stmt), + TREE_TYPE (origin), arg); } if (debug_args == NULL) debug_args = decl_debug_args_insert (callee_decl); + unsigned int ix; + tree ddecl = NULL_TREE; for (ix = 0; vec_safe_iterate (*debug_args, ix, &ddecl); ix += 2) if (ddecl == origin) { @@ -427,7 +802,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt, vec_safe_push (*debug_args, origin); vec_safe_push (*debug_args, ddecl); } - def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg), stmt); + gimple *def_temp = gimple_build_debug_bind (ddecl, + unshare_expr (arg), stmt); gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT); } } @@ -438,10 +814,34 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt, print_gimple_stmt (dump_file, gsi_stmt (gsi), 0); } - new_stmt = gimple_build_call_vec (callee_decl, vargs); - vargs.release (); - if (gimple_call_lhs (stmt)) - gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); + gcall *new_stmt = gimple_build_call_vec (callee_decl, vargs); + + if (tree lhs = gimple_call_lhs (stmt)) + { + if (!m_skip_return) + gimple_call_set_lhs (new_stmt, lhs); + else if (TREE_CODE (lhs) == SSA_NAME) + { + /* LHS should now by a default-def SSA. Unfortunately default-def + SSA_NAMEs need a backing variable (or at least some code examining + SSAs assumes it is non-NULL). So we either have to re-use the + decl we have at hand or introdice a new one. */ + tree repl = create_tmp_var (TREE_TYPE (lhs), "removed_return"); + repl = get_or_create_ssa_default_def (cfun, repl); + SSA_NAME_IS_DEFAULT_DEF (repl) = true; + imm_use_iterator ui; + use_operand_p use_p; + gimple *using_stmt; + FOR_EACH_IMM_USE_STMT (using_stmt, ui, lhs) + { + FOR_EACH_IMM_USE_ON_STMT (use_p, ui) + { + SET_USE (use_p, repl); + } + update_stmt (using_stmt); + } + } + } gimple_set_block (new_stmt, gimple_block (stmt)); if (gimple_has_location (stmt)) @@ -458,120 +858,398 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt, fprintf (dump_file, "\n"); } gsi_replace (&gsi, new_stmt, true); - if (cs) - cs->set_call_stmt (new_stmt); - do - { - current_node->record_stmt_references (gsi_stmt (gsi)); - gsi_prev (&gsi); - } - while (gsi_stmt (gsi) != gsi_stmt (prev_gsi)); + if (update_references) + do + { + current_node->record_stmt_references (gsi_stmt (gsi)); + gsi_prev (&gsi); + } + while (gsi_stmt (gsi) != gsi_stmt (prev_gsi)); + return new_stmt; } -/* Return true iff BASE_INDEX is in ADJUSTMENTS more than once. */ +/* Dump information contained in the object in textual form to F. */ -static bool -index_in_adjustments_multiple_times_p (int base_index, - ipa_parm_adjustment_vec adjustments) +void +ipa_param_adjustments::dump (FILE *f) { - int i, len = adjustments.length (); - bool one = false; + fprintf (f, " m_always_copy_start: %i\n", m_always_copy_start); + ipa_dump_adjusted_parameters (f, m_adj_params); + if (m_skip_return) + fprintf (f, " Will SKIP return.\n"); +} - for (i = 0; i < len; i++) - { - struct ipa_parm_adjustment *adj; - adj = &adjustments[i]; +/* Dump information contained in the object in textual form to stderr. */ - if (adj->base_index == base_index) - { - if (one) - return true; - else - one = true; - } - } - return false; +void +ipa_param_adjustments::debug () +{ + dump (stderr); } -/* Return adjustments that should have the same effect on function parameters - and call arguments as if they were first changed according to adjustments in - INNER and then by adjustments in OUTER. */ +/* Register that REPLACEMENT should replace parameter described in APM and + optionally as DUMMY to mark transitive splits accross calls. */ -ipa_parm_adjustment_vec -ipa_combine_adjustments (ipa_parm_adjustment_vec inner, - ipa_parm_adjustment_vec outer) +void +ipa_param_body_adjustments::register_replacement (ipa_adjusted_param *apm, + tree replacement, + tree dummy) { - int i, outlen = outer.length (); - int inlen = inner.length (); - int removals = 0; - ipa_parm_adjustment_vec adjustments, tmp; + gcc_checking_assert (apm->op == IPA_PARAM_OP_SPLIT + || apm->op == IPA_PARAM_OP_NEW); + gcc_checking_assert (!apm->prev_clone_adjustment); + ipa_param_body_replacement psr; + psr.base = m_oparms[apm->prev_clone_index]; + psr.repl = replacement; + psr.dummy = dummy; + psr.unit_offset = apm->unit_offset; + m_replacements.safe_push (psr); +} + +/* Copy or not, as appropriate given ID, a pre-existing PARM_DECL T so that + it can be included in the parameters of the modified function. */ - tmp.create (inlen); - for (i = 0; i < inlen; i++) +static tree +carry_over_param (tree t, struct copy_body_data *id) +{ + tree new_parm; + if (id) { - struct ipa_parm_adjustment *n; - n = &inner[i]; + new_parm = remap_decl (t, id); + if (TREE_CODE (new_parm) != PARM_DECL) + new_parm = id->copy_decl (t, id); + } + else + new_parm = t; + return new_parm; +} - if (n->op == IPA_PARM_OP_REMOVE) - removals++; - else +/* Common initialization performed by all ipa_param_body_adjustments + constructors. OLD_FNDECL is the declaration we take original arguments + from, (it may be the same as M_FNDECL). VARS, if non-NULL, is a pointer to + a chained list of new local variables. TREE_MAP is the IPA-CP produced + mapping of trees to constants. + + The function is rather long but it really onlu initializes all data members + of the class. It creates new param DECLs, finds their new types, */ + +void +ipa_param_body_adjustments::common_initialization (tree old_fndecl, + tree *vars, + vec *tree_map) +{ + push_function_arg_decls (&m_oparms, old_fndecl); + auto_vec otypes; + if (TYPE_ARG_TYPES (TREE_TYPE (old_fndecl)) != NULL_TREE) + push_function_arg_types (&otypes, TREE_TYPE (old_fndecl)); + else + { + auto_vec oparms; + push_function_arg_decls (&oparms, old_fndecl); + unsigned ocount = oparms.length (); + otypes.reserve_exact (ocount); + for (unsigned i = 0; i < ocount; i++) + otypes.quick_push (TREE_TYPE (oparms[i])); + } + fill_vector_of_new_param_types (&m_new_types, &otypes, m_adj_params, true); + + auto_vec kept; + kept.reserve_exact (m_oparms.length ()); + kept.quick_grow_cleared (m_oparms.length ()); + auto_vec isra_dummy_decls; + isra_dummy_decls.reserve_exact (m_oparms.length ()); + isra_dummy_decls.quick_grow_cleared (m_oparms.length ()); + + unsigned adj_len = vec_safe_length (m_adj_params); + m_method2func = ((TREE_CODE (TREE_TYPE (m_fndecl)) == METHOD_TYPE) + && (adj_len == 0 + || (*m_adj_params)[0].op != IPA_PARAM_OP_COPY + || (*m_adj_params)[0].base_index != 0)); + + /* The main job of the this function is to go over the vector of adjusted + parameters and create declarations or find corresponding old ones and push + them to m_new_decls. For IPA-SRA replacements it also creates + corresponding m_id->dst_node->clone.performed_splits entries. */ + + m_new_decls.reserve_exact (adj_len); + for (unsigned i = 0; i < adj_len ; i++) + { + ipa_adjusted_param *apm = &(*m_adj_params)[i]; + unsigned prev_index = apm->prev_clone_index; + tree new_parm; + if (apm->op == IPA_PARAM_OP_COPY + || apm->prev_clone_adjustment) { - /* FIXME: Handling of new arguments are not implemented yet. */ - gcc_assert (n->op != IPA_PARM_OP_NEW); - tmp.quick_push (*n); + kept[prev_index] = true; + new_parm = carry_over_param (m_oparms[prev_index], m_id); + m_new_decls.quick_push (new_parm); } + else if (apm->op == IPA_PARAM_OP_NEW + || apm->op == IPA_PARAM_OP_SPLIT) + { + tree new_type = m_new_types[i]; + gcc_checking_assert (new_type); + new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE, + new_type); + const char *prefix = ipa_param_prefixes[apm->param_prefix_index]; + DECL_NAME (new_parm) = create_tmp_var_name (prefix); + DECL_ARTIFICIAL (new_parm) = 1; + DECL_ARG_TYPE (new_parm) = new_type; + DECL_CONTEXT (new_parm) = m_fndecl; + TREE_USED (new_parm) = 1; + DECL_IGNORED_P (new_parm) = 1; + /* We assume all newly created arguments are not addressable. */ + if (TREE_CODE (new_type) == COMPLEX_TYPE + || TREE_CODE (new_type) == VECTOR_TYPE) + DECL_GIMPLE_REG_P (new_parm) = 1; + layout_decl (new_parm, 0); + m_new_decls.quick_push (new_parm); + + if (apm->op == IPA_PARAM_OP_SPLIT) + { + m_split_modifications_p = true; + + if (m_id) + { + tree dummy_decl; + if (!isra_dummy_decls[prev_index]) + { + dummy_decl = copy_decl_to_var (m_oparms[prev_index], + m_id); + /* Any attempt to remap this dummy in this particular + instance of clone materialization should yield + itself. */ + insert_decl_map (m_id, dummy_decl, dummy_decl); + + DECL_CHAIN (dummy_decl) = *vars; + *vars = dummy_decl; + isra_dummy_decls[prev_index] = dummy_decl; + } + else + dummy_decl = isra_dummy_decls[prev_index]; + + register_replacement (apm, new_parm, dummy_decl); + ipa_param_performed_split ps; + ps.dummy_decl = dummy_decl; + ps.unit_offset = apm->unit_offset; + vec_safe_push (m_id->dst_node->clone.performed_splits, ps); + } + else + register_replacement (apm, new_parm); + } + } + else + gcc_unreachable (); } - adjustments.create (outlen + removals); - for (i = 0; i < outlen; i++) + + /* As part of body modifications, we will also have to replace remaining uses + of remaining uses of removed PARM_DECLs (which do not however use the + initial value) with their VAR_DECL copies. + + We do this differently with and without m_id. With m_id, we rely on its + mapping and create a replacement straight away. Without it, we have our + own mechanism for which we have to populate m_removed_decls vector. Just + don't mix them, that is why you should not call + replace_removed_params_ssa_names or perform_cfun_body_modifications when + you construct with ID not equal to NULL. */ + + unsigned op_len = m_oparms.length (); + for (unsigned i = 0; i < op_len; i++) + if (!kept[i]) + { + if (m_id) + { + if (!m_id->decl_map->get (m_oparms[i])) + { + /* TODO: Perhaps at least aggregate-type params could re-use + their isra_dummy_decl here? */ + tree var = copy_decl_to_var (m_oparms[i], m_id); + insert_decl_map (m_id, m_oparms[i], var); + /* Declare this new variable. */ + DECL_CHAIN (var) = *vars; + *vars = var; + } + } + else + { + m_removed_decls.safe_push (m_oparms[i]); + m_removed_map.put (m_oparms[i], m_removed_decls.length () - 1); + } + } + + if (!MAY_HAVE_DEBUG_STMTS) + return; + + /* Finally, when generating debug info, we fill vector m_reset_debug_decls + with removed parameters declarations. We do this in order to re-map their + debug bind statements and create debug decls for them. */ + + if (tree_map) { - struct ipa_parm_adjustment r; - struct ipa_parm_adjustment *out = &outer[i]; - struct ipa_parm_adjustment *in = &tmp[out->base_index]; + /* Do not output debuginfo for parameter declarations as if they vanished + when they were in fact replaced by a constant. */ + auto_vec index_mapping; + bool need_remap = false; - memset (&r, 0, sizeof (r)); - gcc_assert (in->op != IPA_PARM_OP_REMOVE); - if (out->op == IPA_PARM_OP_REMOVE) + if (m_id && m_id->src_node->clone.param_adjustments) { - if (!index_in_adjustments_multiple_times_p (in->base_index, tmp)) - { - r.op = IPA_PARM_OP_REMOVE; - adjustments.quick_push (r); - } - continue; + ipa_param_adjustments *prev_adjustments + = m_id->src_node->clone.param_adjustments; + prev_adjustments->get_updated_indices (&index_mapping); + need_remap = true; } - else + + for (unsigned i = 0; i < tree_map->length (); i++) { - /* FIXME: Handling of new arguments are not implemented yet. */ - gcc_assert (out->op != IPA_PARM_OP_NEW); + int parm_num = (*tree_map)[i]->parm_num; + gcc_assert (parm_num >= 0); + if (need_remap) + parm_num = index_mapping[parm_num]; + kept[parm_num] = true; } + } + + for (unsigned i = 0; i < op_len; i++) + if (!kept[i] && is_gimple_reg (m_oparms[i])) + m_reset_debug_decls.safe_push (m_oparms[i]); +} - r.base_index = in->base_index; - r.type = out->type; +/* Constructor of ipa_param_body_adjustments from a simple list of + modifications to parameters listed in ADJ_PARAMS which will prepare ground + for modification of parameters of fndecl. Return value of the function will + not be removed and the object will assume it does not run as a part of + tree-function_versioning. */ + +ipa_param_body_adjustments +::ipa_param_body_adjustments (vec *adj_params, + tree fndecl) + : m_adj_params (adj_params), m_adjustments (NULL), m_reset_debug_decls (), + m_split_modifications_p (false), m_fndecl (fndecl), m_id (NULL), + m_oparms (), m_new_decls (), m_new_types (), m_replacements (), + m_removed_decls (), m_removed_map (), m_method2func (false) +{ + common_initialization (fndecl, NULL, NULL); +} - /* FIXME: Create nonlocal value too. */ +/* Constructor of ipa_param_body_adjustments from ipa_param_adjustments in + ADJUSTMENTS which will prepare ground for modification of parameters of + fndecl. The object will assume it does not run as a part of + tree-function_versioning. */ + +ipa_param_body_adjustments +::ipa_param_body_adjustments (ipa_param_adjustments *adjustments, + tree fndecl) + : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments), + m_reset_debug_decls (), m_split_modifications_p (false), m_fndecl (fndecl), + m_id (NULL), m_oparms (), m_new_decls (), m_new_types (), + m_replacements (), m_removed_decls (), m_removed_map (), + m_method2func (false) +{ + common_initialization (fndecl, NULL, NULL); +} - if (in->op == IPA_PARM_OP_COPY && out->op == IPA_PARM_OP_COPY) - r.op = IPA_PARM_OP_COPY; - else if (in->op == IPA_PARM_OP_COPY) - r.offset = out->offset; - else if (out->op == IPA_PARM_OP_COPY) - r.offset = in->offset; - else - r.offset = in->offset + out->offset; - adjustments.quick_push (r); +/* Constructor of ipa_param_body_adjustments which sets it up as a part of + running tree_function_versioning. Planned modifications to the function are + in ADJUSTMENTS. FNDECL designates the new function clone which is being + modified. OLD_FNDECL is the function of which FNDECL is a clone (and which + at the time of invocation still share DECL_ARGUMENTS). ID is the + copy_body_data structure driving the wholy body copying process. VARS is a + pointer to the head of the list of new local variables, TREE_MAP is the map + that drives tree substitution in the cloning process. */ + +ipa_param_body_adjustments +::ipa_param_body_adjustments (ipa_param_adjustments *adjustments, + tree fndecl, tree old_fndecl, + copy_body_data *id, tree *vars, + vec *tree_map) + : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments), + m_reset_debug_decls (), m_split_modifications_p (false), m_fndecl (fndecl), + m_id (id), m_oparms (), m_new_decls (), m_new_types (), m_replacements (), + m_removed_decls (), m_removed_map (), m_method2func (false) +{ + common_initialization (old_fndecl, vars, tree_map); +} + +/* Chain new param decls up and return them. */ + +tree +ipa_param_body_adjustments::get_new_param_chain () +{ + tree result; + tree *link = &result; + + unsigned len = vec_safe_length (m_adj_params); + for (unsigned i = 0; i < len; i++) + { + tree new_decl = m_new_decls[i]; + *link = new_decl; + link = &DECL_CHAIN (new_decl); } + *link = NULL_TREE; + return result; +} + +/* Modify the function parameters FNDECL and its type according to the plan in + ADJUSTMENTS. This function needs to be called when the decl has not already + been processed with ipa_param_adjustments::adjust_decl, otherwise just + seting DECL_ARGUMENTS to whatever get_new_param_chain will do is enough. */ + +void +ipa_param_body_adjustments::modify_formal_parameters () +{ + tree orig_type = TREE_TYPE (m_fndecl); + DECL_ARGUMENTS (m_fndecl) = get_new_param_chain (); + + /* When signature changes, we need to clear builtin info. */ + if (fndecl_built_in_p (m_fndecl)) + set_decl_built_in_function (m_fndecl, NOT_BUILT_IN, 0); + + /* At this point, removing return value is only implemented when going + through tree_function_versioning, not when modifying function body + directly. */ + gcc_assert (!m_adjustments || !m_adjustments->m_skip_return); + tree new_type = build_adjusted_function_type (orig_type, &m_new_types, + m_method2func, false); + + TREE_TYPE (m_fndecl) = new_type; + DECL_VIRTUAL_P (m_fndecl) = 0; + DECL_LANG_SPECIFIC (m_fndecl) = NULL; + if (m_method2func) + DECL_VINDEX (m_fndecl) = NULL_TREE; +} - for (i = 0; i < inlen; i++) +/* Given BASE and UNIT_OFFSET, find the corresponding record among replacement + structures. */ + +ipa_param_body_replacement * +ipa_param_body_adjustments::lookup_replacement_1 (tree base, + unsigned unit_offset) +{ + unsigned int len = m_replacements.length (); + for (unsigned i = 0; i < len; i++) { - struct ipa_parm_adjustment *n = &inner[i]; + ipa_param_body_replacement *pbr = &m_replacements[i]; - if (n->op == IPA_PARM_OP_REMOVE) - adjustments.quick_push (*n); + if (pbr->base == base + && (pbr->unit_offset == unit_offset)) + return pbr; } + return NULL; +} - tmp.release (); - return adjustments; +/* Given BASE and UNIT_OFFSET, find the corresponding replacement expression + and return it, assuming it is known it does not hold value by reference or + in reverse storage order. */ + +tree +ipa_param_body_adjustments::lookup_replacement (tree base, unsigned unit_offset) +{ + ipa_param_body_replacement *pbr = lookup_replacement_1 (base, unit_offset); + if (!pbr) + return NULL; + return pbr->repl; } /* If T is an SSA_NAME, return NULL if it is not a default def or @@ -592,165 +1270,634 @@ get_ssa_base_param (tree t, bool ignore_default_def) return t; } -/* Given an expression, return an adjustment entry specifying the - transformation to be done on EXPR. If no suitable adjustment entry - was found, returns NULL. +/* Given an expression, return the structure describing how it should be + replaced if it accesses a part of a split parameter or NULL otherwise. - If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a - default def, otherwise bail on them. + Do not free the result, it will be deallocated when the object is destroyed. - If CONVERT is non-NULL, this function will set *CONVERT if the - expression provided is a component reference. ADJUSTMENTS is the - adjustments vector. */ + If IGNORE_DEFAULT_DEF is cleared, consider only SSA_NAMEs of PARM_DECLs + which are default definitions, if set, consider all SSA_NAMEs of + PARM_DECLs. */ -ipa_parm_adjustment * -ipa_get_adjustment_candidate (tree **expr, bool *convert, - ipa_parm_adjustment_vec adjustments, - bool ignore_default_def) +ipa_param_body_replacement * +ipa_param_body_adjustments::get_expr_replacement (tree expr, + bool ignore_default_def) { - if (TREE_CODE (**expr) == BIT_FIELD_REF - || TREE_CODE (**expr) == IMAGPART_EXPR - || TREE_CODE (**expr) == REALPART_EXPR) - { - *expr = &TREE_OPERAND (**expr, 0); - if (convert) - *convert = true; - } + tree base; + unsigned unit_offset; - poly_int64 offset, size, max_size; - bool reverse; - tree base - = get_ref_base_and_extent (**expr, &offset, &size, &max_size, &reverse); - if (!base || !known_size_p (size) || !known_size_p (max_size)) + if (!isra_get_ref_base_and_offset (expr, &base, &unit_offset)) return NULL; - if (TREE_CODE (base) == MEM_REF) - { - offset += mem_ref_offset (base).force_shwi () * BITS_PER_UNIT; - base = TREE_OPERAND (base, 0); - } - base = get_ssa_base_param (base, ignore_default_def); if (!base || TREE_CODE (base) != PARM_DECL) return NULL; + return lookup_replacement_1 (base, unit_offset); +} - struct ipa_parm_adjustment *cand = NULL; - unsigned int len = adjustments.length (); - for (unsigned i = 0; i < len; i++) - { - struct ipa_parm_adjustment *adj = &adjustments[i]; +/* Given OLD_DECL, which is a PARM_DECL of a parameter that is being removed + (which includes it being split or replaced), return a new variable that + should be used for any SSA names that will remain in the function that + previously belonged to OLD_DECL. */ - if (adj->base == base - && (known_eq (adj->offset, offset) || adj->op == IPA_PARM_OP_REMOVE)) - { - cand = adj; - break; - } +tree +ipa_param_body_adjustments::get_replacement_ssa_base (tree old_decl) +{ + unsigned *idx = m_removed_map.get (old_decl); + if (!idx) + return NULL; + + tree repl; + if (TREE_CODE (m_removed_decls[*idx]) == PARM_DECL) + { + gcc_assert (m_removed_decls[*idx] == old_decl); + repl = copy_var_decl (old_decl, DECL_NAME (old_decl), + TREE_TYPE (old_decl)); + m_removed_decls[*idx] = repl; } + else + repl = m_removed_decls[*idx]; + return repl; +} + +/* If OLD_NAME, which is being defined by statement STMT, is an SSA_NAME of a + parameter which is to be removed because its value is not used, create a new + SSA_NAME relating to a replacement VAR_DECL, replace all uses of the + original with it and return it. If there is no need to re-map, return NULL. + ADJUSTMENTS is a pointer to a vector of IPA-SRA adjustments. */ + +tree +ipa_param_body_adjustments::replace_removed_params_ssa_names (tree old_name, + gimple *stmt) +{ + gcc_assert (!m_id); + if (TREE_CODE (old_name) != SSA_NAME) + return NULL; + + tree decl = SSA_NAME_VAR (old_name); + if (decl == NULL_TREE + || TREE_CODE (decl) != PARM_DECL) + return NULL; - if (!cand || cand->op == IPA_PARM_OP_COPY || cand->op == IPA_PARM_OP_REMOVE) + tree repl = get_replacement_ssa_base (decl); + if (!repl) return NULL; - return cand; + + tree new_name = make_ssa_name (repl, stmt); + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_name) + = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (old_name); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "replacing an SSA name of a removed param "); + print_generic_expr (dump_file, old_name); + fprintf (dump_file, " with "); + print_generic_expr (dump_file, new_name); + fprintf (dump_file, "\n"); + } + + replace_uses_by (old_name, new_name); + return new_name; } -/* If the expression *EXPR should be replaced by a reduction of a parameter, do - so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT - specifies whether the function should care about type incompatibility the - current and new expressions. If it is false, the function will leave - incompatibility issues to the caller. Return true iff the expression - was modified. */ +/* If the expression *EXPR_P should be replaced, do so. CONVERT specifies + whether the function should care about type incompatibility of the current + and new expressions. If it is false, the function will leave + incompatibility issues to the caller - note that when the function + encounters a BIT_FIELD_REF, IMAGPART_EXPR or REALPART_EXPR, it will modify + their bases instead of the expressions themselves and then also performs any + necessary conversions. */ bool -ipa_modify_expr (tree *expr, bool convert, - ipa_parm_adjustment_vec adjustments) +ipa_param_body_adjustments::modify_expression (tree *expr_p, bool convert) { - struct ipa_parm_adjustment *cand - = ipa_get_adjustment_candidate (&expr, &convert, adjustments, false); - if (!cand) - return false; + tree expr = *expr_p; - tree src; - if (cand->by_ref) + if (TREE_CODE (expr) == BIT_FIELD_REF + || TREE_CODE (expr) == IMAGPART_EXPR + || TREE_CODE (expr) == REALPART_EXPR) { - src = build_simple_mem_ref (cand->new_decl); - REF_REVERSE_STORAGE_ORDER (src) = cand->reverse; + expr_p = &TREE_OPERAND (expr, 0); + expr = *expr_p; + convert = true; } - else - src = cand->new_decl; + ipa_param_body_replacement *pbr = get_expr_replacement (expr, false); + if (!pbr) + return false; + + tree repl = pbr->repl; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "About to replace expr "); - print_generic_expr (dump_file, *expr); + print_generic_expr (dump_file, expr); fprintf (dump_file, " with "); - print_generic_expr (dump_file, src); + print_generic_expr (dump_file, repl); fprintf (dump_file, "\n"); } - if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type)) + if (convert && !useless_type_conversion_p (TREE_TYPE (expr), + TREE_TYPE (repl))) { - tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src); - *expr = vce; + tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (expr), repl); + *expr_p = vce; } else - *expr = src; + *expr_p = repl; return true; } -/* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human - friendly way, assuming they are meant to be applied to FNDECL. */ +/* If the assignment statement STMT contains any expressions that need to + replaced with a different one as noted by ADJUSTMENTS, do so. Handle any + potential type incompatibilities. If any conversion sttements have to be + pre-pended to STMT, they will be added to EXTRA_STMTS. Return true iff the + statement was modified. */ -void -ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments, - tree fndecl) +bool +ipa_param_body_adjustments::modify_assignment (gimple *stmt, + gimple_seq *extra_stmts) { - int i, len = adjustments.length (); - bool first = true; - vec parms = ipa_get_vector_of_formal_parms (fndecl); + tree *lhs_p, *rhs_p; + bool any; - fprintf (file, "IPA param adjustments: "); - for (i = 0; i < len; i++) - { - struct ipa_parm_adjustment *adj; - adj = &adjustments[i]; + if (!gimple_assign_single_p (stmt)) + return false; - if (!first) - fprintf (file, " "); + rhs_p = gimple_assign_rhs1_ptr (stmt); + lhs_p = gimple_assign_lhs_ptr (stmt); + + any = modify_expression (lhs_p, false); + any |= modify_expression (rhs_p, false); + if (any + && !useless_type_conversion_p (TREE_TYPE (*lhs_p), TREE_TYPE (*rhs_p))) + { + if (TREE_CODE (*rhs_p) == CONSTRUCTOR) + { + /* V_C_Es of constructors can cause trouble (PR 42714). */ + if (is_gimple_reg_type (TREE_TYPE (*lhs_p))) + *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); + else + *rhs_p = build_constructor (TREE_TYPE (*lhs_p), + NULL); + } else - first = false; + { + tree new_rhs = fold_build1_loc (gimple_location (stmt), + VIEW_CONVERT_EXPR, TREE_TYPE (*lhs_p), + *rhs_p); + tree tmp = force_gimple_operand (new_rhs, extra_stmts, true, + NULL_TREE); + gimple_assign_set_rhs1 (stmt, tmp); + } + return true; + } + + return any; +} + +/* Data passed to remap_split_decl_to_dummy through walk_tree. */ + +struct simple_tree_swap_info +{ + /* Change FROM to TO. */ + tree from, to; + /* And set DONE to true when doing so. */ + bool done; +}; + +/* Simple remapper to remap a split parameter to the same expression based on a + special dummy decl so that edge redirections can detect transitive splitting + and finish them. */ - fprintf (file, "%i. base_index: %i - ", i, adj->base_index); - print_generic_expr (file, parms[adj->base_index]); - if (adj->base) +static tree +remap_split_decl_to_dummy (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + + if (DECL_P (t) || TREE_CODE (t) == SSA_NAME) + { + struct simple_tree_swap_info *swapinfo + = (struct simple_tree_swap_info *) data; + if (t == swapinfo->from + || (TREE_CODE (t) == SSA_NAME + && SSA_NAME_VAR (t) == swapinfo->from)) { - fprintf (file, ", base: "); - print_generic_expr (file, adj->base); + *tp = swapinfo->to; + swapinfo->done = true; + } + *walk_subtrees = 0; + } + else if (TYPE_P (t)) + *walk_subtrees = 0; + else + *walk_subtrees = 1; + return NULL_TREE; +} + + +/* If the call statement pointed at by STMT_P contains any expressions that + need to replaced with a different one as noted by ADJUSTMENTS, do so. f the + statement needs to be rebuilt, do so. Return true if any modifications have + been performed. + + If the method is invoked as a part of IPA clone materialization and if any + parameter split is transitive, i.e. it applies to the functin that is being + modified and also to the callee of the statement, replace the parameter + passed to old callee with an equivalent expression based on a dummy decl + followed by PARM_DECLs representing the actual replacements. The actual + replacements will be then converted into SSA_NAMEs and then + ipa_param_adjustments::modify_call will find the appropriate ones and leave + only those in the call. */ + +bool +ipa_param_body_adjustments::modify_call_stmt (gcall **stmt_p) +{ + gcall *stmt = *stmt_p; + auto_vec pass_through_args; + auto_vec pass_through_pbr_indices; + + if (m_split_modifications_p && m_id) + { + for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) + { + tree t = gimple_call_arg (stmt, i); + gcc_assert (TREE_CODE (t) != BIT_FIELD_REF + && TREE_CODE (t) != IMAGPART_EXPR + && TREE_CODE (t) != REALPART_EXPR); + + tree base; + unsigned unit_offset; + if (!isra_get_ref_base_and_offset (t, &base, &unit_offset)) + continue; + + bool by_ref = false; + if (TREE_CODE (base) == SSA_NAME) + { + if (!SSA_NAME_IS_DEFAULT_DEF (base)) + continue; + base = SSA_NAME_VAR (base); + gcc_checking_assert (base); + by_ref = true; + } + if (TREE_CODE (base) != PARM_DECL) + continue; + + bool base_among_replacements = false; + unsigned j, repl_list_len = m_replacements.length (); + for (j = 0; j < repl_list_len; j++) + { + ipa_param_body_replacement *pbr = &m_replacements[j]; + if (pbr->base == base) + { + base_among_replacements = true; + break; + } + } + if (!base_among_replacements) + continue; + + /* We still have to distinguish between an end-use that we have to + transform now and a pass-through, which happens in the following + two cases. */ + + /* TODO: After we adjust ptr_parm_has_nonarg_uses to also consider + &MEM_REF[ssa_name + offset], we will also have to detect that case + here. */ + + if (TREE_CODE (t) == SSA_NAME + && SSA_NAME_IS_DEFAULT_DEF (t) + && SSA_NAME_VAR (t) + && TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL) + { + /* This must be a by_reference pass-through. */ + gcc_assert (POINTER_TYPE_P (TREE_TYPE (t))); + pass_through_args.safe_push (i); + pass_through_pbr_indices.safe_push (j); + } + else if (!by_ref && AGGREGATE_TYPE_P (TREE_TYPE (t))) + { + /* Currently IPA-SRA guarantees the aggregate access type + exactly matches in this case. So if it does not match, it is + a pass-through argument that will be sorted out at edge + redirection time. */ + ipa_param_body_replacement *pbr + = lookup_replacement_1 (base, unit_offset); + + if (!pbr + || (TYPE_MAIN_VARIANT (TREE_TYPE (t)) + != TYPE_MAIN_VARIANT (TREE_TYPE (pbr->repl)))) + { + pass_through_args.safe_push (i); + pass_through_pbr_indices.safe_push (j); + } + } } - if (adj->new_decl) + } + + unsigned nargs = gimple_call_num_args (stmt); + if (!pass_through_args.is_empty ()) + { + auto_vec vargs; + unsigned pt_idx = 0; + for (unsigned i = 0; i < nargs; i++) { - fprintf (file, ", new_decl: "); - print_generic_expr (file, adj->new_decl); + if (pt_idx < pass_through_args.length () + && i == pass_through_args[pt_idx]) + { + unsigned j = pass_through_pbr_indices[pt_idx]; + pt_idx++; + tree base = m_replacements[j].base; + + /* Map base will get mapped to the special transitive-isra marker + dummy decl. */ + struct simple_tree_swap_info swapinfo; + swapinfo.from = base; + swapinfo.to = m_replacements[j].dummy; + swapinfo.done = false; + tree arg = gimple_call_arg (stmt, i); + walk_tree (&arg, remap_split_decl_to_dummy, &swapinfo, NULL); + gcc_assert (swapinfo.done); + vargs.safe_push (arg); + /* Now let's push all replacements pertaining to this parameter + so that all gimple register ones get correct SSA_NAMES. Edge + redirection will weed out the dummy argument as well as all + unused replacements later. */ + unsigned int repl_list_len = m_replacements.length (); + for (; j < repl_list_len; j++) + { + if (m_replacements[j].base != base) + break; + vargs.safe_push (m_replacements[j].repl); + } + } + else + { + tree t = gimple_call_arg (stmt, i); + modify_expression (&t, true); + vargs.safe_push (t); + } } - if (adj->new_ssa_base) + gcall *new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs); + gimple_call_set_chain (new_stmt, gimple_call_chain (stmt)); + gimple_call_copy_flags (new_stmt, stmt); + if (tree lhs = gimple_call_lhs (stmt)) { - fprintf (file, ", new_ssa_base: "); - print_generic_expr (file, adj->new_ssa_base); + modify_expression (&lhs, false); + gimple_call_set_lhs (new_stmt, lhs); } + *stmt_p = new_stmt; + return true; + } - if (adj->op == IPA_PARM_OP_COPY) - fprintf (file, ", copy_param"); - else if (adj->op == IPA_PARM_OP_REMOVE) - fprintf (file, ", remove_param"); - else + /* Otherwise, no need to rebuild the statement, let's just modify arguments + and the LHS if/as appropriate. */ + bool modified = false; + for (unsigned i = 0; i < nargs; i++) + { + tree *t = gimple_call_arg_ptr (stmt, i); + modified |= modify_expression (t, true); + } + + if (gimple_call_lhs (stmt)) + { + tree *t = gimple_call_lhs_ptr (stmt); + modified |= modify_expression (t, false); + } + + return modified; +} + +/* If the statement STMT contains any expressions that need to replaced with a + different one as noted by ADJUSTMENTS, do so. Handle any potential type + incompatibilities. If any conversion sttements have to be pre-pended to + STMT, they will be added to EXTRA_STMTS. Return true iff the statement was + modified. */ + +bool +ipa_param_body_adjustments::modify_gimple_stmt (gimple **stmt, + gimple_seq *extra_stmts) +{ + bool modified = false; + tree *t; + + switch (gimple_code (*stmt)) + { + case GIMPLE_RETURN: + t = gimple_return_retval_ptr (as_a (*stmt)); + if (m_adjustments && m_adjustments->m_skip_return) + *t = NULL_TREE; + else if (*t != NULL_TREE) + modified |= modify_expression (t, true); + break; + + case GIMPLE_ASSIGN: + modified |= modify_assignment (*stmt, extra_stmts); + break; + + case GIMPLE_CALL: + modified |= modify_call_stmt ((gcall **) stmt); + break; + + case GIMPLE_ASM: + { + gasm *asm_stmt = as_a (*stmt); + for (unsigned i = 0; i < gimple_asm_ninputs (asm_stmt); i++) + { + t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i)); + modified |= modify_expression (t, true); + } + for (unsigned i = 0; i < gimple_asm_noutputs (asm_stmt); i++) + { + t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i)); + modified |= modify_expression (t, false); + } + } + break; + + default: + break; + } + return modified; +} + + +/* Traverse body of the current function and perform the requested adjustments + on its statements. Return true iff the CFG has been changed. */ + +bool +ipa_param_body_adjustments::modify_cfun_body () +{ + bool cfg_changed = false; + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + gimple_stmt_iterator gsi; + + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gphi *phi = as_a (gsi_stmt (gsi)); + tree new_lhs, old_lhs = gimple_phi_result (phi); + new_lhs = replace_removed_params_ssa_names (old_lhs, phi); + if (new_lhs) + { + gimple_phi_set_result (phi, new_lhs); + release_ssa_name (old_lhs); + } + } + + gsi = gsi_start_bb (bb); + while (!gsi_end_p (gsi)) + { + gimple *stmt = gsi_stmt (gsi); + gimple *stmt_copy = stmt; + gimple_seq extra_stmts = NULL; + bool modified = modify_gimple_stmt (&stmt, &extra_stmts); + if (stmt != stmt_copy) + { + gcc_checking_assert (modified); + gsi_replace (&gsi, stmt, false); + } + if (!gimple_seq_empty_p (extra_stmts)) + gsi_insert_seq_before (&gsi, extra_stmts, GSI_SAME_STMT); + + def_operand_p defp; + ssa_op_iter iter; + FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF) + { + tree old_def = DEF_FROM_PTR (defp); + if (tree new_def = replace_removed_params_ssa_names (old_def, + stmt)) + { + SET_DEF (defp, new_def); + release_ssa_name (old_def); + modified = true; + } + } + + if (modified) + { + update_stmt (stmt); + if (maybe_clean_eh_stmt (stmt) + && gimple_purge_dead_eh_edges (gimple_bb (stmt))) + cfg_changed = true; + } + gsi_next (&gsi); + } + } + + return cfg_changed; +} + +/* Call gimple_debug_bind_reset_value on all debug statements describing + gimple register parameters that are being removed or replaced. */ + +void +ipa_param_body_adjustments::reset_debug_stmts () +{ + int i, len; + gimple_stmt_iterator *gsip = NULL, gsi; + + if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun))) + { + gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); + gsip = &gsi; + } + len = m_reset_debug_decls.length (); + for (i = 0; i < len; i++) + { + imm_use_iterator ui; + gimple *stmt; + gdebug *def_temp; + tree name, vexpr, copy = NULL_TREE; + use_operand_p use_p; + tree decl = m_reset_debug_decls[i]; + + gcc_checking_assert (is_gimple_reg (decl)); + name = ssa_default_def (cfun, decl); + vexpr = NULL; + if (name) + FOR_EACH_IMM_USE_STMT (stmt, ui, name) + { + if (gimple_clobber_p (stmt)) + { + gimple_stmt_iterator cgsi = gsi_for_stmt (stmt); + unlink_stmt_vdef (stmt); + gsi_remove (&cgsi, true); + release_defs (stmt); + continue; + } + /* All other users must have been removed by function body + modification. */ + gcc_assert (is_gimple_debug (stmt)); + if (vexpr == NULL && gsip != NULL) + { + vexpr = make_node (DEBUG_EXPR_DECL); + def_temp = gimple_build_debug_source_bind (vexpr, decl, NULL); + DECL_ARTIFICIAL (vexpr) = 1; + TREE_TYPE (vexpr) = TREE_TYPE (name); + SET_DECL_MODE (vexpr, DECL_MODE (decl)); + gsi_insert_before (gsip, def_temp, GSI_SAME_STMT); + } + if (vexpr) + { + FOR_EACH_IMM_USE_ON_STMT (use_p, ui) + SET_USE (use_p, vexpr); + } + else + gimple_debug_bind_reset_value (stmt); + update_stmt (stmt); + } + /* Create a VAR_DECL for debug info purposes. */ + if (!DECL_IGNORED_P (decl)) { - fprintf (file, ", offset "); - print_dec (adj->offset, file); + copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl), + VAR_DECL, DECL_NAME (decl), + TREE_TYPE (decl)); + if (DECL_PT_UID_SET_P (decl)) + SET_DECL_PT_UID (copy, DECL_PT_UID (decl)); + TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); + TREE_READONLY (copy) = TREE_READONLY (decl); + TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); + DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (decl); + DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (decl); + DECL_IGNORED_P (copy) = DECL_IGNORED_P (decl); + DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl); + DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; + SET_DECL_RTL (copy, 0); + TREE_USED (copy) = 1; + DECL_CONTEXT (copy) = current_function_decl; + add_local_decl (cfun, copy); + DECL_CHAIN (copy) + = BLOCK_VARS (DECL_INITIAL (current_function_decl)); + BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy; + } + if (gsip != NULL && copy && target_for_debug_bind (decl)) + { + gcc_assert (TREE_CODE (decl) == PARM_DECL); + if (vexpr) + def_temp = gimple_build_debug_bind (copy, vexpr, NULL); + else + def_temp = gimple_build_debug_source_bind (copy, decl, + NULL); + gsi_insert_before (gsip, def_temp, GSI_SAME_STMT); } - if (adj->by_ref) - fprintf (file, ", by_ref"); - print_node_brief (file, ", type: ", adj->type, 0); - fprintf (file, "\n"); } - parms.release (); +} + +/* Perform all necessary body changes to change signature, body and debug info + of fun according to adjustments passed at construction. Return true if CFG + was changed in any way. The main entry point for modification of standalone + functions that is not part of IPA clone materialization. */ + +bool +ipa_param_body_adjustments::perform_cfun_body_modifications () +{ + bool cfg_changed; + modify_formal_parameters (); + cfg_changed = modify_cfun_body (); + reset_debug_stmts (); + + return cfg_changed; } diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h index 71fc4a2..34477da 100644 --- a/gcc/ipa-param-manipulation.h +++ b/gcc/ipa-param-manipulation.h @@ -16,101 +16,416 @@ 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 -. */ +. + + + +This file defines classes and other data structures that are used to manipulate +the prototype of a function, especially to create, remove or split its formal +parameters, but also to remove its return value, and also its call statements +correspondingly. + +The most basic one is a vector of structures ipa_adjusted_param. It is simply +a description how the new parameters should look like after the transformation +in what way they relate to the previous ones (if in any). Such relation to an +old parameter can be an outright copy or an IPA-SRA replacement. If an old +parameter is not listed or otherwise mentioned, it is removed as unused or at +least unnecessary. Note that this most basic structure does not work for +modifying calls of functions with variable number of arguments. + +Class ipa_param_adjustments is only a little more than a thin encapsulation of +a vector of ipa_param_adjustments. Along with this vector it contains an index +of the first potential vararg argument and a boolean flag whether the return +value should be removed or not. Moreover, the class contains method +modify_call which can transform a call statement so that it correctly calls a +modified function. These two data structures were designed to have a small +memory footprint because they are allocated for each clone of a call graph node +that has its prototype changed and live until the end of IPA clone +materialization and call redirection phase. + +On the other hand, class ipa_param_body_adjustments can afford to allocate more +data because its life span is much smaller, it is allocated and destroyed in +the course of materialization of each single clone that needs it or only when a +particular pass needs to change a function it is operating on. This class has +various methods required to change function declaration and the body of the +function according to instructions given either by class ipa_param_adjustments +or only a vector of ipa_adjusted_params. + +When these classes are used in the context of call graph clone materialization +and subsequent call statement redirection - which is the point at which we +modify arguments in call statements - they need to cooperate with each other in +order to handle what we refer to as transitive (IPA-SRA) splits. These are +situations when a formal parameter of one function is split into several +smaller ones and some of them are then passed on in a call to another function +because the formal parameter of this callee has also been split. + +Consider a simple example: + +struct S {int a, b, c;}; +struct Z {int x; S s;}; + +foo (S s) +{ + use (s.b); +} + +bar (Z z) +{ + use (z.s.a); + foo (z.s); +} + +baz () +{ + bar (*global); +} + +Both bar and foo would have their parameter split. Foo would receive one +replacement representing s.b. Function bar would see its parameter split into +one replacement representing z.s.a and another representing z.s.b which would +be passed on to foo. It would be a so called transitive split IPA-SRA +replacement, one which is passed in a call as an actual argument to another +IPA-SRA replacement in another function. + +Note that the call chain the example can be arbitrarily long and recursive and +that any function in it can be cloned by another IPA pass and any number of +adjacent functions in the call chain can be inlined into each other. Call +redirection takes place only after bodies of the function have been modified by +all of the above. + +Call redirection has to be able to find the right decl or SSA_NAME that +corresponds to the transitive split in the caller. The SSA names are assigned +right after clone materialization/ modification and cannot be "added" +afterwards. Moreover, if the caller has been inlined the SSA_NAMEs in question +no longer belong to PARM_DECLs but to VAR_DECLs, indistinguishable from any +others. + +Therefore, when clone materialization finds a call statement which it knows is +a part of a transitive split, it will modify it into: + + foo (DUMMY_Z_VAR.s, repl_for_a, repl_for_b, ); + +It will also store {DUMMY_S_VAR, 32} and {DUMMY_S_VAR, 64} representing offsets +of z.s.a and z.s.b (assuming a 32-bit int) into foo's cgraph node +clone->performed_splits vector (which is storing structures of type +ipa_param_performed_split also defined in this header file). + +Call redirection will identify that expression DUMMY_Z_VAR.s is based on a +variable stored in performed_splits vector and learn that the following +arguments, already in SSA form, represent offsets 32 and 64 in a split original +parameter. It subtracts offset of DUMMY_Z_VAR.s from 32 and 64 and arrives at +offsets 0 and 32 within callee's original parameter. At this point it also +knows from the call graph that only the bit with offset 32 is needed and so +changes the call statement into final: + +bar (repl_for_b, ); */ #ifndef IPA_PARAM_MANIPULATION_H #define IPA_PARAM_MANIPULATION_H +/* Indices into ipa_param_prefixes to identify a human-readable prefix for newly + synthesized parameters. Keep in sync with the array. */ +enum ipa_param_name_prefix_indices + { + IPA_PARAM_PREFIX_SYNTH, + IPA_PARAM_PREFIX_ISRA, + IPA_PARAM_PREFIX_SIMD, + IPA_PARAM_PREFIX_MASK, + IPA_PARAM_PREFIX_COUNT +}; + +/* We do not support manipulating functions with more than + 1< *adj_params); + +/* Structure to remember the split performed on a node so that edge redirection + (i.e. splitting arguments of call statements) know how split formal + parameters of the caller are represented. */ + +struct GTY(()) ipa_param_performed_split +{ + /* The dummy VAR_DECL that was created instead of the split parameter that + sits in the call in the meantime between clone materialization and call + redirection. All entries in a vector of performed splits that correspond + to the same dumy decl must be grouped together. */ + tree dummy_decl; + /* Offset into the original parameter. */ + unsigned unit_offset; +}; + +/* Class used to record planned modifications to parameters of a function and + also to perform necessary modifications at the caller side at the gimple + level. Used to describe all cgraph node clones that have their parameters + changed, therefore the class should only have a small memory footprint. */ + +class GTY(()) ipa_param_adjustments +{ +public: + /* Constructor from NEW_PARAMS showing how new parameters should look like + plus copying any pre-existing actual arguments starting from argument + with index ALWAYS_COPY_START (if non-negative, negative means do not copy + anything beyond what is described in NEW_PARAMS), and SKIP_RETURN, which + indicates that the function should return void after transformation. */ + + ipa_param_adjustments (vec *new_params, + int always_copy_start, bool skip_return) + : m_adj_params (new_params), m_always_copy_start (always_copy_start), + m_skip_return (skip_return) + {} + + /* Modify a call statement arguments (and possibly remove the return value) + as described in the data fields of this class. */ + gcall *modify_call (gcall *stmt, + vec *performed_splits, + tree callee_decl, bool update_references); + /* Return if the first parameter is left intact. */ + bool first_param_intact_p (); + /* Build a function type corresponding to the modified call. */ + tree build_new_function_type (tree old_type, bool type_is_original_p); + /* Build a declaration corresponding to the target of the modified call. */ + tree adjust_decl (tree orig_decl); + /* Fill a vector marking which parameters are intact by the described + modifications. */ + void get_surviving_params (vec *surviving_params); + /* Fill a vector with new indices of surviving original parameters. */ + void get_updated_indices (vec *new_indices); + + void dump (FILE *f); + void debug (); + + /* How the known part of arguments should look like. */ + vec *m_adj_params; + + /* If non-negative, copy any arguments starting at this offset without any + modifications so that functions with variable number of arguments can be + modified. This number should be equal to the number of original forma + parameters. */ + int m_always_copy_start; + /* If true, make the function not return any value. */ + bool m_skip_return; + +private: + ipa_param_adjustments () {} + + void init (vec *cur_params); + int get_max_base_index (); + bool method2func_p (tree orig_type); +}; + +/* Structure used to map expressions accessing split or replaced parameters to + new PARM_DECLs. */ + +struct ipa_param_body_replacement +{ + /* The old decl of the original parameter. */ + tree base; + /* The new decl it should be replaced with. */ + tree repl; + /* When modifying clones during IPA clone materialization, this is a dummy + decl used to mark calls in which we need to apply transitive splitting, + these dummy delcls are inserted as arguments to such calls and then + followed by all the replacements with offset info stored in + ipa_param_performed_split. + + Users of ipa_param_body_adjustments that modify standalone functions + outside of IPA clone materialization can use this field for their internal + purposes. */ + tree dummy; + /* The offset within BASE that REPL represents. */ + unsigned unit_offset; +}; + +struct ipa_replace_map; + +/* Class used when actually performing adjustments to formal parameters of a + function to map accesses that need to be replaced to replacements. The + class attempts to work in two very different sets of circumstances: as a + part of tree-inine.c's tree_function_versioning machinery to clone functions + (when M_ID is not NULL) and in s standalone fashion, modifying an existing + function in place (when M_ID is NULL). While a lot of stuff handled in a + unified way in both modes, there are many aspects of the processs that + requires distinct paths. */ + +class ipa_param_body_adjustments +{ +public: + /* Constructor to use from within tree-inline. */ + ipa_param_body_adjustments (ipa_param_adjustments *adjustments, + tree fndecl, tree old_fndecl, + struct copy_body_data *id, tree *vars, + vec *tree_map); + /* Constructor to use for modifying a function outside of tree-inline from an + instance of ipa_param_adjustments. */ + ipa_param_body_adjustments (ipa_param_adjustments *adjustments, + tree fndecl); + /* Constructor to use for modifying a function outside of tree-inline from a + simple vector of desired parameter modification. */ + ipa_param_body_adjustments (vec *adj_params, + tree fndecl); + + /* The do-it-all function for modifying a function outside of + tree-inline. */ + bool perform_cfun_body_modifications (); + + /* Change the PARM_DECLs. */ + void modify_formal_parameters (); + /* Register a replacement decl for the transformation done in APM. */ + void register_replacement (ipa_adjusted_param *apm, tree replacement, + tree dummy = NULL_TREE); + /* Lookup a replacement for a given offset within a given parameter. */ + tree lookup_replacement (tree base, unsigned unit_offset); + /* Lookup a replacement for an expression, if there is one. */ + ipa_param_body_replacement *get_expr_replacement (tree expr, + bool ignore_default_def); + /* Lookup the new base for surviving names previously belonging to a + parameter. */ + tree get_replacement_ssa_base (tree old_decl); + /* Modify a statement. */ + bool modify_gimple_stmt (gimple **stmt, gimple_seq *extra_stmts); + /* Return the new chain of parameters. */ + tree get_new_param_chain (); + + /* Pointers to data structures defining how the function should be + modified. */ + vec *m_adj_params; + ipa_param_adjustments *m_adjustments; + + /* Vector of old parameter declarations that must have their debug bind + statements re-mapped and debug decls created. */ + + auto_vec m_reset_debug_decls; + + /* Set to true if there are any IPA_PARAM_OP_SPLIT adjustments among stored + adjustments. */ + bool m_split_modifications_p; +private: + void common_initialization (tree old_fndecl, tree *vars, + vec *tree_map); + unsigned get_base_index (ipa_adjusted_param *apm); + ipa_param_body_replacement *lookup_replacement_1 (tree base, + unsigned unit_offset); + tree replace_removed_params_ssa_names (tree old_name, gimple *stmt); + bool modify_expression (tree *expr_p, bool convert); + bool modify_assignment (gimple *stmt, gimple_seq *extra_stmts); + bool modify_call_stmt (gcall **stmt_p); + bool modify_cfun_body (); + void reset_debug_stmts (); + + /* Declaration of the function that is being transformed. */ + + tree m_fndecl; + + /* If non-NULL, the tree-inline master data structure guiding materialization + of the current clone. */ + struct copy_body_data *m_id; + + /* Vector of old parameter declarations (before changing them). */ + + auto_vec m_oparms; + + /* Vector of parameter declarations the function will have after + transformation. */ + + auto_vec m_new_decls; + + /* If the function type has non-NULL TYPE_ARG_TYPES, this is the vector of + these types after transformation, otherwise an empty one. */ + + auto_vec m_new_types; + + /* Vector of structures telling how to replace old parameters in in the + function body. TODO: Even though there usually be only few, but should we + use a hash? */ + + auto_vec m_replacements; + + /* Vector for remapping SSA_BASES from old parameter declarations that are + being removed as a part of the transformation. Before a new VAR_DECL is + created, it holds the old PARM_DECL, once the variable is built it is + stored here. */ + + auto_vec m_removed_decls; + + /* Hash to quickly lookup the item in m_removed_decls given the old decl. */ + + hash_map m_removed_map; + + /* True iff the transformed function is a class method that is about to loose + its this pointer and must be converted to a normal function. */ + + bool m_method2func; }; -typedef vec ipa_parm_adjustment_vec; - -vec ipa_get_vector_of_formal_parms (tree fndecl); -vec ipa_get_vector_of_formal_parm_types (tree fntype); -void ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec); -void ipa_modify_call_arguments (struct cgraph_edge *, gcall *, - ipa_parm_adjustment_vec); -ipa_parm_adjustment_vec ipa_combine_adjustments (ipa_parm_adjustment_vec, - ipa_parm_adjustment_vec); -void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree); - -bool ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec); -ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *, - ipa_parm_adjustment_vec, - bool); +void push_function_arg_decls (vec *args, tree fndecl); +void push_function_arg_types (vec *types, tree fntype); #endif /* IPA_PARAM_MANIPULATION_H */ diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index a23aa25..2f2b070 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -4851,31 +4851,24 @@ adjust_agg_replacement_values (struct cgraph_node *node, struct ipa_agg_replacement_value *aggval) { struct ipa_agg_replacement_value *v; - int i, c = 0, d = 0, *adj; - if (!node->clone.combined_args_to_skip) + if (!node->clone.param_adjustments) return; + auto_vec new_indices; + node->clone.param_adjustments->get_updated_indices (&new_indices); for (v = aggval; v; v = v->next) { - gcc_assert (v->index >= 0); - if (c < v->index) - c = v->index; - } - c++; - - adj = XALLOCAVEC (int, c); - for (i = 0; i < c; i++) - if (bitmap_bit_p (node->clone.combined_args_to_skip, i)) - { - adj[i] = -1; - d++; - } - else - adj[i] = i - d; + gcc_checking_assert (v->index >= 0); - for (v = aggval; v; v = v->next) - v->index = adj[v->index]; + if ((unsigned) v->index < new_indices.length ()) + v->index = new_indices[v->index]; + else + /* This can happen if we know about a constant passed by reference by + an argument which is never actually used for anything, let alone + loading that constant. */ + v->index = -1; + } } /* Dominator walker driving the ipcp modification phase. */ @@ -5001,24 +4994,41 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb) static void ipcp_update_bits (struct cgraph_node *node) { - tree parm = DECL_ARGUMENTS (node->decl); - tree next_parm = parm; ipcp_transformation *ts = ipcp_get_transformation_summary (node); if (!ts || vec_safe_length (ts->bits) == 0) return; - vec &bits = *ts->bits; unsigned count = bits.length (); + if (!count) + return; - for (unsigned i = 0; i < count; ++i, parm = next_parm) + auto_vec new_indices; + bool need_remapping = false; + if (node->clone.param_adjustments) { - if (node->clone.combined_args_to_skip - && bitmap_bit_p (node->clone.combined_args_to_skip, i)) - continue; + node->clone.param_adjustments->get_updated_indices (&new_indices); + need_remapping = true; + } + auto_vec parm_decls; + push_function_arg_decls (&parm_decls, node->decl); + for (unsigned i = 0; i < count; ++i) + { + tree parm; + if (need_remapping) + { + if (i >= new_indices.length ()) + continue; + int idx = new_indices[i]; + if (idx < 0) + continue; + parm = parm_decls[idx]; + } + else + parm = parm_decls[i]; gcc_checking_assert (parm); - next_parm = DECL_CHAIN (parm); + if (!bits[i] || !(INTEGRAL_TYPE_P (TREE_TYPE (parm)) @@ -5093,22 +5103,42 @@ ipcp_update_bits (struct cgraph_node *node) static void ipcp_update_vr (struct cgraph_node *node) { - tree fndecl = node->decl; - tree parm = DECL_ARGUMENTS (fndecl); - tree next_parm = parm; ipcp_transformation *ts = ipcp_get_transformation_summary (node); if (!ts || vec_safe_length (ts->m_vr) == 0) return; const vec &vr = *ts->m_vr; unsigned count = vr.length (); + if (!count) + return; - for (unsigned i = 0; i < count; ++i, parm = next_parm) + auto_vec new_indices; + bool need_remapping = false; + if (node->clone.param_adjustments) { - if (node->clone.combined_args_to_skip - && bitmap_bit_p (node->clone.combined_args_to_skip, i)) - continue; + node->clone.param_adjustments->get_updated_indices (&new_indices); + need_remapping = true; + } + auto_vec parm_decls; + push_function_arg_decls (&parm_decls, node->decl); + + for (unsigned i = 0; i < count; ++i) + { + tree parm; + int remapped_idx; + if (need_remapping) + { + if (i >= new_indices.length ()) + continue; + remapped_idx = new_indices[i]; + if (remapped_idx < 0) + continue; + } + else + remapped_idx = i; + + parm = parm_decls[remapped_idx]; + gcc_checking_assert (parm); - next_parm = DECL_CHAIN (parm); tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm); if (!ddef || !is_gimple_reg (parm)) @@ -5123,7 +5153,8 @@ ipcp_update_vr (struct cgraph_node *node) { if (dump_file) { - fprintf (dump_file, "Setting value range of param %u ", i); + fprintf (dump_file, "Setting value range of param %u " + "(now %i) ", i, remapped_idx); fprintf (dump_file, "%s[", (vr[i].type == VR_ANTI_RANGE) ? "~" : ""); print_decs (vr[i].min, dump_file); diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index cecfe05..375a15c 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -1326,13 +1326,38 @@ split_function (basic_block return_bb, class split_point *split_point, } } + ipa_param_adjustments *adjustments; + bool skip_return = (!split_part_return_p + || !split_point->split_part_set_retval); + /* TODO: Perhaps get rid of args_to_skip entirely, after we make sure the + debug info generation and discrepancy avoiding works well too. */ + if ((args_to_skip && !bitmap_empty_p (args_to_skip)) + || skip_return) + { + vec *new_params = NULL; + unsigned j; + for (parm = DECL_ARGUMENTS (current_function_decl), j = 0; + parm; parm = DECL_CHAIN (parm), j++) + if (!args_to_skip || !bitmap_bit_p (args_to_skip, j)) + { + ipa_adjusted_param adj; + memset (&adj, 0, sizeof (adj)); + adj.op = IPA_PARAM_OP_COPY; + adj.base_index = j; + adj.prev_clone_index = j; + vec_safe_push (new_params, adj); + } + adjustments = new ipa_param_adjustments (new_params, j, skip_return); + } + else + adjustments = NULL; + /* Now create the actual clone. */ cgraph_edge::rebuild_edges (); node = cur_node->create_version_clone_with_body - (vNULL, NULL, args_to_skip, - !split_part_return_p || !split_point->split_part_set_retval, + (vNULL, NULL, adjustments, split_point->split_bbs, split_point->entry_bb, "part"); - + delete adjustments; node->split_part = true; if (cur_node->same_comdat_group) @@ -1469,6 +1494,7 @@ split_function (basic_block return_bb, class split_point *split_point, = gimple_build_debug_bind (ddecl, unshare_expr (arg), call); gsi_insert_after (&gsi, def_temp, GSI_NEW_STMT); } + BITMAP_FREE (args_to_skip); } /* We avoid address being taken on any variable used by split part, diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c new file mode 100644 index 0000000..a32defb --- /dev/null +++ b/gcc/ipa-sra.c @@ -0,0 +1,4049 @@ +/* Interprocedural scalar replacement of aggregates + Copyright (C) 2008-2019 Free Software Foundation, Inc. + + Contributed by Martin Jambor + +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 +. */ + +/* IPA-SRA is an interprocedural pass that removes unused function return + values (turning functions returning a value which is never used into void + functions), removes unused function parameters. It can also replace an + aggregate parameter by a set of other parameters representing part of the + original, turning those passed by reference into new ones which pass the + value directly. + + The pass is a true IPA one, which means that it works in three stages in + order to be able to take advantage of LTO. First, summaries about functions + and each calls are generated. Function summaries (often called call graph + node summaries) contain mainly information about which parameters are + potential transformation candidates and which bits of candidates are + accessed. We differentiate between accesses done as a part of a call + statement (which might be not necessary if the callee is also transformed) + and others (which are mandatory). Call summaries (often called call graph + edge summaries) contain information about which function formal parameters + feed into which actual call arguments so that if two parameters are only + used in a sum which is then passed to another function which then however + does not use this parameter, all three parameters of the two functions can + be eliminated. Edge summaries also have flags whether the return value is + used or if it is only returned in the caller too. In LTO mode these + summaries are then streamed to the object file in the compilation phase and + streamed back in in the WPA analysis stage. + + The interprocedural analysis phase traverses the graph in topological order + in two sweeps, one in each direction. First, from callees to callers for + parameter removal and splitting. Each strongly-connected component is + processed iteratively until the situation in it stabilizes. The pass from + callers to callees is then carried out to remove unused return values in a + very similar fashion. + + Because parameter manipulation has big implications for call redirection + which is done only after all call graph nodes materialize, the + transformation phase is not part of this patch but is carried out by the + clone materialization and edge redirection itself, see comments in + ipa-param-manipulation.h for more details. */ + + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "predict.h" +#include "tree-pass.h" +#include "ssa.h" +#include "cgraph.h" +#include "gimple-pretty-print.h" +#include "alias.h" +#include "tree-eh.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "tree-dfa.h" +#include "tree-sra.h" +#include "symbol-summary.h" +#include "params.h" +#include "dbgcnt.h" +#include "tree-inline.h" +#include "ipa-utils.h" +#include "builtins.h" +#include "cfganal.h" +#include "tree-streamer.h" + + +/* Bits used to track size of an aggregate in bytes interprocedurally. */ +#define ISRA_ARG_SIZE_LIMIT_BITS 16 +#define ISRA_ARG_SIZE_LIMIT (1 << ISRA_ARG_SIZE_LIMIT_BITS) +/* How many parameters can feed into a call actual argument and still be + tracked. */ +#define IPA_SRA_MAX_PARAM_FLOW_LEN 7 + +/* Structure describing accesses to a specific portion of an aggregate + parameter, as given by the offset and size. Any smaller accesses that occur + within a function that fall within another access form a tree. The pass + cannot analyze parameters with only partially overlapping accesses. */ + +struct GTY(()) param_access +{ + /* Type that a potential replacement should have. This field only has + meaning in the summary building and transformation phases, when it is + reconstructoed from the body. Must not be touched in IPA analysys + stage. */ + tree type; + + /* Alias reference type to be used in MEM_REFs when adjusting caller + arguments. */ + tree alias_ptr_type; + + /* Values returned by get_ref_base_and_extent but converted to bytes and + stored as unsigned ints. */ + unsigned unit_offset; + unsigned unit_size : ISRA_ARG_SIZE_LIMIT_BITS; + + /* Set once we are sure that the access will really end up in a potentially + transformed function - initially not set for portions of formal parameters + that are only used as actual function arguments passed to callees. */ + unsigned certain : 1; + /* Set if the access has a reversed scalar storage order. */ + unsigned reverse : 1; +}; + +/* This structure has the same purpose as the one above and additoonally it + contains some fields that are only necessary in the summary generation + phase. */ + +struct gensum_param_access +{ + /* Values returned by get_ref_base_and_extent. */ + HOST_WIDE_INT offset; + HOST_WIDE_INT size; + + /* if this access has any children (in terms of the definition above), this + points to the first one. */ + struct gensum_param_access *first_child; + /* In intraprocedural SRA, pointer to the next sibling in the access tree as + described above. */ + struct gensum_param_access *next_sibling; + + /* Type that a potential replacement should have. This field only has + meaning in the summary building and transformation phases, when it is + reconstructoed from the body. Must not be touched in IPA analysys + stage. */ + tree type; + /* Alias refrerence type to be used in MEM_REFs when adjusting caller + arguments. */ + tree alias_ptr_type; + + /* Have there been writes to or reads from this exact location except for as + arguments to a function call that can be tracked. */ + bool nonarg; + + /* Set if the access has a reversed scalar storage order. */ + bool reverse; +}; + +/* Summary describing a parameter in the IPA stages. */ + +struct GTY(()) isra_param_desc +{ + /* List of access representatives to the parameters, sorted according to + their offset. */ + vec *accesses; + + /* Unit size limit of total size of all replacements. */ + unsigned param_size_limit : ISRA_ARG_SIZE_LIMIT_BITS; + /* Sum of unit sizes of all certain replacements. */ + unsigned size_reached : ISRA_ARG_SIZE_LIMIT_BITS; + + /* A parameter that is used only in call arguments and can be removed if all + concerned actual arguments are removed. */ + unsigned locally_unused : 1; + /* An aggregate that is a candidate for breaking up or complete removal. */ + unsigned split_candidate : 1; + /* Is this a parameter passing stuff by reference? */ + unsigned by_ref : 1; +}; + +/* Structure used when generating summaries that describes a parameter. */ + +struct gensum_param_desc +{ + /* Roots of param_accesses. */ + gensum_param_access *accesses; + /* Number of accesses in the access tree rooted in field accesses. */ + unsigned access_count; + + /* If the below is non-zero, this is the nuber of uses as actual arguents. */ + int call_uses; + /* Number of times this parameter has been directly passed to. */ + unsigned ptr_pt_count; + + /* Size limit of total size of all replacements. */ + unsigned param_size_limit; + /* Sum of sizes of nonarg accesses. */ + unsigned nonarg_acc_size; + + /* A parameter that is used only in call arguments and can be removed if all + concerned actual arguments are removed. */ + bool locally_unused; + /* An aggregate that is a candidate for breaking up or a pointer passing data + by reference that is a candidate for being converted to a set of + parameters passing thosa data by value. */ + bool split_candidate; + /* Is this a parameter passing stuff by reference? */ + bool by_ref; + + /* The number of this parameter as they are ordered in function decl. */ + int param_number; + /* For parameters passing data by reference, this is parameter index to + compute indices to bb_dereferences. */ + int deref_index; +}; + +/* Properly deallocate accesses of DESC. TODO: Since this data strucutre is + not in GC memory, this is not necessary and we can consider removing the + function. */ + +static void +free_param_decl_accesses (isra_param_desc *desc) +{ + unsigned len = vec_safe_length (desc->accesses); + for (unsigned i = 0; i < len; ++i) + ggc_free ((*desc->accesses)[i]); + vec_free (desc->accesses); +} + +/* Class used to convey information about functions from the + intra-procedurwl analysis stage to inter-procedural one. */ + +class GTY((for_user)) isra_func_summary +{ +public: + /* initialize the object. */ + + isra_func_summary () + : m_parameters (NULL), m_candidate (false), m_returns_value (false), + m_return_ignored (false), m_queued (false) + {} + + /* Destroy m_parameters. */ + + ~isra_func_summary (); + + /* Mark the function as not a candidate for any IPA-SRA transofrmation. + Return true if it was a candidate until now. */ + + bool zap (); + + /* Vector of parameter descriptors corresponding to the function being + analyzed. */ + vec *m_parameters; + + /* Whether the node is even a candidate for any IPA-SRA transformation at + all. */ + unsigned m_candidate : 1; + + /* Whether the original function returns any value. */ + unsigned m_returns_value : 1; + + /* Set to true if all call statements do not actually use the returned + value. */ + + unsigned m_return_ignored : 1; + + /* Whether the node is already queued in IPA SRA stack during processing of + call graphs SCCs. */ + + unsigned m_queued : 1; +}; + +/* Claen up and deallocate isra_func_summary points to. TODO: Since this data + strucutre is not in GC memory, this is not necessary and we can consider + removing the destructor. */ + +isra_func_summary::~isra_func_summary () +{ + unsigned len = vec_safe_length (m_parameters); + for (unsigned i = 0; i < len; ++i) + free_param_decl_accesses (&(*m_parameters)[i]); + vec_free (m_parameters); +} + + +/* Mark the function as not a candidate for any IPA-SRA transofrmation. Return + true if it was a candidate until now. */ + +bool +isra_func_summary::zap () +{ + bool ret = m_candidate; + m_candidate = false; + + unsigned len = vec_safe_length (m_parameters); + for (unsigned i = 0; i < len; ++i) + free_param_decl_accesses (&(*m_parameters)[i]); + vec_free (m_parameters); + + return ret; +} + +/* Structure to describe which formal parameters feed into a particular actual + arguments. */ + +struct isra_param_flow +{ + /* Number of elements in array inputs that contain valid data. */ + char length; + /* Indices of formal parameters that feed into the described actual argument. + If aggregate_pass_through or pointer_pass_through below are true, it must + contain exactly one element which is passed through from a formal + parameter if the given number. Otherwise, the array contains indices of + collee's formal parameters which are used to calculate value of this + actual argument. */ + unsigned char inputs[IPA_SRA_MAX_PARAM_FLOW_LEN]; + + /* Offset within the formal parameter. */ + unsigned unit_offset; + /* Size of the portion of the formal parameter that is being passed. */ + unsigned unit_size : ISRA_ARG_SIZE_LIMIT_BITS; + + /* True when the value of this actual copy is a portion of a formal + parameter. */ + unsigned aggregate_pass_through : 1; + /* True when the value of this actual copy is a verbatim pass through of an + obtained pointer. */ + unsigned pointer_pass_through : 1; + /* True when it is safe to copy access candidates here from the callee, which + would mean introducing dereferences into callers of the caller. */ + unsigned safe_to_import_accesses : 1; +}; + +/* Strucutre used to convey information about calls from the intra-procedurwl + analysis stage to inter-procedural one. */ + +class isra_call_summary +{ +public: + isra_call_summary () + : m_arg_flow (), m_return_ignored (false), m_return_returned (false), + m_bit_aligned_arg (false) + {} + + void init_inputs (unsigned arg_count); + void dump (FILE *f); + + /* Information about what formal parameters of the caller are used to compute + indivisual actual arguments of this call. */ + auto_vec m_arg_flow; + + /* Set to true if the call statement does not have a LHS. */ + unsigned m_return_ignored : 1; + + /* Set to true if the LHS of call statement is only used to construct the + return value of the caller. */ + unsigned m_return_returned : 1; + + /* Set when any of the call arguments are not byte-aligned. */ + unsigned m_bit_aligned_arg : 1; +}; + +/* Class to manage function summaries. */ + +class GTY((user)) ipa_sra_function_summaries + : public function_summary +{ +public: + ipa_sra_function_summaries (symbol_table *table, bool ggc): + function_summary (table, ggc) { } + + virtual void duplicate (cgraph_node *, cgraph_node *, + isra_func_summary *old_sum, + isra_func_summary *new_sum); +}; + +/* Hook that is called by summary when a node is duplicated. */ + +void +ipa_sra_function_summaries::duplicate (cgraph_node *, cgraph_node *, + isra_func_summary *old_sum, + isra_func_summary *new_sum) +{ + /* TODO: Somehow stop copying when ISRA is doing the cloning, it is + useless. */ + new_sum->m_candidate = old_sum->m_candidate; + new_sum->m_returns_value = old_sum->m_returns_value; + new_sum->m_return_ignored = old_sum->m_return_ignored; + gcc_assert (!old_sum->m_queued); + new_sum->m_queued = false; + + unsigned param_count = vec_safe_length (old_sum->m_parameters); + if (!param_count) + return; + vec_safe_reserve_exact (new_sum->m_parameters, param_count); + new_sum->m_parameters->quick_grow_cleared (param_count); + for (unsigned i = 0; i < param_count; i++) + { + isra_param_desc *s = &(*old_sum->m_parameters)[i]; + isra_param_desc *d = &(*new_sum->m_parameters)[i]; + + d->param_size_limit = s->param_size_limit; + d->size_reached = s->size_reached; + d->locally_unused = s->locally_unused; + d->split_candidate = s->split_candidate; + d->by_ref = s->by_ref; + + unsigned acc_count = vec_safe_length (s->accesses); + vec_safe_reserve_exact (d->accesses, acc_count); + for (unsigned j = 0; j < acc_count; j++) + { + param_access *from = (*s->accesses)[j]; + param_access *to = ggc_cleared_alloc (); + to->type = from->type; + to->alias_ptr_type = from->alias_ptr_type; + to->unit_offset = from->unit_offset; + to->unit_size = from->unit_size; + to->certain = from->certain; + d->accesses->quick_push (to); + } + } +} + +/* Pointer to the pass function summary holder. */ + +static GTY(()) ipa_sra_function_summaries *func_sums; + +/* Class to manage call summaries. */ + +class ipa_sra_call_summaries: public call_summary +{ +public: + ipa_sra_call_summaries (symbol_table *table): + call_summary (table) { } + + /* Duplicate info when an edge is cloned. */ + virtual void duplicate (cgraph_edge *, cgraph_edge *, + isra_call_summary *old_sum, + isra_call_summary *new_sum); +}; + +static ipa_sra_call_summaries *call_sums; + + +/* Initialize m_arg_flow of a particular instance of isra_call_summary. + ARG_COUNT is the number of actual arguments passed. */ + +void +isra_call_summary::init_inputs (unsigned arg_count) +{ + if (arg_count == 0) + { + gcc_checking_assert (m_arg_flow.length () == 0); + return; + } + if (m_arg_flow.length () == 0) + { + m_arg_flow.reserve_exact (arg_count); + m_arg_flow.quick_grow_cleared (arg_count); + } + else + gcc_checking_assert (arg_count == m_arg_flow.length ()); +} + +/* Dump all information in call summary to F. */ + +void +isra_call_summary::dump (FILE *f) +{ + if (m_return_ignored) + fprintf (f, " return value ignored\n"); + if (m_return_returned) + fprintf (f, " return value used only to compute caller return value\n"); + for (unsigned i = 0; i < m_arg_flow.length (); i++) + { + fprintf (f, " Parameter %u:\n", i); + isra_param_flow *ipf = &m_arg_flow[i]; + + if (ipf->length) + { + bool first = true; + fprintf (f, " Scalar param sources: "); + for (int j = 0; j < ipf->length; j++) + { + if (!first) + fprintf (f, ", "); + else + first = false; + fprintf (f, "%i", (int) ipf->inputs[j]); + } + fprintf (f, "\n"); + } + if (ipf->aggregate_pass_through) + fprintf (f, " Aggregate pass through from the param given above, " + "unit offset: %u , unit size: %u\n", + ipf->unit_offset, ipf->unit_size); + if (ipf->pointer_pass_through) + fprintf (f, " Pointer pass through from the param given above, " + "safe_to_import_accesses: %u\n", ipf->safe_to_import_accesses); + } +} + +/* Duplicate edge summare when an edge is cloned. */ + +void +ipa_sra_call_summaries::duplicate (cgraph_edge *, cgraph_edge *, + isra_call_summary *old_sum, + isra_call_summary *new_sum) +{ + unsigned arg_count = old_sum->m_arg_flow.length (); + new_sum->init_inputs (arg_count); + for (unsigned i = 0; i < arg_count; i++) + new_sum->m_arg_flow[i] = old_sum->m_arg_flow[i]; + + new_sum->m_return_ignored = old_sum->m_return_ignored; + new_sum->m_return_returned = old_sum->m_return_returned; + new_sum->m_bit_aligned_arg = old_sum->m_bit_aligned_arg; +} + + +/* With all GTY stuff done, we can move to anonymous namespace. */ +namespace { +/* Quick mapping from a decl to its param descriptor. */ + +hash_map *decl2desc; + +/* Countdown of allowe Alias analysis steps during summary building. */ + +int aa_walking_limit; + +/* This is a table in which for each basic block and parameter there is a + distance (offset + size) in that parameter which is dereferenced and + accessed in that BB. */ +HOST_WIDE_INT *bb_dereferences = NULL; +/* How many by-reference parameters there are in the current function. */ +int by_ref_count; + +/* Bitmap of BBs that can cause the function to "stop" progressing by + returning, throwing externally, looping infinitely or calling a function + which might abort etc.. */ +bitmap final_bbs; + +/* Obstack to allocate various small structures required only when generating + summary for a function. */ +struct obstack gensum_obstack; + +/* Return false the function is apparently unsuitable for IPA-SRA based on it's + attributes, return true otherwise. NODE is the cgraph node of the current + function. */ + +static bool +ipa_sra_preliminary_function_checks (cgraph_node *node) +{ + if (!node->local.can_change_signature) + { + if (dump_file) + fprintf (dump_file, "Function cannot change signature.\n"); + return false; + } + + if (!tree_versionable_function_p (node->decl)) + { + if (dump_file) + fprintf (dump_file, "Function is not versionable.\n"); + return false; + } + + if (!opt_for_fn (node->decl, optimize) + || !opt_for_fn (node->decl, flag_ipa_sra)) + { + if (dump_file) + fprintf (dump_file, "Not optimizing or IPA-SRA turned off for this " + "function.\n"); + return false; + } + + if (DECL_VIRTUAL_P (node->decl)) + { + if (dump_file) + fprintf (dump_file, "Function is a virtual method.\n"); + return false; + } + + struct function *fun = DECL_STRUCT_FUNCTION (node->decl); + if (fun->stdarg) + { + if (dump_file) + fprintf (dump_file, "Function uses stdarg. \n"); + return false; + } + + if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) + { + if (dump_file) + fprintf (dump_file, "Function type has attributes. \n"); + return false; + } + + if (DECL_DISREGARD_INLINE_LIMITS (node->decl)) + { + if (dump_file) + fprintf (dump_file, "Always inline function will be inlined " + "anyway. \n"); + return false; + } + + return true; +} + +/* Print access tree starting at ACCESS to F. */ + +static void +dump_gensum_access (FILE *f, gensum_param_access *access, unsigned indent) +{ + fprintf (f, " "); + for (unsigned i = 0; i < indent; i++) + fprintf (f, " "); + fprintf (f, " * Access to offset: " HOST_WIDE_INT_PRINT_DEC, + access->offset); + fprintf (f, ", size: " HOST_WIDE_INT_PRINT_DEC, access->size); + fprintf (f, ", type: "); + print_generic_expr (f, access->type); + fprintf (f, ", alias_ptr_type: "); + print_generic_expr (f, access->alias_ptr_type); + fprintf (f, ", nonarg: %u, reverse: %u\n", access->nonarg, access->reverse); + for (gensum_param_access *ch = access->first_child; + ch; + ch = ch->next_sibling) + dump_gensum_access (f, ch, indent + 2); +} + + +/* Print access tree starting at ACCESS to F. */ + +static void +dump_isra_access (FILE *f, param_access *access) +{ + fprintf (f, " * Access to unit offset: %u", access->unit_offset); + fprintf (f, ", unit size: %u", access->unit_size); + fprintf (f, ", type: "); + print_generic_expr (f, access->type); + fprintf (f, ", alias_ptr_type: "); + print_generic_expr (f, access->alias_ptr_type); + if (access->certain) + fprintf (f, ", certain"); + else + fprintf (f, ", not-certain"); + if (access->reverse) + fprintf (f, ", reverse"); + fprintf (f, "\n"); +} + +/* Dump access tree starting at ACCESS to stderr. */ + +DEBUG_FUNCTION void +debug_isra_access (param_access *access) +{ + dump_isra_access (stderr, access); +} + +/* Dump DESC to F. */ + +static void +dump_gensum_param_descriptor (FILE *f, gensum_param_desc *desc) +{ + if (desc->locally_unused) + fprintf (f, " unused with %i call_uses\n", desc->call_uses); + if (!desc->split_candidate) + { + fprintf (f, " not a candidate\n"); + return; + } + if (desc->by_ref) + fprintf (f, " by_ref with %u pass throughs\n", desc->ptr_pt_count); + + for (gensum_param_access *acc = desc->accesses; acc; acc = acc->next_sibling) + dump_gensum_access (f, acc, 2); +} + +/* Dump all parameter descriptors in IFS, assuming it describes FNDECl, to + F. */ + +static void +dump_gensum_param_descriptors (FILE *f, tree fndecl, + vec *param_descriptions) +{ + tree parm = DECL_ARGUMENTS (fndecl); + for (unsigned i = 0; + i < param_descriptions->length (); + ++i, parm = DECL_CHAIN (parm)) + { + fprintf (f, " Descriptor for parameter %i ", i); + print_generic_expr (f, parm, TDF_UID); + fprintf (f, "\n"); + dump_gensum_param_descriptor (f, &(*param_descriptions)[i]); + } +} + + +/* Dump DESC to F. */ + +static void +dump_isra_param_descriptor (FILE *f, isra_param_desc *desc) +{ + if (desc->locally_unused) + { + fprintf (f, " (locally) unused\n"); + } + if (!desc->split_candidate) + { + fprintf (f, " not a candidate for splitting\n"); + return; + } + fprintf (f, " param_size_limit: %u, size_reached: %u%s\n", + desc->param_size_limit, desc->size_reached, + desc->by_ref ? ", by_ref" : ""); + + for (unsigned i = 0; i < vec_safe_length (desc->accesses); ++i) + { + param_access *access = (*desc->accesses)[i]; + dump_isra_access (f, access); + } +} + +/* Dump all parameter descriptors in IFS, assuming it describes FNDECl, to + F. */ + +static void +dump_isra_param_descriptors (FILE *f, tree fndecl, + isra_func_summary *ifs) +{ + tree parm = DECL_ARGUMENTS (fndecl); + if (!ifs->m_parameters) + { + fprintf (f, " parameter descriptors not available\n"); + return; + } + + for (unsigned i = 0; + i < ifs->m_parameters->length (); + ++i, parm = DECL_CHAIN (parm)) + { + fprintf (f, " Descriptor for parameter %i ", i); + print_generic_expr (f, parm, TDF_UID); + fprintf (f, "\n"); + dump_isra_param_descriptor (f, &(*ifs->m_parameters)[i]); + } +} + +/* Add SRC to inputs of PARAM_FLOW, unless it would exceed storage. If the + function fails return false, otherwise return true. SRC must fit into an + unsigned char. Used for purposes of transitive unused parameter + removal. */ + +static bool +add_src_to_param_flow (isra_param_flow *param_flow, int src) +{ + gcc_checking_assert (src >= 0 && src <= UCHAR_MAX); + if (param_flow->length == IPA_SRA_MAX_PARAM_FLOW_LEN) + return false; + + param_flow->inputs[(int) param_flow->length] = src; + param_flow->length++; + return true; +} + +/* Add a SRC to the inputs of PARAM_FLOW unless it is already there and assert + it is the only input. Used for purposes of transitive parameter + splitting. */ + +static void +set_single_param_flow_source (isra_param_flow *param_flow, int src) +{ + gcc_checking_assert (src >= 0 && src <= UCHAR_MAX); + if (param_flow->length == 0) + { + param_flow->inputs[0] = src; + param_flow->length = 1; + } + else if (param_flow->length == 1) + gcc_assert (param_flow->inputs[0] == src); + else + gcc_unreachable (); +} + +/* Assert that there is only a single value in PARAM_FLOW's inputs and return + it. */ + +static unsigned +get_single_param_flow_source (const isra_param_flow *param_flow) +{ + gcc_assert (param_flow->length == 1); + return param_flow->inputs[0]; +} + +/* Inspect all uses of NAME and simple arithmetic calculations involving NAME + in NODE and return a negative number if any of them is used for something + else than either an actual call argument, simple arithmetic operation or + debug statement. If there are no such uses, return the number of actual + arguments that this parameter eventually feeds to (or zero if there is none). + For any such parameter, mark PARM_NUM as one of its sources. ANALYZED is a + bitmap that tracks which SSA names we have already started + investigating. */ + +static int +isra_track_scalar_value_uses (cgraph_node *node, tree name, int parm_num, + bitmap analyzed) +{ + int res = 0; + imm_use_iterator imm_iter; + gimple *stmt; + + FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name) + { + if (is_gimple_debug (stmt)) + continue; + + /* TODO: We could handle at least const builtin functions like arithmetic + operations below. */ + if (is_gimple_call (stmt)) + { + int all_uses = 0; + use_operand_p use_p; + FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) + all_uses++; + + gcall *call = as_a (stmt); + unsigned arg_count; + if (gimple_call_internal_p (call) + || (arg_count = gimple_call_num_args (call)) == 0) + { + res = -1; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + + cgraph_edge *cs = node->get_edge (stmt); + gcc_checking_assert (cs); + isra_call_summary *csum = call_sums->get_create (cs); + csum->init_inputs (arg_count); + + int simple_uses = 0; + for (unsigned i = 0; i < arg_count; i++) + if (gimple_call_arg (call, i) == name) + { + if (!add_src_to_param_flow (&csum->m_arg_flow[i], parm_num)) + { + simple_uses = -1; + break; + } + simple_uses++; + } + + if (simple_uses < 0 + || all_uses != simple_uses) + { + res = -1; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + res += all_uses; + } + else if ((is_gimple_assign (stmt) && !gimple_has_volatile_ops (stmt)) + || gimple_code (stmt) == GIMPLE_PHI) + { + tree lhs; + if (gimple_code (stmt) == GIMPLE_PHI) + lhs = gimple_phi_result (stmt); + else + lhs = gimple_assign_lhs (stmt); + + if (TREE_CODE (lhs) != SSA_NAME) + { + res = -1; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + gcc_assert (!gimple_vdef (stmt)); + if (bitmap_set_bit (analyzed, SSA_NAME_VERSION (lhs))) + { + int tmp = isra_track_scalar_value_uses (node, lhs, parm_num, + analyzed); + if (tmp < 0) + { + res = tmp; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + res += tmp; + } + } + else + { + res = -1; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + } + return res; +} + +/* Inspect all uses of PARM, which must be a gimple register, in FUN (which is + also described by NODE) and simple arithmetic calculations involving PARM + and return false if any of them is used for something else than either an + actual call argument, simple arithmetic operation or debug statement. If + there are no such uses, return true and store the number of actual arguments + that this parameter eventually feeds to (or zero if there is none) to + *CALL_USES_P. For any such parameter, mark PARM_NUM as one of its + sources. + + This function is similar to ptr_parm_has_nonarg_uses but its results are + meant for unused parameter removal, as opposed to splitting of parameters + passed by reference or converting them to passed by value. + */ + +static bool +isra_track_scalar_param_local_uses (function *fun, cgraph_node *node, tree parm, + int parm_num, int *call_uses_p) +{ + gcc_checking_assert (is_gimple_reg (parm)); + + tree name = ssa_default_def (fun, parm); + if (!name || has_zero_uses (name)) + { + *call_uses_p = 0; + return false; + } + + /* Edge summaries can only handle callers with fewer than 256 parameters. */ + if (parm_num > UCHAR_MAX) + return true; + + bitmap analyzed = BITMAP_ALLOC (NULL); + int call_uses = isra_track_scalar_value_uses (node, name, parm_num, analyzed); + BITMAP_FREE (analyzed); + if (call_uses < 0) + return true; + *call_uses_p = call_uses; + return false; +} + +/* Scan immediate uses of a default definition SSA name of a parameter PARM and + examine whether there are any nonarg uses that are not actual arguments or + otherwise infeasible uses. If so, return true, otherwise return false. + Create pass-through IPA flow records for any direct uses as argument calls + and if returning false, store their number into *PT_COUNT_P. NODE and FUN + must represent the function that is currently analyzed, PARM_NUM must be the + index of the analyzed parameter. + + This function is similar to isra_track_scalar_param_local_uses but its + results are meant for splitting of parameters passed by reference or turning + them into bits passed by value, as opposed to generic unused parameter + removal. + */ + +static bool +ptr_parm_has_nonarg_uses (cgraph_node *node, function *fun, tree parm, + int parm_num, unsigned *pt_count_p) +{ + imm_use_iterator ui; + gimple *stmt; + tree name = ssa_default_def (fun, parm); + bool ret = false; + unsigned pt_count = 0; + + if (!name || has_zero_uses (name)) + return false; + + /* Edge summaries can only handle callers with fewer than 256 parameters. */ + if (parm_num > UCHAR_MAX) + return true; + + FOR_EACH_IMM_USE_STMT (stmt, ui, name) + { + unsigned uses_ok = 0; + use_operand_p use_p; + + if (is_gimple_debug (stmt)) + continue; + + if (gimple_assign_single_p (stmt)) + { + tree rhs = gimple_assign_rhs1 (stmt); + while (handled_component_p (rhs)) + rhs = TREE_OPERAND (rhs, 0); + if (TREE_CODE (rhs) == MEM_REF + && TREE_OPERAND (rhs, 0) == name + && integer_zerop (TREE_OPERAND (rhs, 1)) + && types_compatible_p (TREE_TYPE (rhs), + TREE_TYPE (TREE_TYPE (name))) + && !TREE_THIS_VOLATILE (rhs)) + uses_ok++; + } + else if (is_gimple_call (stmt)) + { + gcall *call = as_a (stmt); + unsigned arg_count; + if (gimple_call_internal_p (call) + || (arg_count = gimple_call_num_args (call)) == 0) + { + ret = true; + BREAK_FROM_IMM_USE_STMT (ui); + } + + cgraph_edge *cs = node->get_edge (stmt); + gcc_checking_assert (cs); + isra_call_summary *csum = call_sums->get_create (cs); + csum->init_inputs (arg_count); + + for (unsigned i = 0; i < arg_count; ++i) + { + tree arg = gimple_call_arg (stmt, i); + + if (arg == name) + { + /* TODO: Allow &MEM_REF[name + offset] here, + ipa_param_body_adjustments::modify_call_stmt has to be + adjusted too. */ + csum->m_arg_flow[i].pointer_pass_through = true; + set_single_param_flow_source (&csum->m_arg_flow[i], parm_num); + pt_count++; + uses_ok++; + continue; + } + + while (handled_component_p (arg)) + arg = TREE_OPERAND (arg, 0); + if (TREE_CODE (arg) == MEM_REF + && TREE_OPERAND (arg, 0) == name + && integer_zerop (TREE_OPERAND (arg, 1)) + && types_compatible_p (TREE_TYPE (arg), + TREE_TYPE (TREE_TYPE (name))) + && !TREE_THIS_VOLATILE (arg)) + uses_ok++; + } + } + + /* If the number of valid uses does not match the number of + uses in this stmt there is an unhandled use. */ + unsigned all_uses = 0; + FOR_EACH_IMM_USE_ON_STMT (use_p, ui) + all_uses++; + + gcc_checking_assert (uses_ok <= all_uses); + if (uses_ok != all_uses) + { + ret = true; + BREAK_FROM_IMM_USE_STMT (ui); + } + } + + *pt_count_p = pt_count; + return ret; +} + +/* Initialize vector of parameter descriptors of NODE. Return true if there + are any candidates for splitting or unused aggregate parameter removal (the + function may return false if there are candidates for removal of register + parameters) and function body must be scanned. */ + +static bool +create_parameter_descriptors (cgraph_node *node, + vec *param_descriptions) +{ + function *fun = DECL_STRUCT_FUNCTION (node->decl); + bool ret = false; + + int num = 0; + for (tree parm = DECL_ARGUMENTS (node->decl); + parm; + parm = DECL_CHAIN (parm), num++) + { + const char *msg; + gensum_param_desc *desc = &(*param_descriptions)[num]; + /* param_descriptions vector is grown cleared in the caller. */ + desc->param_number = num; + decl2desc->put (parm, desc); + + if (dump_file && (dump_flags & TDF_DETAILS)) + print_generic_expr (dump_file, parm, TDF_UID); + + int scalar_call_uses; + tree type = TREE_TYPE (parm); + if (TREE_THIS_VOLATILE (parm)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, is volatile\n"); + continue; + } + if (!is_gimple_reg_type (type) && is_va_list_type (type)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, is a va_list type\n"); + continue; + } + if (TREE_ADDRESSABLE (parm)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, is addressable\n"); + continue; + } + if (TREE_ADDRESSABLE (type)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, type cannot be split\n"); + continue; + } + + if (is_gimple_reg (parm) + && !isra_track_scalar_param_local_uses (fun, node, parm, num, + &scalar_call_uses)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " is a scalar with only %i call uses\n", + scalar_call_uses); + + desc->locally_unused = true; + desc->call_uses = scalar_call_uses; + } + + if (POINTER_TYPE_P (type)) + { + type = TREE_TYPE (type); + + if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, reference to " + "a function\n"); + continue; + } + if (TYPE_VOLATILE (type)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, reference to " + "a volatile type\n"); + continue; + } + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_NONALIASED_COMPONENT (type)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, reference to a" + "nonaliased component array\n"); + continue; + } + if (!is_gimple_reg (parm)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, a reference which is " + "not a gimple register (probably addressable)\n"); + continue; + } + if (is_va_list_type (type)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, reference to " + "a va list\n"); + continue; + } + if (ptr_parm_has_nonarg_uses (node, fun, parm, num, + &desc->ptr_pt_count)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, reference has " + "nonarg uses\n"); + continue; + } + desc->by_ref = true; + } + else if (!AGGREGATE_TYPE_P (type)) + { + /* This is in an else branch because scalars passed by reference are + still candidates to be passed by value. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, not an aggregate\n"); + continue; + } + + if (!COMPLETE_TYPE_P (type)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, not a complete type\n"); + continue; + } + if (!tree_fits_uhwi_p (TYPE_SIZE (type))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, size not representable\n"); + continue; + } + unsigned HOST_WIDE_INT type_size + = tree_to_uhwi (TYPE_SIZE (type)) / BITS_PER_UNIT; + if (type_size == 0 + || type_size >= ISRA_ARG_SIZE_LIMIT) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, has zero or huge size\n"); + continue; + } + if (type_internals_preclude_sra_p (type, &msg)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a candidate, %s\n", msg); + continue; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " is a candidate\n"); + + ret = true; + desc->split_candidate = true; + if (desc->by_ref) + desc->deref_index = by_ref_count++; + } + return ret; +} + +/* Return pointer to descriptor of parameter DECL or NULL if it cannot be + found, which happens if DECL is for a static chain. */ + +static gensum_param_desc * +get_gensum_param_desc (tree decl) +{ + gcc_checking_assert (TREE_CODE (decl) == PARM_DECL); + gensum_param_desc **slot = decl2desc->get (decl); + if (!slot) + /* This can happen for static chains which we cannot handle so far. */ + return NULL; + gcc_checking_assert (*slot); + return *slot; +} + + +/* Remove parameter described by DESC from candidates for IPA-SRA splitting and + write REASON to the dump file if there is one. */ + +static void +disqualify_split_candidate (gensum_param_desc *desc, const char *reason) +{ + if (!desc->split_candidate) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "! Disqualifying parameter number %i - %s\n", + desc->param_number, reason); + + desc->split_candidate = false; +} + +/* Remove DECL from candidates for IPA-SRA and write REASON to the dump file if + there is one. */ + +static void +disqualify_split_candidate (tree decl, const char *reason) +{ + gensum_param_desc *desc = get_gensum_param_desc (decl); + if (desc) + disqualify_split_candidate (desc, reason); +} + +/* Allocate a new access to DESC and fill it in with OFFSET and SIZE. But + first, check that there are not too many of them already. If so, do not + allocate anything and return NULL. */ + +static gensum_param_access * +allocate_access (gensum_param_desc *desc, + HOST_WIDE_INT offset, HOST_WIDE_INT size) +{ + if (desc->access_count + == (unsigned) PARAM_VALUE (PARAM_IPA_SRA_MAX_REPLACEMENTS)) + { + disqualify_split_candidate (desc, "Too many replacement candidates"); + return NULL; + } + + gensum_param_access *access + = (gensum_param_access *) obstack_alloc (&gensum_obstack, + sizeof (gensum_param_access)); + memset (access, 0, sizeof (*access)); + access->offset = offset; + access->size = size; + return access; +} + +/* In what context scan_expr_access has been called, whether it deals with a + load, a function argument, or a store. */ + +enum isra_scan_context {ISRA_CTX_LOAD, ISRA_CTX_ARG, ISRA_CTX_STORE}; + +/* Return an access describing memory access to the variable described by DESC + at OFFSET with SIZE in context CTX, starting at pointer to the linked list + at a certaint tree level FIRST. Attempt to create it and put into the + appropriate place in the access tree if does not exist, but fail and return + NULL if there are already too many accesses, if it would create a partially + overlapping access or if an access would end up withiin a pre-existing + non-call access. */ + +static gensum_param_access * +get_access_1 (gensum_param_desc *desc, gensum_param_access **first, + HOST_WIDE_INT offset, HOST_WIDE_INT size, isra_scan_context ctx) +{ + gensum_param_access *access = *first, **ptr = first; + + if (!access) + { + /* No pre-existing access at this level, just create it. */ + gensum_param_access *a = allocate_access (desc, offset, size); + if (!a) + return NULL; + *first = a; + return *first; + } + + if (access->offset >= offset + size) + { + /* We want to squeeze it in front of the very first access, just do + it. */ + gensum_param_access *r = allocate_access (desc, offset, size); + if (!r) + return NULL; + r->next_sibling = access; + *first = r; + return r; + } + + /* Skip all accesses that have to come before us until the next sibling is + already too far. */ + while (offset >= access->offset + access->size + && access->next_sibling + && access->next_sibling->offset < offset + size) + { + ptr = &access->next_sibling; + access = access->next_sibling; + } + + /* At this point we know we do not belong before access. */ + gcc_assert (access->offset < offset + size); + + if (access->offset == offset && access->size == size) + /* We found what we were looking for. */ + return access; + + if (access->offset <= offset + && access->offset + access->size >= offset + size) + { + /* We fit into access which is larger than us. We need to find/create + something below access. But we only allow nesting in call + arguments. */ + if (access->nonarg) + return NULL; + + return get_access_1 (desc, &access->first_child, offset, size, ctx); + } + + if (offset <= access->offset + && offset + size >= access->offset + access->size) + /* We are actually bigger than access, which fully fits into us, take its + place and make all accesses fitting into it its children. */ + { + /* But first, we only allow nesting in call arguments so check if that is + what we are trying to represent. */ + if (ctx != ISRA_CTX_ARG) + return NULL; + + gensum_param_access *r = allocate_access (desc, offset, size); + if (!r) + return NULL; + r->first_child = access; + + while (access->next_sibling + && access->next_sibling->offset < offset + size) + access = access->next_sibling; + if (access->offset + access->size > offset + size) + { + /* This must be a different access, which are sorted, so the + following must be true and this signals a partial overlap. */ + gcc_assert (access->offset > offset); + return NULL; + } + + r->next_sibling = access->next_sibling; + access->next_sibling = NULL; + *ptr = r; + return r; + } + + if (offset >= access->offset + access->size) + { + /* We belong after access. */ + gensum_param_access *r = allocate_access (desc, offset, size); + if (!r) + return NULL; + r->next_sibling = access->next_sibling; + access->next_sibling = r; + return r; + } + + if (offset < access->offset) + { + /* We know the following, otherwise we would have created a + super-access. */ + gcc_checking_assert (offset + size < access->offset + access->size); + return NULL; + } + + if (offset + size > access->offset + access->size) + { + /* Likewise. */ + gcc_checking_assert (offset > access->offset); + return NULL; + } + + gcc_unreachable (); +} + +/* Return an access describing memory access to the variable described by DESC + at OFFSET with SIZE in context CTX, mark it as used in context CTX. Attempt + to create if it does not exist, but fail and return NULL if there are + already too many accesses, if it would create a partially overlapping access + or if an access woule end up in a non-call access. */ + +static gensum_param_access * +get_access (gensum_param_desc *desc, HOST_WIDE_INT offset, HOST_WIDE_INT size, + isra_scan_context ctx) +{ + gcc_checking_assert (desc->split_candidate); + + gensum_param_access *access = get_access_1 (desc, &desc->accesses, offset, + size, ctx); + if (!access) + { + disqualify_split_candidate (desc, + "Bad access overlap or too many accesses"); + return NULL; + } + + switch (ctx) + { + case ISRA_CTX_STORE: + gcc_assert (!desc->by_ref); + /* Fall-through */ + case ISRA_CTX_LOAD: + access->nonarg = true; + break; + case ISRA_CTX_ARG: + break; + } + + return access; +} + +/* Verify that parameter access tree starting with ACCESS is in good shape. + PARENT_OFFSET and PARENT_SIZE are the ciorresponding fields of parent of + ACCESS or zero if there is none. */ + +static bool +verify_access_tree_1 (gensum_param_access *access, HOST_WIDE_INT parent_offset, + HOST_WIDE_INT parent_size) +{ + while (access) + { + gcc_assert (access->offset >= 0 && access->size > 0); + + if (parent_size != 0) + { + if (access->offset < parent_offset) + { + error ("Access offset before parent offset"); + return true; + } + if (access->size >= parent_size) + { + error ("Access size greater or equal to its parent size"); + return true; + } + if (access->offset + access->size > parent_offset + parent_size) + { + error ("Access terminates outside of its parent"); + return true; + } + } + + if (verify_access_tree_1 (access->first_child, access->offset, + access->size)) + return true; + + if (access->next_sibling + && (access->next_sibling->offset < access->offset + access->size)) + { + error ("Access overlaps with its sibling"); + return true; + } + + access = access->next_sibling; + } + return false; +} + +/* Verify that parameter access tree starting with ACCESS is in good shape, + halt compilation and dump the tree to stderr if not. */ + +DEBUG_FUNCTION void +isra_verify_access_tree (gensum_param_access *access) +{ + if (verify_access_tree_1 (access, 0, 0)) + { + for (; access; access = access->next_sibling) + dump_gensum_access (stderr, access, 2); + internal_error ("IPA-SRA access verification failed"); + } +} + + +/* Callback of walk_stmt_load_store_addr_ops visit_addr used to determine + GIMPLE_ASM operands with memory constrains which cannot be scalarized. */ + +static bool +asm_visit_addr (gimple *, tree op, tree, void *) +{ + op = get_base_address (op); + if (op + && TREE_CODE (op) == PARM_DECL) + disqualify_split_candidate (op, "Non-scalarizable GIMPLE_ASM operand."); + + return false; +} + +/* Mark a dereference of parameter identified by DESC of distance DIST in a + basic block BB, unless the BB has already been marked as a potentially + final. */ + +static void +mark_param_dereference (gensum_param_desc *desc, HOST_WIDE_INT dist, + basic_block bb) +{ + gcc_assert (desc->by_ref); + gcc_checking_assert (desc->split_candidate); + + if (bitmap_bit_p (final_bbs, bb->index)) + return; + + int idx = bb->index * by_ref_count + desc->deref_index; + if (bb_dereferences[idx] < dist) + bb_dereferences[idx] = dist; +} + +/* Return true, if any potential replacements should use NEW_TYPE as opposed to + previously recorded OLD_TYPE. */ + +static bool +type_prevails_p (tree old_type, tree new_type) +{ + if (old_type == new_type) + return false; + + /* Non-aggregates are always better. */ + if (!is_gimple_reg_type (old_type) + && is_gimple_reg_type (new_type)) + return true; + if (is_gimple_reg_type (old_type) + && !is_gimple_reg_type (new_type)) + return false; + + /* Prefer any complex or vector type over any other scalar type. */ + if (TREE_CODE (old_type) != COMPLEX_TYPE + && TREE_CODE (old_type) != VECTOR_TYPE + && (TREE_CODE (new_type) == COMPLEX_TYPE + || TREE_CODE (new_type) == VECTOR_TYPE)) + return true; + if ((TREE_CODE (old_type) == COMPLEX_TYPE + || TREE_CODE (old_type) == VECTOR_TYPE) + && TREE_CODE (new_type) != COMPLEX_TYPE + && TREE_CODE (new_type) != VECTOR_TYPE) + return false; + + /* Use the integral type with the bigger precision. */ + if (INTEGRAL_TYPE_P (old_type) + && INTEGRAL_TYPE_P (new_type)) + return (TYPE_PRECISION (new_type) > TYPE_PRECISION (old_type)); + + /* Attempt to disregard any integral type with non-full precision. */ + if (INTEGRAL_TYPE_P (old_type) + && (TREE_INT_CST_LOW (TYPE_SIZE (old_type)) + != TYPE_PRECISION (old_type))) + return true; + if (INTEGRAL_TYPE_P (new_type) + && (TREE_INT_CST_LOW (TYPE_SIZE (new_type)) + != TYPE_PRECISION (new_type))) + return false; + /* Stabilize the selection. */ + return TYPE_UID (old_type) < TYPE_UID (new_type); +} + +/* When scanning an expression which is a call argument, this structure + specifies the call and the position of the agrument. */ + +struct scan_call_info +{ + /* Call graph edge representing the call. */ + cgraph_edge *cs; + /* Total number of arguments in the call. */ + unsigned argument_count; + /* Number of the actual argument being scanned. */ + unsigned arg_idx; +}; + +/* Record use of ACCESS which belongs to a parameter described by DESC in a + call argument described by CALL_INFO. */ + +static void +record_nonregister_call_use (gensum_param_desc *desc, + scan_call_info *call_info, + unsigned unit_offset, unsigned unit_size) +{ + isra_call_summary *csum = call_sums->get_create (call_info->cs); + csum->init_inputs (call_info->argument_count); + + isra_param_flow *param_flow = &csum->m_arg_flow[call_info->arg_idx]; + param_flow->aggregate_pass_through = true; + set_single_param_flow_source (param_flow, desc->param_number); + param_flow->unit_offset = unit_offset; + param_flow->unit_size = unit_size; + desc->call_uses++; +} + +/* Callback of walk_aliased_vdefs, just mark that there was a possible + modification. */ + +static bool +mark_maybe_modified (ao_ref *, tree, void *data) +{ + bool *maybe_modified = (bool *) data; + *maybe_modified = true; + return true; +} + +/* Analyze expression EXPR from GIMPLE for accesses to parameters. CTX + specifies whether EXPR is used in a load, store or as an argument call. BB + must be the basic block in which expr resides. If CTX specifies call + arguemnt context, CALL_INFO must describe tha call and argument position, + otherwise it is ignored. */ + +static void +scan_expr_access (tree expr, gimple *stmt, isra_scan_context ctx, + basic_block bb, scan_call_info *call_info = NULL) +{ + poly_int64 poffset, psize, pmax_size; + HOST_WIDE_INT offset, size, max_size; + tree base; + bool deref = false; + bool reverse; + + if (TREE_CODE (expr) == BIT_FIELD_REF + || TREE_CODE (expr) == IMAGPART_EXPR + || TREE_CODE (expr) == REALPART_EXPR) + expr = TREE_OPERAND (expr, 0); + + base = get_ref_base_and_extent (expr, &poffset, &psize, &pmax_size, &reverse); + + if (TREE_CODE (base) == MEM_REF) + { + tree op = TREE_OPERAND (base, 0); + if (TREE_CODE (op) != SSA_NAME + || !SSA_NAME_IS_DEFAULT_DEF (op)) + return; + base = SSA_NAME_VAR (op); + if (!base) + return; + deref = true; + } + if (TREE_CODE (base) != PARM_DECL) + return; + + gensum_param_desc *desc = get_gensum_param_desc (base); + if (!desc || !desc->split_candidate) + return; + + if (!poffset.is_constant (&offset) + || !psize.is_constant (&size) + || !pmax_size.is_constant (&max_size)) + { + disqualify_split_candidate (desc, "Encountered a polynomial-sized " + "access."); + return; + } + if (size < 0 || size != max_size) + { + disqualify_split_candidate (desc, "Encountered a variable sized access."); + return; + } + if (TREE_CODE (expr) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (expr, 1))) + { + disqualify_split_candidate (desc, "Encountered a bit-field access."); + return; + } + gcc_assert (offset >= 0); + gcc_assert ((offset % BITS_PER_UNIT) == 0); + gcc_assert ((size % BITS_PER_UNIT) == 0); + if ((offset / BITS_PER_UNIT) >= (UINT_MAX - ISRA_ARG_SIZE_LIMIT) + || (size / BITS_PER_UNIT) >= ISRA_ARG_SIZE_LIMIT) + { + disqualify_split_candidate (desc, "Encountered an access with too big " + "offset or size"); + return; + } + + tree type = TREE_TYPE (expr); + unsigned int exp_align = get_object_alignment (expr); + + if (exp_align < TYPE_ALIGN (type)) + { + disqualify_split_candidate (desc, "Underaligned access."); + return; + } + + if (deref) + { + if (!desc->by_ref) + { + disqualify_split_candidate (desc, "Dereferencing a non-reference."); + return; + } + else if (ctx == ISRA_CTX_STORE) + { + disqualify_split_candidate (desc, "Storing to data passed by " + "reference."); + return; + } + + if (!aa_walking_limit) + { + disqualify_split_candidate (desc, "Out of alias analysis step " + "limit."); + return; + } + + gcc_checking_assert (gimple_vuse (stmt)); + bool maybe_modified = false; + ao_ref ar; + + ao_ref_init (&ar, expr); + bitmap visited = BITMAP_ALLOC (NULL); + int walked = walk_aliased_vdefs (&ar, gimple_vuse (stmt), + mark_maybe_modified, &maybe_modified, + &visited, NULL, aa_walking_limit); + BITMAP_FREE (visited); + if (walked > 0) + { + gcc_assert (aa_walking_limit > walked); + aa_walking_limit = aa_walking_limit - walked; + } + if (walked < 0) + aa_walking_limit = 0; + if (maybe_modified || walked < 0) + { + disqualify_split_candidate (desc, "Data passed by reference possibly " + "modified through an alias."); + return; + } + else + mark_param_dereference (desc, offset + size, bb); + } + else + /* Pointer parameters with direct uses should have been ruled out by + analyzing SSA default def when looking at the paremeters. */ + gcc_assert (!desc->by_ref); + + gensum_param_access *access = get_access (desc, offset, size, ctx); + if (!access) + return; + + if (ctx == ISRA_CTX_ARG) + { + gcc_checking_assert (call_info); + + if (!deref) + record_nonregister_call_use (desc, call_info, offset / BITS_PER_UNIT, + size / BITS_PER_UNIT); + else + /* This is not a pass-through of a pointer, this is a use like any + other. */ + access->nonarg = true; + } + + if (!access->type) + { + access->type = type; + access->alias_ptr_type = reference_alias_ptr_type (expr); + access->reverse = reverse; + } + else + { + if (exp_align < TYPE_ALIGN (access->type)) + { + disqualify_split_candidate (desc, "Reference has lower alignment " + "than a previous one."); + return; + } + if (access->alias_ptr_type != reference_alias_ptr_type (expr)) + { + disqualify_split_candidate (desc, "Multiple alias pointer types."); + return; + } + if (access->reverse != reverse) + { + disqualify_split_candidate (desc, "Both normal and reverse " + "scalar storage order."); + return; + } + if (!deref + && (AGGREGATE_TYPE_P (type) || AGGREGATE_TYPE_P (access->type)) + && (TYPE_MAIN_VARIANT (access->type) != TYPE_MAIN_VARIANT (type))) + { + /* We need the same aggregate type on all accesses to be able to + distinguish transformation spots from pass-through arguments in + the transofrmation phase. */ + disqualify_split_candidate (desc, "We do not support aggegate " + "type punning."); + return; + } + + if (type_prevails_p (access->type, type)) + access->type = type; + } +} + +/* Scan body function described by NODE and FUN and create access trees for + parameters. */ + +static void +scan_function (cgraph_node *node, struct function *fun) +{ + basic_block bb; + + FOR_EACH_BB_FN (bb, fun) + { + gimple_stmt_iterator gsi; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (stmt_can_throw_external (fun, stmt)) + bitmap_set_bit (final_bbs, bb->index); + switch (gimple_code (stmt)) + { + case GIMPLE_RETURN: + { + tree t = gimple_return_retval (as_a (stmt)); + if (t != NULL_TREE) + scan_expr_access (t, stmt, ISRA_CTX_LOAD, bb); + bitmap_set_bit (final_bbs, bb->index); + } + break; + + case GIMPLE_ASSIGN: + if (gimple_assign_single_p (stmt) + && !gimple_clobber_p (stmt)) + { + tree rhs = gimple_assign_rhs1 (stmt); + scan_expr_access (rhs, stmt, ISRA_CTX_LOAD, bb); + tree lhs = gimple_assign_lhs (stmt); + scan_expr_access (lhs, stmt, ISRA_CTX_STORE, bb); + } + break; + + case GIMPLE_CALL: + { + unsigned argument_count = gimple_call_num_args (stmt); + scan_call_info call_info; + call_info.cs = node->get_edge (stmt); + call_info.argument_count = argument_count; + + for (unsigned i = 0; i < argument_count; i++) + { + call_info.arg_idx = i; + scan_expr_access (gimple_call_arg (stmt, i), stmt, + ISRA_CTX_ARG, bb, &call_info); + } + + tree lhs = gimple_call_lhs (stmt); + if (lhs) + scan_expr_access (lhs, stmt, ISRA_CTX_STORE, bb); + int flags = gimple_call_flags (stmt); + if ((flags & (ECF_CONST | ECF_PURE)) == 0) + bitmap_set_bit (final_bbs, bb->index); + } + break; + + case GIMPLE_ASM: + { + gasm *asm_stmt = as_a (stmt); + walk_stmt_load_store_addr_ops (asm_stmt, NULL, NULL, NULL, + asm_visit_addr); + bitmap_set_bit (final_bbs, bb->index); + + for (unsigned i = 0; i < gimple_asm_ninputs (asm_stmt); i++) + { + tree t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i)); + scan_expr_access (t, stmt, ISRA_CTX_LOAD, bb); + } + for (unsigned i = 0; i < gimple_asm_noutputs (asm_stmt); i++) + { + tree t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i)); + scan_expr_access (t, stmt, ISRA_CTX_STORE, bb); + } + } + break; + + default: + break; + } + } + } +} + +/* Return true if SSA_NAME NAME is only used in return statements, or if + results of any operations it is involved in are only used in return + statements. ANALYZED is a bitmap that tracks which SSA names we have + already started investigating. */ + +static bool +ssa_name_only_returned_p (tree name, bitmap analyzed) +{ + bool res = true; + imm_use_iterator imm_iter; + gimple *stmt; + + FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name) + { + if (is_gimple_debug (stmt)) + continue; + + if (gimple_code (stmt) == GIMPLE_RETURN) + { + tree t = gimple_return_retval (as_a (stmt)); + if (t != name) + { + res = false; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + } + else if ((is_gimple_assign (stmt) && !gimple_has_volatile_ops (stmt)) + || gimple_code (stmt) == GIMPLE_PHI) + { + /* TODO: And perhaps for const function calls too? */ + tree lhs; + if (gimple_code (stmt) == GIMPLE_PHI) + lhs = gimple_phi_result (stmt); + else + lhs = gimple_assign_lhs (stmt); + + if (TREE_CODE (lhs) != SSA_NAME) + { + res = false; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + gcc_assert (!gimple_vdef (stmt)); + if (bitmap_set_bit (analyzed, SSA_NAME_VERSION (lhs)) + && !ssa_name_only_returned_p (lhs, analyzed)) + { + res = false; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + } + else + { + res = false; + BREAK_FROM_IMM_USE_STMT (imm_iter); + } + } + return res; +} + +/* Inspect the uses of the return value of the call associated with CS, and if + it is not used or if it is only used to construct the return value of the + caller, mark it as such in call or caller summary. Also check for + misaligned arguments. */ + +static void +isra_analyze_call (cgraph_edge *cs) +{ + gcall *call_stmt = cs->call_stmt; + unsigned count = gimple_call_num_args (call_stmt); + isra_call_summary *csum = call_sums->get_create (cs); + + for (unsigned i = 0; i < count; i++) + { + tree arg = gimple_call_arg (call_stmt, i); + if (is_gimple_reg (arg)) + continue; + + tree offset; + poly_int64 bitsize, bitpos; + machine_mode mode; + int unsignedp, reversep, volatilep = 0; + get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode, + &unsignedp, &reversep, &volatilep); + if (!multiple_p (bitpos, BITS_PER_UNIT)) + { + csum->m_bit_aligned_arg = true; + break; + } + } + + tree lhs = gimple_call_lhs (call_stmt); + if (lhs) + { + /* TODO: Also detect aggregates on a LHS of a call that are only returned + from this function (without being read anywhere). */ + if (TREE_CODE (lhs) == SSA_NAME) + { + bitmap analyzed = BITMAP_ALLOC (NULL); + if (ssa_name_only_returned_p (lhs, analyzed)) + csum->m_return_returned = true; + BITMAP_FREE (analyzed); + } + } + else + csum->m_return_ignored = true; +} + +/* Look at all calls going out of NODE, described also by IFS and perform all + analyses necessary for IPA-SRA that are not done at body scan time or done + even when body is not scanned because the function is not a candidate. */ + +static void +isra_analyze_all_outgoing_calls (cgraph_node *node) +{ + for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) + isra_analyze_call (cs); + for (cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee) + isra_analyze_call (cs); +} + +/* Dump a dereferences table with heading STR to file F. */ + +static void +dump_dereferences_table (FILE *f, struct function *fun, const char *str) +{ + basic_block bb; + + fprintf (dump_file, "%s", str); + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (fun), + EXIT_BLOCK_PTR_FOR_FN (fun), next_bb) + { + fprintf (f, "%4i %i ", bb->index, bitmap_bit_p (final_bbs, bb->index)); + if (bb != EXIT_BLOCK_PTR_FOR_FN (fun)) + { + int i; + for (i = 0; i < by_ref_count; i++) + { + int idx = bb->index * by_ref_count + i; + fprintf (f, " %4" HOST_WIDE_INT_PRINT "d", bb_dereferences[idx]); + } + } + fprintf (f, "\n"); + } + fprintf (dump_file, "\n"); +} + +/* Propagate distances in bb_dereferences in the opposite direction than the + control flow edges, in each step storing the maximum of the current value + and the minimum of all successors. These steps are repeated until the table + stabilizes. Note that BBs which might terminate the functions (according to + final_bbs bitmap) never updated in this way. */ + +static void +propagate_dereference_distances (struct function *fun) +{ + basic_block bb; + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_dereferences_table (dump_file, fun, + "Dereference table before propagation:\n"); + + auto_vec queue (last_basic_block_for_fn (fun)); + queue.quick_push (ENTRY_BLOCK_PTR_FOR_FN (fun)); + FOR_EACH_BB_FN (bb, fun) + { + queue.quick_push (bb); + bb->aux = bb; + } + + while (!queue.is_empty ()) + { + edge_iterator ei; + edge e; + bool change = false; + int i; + + bb = queue.pop (); + bb->aux = NULL; + + if (bitmap_bit_p (final_bbs, bb->index)) + continue; + + for (i = 0; i < by_ref_count; i++) + { + int idx = bb->index * by_ref_count + i; + bool first = true; + HOST_WIDE_INT inh = 0; + + FOR_EACH_EDGE (e, ei, bb->succs) + { + int succ_idx = e->dest->index * by_ref_count + i; + + if (e->dest == EXIT_BLOCK_PTR_FOR_FN (fun)) + continue; + + if (first) + { + first = false; + inh = bb_dereferences [succ_idx]; + } + else if (bb_dereferences [succ_idx] < inh) + inh = bb_dereferences [succ_idx]; + } + + if (!first && bb_dereferences[idx] < inh) + { + bb_dereferences[idx] = inh; + change = true; + } + } + + if (change) + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->src->aux) + continue; + + e->src->aux = e->src; + queue.quick_push (e->src); + } + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_dereferences_table (dump_file, fun, + "Dereference table after propagation:\n"); +} + +/* Perform basic checks on ACCESS to PARM described by DESC and all its + children, return true if the parameter cannot be split, otherwise return + true and update *TOTAL_SIZE and *ONLY_CALLS. ENTRY_BB_INDEX must be the + index of the entry BB in the function of PARM. */ + +static bool +check_gensum_access (tree parm, gensum_param_desc *desc, + gensum_param_access *access, + HOST_WIDE_INT *nonarg_acc_size, bool *only_calls, + int entry_bb_index) +{ + if (access->nonarg) + { + *only_calls = false; + *nonarg_acc_size += access->size; + + if (access->first_child) + { + disqualify_split_candidate (desc, "Overlapping non-call uses."); + return true; + } + } + /* Do not decompose a non-BLKmode param in a way that would create + BLKmode params. Especially for by-reference passing (thus, + pointer-type param) this is hardly worthwhile. */ + if (DECL_MODE (parm) != BLKmode + && TYPE_MODE (access->type) == BLKmode) + { + disqualify_split_candidate (desc, "Would convert a non-BLK to a BLK."); + return true; + } + + if (desc->by_ref) + { + int idx = (entry_bb_index * by_ref_count + desc->deref_index); + if ((access->offset + access->size) > bb_dereferences[idx]) + { + disqualify_split_candidate (desc, "Would create a possibly " + "illegal dereference in a caller."); + return true; + } + } + + for (gensum_param_access *ch = access->first_child; + ch; + ch = ch->next_sibling) + if (check_gensum_access (parm, desc, ch, nonarg_acc_size, only_calls, + entry_bb_index)) + return true; + + return false; +} + +/* Copy data from FROM and all of its children to a vector of accesses in IPA + descriptor DESC. */ + +static void +copy_accesses_to_ipa_desc (gensum_param_access *from, isra_param_desc *desc) +{ + param_access *to = ggc_cleared_alloc (); + gcc_checking_assert ((from->offset % BITS_PER_UNIT) == 0); + gcc_checking_assert ((from->size % BITS_PER_UNIT) == 0); + to->unit_offset = from->offset / BITS_PER_UNIT; + to->unit_size = from->size / BITS_PER_UNIT; + to->type = from->type; + to->alias_ptr_type = from->alias_ptr_type; + to->certain = from->nonarg; + to->reverse = from->reverse; + vec_safe_push (desc->accesses, to); + + for (gensum_param_access *ch = from->first_child; + ch; + ch = ch->next_sibling) + copy_accesses_to_ipa_desc (ch, desc); +} + +/* Analyze function body scan results stored in param_accesses and + param_accesses, detect possible transformations and store information of + those in function summary. NODE, FUN and IFS are all various structures + describing the currently analyzed function. */ + +static void +process_scan_results (cgraph_node *node, struct function *fun, + isra_func_summary *ifs, + vec *param_descriptions) +{ + bool check_pass_throughs = false; + bool dereferences_propagated = false; + tree parm = DECL_ARGUMENTS (node->decl); + unsigned param_count = param_descriptions->length(); + + for (unsigned desc_index = 0; + desc_index < param_count; + desc_index++, parm = DECL_CHAIN (parm)) + { + gensum_param_desc *desc = &(*param_descriptions)[desc_index]; + if (!desc->locally_unused && !desc->split_candidate) + continue; + + if (flag_checking) + isra_verify_access_tree (desc->accesses); + + if (!dereferences_propagated + && desc->by_ref + && desc->accesses) + { + propagate_dereference_distances (fun); + dereferences_propagated = true; + } + + HOST_WIDE_INT nonarg_acc_size = 0; + bool only_calls = true; + bool check_failed = false; + + int entry_bb_index = ENTRY_BLOCK_PTR_FOR_FN (fun)->index; + for (gensum_param_access *acc = desc->accesses; + acc; + acc = acc->next_sibling) + if (check_gensum_access (parm, desc, acc, &nonarg_acc_size, &only_calls, + entry_bb_index)) + { + check_failed = true; + break; + } + if (check_failed) + continue; + + if (only_calls) + desc->locally_unused = true; + + HOST_WIDE_INT cur_param_size + = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (parm))); + HOST_WIDE_INT param_size_limit; + if (!desc->by_ref || optimize_function_for_size_p (fun)) + param_size_limit = cur_param_size; + else + param_size_limit = (PARAM_VALUE (PARAM_IPA_SRA_PTR_GROWTH_FACTOR) + * cur_param_size); + if (nonarg_acc_size > param_size_limit + || (!desc->by_ref && nonarg_acc_size == param_size_limit)) + { + disqualify_split_candidate (desc, "Would result into a too big set of" + "replacements."); + } + else + { + /* create_parameter_descriptors makes sure unit sizes of all + candidate parameters fit unsigned integers restricted to + ISRA_ARG_SIZE_LIMIT. */ + desc->param_size_limit = param_size_limit / BITS_PER_UNIT; + desc->nonarg_acc_size = nonarg_acc_size / BITS_PER_UNIT; + if (desc->split_candidate && desc->ptr_pt_count) + { + gcc_assert (desc->by_ref); + check_pass_throughs = true; + } + } + } + + /* When a pointer parameter is passed-through to a callee, in which it is + only used to read only one or a few items, we can attempt to transform it + to obtaining and passing through the items instead of the pointer. But we + must take extra care that 1) we do not introduce any segfault by moving + dereferences above control flow and that 2) the data is not modified + through an alias in this function. The IPA analysis must not introduce + any accesses candidates unless it can prove both. + + The current solution is very crude as it consists of ensuring that the + call postdominates entry BB and that the definition of VUSE of the call is + default definition. TODO: For non-recursive callees in the same + compilation unit we could do better by doing analysis in topological order + an looking into access candidates of callees, using their alias_ptr_types + to attempt real AA. We could also use the maximum known dereferenced + offset in this function at IPA level. + + TODO: Measure the overhead and the effect of just being pessimistic. + Maybe this is ony -O3 material? + */ + bool pdoms_calculated = false; + if (check_pass_throughs) + for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) + { + gcall *call_stmt = cs->call_stmt; + tree vuse = gimple_vuse (call_stmt); + + /* If the callee is a const function, we don't get a VUSE. In such + case there will be no memory accesses in the called function (or the + const attribute is wrong) and then we just don't care. */ + bool uses_memory_as_obtained = vuse && SSA_NAME_IS_DEFAULT_DEF (vuse); + + unsigned count = gimple_call_num_args (call_stmt); + isra_call_summary *csum = call_sums->get_create (cs); + csum->init_inputs (count); + for (unsigned argidx = 0; argidx < count; argidx++) + { + if (!csum->m_arg_flow[argidx].pointer_pass_through) + continue; + unsigned pidx + = get_single_param_flow_source (&csum->m_arg_flow[argidx]); + gensum_param_desc *desc = &(*param_descriptions)[pidx]; + if (!desc->split_candidate) + { + csum->m_arg_flow[argidx].pointer_pass_through = false; + continue; + } + if (!uses_memory_as_obtained) + continue; + + /* Post-dominator check placed last, hoping that it usually won't + be needed. */ + if (!pdoms_calculated) + { + gcc_checking_assert (cfun); + add_noreturn_fake_exit_edges (); + connect_infinite_loops_to_exit (); + calculate_dominance_info (CDI_POST_DOMINATORS); + pdoms_calculated = true; + } + if (dominated_by_p (CDI_POST_DOMINATORS, + gimple_bb (call_stmt), + single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)))) + csum->m_arg_flow[argidx].safe_to_import_accesses = true; + } + + } + if (pdoms_calculated) + { + free_dominance_info (CDI_POST_DOMINATORS); + remove_fake_exit_edges (); + } + + /* TODO: Add early exit if we disqualified everything. This also requires + that we either relax the restriction that + ipa_param_adjustments.m_always_copy_start mut be the number of PARM_DECLs + or store the number of parameters to IPA-SRA function summary and use that + when just removing params. */ + + vec_safe_reserve_exact (ifs->m_parameters, param_count); + ifs->m_parameters->quick_grow_cleared (param_count); + for (unsigned desc_index = 0; desc_index < param_count; desc_index++) + { + gensum_param_desc *s = &(*param_descriptions)[desc_index]; + isra_param_desc *d = &(*ifs->m_parameters)[desc_index]; + + d->param_size_limit = s->param_size_limit; + d->size_reached = s->nonarg_acc_size; + d->locally_unused = s->locally_unused; + d->split_candidate = s->split_candidate; + d->by_ref = s->by_ref; + + for (gensum_param_access *acc = s->accesses; + acc; + acc = acc->next_sibling) + copy_accesses_to_ipa_desc (acc, d); + } + + if (dump_file) + dump_isra_param_descriptors (dump_file, node->decl, ifs); +} + +/* Return true if there are any overlaps among certain accesses of DESC. If + non-NULL, set *CERTAIN_ACCESS_PRESENT_P upon encountering a certain accesss + too. DESC is assumed to be a split candidate that is not locally + unused. */ + +static bool +overlapping_certain_accesses_p (isra_param_desc *desc, + bool *certain_access_present_p) +{ + unsigned pclen = vec_safe_length (desc->accesses); + for (unsigned i = 0; i < pclen; i++) + { + param_access *a1 = (*desc->accesses)[i]; + + if (!a1->certain) + continue; + if (certain_access_present_p) + *certain_access_present_p = true; + for (unsigned j = i + 1; j < pclen; j++) + { + param_access *a2 = (*desc->accesses)[j]; + if (a2->certain + && a1->unit_offset < a2->unit_offset + a2->unit_size + && a1->unit_offset + a1->unit_size > a2->unit_offset) + return true; + } + } + return false; +} + +/* Check for any overlaps of certain param accesses among splitting candidates + and signal an ICE if there are any. If CERTAIN_MUST_EXIST is set, also + check that used splitting candidates have at least one certain access. */ + +static void +verify_splitting_accesses (cgraph_node *node, bool certain_must_exist) +{ + isra_func_summary *ifs = func_sums->get (node); + if (!ifs || !ifs->m_candidate) + return; + unsigned param_count = vec_safe_length (ifs->m_parameters); + for (unsigned pidx = 0; pidx < param_count; pidx++) + { + isra_param_desc *desc = &(*ifs->m_parameters)[pidx]; + if (!desc->split_candidate || desc->locally_unused) + continue; + + bool certain_access_present = !certain_must_exist; + if (overlapping_certain_accesses_p (desc, &certain_access_present)) + internal_error ("Function %s, parameter %u, has IPA_SRA accesses " + "which overlap", node->dump_name (), pidx); + if (!certain_access_present) + internal_error ("Function %s, parameter %u, is used but does not " + "have any certain IPA-SRA access", + node->dump_name (), pidx); + } +} + +/* Intraprocedural part of IPA-SRA analysis. Scan function body of NODE and + create a summary structure describing IPA-SRA opportunities and constraints + in it. */ + +static void +ipa_sra_summarize_function (cgraph_node *node) +{ + if (dump_file) + fprintf (dump_file, "Creating summary for %s/%i:\n", node->name (), + node->order); + if (!ipa_sra_preliminary_function_checks (node)) + return; + gcc_obstack_init (&gensum_obstack); + isra_func_summary *ifs = func_sums->get_create (node); + ifs->m_candidate = true; + tree ret = TREE_TYPE (TREE_TYPE (node->decl)); + ifs->m_returns_value = (TREE_CODE (ret) != VOID_TYPE); + + decl2desc = new hash_map; + unsigned count = 0; + for (tree parm = DECL_ARGUMENTS (node->decl); parm; parm = DECL_CHAIN (parm)) + count++; + + if (count > 0) + { + auto_vec param_descriptions (count); + param_descriptions.reserve_exact (count); + param_descriptions.quick_grow_cleared (count); + + bool cfun_pushed = false; + struct function *fun = DECL_STRUCT_FUNCTION (node->decl); + if (create_parameter_descriptors (node, ¶m_descriptions)) + { + push_cfun (fun); + cfun_pushed = true; + final_bbs = BITMAP_ALLOC (NULL); + bb_dereferences = XCNEWVEC (HOST_WIDE_INT, + by_ref_count + * last_basic_block_for_fn (fun)); + aa_walking_limit = PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS); + scan_function (node, fun); + + if (dump_file) + { + dump_gensum_param_descriptors (dump_file, node->decl, + ¶m_descriptions); + fprintf (dump_file, "----------------------------------------\n"); + } + } + process_scan_results (node, fun, ifs, ¶m_descriptions); + + if (cfun_pushed) + pop_cfun (); + if (bb_dereferences) + { + free (bb_dereferences); + bb_dereferences = NULL; + BITMAP_FREE (final_bbs); + final_bbs = NULL; + } + } + isra_analyze_all_outgoing_calls (node); + + delete decl2desc; + decl2desc = NULL; + obstack_free (&gensum_obstack, NULL); + if (dump_file) + fprintf (dump_file, "\n\n"); + if (flag_checking) + verify_splitting_accesses (node, false); + return; +} + +/* Intraprocedural part of IPA-SRA analysis. Scan bodies of all functions in + this compilation unit and create summary structures describing IPA-SRA + opportunities and constraints in them. */ + +static void +ipa_sra_generate_summary (void) +{ + struct cgraph_node *node; + + gcc_checking_assert (!func_sums); + gcc_checking_assert (!call_sums); + func_sums + = (new (ggc_cleared_alloc ()) + ipa_sra_function_summaries (symtab, true)); + call_sums = new ipa_sra_call_summaries (symtab); + + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) + ipa_sra_summarize_function (node); + return; +} + +/* Write intraproceural analysis information about E and all of its outgoing + edges into a stream for LTO WPA. */ + +static void +isra_write_edge_summary (output_block *ob, cgraph_edge *e) +{ + isra_call_summary *csum = call_sums->get (e); + unsigned input_count = csum->m_arg_flow.length (); + streamer_write_uhwi (ob, input_count); + for (unsigned i = 0; i < input_count; i++) + { + isra_param_flow *ipf = &csum->m_arg_flow[i]; + streamer_write_hwi (ob, ipf->length); + bitpack_d bp = bitpack_create (ob->main_stream); + for (int j = 0; j < ipf->length; j++) + bp_pack_value (&bp, ipf->inputs[j], 8); + bp_pack_value (&bp, ipf->aggregate_pass_through, 1); + bp_pack_value (&bp, ipf->pointer_pass_through, 1); + bp_pack_value (&bp, ipf->safe_to_import_accesses, 1); + streamer_write_bitpack (&bp); + streamer_write_uhwi (ob, ipf->unit_offset); + streamer_write_uhwi (ob, ipf->unit_size); + } + bitpack_d bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, csum->m_return_ignored, 1); + bp_pack_value (&bp, csum->m_return_returned, 1); + bp_pack_value (&bp, csum->m_bit_aligned_arg, 1); + streamer_write_bitpack (&bp); +} + +/* Write intraproceural analysis information about NODE and all of its outgoing + edges into a stream for LTO WPA. */ + +static void +isra_write_node_summary (output_block *ob, cgraph_node *node) +{ + isra_func_summary *ifs = func_sums->get (node); + lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder; + int node_ref = lto_symtab_encoder_encode (encoder, node); + streamer_write_uhwi (ob, node_ref); + + unsigned param_desc_count = vec_safe_length (ifs->m_parameters); + streamer_write_uhwi (ob, param_desc_count); + for (unsigned i = 0; i < param_desc_count; i++) + { + isra_param_desc *desc = &(*ifs->m_parameters)[i]; + unsigned access_count = vec_safe_length (desc->accesses); + streamer_write_uhwi (ob, access_count); + for (unsigned j = 0; j < access_count; j++) + { + param_access *acc = (*desc->accesses)[j]; + stream_write_tree (ob, acc->type, true); + stream_write_tree (ob, acc->alias_ptr_type, true); + streamer_write_uhwi (ob, acc->unit_offset); + streamer_write_uhwi (ob, acc->unit_size); + bitpack_d bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, acc->certain, 1); + streamer_write_bitpack (&bp); + } + streamer_write_uhwi (ob, desc->param_size_limit); + streamer_write_uhwi (ob, desc->size_reached); + bitpack_d bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, desc->locally_unused, 1); + bp_pack_value (&bp, desc->split_candidate, 1); + bp_pack_value (&bp, desc->by_ref, 1); + streamer_write_bitpack (&bp); + } + bitpack_d bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, ifs->m_candidate, 1); + bp_pack_value (&bp, ifs->m_returns_value, 1); + bp_pack_value (&bp, ifs->m_return_ignored, 1); + gcc_assert (!ifs->m_queued); + streamer_write_bitpack (&bp); + + for (cgraph_edge *e = node->callees; e; e = e->next_callee) + isra_write_edge_summary (ob, e); + for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee) + isra_write_edge_summary (ob, e); +} + +/* Write intraproceural analysis information into a stream for LTO WPA. */ + +static void +ipa_sra_write_summary (void) +{ + if (!func_sums || !call_sums) + return; + + struct output_block *ob = create_output_block (LTO_section_ipa_sra); + lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder; + ob->symbol = NULL; + + unsigned int count = 0; + lto_symtab_encoder_iterator lsei; + for (lsei = lsei_start_function_in_partition (encoder); + !lsei_end_p (lsei); + lsei_next_function_in_partition (&lsei)) + { + cgraph_node *node = lsei_cgraph_node (lsei); + if (node->has_gimple_body_p () + && func_sums->get (node) != NULL) + count++; + } + streamer_write_uhwi (ob, count); + + /* Process all of the functions. */ + for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei); + lsei_next_function_in_partition (&lsei)) + { + cgraph_node *node = lsei_cgraph_node (lsei); + if (node->has_gimple_body_p () + && func_sums->get (node) != NULL) + isra_write_node_summary (ob, node); + } + streamer_write_char_stream (ob->main_stream, 0); + produce_asm (ob, NULL); + destroy_output_block (ob); +} + +/* Read intraproceural analysis information about E and all of its outgoing + edges into a stream for LTO WPA. */ + +static void +isra_read_edge_summary (struct lto_input_block *ib, cgraph_edge *cs) +{ + isra_call_summary *csum = call_sums->get_create (cs); + unsigned input_count = streamer_read_uhwi (ib); + csum->init_inputs (input_count); + for (unsigned i = 0; i < input_count; i++) + { + isra_param_flow *ipf = &csum->m_arg_flow[i]; + ipf->length = streamer_read_hwi (ib); + bitpack_d bp = streamer_read_bitpack (ib); + for (int j = 0; j < ipf->length; j++) + ipf->inputs[j] = bp_unpack_value (&bp, 8); + ipf->aggregate_pass_through = bp_unpack_value (&bp, 1); + ipf->pointer_pass_through = bp_unpack_value (&bp, 1); + ipf->safe_to_import_accesses = bp_unpack_value (&bp, 1); + ipf->unit_offset = streamer_read_uhwi (ib); + ipf->unit_size = streamer_read_uhwi (ib); + } + bitpack_d bp = streamer_read_bitpack (ib); + csum->m_return_ignored = bp_unpack_value (&bp, 1); + csum->m_return_returned = bp_unpack_value (&bp, 1); + csum->m_bit_aligned_arg = bp_unpack_value (&bp, 1); +} + +/* Read intraproceural analysis information about NODE and all of its outgoing + edges into a stream for LTO WPA. */ + +static void +isra_read_node_info (struct lto_input_block *ib, cgraph_node *node, + struct data_in *data_in) +{ + isra_func_summary *ifs = func_sums->get_create (node); + unsigned param_desc_count = streamer_read_uhwi (ib); + if (param_desc_count > 0) + { + vec_safe_reserve_exact (ifs->m_parameters, param_desc_count); + ifs->m_parameters->quick_grow_cleared (param_desc_count); + } + for (unsigned i = 0; i < param_desc_count; i++) + { + isra_param_desc *desc = &(*ifs->m_parameters)[i]; + unsigned access_count = streamer_read_uhwi (ib); + for (unsigned j = 0; j < access_count; j++) + { + param_access *acc = ggc_cleared_alloc (); + acc->type = stream_read_tree (ib, data_in); + acc->alias_ptr_type = stream_read_tree (ib, data_in); + acc->unit_offset = streamer_read_uhwi (ib); + acc->unit_size = streamer_read_uhwi (ib); + bitpack_d bp = streamer_read_bitpack (ib); + acc->certain = bp_unpack_value (&bp, 1); + vec_safe_push (desc->accesses, acc); + } + desc->param_size_limit = streamer_read_uhwi (ib); + desc->size_reached = streamer_read_uhwi (ib); + bitpack_d bp = streamer_read_bitpack (ib); + desc->locally_unused = bp_unpack_value (&bp, 1); + desc->split_candidate = bp_unpack_value (&bp, 1); + desc->by_ref = bp_unpack_value (&bp, 1); + } + bitpack_d bp = streamer_read_bitpack (ib); + ifs->m_candidate = bp_unpack_value (&bp, 1); + ifs->m_returns_value = bp_unpack_value (&bp, 1); + ifs->m_return_ignored = bp_unpack_value (&bp, 1); + ifs->m_queued = 0; + + for (cgraph_edge *e = node->callees; e; e = e->next_callee) + isra_read_edge_summary (ib, e); + for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee) + isra_read_edge_summary (ib, e); +} + +/* Read IPA-SRA summaries from a section in file FILE_DATA of length LEN with + data DATA. TODO: This function was copied almost verbatim from ipa-prop.c, + it should be possible to unify them somehow. */ + +static void +isra_read_summary_section (struct lto_file_decl_data *file_data, + const char *data, size_t len) +{ + const struct lto_function_header *header = + (const struct lto_function_header *) data; + const int cfg_offset = sizeof (struct lto_function_header); + const int main_offset = cfg_offset + header->cfg_size; + const int string_offset = main_offset + header->main_size; + struct data_in *data_in; + unsigned int i; + unsigned int count; + + lto_input_block ib_main ((const char *) data + main_offset, + header->main_size, file_data->mode_table); + + data_in = + lto_data_in_create (file_data, (const char *) data + string_offset, + header->string_size, vNULL); + count = streamer_read_uhwi (&ib_main); + + for (i = 0; i < count; i++) + { + unsigned int index; + struct cgraph_node *node; + lto_symtab_encoder_t encoder; + + index = streamer_read_uhwi (&ib_main); + encoder = file_data->symtab_node_encoder; + node = dyn_cast (lto_symtab_encoder_deref (encoder, + index)); + gcc_assert (node->definition); + isra_read_node_info (&ib_main, node, data_in); + } + lto_free_section_data (file_data, LTO_section_ipa_sra, NULL, data, + len); + lto_data_in_delete (data_in); +} + +/* Read intraproceural analysis information into a stream for LTO WPA. */ + +static void +ipa_sra_read_summary (void) +{ + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); + struct lto_file_decl_data *file_data; + unsigned int j = 0; + + gcc_checking_assert (!func_sums); + gcc_checking_assert (!call_sums); + func_sums + = (new (ggc_cleared_alloc ()) + ipa_sra_function_summaries (symtab, true)); + call_sums = new ipa_sra_call_summaries (symtab); + + while ((file_data = file_data_vec[j++])) + { + size_t len; + const char *data = lto_get_section_data (file_data, LTO_section_ipa_sra, + NULL, &len); + if (data) + isra_read_summary_section (file_data, data, len); + } +} + +/* Dump all IPA-SRA summary data for all cgraph nodes and edges to file F. */ + +static void +ipa_sra_dump_all_summaries (FILE *f) +{ + cgraph_node *node; + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) + { + fprintf (f, "\nSummary for node %s:\n", node->dump_name ()); + + isra_func_summary *ifs = func_sums->get (node); + if (!ifs) + { + fprintf (f, " Function does not have any associated IPA-SRA " + "summary\n"); + continue; + } + if (!ifs->m_candidate) + { + fprintf (f, " Not a candidate function\n"); + continue; + } + if (ifs->m_returns_value) + fprintf (f, " Returns value\n"); + if (vec_safe_is_empty (ifs->m_parameters)) + fprintf (f, " No parameter information. \n"); + else + for (unsigned i = 0; i < ifs->m_parameters->length (); ++i) + { + fprintf (f, " Descriptor for parameter %i:\n", i); + dump_isra_param_descriptor (f, &(*ifs->m_parameters)[i]); + } + fprintf (f, "\n"); + + struct cgraph_edge *cs; + for (cs = node->callees; cs; cs = cs->next_callee) + { + fprintf (f, " Summary for edge %s->%s:\n", cs->caller->dump_name (), + cs->callee->dump_name ()); + isra_call_summary *csum = call_sums->get (cs); + if (csum) + csum->dump (f); + else + fprintf (f, " Call summary is MISSING!\n"); + } + + } + fprintf (f, "\n\n"); +} + +/* Perform function-scope viability tests that can be only made at IPA level + and return false if the function is deemed unsuitable for IPA-SRA. */ + +static bool +ipa_sra_ipa_function_checks (cgraph_node *node) +{ + if (!node->can_be_local_p ()) + { + if (dump_file) + fprintf (dump_file, "Function %s disqualified because it cannot be " + "made local.\n", node->dump_name ()); + return false; + } + if (!node->local.can_change_signature) + { + if (dump_file) + fprintf (dump_file, "Function can not change signature.\n"); + return false; + } + + return true; +} + +/* Issues found out by check_callers_for_issues. */ + +struct caller_issues +{ + /* There is a thunk among callers. */ + bool thunk; + /* Call site with no available information. */ + bool unknown_callsite; + /* There is a bit-aligned load into one of non-gimple-typed arguments. */ + bool bit_aligned_aggregate_argument; +}; + +/* Worker for call_for_symbol_and_aliases, set any flags of passed caller_issues + that apply. */ + +static bool +check_for_caller_issues (struct cgraph_node *node, void *data) +{ + struct caller_issues *issues = (struct caller_issues *) data; + + for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) + { + if (cs->caller->thunk.thunk_p) + { + issues->thunk = true; + /* TODO: We should be able to process at least some types of + thunks. */ + return true; + } + + isra_call_summary *csum = call_sums->get (cs); + if (!csum) + { + issues->unknown_callsite = true; + return true; + } + + if (csum->m_bit_aligned_arg) + issues->bit_aligned_aggregate_argument = true; + } + return false; +} + +/* Look at all incoming edges to NODE, including aliases and thunks and look + for problems. Return true if NODE type should not be modified at all. */ + +static bool +check_all_callers_for_issues (cgraph_node *node) +{ + struct caller_issues issues; + memset (&issues, 0, sizeof (issues)); + + node->call_for_symbol_and_aliases (check_for_caller_issues, &issues, true); + if (issues.unknown_callsite) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "A call of %s has not been analyzed. Disabling " + "all modifications.\n", node->dump_name ()); + return true; + } + /* TODO: We should be able to process at least some types of thunks. */ + if (issues.thunk) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "A call of %s is through thunk, which are not" + " handled yet. Disabling all modifications.\n", + node->dump_name ()); + return true; + } + + if (issues.bit_aligned_aggregate_argument) + { + /* Let's only remove parameters/return values from such functions. + TODO: We could only prevent splitting the problematic parameters if + anybody thinks it is worth it. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "A call of %s has bit-alinged aggregate argument," + " disabling parameter splitting.\n", node->dump_name ()); + + isra_func_summary *ifs = func_sums->get (node); + gcc_checking_assert (ifs); + unsigned param_count = vec_safe_length (ifs->m_parameters); + for (unsigned i = 0; i < param_count; i++) + (*ifs->m_parameters)[i].split_candidate = false; + } + return false; +} + +/* Find the access with corresponding OFFSET and SIZE among accesses in + PARAM_DESC and return it or NULL if such an access is not there. */ + +static param_access * +find_param_access (isra_param_desc *param_desc, unsigned offset, unsigned size) +{ + unsigned pclen = vec_safe_length (param_desc->accesses); + + /* The search is linear but the number of stored accesses is bound by + PARAM_IPA_SRA_MAX_REPLACEMENTS, so most probably 8. */ + + for (unsigned i = 0; i < pclen; i++) + if ((*param_desc->accesses)[i]->unit_offset == offset + && (*param_desc->accesses)[i]->unit_size == size) + return (*param_desc->accesses)[i]; + + return NULL; +} + +/* Return iff the total size of definite replacement SIZE would violate the + limit set for it in PARAM. */ + +static bool +size_would_violate_limit_p (isra_param_desc *desc, unsigned size) +{ + unsigned limit = desc->param_size_limit; + if (size > limit + || (!desc->by_ref && size == limit)) + return true; + return false; +} + +/* Increase reached size of DESC by SIZE or disqualify it if it would violate + the set limit. IDX is the parameter number which is dumped when + disqualifying. */ + +static void +bump_reached_size (isra_param_desc *desc, unsigned size, unsigned idx) +{ + unsigned after = desc->size_reached + size; + if (size_would_violate_limit_p (desc, after)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " ...size limit reached, disqualifying " + "candidate parameter %u\n", idx); + desc->split_candidate = false; + return; + } + desc->size_reached = after; +} + +/* Take all actions required to deal with an edge CS that represents a call to + an unknown or un-analyzed function, for both parameter removal and + splitting. */ + +static void +process_edge_to_unknown_caller (cgraph_edge *cs) +{ + isra_func_summary *from_ifs = func_sums->get (cs->caller); + gcc_checking_assert (from_ifs); + isra_call_summary *csum = call_sums->get (cs); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Processing an edge to an unknown caller from %s:\n", + cs->caller->dump_name ()); + + unsigned args_count = csum->m_arg_flow.length (); + for (unsigned i = 0; i < args_count; i++) + { + isra_param_flow *ipf = &csum->m_arg_flow[i]; + + if (ipf->pointer_pass_through) + { + isra_param_desc *param_desc + = &(*from_ifs->m_parameters)[get_single_param_flow_source (ipf)]; + param_desc->locally_unused = false; + param_desc->split_candidate = false; + continue; + } + if (ipf->aggregate_pass_through) + { + unsigned idx = get_single_param_flow_source (ipf); + isra_param_desc *param_desc = &(*from_ifs->m_parameters)[idx]; + + param_desc->locally_unused = false; + if (!param_desc->split_candidate) + continue; + gcc_assert (!param_desc->by_ref); + param_access *pacc = find_param_access (param_desc, ipf->unit_offset, + ipf->unit_size); + gcc_checking_assert (pacc); + pacc->certain = true; + if (overlapping_certain_accesses_p (param_desc, NULL)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " ...leading to overlap, " + " disqualifying candidate parameter %u\n", + idx); + param_desc->split_candidate = false; + } + else + bump_reached_size (param_desc, pacc->unit_size, idx); + ipf->aggregate_pass_through = false; + continue; + } + + for (int j = 0; j < ipf->length; j++) + { + int input_idx = ipf->inputs[j]; + (*from_ifs->m_parameters)[input_idx].locally_unused = false; + } + } +} + +/* Propagate parameter removal information through cross-SCC edge CS, + i.e. decrease the use count in the caller parameter descriptor for each use + in this call. */ + +static void +param_removal_cross_scc_edge (cgraph_edge *cs) +{ + enum availability availability; + cgraph_node *callee = cs->callee->function_symbol (&availability); + isra_func_summary *to_ifs = func_sums->get (callee); + if (!to_ifs || !to_ifs->m_candidate + || (availability < AVAIL_AVAILABLE) + || vec_safe_is_empty (to_ifs->m_parameters)) + { + process_edge_to_unknown_caller (cs); + return; + } + isra_func_summary *from_ifs = func_sums->get (cs->caller); + gcc_checking_assert (from_ifs); + + isra_call_summary *csum = call_sums->get (cs); + unsigned args_count = csum->m_arg_flow.length (); + unsigned param_count = vec_safe_length (to_ifs->m_parameters); + + for (unsigned i = 0; i < args_count; i++) + { + bool unused_in_callee; + if (i < param_count) + unused_in_callee = (*to_ifs->m_parameters)[i].locally_unused; + else + unused_in_callee = false; + + if (!unused_in_callee) + { + isra_param_flow *ipf = &csum->m_arg_flow[i]; + for (int j = 0; j < ipf->length; j++) + { + int input_idx = ipf->inputs[j]; + (*from_ifs->m_parameters)[input_idx].locally_unused = false; + } + } + } +} + +/* Unless it is already there, push NODE which is also described by IFS to + STACK. */ + +static void +isra_push_node_to_stack (cgraph_node *node, isra_func_summary *ifs, + vec *stack) +{ + if (!ifs->m_queued) + { + ifs->m_queued = true; + stack->safe_push (node); + } +} + +/* If parameter with index INPUT_IDX is marked as locally unused, mark it as + used and push CALLER on STACK. */ + +static void +isra_mark_caller_param_used (isra_func_summary *from_ifs, int input_idx, + cgraph_node *caller, vec *stack) +{ + if ((*from_ifs->m_parameters)[input_idx].locally_unused) + { + (*from_ifs->m_parameters)[input_idx].locally_unused = false; + isra_push_node_to_stack (caller, from_ifs, stack); + } +} + + +/* Propagate information that any parameter is not used only locally within a + SCC accross CS to the caller, which must be in the same SCC as the + callee. Push any callers that need to be re-processed to STACK. */ + +static void +propagate_used_across_scc_edge (cgraph_edge *cs, vec *stack) +{ + isra_func_summary *from_ifs = func_sums->get (cs->caller); + if (!from_ifs || vec_safe_is_empty (from_ifs->m_parameters)) + return; + + isra_call_summary *csum = call_sums->get (cs); + gcc_checking_assert (csum); + unsigned args_count = csum->m_arg_flow.length (); + enum availability availability; + cgraph_node *callee = cs->callee->function_symbol (&availability); + isra_func_summary *to_ifs = func_sums->get (callee); + + unsigned param_count + = (to_ifs && (availability >= AVAIL_AVAILABLE)) + ? vec_safe_length (to_ifs->m_parameters) : 0; + for (unsigned i = 0; i < args_count; i++) + { + if (i < param_count + && (*to_ifs->m_parameters)[i].locally_unused) + continue; + + /* The argument is needed in the callee it, we must mark the parameter as + used also in the caller and its callers within this SCC. */ + isra_param_flow *ipf = &csum->m_arg_flow[i]; + for (int j = 0; j < ipf->length; j++) + { + int input_idx = ipf->inputs[j]; + isra_mark_caller_param_used (from_ifs, input_idx, cs->caller, stack); + } + } +} + +/* Propagate information that any parameter is not used only locally within a + SCC (i.e. is used also elsewhere) to all callers of NODE that are in the + same SCC. Push any callers that need to be re-processed to STACK. */ + +static bool +propagate_used_to_scc_callers (cgraph_node *node, void *data) +{ + vec *stack = (vec *) data; + cgraph_edge *cs; + for (cs = node->callers; cs; cs = cs->next_caller) + if (ipa_edge_within_scc (cs)) + propagate_used_across_scc_edge (cs, stack); + return false; +} + +/* Return true iff all certain accesses in ARG_DESC are also present as + certain accesses in PARAM_DESC. */ + +static bool +all_callee_accesses_present_p (isra_param_desc *param_desc, + isra_param_desc *arg_desc) +{ + unsigned aclen = vec_safe_length (arg_desc->accesses); + for (unsigned j = 0; j < aclen; j++) + { + param_access *argacc = (*arg_desc->accesses)[j]; + if (!argacc->certain) + continue; + param_access *pacc = find_param_access (param_desc, argacc->unit_offset, + argacc->unit_size); + if (!pacc || !pacc->certain) + return false; + } + return true; +} + +/* Type internal to function pull_accesses_from_callee. Unfortunately gcc 4.8 + does not allow instantiating an auto_vec with a type defined within a + function so it is a global type. */ +enum acc_prop_kind {ACC_PROP_DONT, ACC_PROP_COPY, ACC_PROP_CERTAIN}; + + +/* Attempt to propagate all definite accesses from ARG_DESC to PARAM_DESC, if + they would not violate some constraint there. If successful, return NULL, + otherwise return the string reason for failure (which can be written to the + dump file). DELTA_OFFSET is the known offset of the actual argument withing + the formal parameter (so of ARG_DESCS within PARAM_DESCS), ARG_SIZE is the + size of the actual argument or zero, if not known. In case of success, set + *CHANGE_P to true if propagation actually changed anything. */ + +static const char * +pull_accesses_from_callee (isra_param_desc *param_desc, + isra_param_desc *arg_desc, + unsigned delta_offset, unsigned arg_size, + bool *change_p) +{ + unsigned pclen = vec_safe_length (param_desc->accesses); + unsigned aclen = vec_safe_length (arg_desc->accesses); + unsigned prop_count = 0; + unsigned prop_size = 0; + bool change = false; + + auto_vec prop_kinds (aclen); + for (unsigned j = 0; j < aclen; j++) + { + param_access *argacc = (*arg_desc->accesses)[j]; + prop_kinds.safe_push (ACC_PROP_DONT); + + if (arg_size > 0 + && argacc->unit_offset + argacc->unit_size > arg_size) + return "callee access outsize size boundary"; + + if (!argacc->certain) + continue; + + unsigned offset = argacc->unit_offset + delta_offset; + /* Given that accesses are initially stored according to increasing + offset and decreasing size in case of equal offsets, the following + searches could be written more efficiently if we kept the ordering + when copying. But the number of accesses is capped at + PARAM_IPA_SRA_MAX_REPLACEMENTS (so most likely 8) and the code gets + messy quickly, so let's improve on that only if necessary. */ + + bool exact_match = false; + for (unsigned i = 0; i < pclen; i++) + { + /* Check for overlaps. */ + param_access *pacc = (*param_desc->accesses)[i]; + if (pacc->unit_offset == offset + && pacc->unit_size == argacc->unit_size) + { + if (argacc->alias_ptr_type != pacc->alias_ptr_type + || !types_compatible_p (argacc->type, pacc->type)) + return "propagated access types would not match existing ones"; + + exact_match = true; + if (!pacc->certain) + { + prop_kinds[j] = ACC_PROP_CERTAIN; + prop_size += argacc->unit_size; + change = true; + } + continue; + } + + if (offset < pacc->unit_offset + pacc->unit_size + && offset + argacc->unit_size > pacc->unit_offset) + { + /* None permissible with load accesses, possible to fit into + argument ones. */ + if (pacc->certain + || offset < pacc->unit_offset + || (offset + argacc->unit_size + > pacc->unit_offset + pacc->unit_size)) + return "a propagated access would conflict in caller"; + } + } + + if (!exact_match) + { + prop_kinds[j] = ACC_PROP_COPY; + prop_count++; + prop_size += argacc->unit_size; + change = true; + } + } + + if (!change) + return NULL; + + if ((prop_count + pclen + > (unsigned) PARAM_VALUE (PARAM_IPA_SRA_MAX_REPLACEMENTS)) + || size_would_violate_limit_p (param_desc, + param_desc->size_reached + prop_size)) + return "propagating accesses would violate the count or size limit"; + + *change_p = true; + for (unsigned j = 0; j < aclen; j++) + { + if (prop_kinds[j] == ACC_PROP_COPY) + { + param_access *argacc = (*arg_desc->accesses)[j]; + + param_access *copy = ggc_cleared_alloc (); + copy->unit_offset = argacc->unit_offset + delta_offset; + copy->unit_size = argacc->unit_size; + copy->type = argacc->type; + copy->alias_ptr_type = argacc->alias_ptr_type; + copy->certain = true; + vec_safe_push (param_desc->accesses, copy); + } + else if (prop_kinds[j] == ACC_PROP_CERTAIN) + { + param_access *argacc = (*arg_desc->accesses)[j]; + param_access *csp + = find_param_access (param_desc, argacc->unit_offset + delta_offset, + argacc->unit_size); + csp->certain = true; + } + } + + param_desc->size_reached += prop_size; + + return NULL; +} + +/* Propagate parameter splitting information through call graph edge CS. + Return true if any changes that might need to be propagated within SCCs have + been made. The function also clears the aggregate_pass_through and + pointer_pass_through in call summarries which do not need to be processed + again if this CS is revisited when iterating while changes are propagated + within an SCC. */ + +static bool +param_splitting_across_edge (cgraph_edge *cs) +{ + bool res = false; + bool cross_scc = !ipa_edge_within_scc (cs); + enum availability availability; + cgraph_node *callee = cs->callee->function_symbol (&availability); + isra_func_summary *from_ifs = func_sums->get (cs->caller); + gcc_checking_assert (from_ifs && from_ifs->m_parameters); + + isra_call_summary *csum = call_sums->get (cs); + gcc_checking_assert (csum); + unsigned args_count = csum->m_arg_flow.length (); + isra_func_summary *to_ifs = func_sums->get (callee); + unsigned param_count + = ((to_ifs && to_ifs->m_candidate && (availability >= AVAIL_AVAILABLE)) + ? vec_safe_length (to_ifs->m_parameters) + : 0); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Splitting accross %s->%s:\n", + cs->caller->dump_name (), callee->dump_name ()); + + unsigned i; + for (i = 0; (i < args_count) && (i < param_count); i++) + { + isra_param_desc *arg_desc = &(*to_ifs->m_parameters)[i]; + isra_param_flow *ipf = &csum->m_arg_flow[i]; + + if (arg_desc->locally_unused) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " ->%u: unused in callee\n", i); + ipf->pointer_pass_through = false; + continue; + } + + if (ipf->pointer_pass_through) + { + int idx = get_single_param_flow_source (ipf); + isra_param_desc *param_desc = &(*from_ifs->m_parameters)[idx]; + if (!param_desc->split_candidate) + continue; + gcc_assert (param_desc->by_ref); + + if (!arg_desc->split_candidate || !arg_desc->by_ref) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: not candidate or not by " + "reference in callee\n", idx, i); + param_desc->split_candidate = false; + ipf->pointer_pass_through = false; + res = true; + } + else if (!ipf->safe_to_import_accesses) + { + if (!all_callee_accesses_present_p (param_desc, arg_desc)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: cannot import accesses.\n", + idx, i); + param_desc->split_candidate = false; + ipf->pointer_pass_through = false; + res = true; + + } + else + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: verified callee accesses " + "present.\n", idx, i); + if (cross_scc) + ipf->pointer_pass_through = false; + } + } + else + { + const char *pull_failure + = pull_accesses_from_callee (param_desc, arg_desc, 0, 0, &res); + if (pull_failure) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: by_ref access pull " + "failed: %s.\n", idx, i, pull_failure); + param_desc->split_candidate = false; + ipf->pointer_pass_through = false; + res = true; + } + else + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: by_ref access pull " + "succeeded.\n", idx, i); + if (cross_scc) + ipf->pointer_pass_through = false; + } + } + } + else if (ipf->aggregate_pass_through) + { + int idx = get_single_param_flow_source (ipf); + isra_param_desc *param_desc = &(*from_ifs->m_parameters)[idx]; + if (!param_desc->split_candidate) + continue; + gcc_assert (!param_desc->by_ref); + param_access *pacc = find_param_access (param_desc, ipf->unit_offset, + ipf->unit_size); + gcc_checking_assert (pacc); + + if (pacc->certain) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: already certain\n", idx, i); + ipf->aggregate_pass_through = false; + } + else if (!arg_desc->split_candidate || arg_desc->by_ref) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: not candidate or by " + "reference in callee\n", idx, i); + + pacc->certain = true; + if (overlapping_certain_accesses_p (param_desc, NULL)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " ...leading to overlap, " + " disqualifying candidate parameter %u\n", + idx); + param_desc->split_candidate = false; + } + else + bump_reached_size (param_desc, pacc->unit_size, idx); + + ipf->aggregate_pass_through = false; + res = true; + } + else + { + const char *pull_failure + = pull_accesses_from_callee (param_desc, arg_desc, + ipf->unit_offset, + ipf->unit_size, &res); + if (pull_failure) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: arg access pull " + "failed: %s.\n", idx, i, pull_failure); + + ipf->aggregate_pass_through = false; + pacc->certain = true; + + if (overlapping_certain_accesses_p (param_desc, NULL)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " ...leading to overlap, " + " disqualifying candidate parameter %u\n", + idx); + param_desc->split_candidate = false; + } + else + bump_reached_size (param_desc, pacc->unit_size, idx); + + res = true; + } + else + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: arg access pull " + "succeeded.\n", idx, i); + if (cross_scc) + ipf->aggregate_pass_through = false; + } + } + } + } + + /* Handle argument-parameter count mismatches. */ + for (; (i < args_count); i++) + { + isra_param_flow *ipf = &csum->m_arg_flow[i]; + + if (ipf->pointer_pass_through || ipf->aggregate_pass_through) + { + int idx = get_single_param_flow_source (ipf); + ipf->pointer_pass_through = false; + ipf->aggregate_pass_through = false; + isra_param_desc *param_desc = &(*from_ifs->m_parameters)[idx]; + if (!param_desc->split_candidate) + continue; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: no corresponding formal parameter\n", + idx, i); + param_desc->split_candidate = false; + res = true; + } + } + return res; +} + +/* Worker for call_for_symbol_and_aliases, look at all callers and if all their + callers ignore the return value, or come from the same SCC and use the + return value only to compute their return value, return false, otherwise + return true. */ + +static bool +retval_used_p (cgraph_node *node, void *) +{ + for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) + { + isra_call_summary *csum = call_sums->get (cs); + gcc_checking_assert (csum); + if (csum->m_return_ignored) + continue; + if (!csum->m_return_returned) + return true; + + isra_func_summary *from_ifs = func_sums->get (cs->caller); + if (!from_ifs || !from_ifs->m_candidate) + return true; + + if (!ipa_edge_within_scc (cs) + && !from_ifs->m_return_ignored) + return true; + } + + return false; +} + +/* Push into NEW_PARAMS all required parameter adjustment entries to copy or + modify parameter which originally had index BASE_INDEX, in the adjustment + vector of parent clone (if any) had PREV_CLONE_INDEX and was described by + PREV_ADJUSTMENT. If the parent clone is the original function, + PREV_ADJUSTMENT is NULL and PREV_CLONE_INDEX is equal to BASE_INDEX. */ + + +static void +push_param_adjustments_for_index (isra_func_summary *ifs, unsigned base_index, + unsigned prev_clone_index, + ipa_adjusted_param *prev_adjustment, + vec **new_params) +{ + isra_param_desc *desc = &(*ifs->m_parameters)[base_index]; + if (desc->locally_unused) + { + if (dump_file) + fprintf (dump_file, " Will remove parameter %u\n", base_index); + return; + } + + if (!desc->split_candidate) + { + ipa_adjusted_param adj; + if (prev_adjustment) + { + adj = *prev_adjustment; + adj.prev_clone_adjustment = true; + adj.prev_clone_index = prev_clone_index; + } + else + { + memset (&adj, 0, sizeof (adj)); + adj.op = IPA_PARAM_OP_COPY; + adj.base_index = base_index; + adj.prev_clone_index = prev_clone_index; + } + vec_safe_push ((*new_params), adj); + return; + } + + if (dump_file) + fprintf (dump_file, " Will split parameter %u\n", base_index); + + gcc_assert (!prev_adjustment || prev_adjustment->op == IPA_PARAM_OP_COPY); + unsigned aclen = vec_safe_length (desc->accesses); + for (unsigned j = 0; j < aclen; j++) + { + param_access *pa = (*desc->accesses)[j]; + if (!pa->certain) + continue; + if (dump_file) + fprintf (dump_file, " - component at byte offset %u, " + "size %u\n", pa->unit_offset, pa->unit_size); + + ipa_adjusted_param adj; + memset (&adj, 0, sizeof (adj)); + adj.op = IPA_PARAM_OP_SPLIT; + adj.base_index = base_index; + adj.prev_clone_index = prev_clone_index; + adj.param_prefix_index = IPA_PARAM_PREFIX_ISRA; + adj.reverse = pa->reverse; + adj.type = pa->type; + adj.alias_ptr_type = pa->alias_ptr_type; + adj.unit_offset = pa->unit_offset; + vec_safe_push ((*new_params), adj); + } +} + + +/* Do finall processing of results of IPA propagation regarding NODE, clone it + if appropriate. */ + +static void +process_isra_node_results (cgraph_node *node, + hash_map *clone_num_suffixes) +{ + isra_func_summary *ifs = func_sums->get (node); + if (!ifs || !ifs->m_candidate) + return; + + auto_vec surviving_params; + bool check_surviving = false; + if (node->clone.param_adjustments) + { + check_surviving = true; + node->clone.param_adjustments->get_surviving_params (&surviving_params); + } + + unsigned param_count = vec_safe_length (ifs->m_parameters); + bool will_change_function = false; + if (ifs->m_returns_value && ifs->m_return_ignored) + will_change_function = true; + else + for (unsigned i = 0; i < param_count; i++) + { + isra_param_desc *desc = &(*ifs->m_parameters)[i]; + if ((desc->locally_unused || desc->split_candidate) + /* Make sure we do not clone just to attempt to remove an already + removed unused argument. */ + && (!check_surviving + || (i < surviving_params.length () + && surviving_params[i]))) + { + will_change_function = true; + break; + } + } + if (!will_change_function) + return; + + if (dump_file) + { + fprintf (dump_file, "\nEvaluating analysis results for %s\n", + node->dump_name ()); + if (ifs->m_returns_value && ifs->m_return_ignored) + fprintf (dump_file, " Will remove return value.\n"); + } + + vec *new_params = NULL; + if (ipa_param_adjustments *old_adjustments = node->clone.param_adjustments) + { + unsigned old_adj_len = vec_safe_length (old_adjustments->m_adj_params); + for (unsigned i = 0; i < old_adj_len; i++) + { + ipa_adjusted_param *old_adj = &(*old_adjustments->m_adj_params)[i]; + push_param_adjustments_for_index (ifs, old_adj->base_index, i, + old_adj, &new_params); + } + } + else + for (unsigned i = 0; i < param_count; i++) + push_param_adjustments_for_index (ifs, i, i, NULL, &new_params); + + ipa_param_adjustments *new_adjustments + = (new (ggc_alloc ()) + ipa_param_adjustments (new_params, param_count, + ifs->m_returns_value && ifs->m_return_ignored)); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\n Created adjustments:\n"); + new_adjustments->dump (dump_file); + } + + unsigned &suffix_counter = clone_num_suffixes->get_or_insert ( + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME ( + node->decl))); + vec callers = node->collect_callers (); + cgraph_node *new_node + = node->create_virtual_clone (callers, NULL, new_adjustments, "isra", + suffix_counter); + suffix_counter++; + + if (dump_file) + fprintf (dump_file, " Created new node %s\n", new_node->dump_name ()); + callers.release (); +} + +/* Check which parameters of NODE described by IFS have survived until IPA-SRA + and disable transformations for those which have not or which should not + transformed because the associated debug counter reached its limit. Return + true if none survived or if there were no candidates to begin with. */ + +static bool +disable_unavailable_parameters (cgraph_node *node, isra_func_summary *ifs) +{ + bool ret = true; + unsigned len = vec_safe_length (ifs->m_parameters); + if (!len) + return true; + + auto_vec surviving_params; + bool check_surviving = false; + if (node->clone.param_adjustments) + { + check_surviving = true; + node->clone.param_adjustments->get_surviving_params (&surviving_params); + } + bool dumped_first = false; + for (unsigned i = 0; i < len; i++) + { + isra_param_desc *desc = &(*ifs->m_parameters)[i]; + if (!dbg_cnt (ipa_sra_params)) + { + desc->locally_unused = false; + desc->split_candidate = false; + } + else if (check_surviving + && (i >= surviving_params.length () + || !surviving_params[i])) + { + /* Even if the parameter was removed by a previous IPA pass, we do + not clear locally_unused because if it really is unused, this + information might be useful in callers. */ + desc->split_candidate = false; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + if (!dumped_first) + { + fprintf (dump_file, + "The following parameters of %s are dead on " + "arrival:", node->dump_name ()); + dumped_first = true; + } + fprintf (dump_file, " %u", i); + } + } + else if (desc->locally_unused || desc->split_candidate) + ret = false; + } + + if (dumped_first) + fprintf (dump_file, "\n"); + + return ret; +} + + +/* Run the interprocedural part of IPA-SRA. */ + +static unsigned int +ipa_sra_analysis (void) +{ + if (dump_file) + { + fprintf (dump_file, "\n========== IPA-SRA IPA stage ==========\n"); + ipa_sra_dump_all_summaries (dump_file); + } + + gcc_checking_assert (func_sums); + gcc_checking_assert (call_sums); + cgraph_node **order = XCNEWVEC (cgraph_node *, symtab->cgraph_count); + auto_vec stack; + int node_scc_count = ipa_reduced_postorder (order, true, NULL); + + /* One sweep from callees to callers for parameter removal and splitting. */ + for (int i = 0; i < node_scc_count; i++) + { + cgraph_node *scc_rep = order[i]; + vec cycle_nodes = ipa_get_nodes_in_cycle (scc_rep); + unsigned j; + + /* Preliminary IPA function level checks and first step of parameter + removal. */ + cgraph_node *v; + FOR_EACH_VEC_ELT (cycle_nodes, j, v) + { + isra_func_summary *ifs = func_sums->get (v); + if (!ifs || !ifs->m_candidate) + continue; + if (!ipa_sra_ipa_function_checks (v) + || check_all_callers_for_issues (v)) + { + ifs->zap (); + continue; + } + if (disable_unavailable_parameters (v, ifs)) + continue; + for (cgraph_edge *cs = v->indirect_calls; cs; cs = cs->next_callee) + process_edge_to_unknown_caller (cs); + for (cgraph_edge *cs = v->callees; cs; cs = cs->next_callee) + if (!ipa_edge_within_scc (cs)) + param_removal_cross_scc_edge (cs); + } + + /* Look at edges within the current SCC and propagate used-ness accross + them, pushing onto the stack all notes which might need to be + revisited. */ + FOR_EACH_VEC_ELT (cycle_nodes, j, v) + v->call_for_symbol_thunks_and_aliases (propagate_used_to_scc_callers, + &stack, true); + + /* Keep revisiting and pushing until nothing changes. */ + while (!stack.is_empty ()) + { + cgraph_node *v = stack.pop (); + isra_func_summary *ifs = func_sums->get (v); + gcc_checking_assert (ifs && ifs->m_queued); + ifs->m_queued = false; + + v->call_for_symbol_thunks_and_aliases (propagate_used_to_scc_callers, + &stack, true); + } + + /* Parameter splitting. */ + bool repeat_scc_access_propagation; + do + { + repeat_scc_access_propagation = false; + FOR_EACH_VEC_ELT (cycle_nodes, j, v) + { + isra_func_summary *ifs = func_sums->get (v); + if (!ifs + || !ifs->m_candidate + || vec_safe_is_empty (ifs->m_parameters)) + continue; + for (cgraph_edge *cs = v->callees; cs; cs = cs->next_callee) + if (param_splitting_across_edge (cs)) + repeat_scc_access_propagation = true; + } + } + while (repeat_scc_access_propagation); + + if (flag_checking) + FOR_EACH_VEC_ELT (cycle_nodes, j, v) + verify_splitting_accesses (v, true); + + cycle_nodes.release (); + } + + /* One sweep from caller to callees for result removal. */ + for (int i = node_scc_count - 1; i >= 0 ; i--) + { + cgraph_node *scc_rep = order[i]; + vec cycle_nodes = ipa_get_nodes_in_cycle (scc_rep); + unsigned j; + + cgraph_node *v; + FOR_EACH_VEC_ELT (cycle_nodes, j, v) + { + isra_func_summary *ifs = func_sums->get (v); + if (!ifs || !ifs->m_candidate) + continue; + + bool return_needed + = (ifs->m_returns_value + && (!dbg_cnt (ipa_sra_retvalues) + || v->call_for_symbol_and_aliases (retval_used_p, + NULL, true))); + ifs->m_return_ignored = !return_needed; + if (return_needed) + isra_push_node_to_stack (v, ifs, &stack); + } + + while (!stack.is_empty ()) + { + cgraph_node *node = stack.pop (); + isra_func_summary *ifs = func_sums->get (node); + gcc_checking_assert (ifs && ifs->m_queued); + ifs->m_queued = false; + + for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) + if (ipa_edge_within_scc (cs) + && call_sums->get (cs)->m_return_returned) + { + enum availability av; + cgraph_node *callee = cs->callee->function_symbol (&av); + isra_func_summary *to_ifs = func_sums->get (callee); + if (to_ifs && to_ifs->m_return_ignored) + { + to_ifs->m_return_ignored = false; + isra_push_node_to_stack (callee, to_ifs, &stack); + } + } + } + cycle_nodes.release (); + } + + ipa_free_postorder_info (); + free (order); + + if (dump_file) + { + if (dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "\n========== IPA-SRA propagation final state " + " ==========\n"); + ipa_sra_dump_all_summaries (dump_file); + } + fprintf (dump_file, "\n========== IPA-SRA decisions ==========\n"); + } + + hash_map *clone_num_suffixes + = new hash_map; + + cgraph_node *node; + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) + process_isra_node_results (node, clone_num_suffixes); + + delete clone_num_suffixes; + func_sums->release (); + func_sums = NULL; + call_sums->release (); + call_sums = NULL; + + if (dump_file) + fprintf (dump_file, "\n========== IPA SRA IPA analysis done " + "==========\n\n"); + return 0; +} + + +const pass_data pass_data_ipa_sra = +{ + IPA_PASS, /* type */ + "sra", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_IPA_SRA, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + ( TODO_dump_symtab | TODO_remove_functions ), /* todo_flags_finish */ +}; + +class pass_ipa_sra : public ipa_opt_pass_d +{ +public: + pass_ipa_sra (gcc::context *ctxt) + : ipa_opt_pass_d (pass_data_ipa_sra, ctxt, + ipa_sra_generate_summary, /* generate_summary */ + ipa_sra_write_summary, /* write_summary */ + ipa_sra_read_summary, /* read_summary */ + NULL , /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + /* TODO: We should remove the optimize check after we ensure we never run + IPA passes when not optimizing. */ + return (flag_ipa_sra && optimize); + } + + virtual unsigned int execute (function *) { return ipa_sra_analysis (); } + +}; // class pass_ipa_sra + +} // anon namespace + +ipa_opt_pass_d * +make_pass_ipa_sra (gcc::context *ctxt) +{ + return new pass_ipa_sra (ctxt); +} + + +#include "gt-ipa-sra.h" diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index bc0f010..147975b 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -1804,8 +1804,7 @@ output_cgraph_opt_summary_p (struct cgraph_node *node) { return ((node->clone_of || node->former_clone_of) && (node->clone.tree_map - || node->clone.args_to_skip - || node->clone.combined_args_to_skip)); + || node->clone.param_adjustments)); } /* Output optimization summary for EDGE to OB. */ @@ -1822,42 +1821,53 @@ output_node_opt_summary (struct output_block *ob, struct cgraph_node *node, lto_symtab_encoder_t encoder) { - unsigned int index; - bitmap_iterator bi; struct ipa_replace_map *map; - struct bitpack_d bp; int i; struct cgraph_edge *e; - if (node->clone.args_to_skip) - { - streamer_write_uhwi (ob, bitmap_count_bits (node->clone.args_to_skip)); - EXECUTE_IF_SET_IN_BITMAP (node->clone.args_to_skip, 0, index, bi) - streamer_write_uhwi (ob, index); - } - else - streamer_write_uhwi (ob, 0); - if (node->clone.combined_args_to_skip) + /* TODO: Should this code be moved to ipa-param-manipulation? */ + struct bitpack_d bp; + bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, (node->clone.param_adjustments != NULL), 1); + streamer_write_bitpack (&bp); + if (ipa_param_adjustments *adjustments = node->clone.param_adjustments) { - streamer_write_uhwi (ob, bitmap_count_bits (node->clone.combined_args_to_skip)); - EXECUTE_IF_SET_IN_BITMAP (node->clone.combined_args_to_skip, 0, index, bi) - streamer_write_uhwi (ob, index); + streamer_write_uhwi (ob, vec_safe_length (adjustments->m_adj_params)); + ipa_adjusted_param *adj; + FOR_EACH_VEC_SAFE_ELT (adjustments->m_adj_params, i, adj) + { + bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, adj->base_index, IPA_PARAM_MAX_INDEX_BITS); + bp_pack_value (&bp, adj->prev_clone_index, IPA_PARAM_MAX_INDEX_BITS); + bp_pack_value (&bp, adj->op, 2); + bp_pack_value (&bp, adj->param_prefix_index, 2); + bp_pack_value (&bp, adj->prev_clone_adjustment, 1); + bp_pack_value (&bp, adj->reverse, 1); + bp_pack_value (&bp, adj->user_flag, 1); + streamer_write_bitpack (&bp); + if (adj->op == IPA_PARAM_OP_SPLIT + || adj->op == IPA_PARAM_OP_NEW) + { + stream_write_tree (ob, adj->type, true); + if (adj->op == IPA_PARAM_OP_SPLIT) + { + stream_write_tree (ob, adj->alias_ptr_type, true); + streamer_write_uhwi (ob, adj->unit_offset); + } + } + } + streamer_write_hwi (ob, adjustments->m_always_copy_start); + bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, node->clone.param_adjustments->m_skip_return, 1); + streamer_write_bitpack (&bp); } - else - streamer_write_uhwi (ob, 0); + streamer_write_uhwi (ob, vec_safe_length (node->clone.tree_map)); FOR_EACH_VEC_SAFE_ELT (node->clone.tree_map, i, map) { - /* At the moment we assume all old trees to be PARM_DECLs, because we have no - mechanism to store function local declarations into summaries. */ - gcc_assert (!map->old_tree); streamer_write_uhwi (ob, map->parm_num); gcc_assert (EXPR_LOCATION (map->new_tree) == UNKNOWN_LOCATION); stream_write_tree (ob, map->new_tree, true); - bp = bitpack_create (ob->main_stream); - bp_pack_value (&bp, map->replace_p, 1); - bp_pack_value (&bp, map->ref_p, 1); - streamer_write_bitpack (&bp); } if (lto_symtab_encoder_in_partition_p (encoder, node)) @@ -1922,26 +1932,49 @@ input_node_opt_summary (struct cgraph_node *node, { int i; int count; - int bit; - struct bitpack_d bp; struct cgraph_edge *e; - count = streamer_read_uhwi (ib_main); - if (count) - node->clone.args_to_skip = BITMAP_GGC_ALLOC (); - for (i = 0; i < count; i++) - { - bit = streamer_read_uhwi (ib_main); - bitmap_set_bit (node->clone.args_to_skip, bit); - } - count = streamer_read_uhwi (ib_main); - if (count) - node->clone.combined_args_to_skip = BITMAP_GGC_ALLOC (); - for (i = 0; i < count; i++) + /* TODO: Should this code be moved to ipa-param-manipulation? */ + struct bitpack_d bp; + bp = streamer_read_bitpack (ib_main); + bool have_adjustments = bp_unpack_value (&bp, 1); + if (have_adjustments) { - bit = streamer_read_uhwi (ib_main); - bitmap_set_bit (node->clone.combined_args_to_skip, bit); + count = streamer_read_uhwi (ib_main); + vec *new_params = NULL; + for (i = 0; i < count; i++) + { + ipa_adjusted_param adj; + memset (&adj, 0, sizeof (adj)); + bp = streamer_read_bitpack (ib_main); + adj.base_index = bp_unpack_value (&bp, IPA_PARAM_MAX_INDEX_BITS); + adj.prev_clone_index + = bp_unpack_value (&bp, IPA_PARAM_MAX_INDEX_BITS); + adj.op = (enum ipa_parm_op) bp_unpack_value (&bp, 2); + adj.param_prefix_index = bp_unpack_value (&bp, 2); + adj.prev_clone_adjustment = bp_unpack_value (&bp, 1); + adj.reverse = bp_unpack_value (&bp, 1); + adj.user_flag = bp_unpack_value (&bp, 1); + if (adj.op == IPA_PARAM_OP_SPLIT + || adj.op == IPA_PARAM_OP_NEW) + { + adj.type = stream_read_tree (ib_main, data_in); + if (adj.op == IPA_PARAM_OP_SPLIT) + { + adj.alias_ptr_type = stream_read_tree (ib_main, data_in); + adj.unit_offset = streamer_read_uhwi (ib_main); + } + } + vec_safe_push (new_params, adj); + } + int always_copy_start = streamer_read_hwi (ib_main); + bp = streamer_read_bitpack (ib_main); + bool skip_return = bp_unpack_value (&bp, 1); + node->clone.param_adjustments + = (new (ggc_alloc ()) + ipa_param_adjustments (new_params, always_copy_start, skip_return)); } + count = streamer_read_uhwi (ib_main); for (i = 0; i < count; i++) { @@ -1949,11 +1982,7 @@ input_node_opt_summary (struct cgraph_node *node, vec_safe_push (node->clone.tree_map, map); map->parm_num = streamer_read_uhwi (ib_main); - map->old_tree = NULL; map->new_tree = stream_read_tree (ib_main, data_in); - bp = streamer_read_bitpack (ib_main); - map->replace_p = bp_unpack_value (&bp, 1); - map->ref_p = bp_unpack_value (&bp, 1); } for (e = node->callees; e; e = e->next_callee) input_edge_opt_summary (e, ib_main); diff --git a/gcc/lto-section-in.c b/gcc/lto-section-in.c index 0bdcf62..d5feebf 100644 --- a/gcc/lto-section-in.c +++ b/gcc/lto-section-in.c @@ -53,7 +53,8 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] = "offload_table", "mode_table", "hsa", - "lto" + "lto", + "ipa-sra" }; /* Hooks so that the ipa passes can call into the lto front end to get diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index bf755a6..ddf3de0 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -235,6 +235,7 @@ enum lto_section_type LTO_section_mode_table, LTO_section_ipa_hsa, LTO_section_lto, + LTO_section_ipa_sra, LTO_N_SECTION_TYPES /* Must be last. */ }; diff --git a/gcc/multiple_target.c b/gcc/multiple_target.c index 7aea684..968c8cf 100644 --- a/gcc/multiple_target.c +++ b/gcc/multiple_target.c @@ -311,9 +311,8 @@ create_target_clone (cgraph_node *node, bool definition, char *name, if (definition) { new_node = node->create_version_clone_with_body (vNULL, NULL, - NULL, false, - NULL, NULL, - name, attributes); + NULL, NULL, + NULL, name, attributes); if (new_node == NULL) return NULL; new_node->force_output = true; diff --git a/gcc/omp-simd-clone.c b/gcc/omp-simd-clone.c index a078033..d71a963 100644 --- a/gcc/omp-simd-clone.c +++ b/gcc/omp-simd-clone.c @@ -86,21 +86,23 @@ simd_clone_struct_copy (struct cgraph_simd_clone *to, * sizeof (struct cgraph_simd_clone_arg)))); } -/* Return vector of parameter types of function FNDECL. This uses - TYPE_ARG_TYPES if available, otherwise falls back to types of +/* Fill an empty vector ARGS with parameter types of function FNDECL. This + uses TYPE_ARG_TYPES if available, otherwise falls back to types of DECL_ARGUMENTS types. */ -static vec -simd_clone_vector_of_formal_parm_types (tree fndecl) +static void +simd_clone_vector_of_formal_parm_types (vec *args, tree fndecl) { if (TYPE_ARG_TYPES (TREE_TYPE (fndecl))) - return ipa_get_vector_of_formal_parm_types (TREE_TYPE (fndecl)); - vec args = ipa_get_vector_of_formal_parms (fndecl); + { + push_function_arg_types (args, TREE_TYPE (fndecl)); + return; + } + push_function_arg_decls (args, fndecl); unsigned int i; tree arg; - FOR_EACH_VEC_ELT (args, i, arg) - args[i] = TREE_TYPE (args[i]); - return args; + FOR_EACH_VEC_ELT (*args, i, arg) + (*args)[i] = TREE_TYPE ((*args)[i]); } /* Given a simd function in NODE, extract the simd specific @@ -113,7 +115,8 @@ static struct cgraph_simd_clone * simd_clone_clauses_extract (struct cgraph_node *node, tree clauses, bool *inbranch_specified) { - vec args = simd_clone_vector_of_formal_parm_types (node->decl); + auto_vec args; + simd_clone_vector_of_formal_parm_types (&args, node->decl); tree t; int n; *inbranch_specified = false; @@ -192,14 +195,12 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses, { warning_at (OMP_CLAUSE_LOCATION (t), 0, "ignoring large linear step"); - args.release (); return NULL; } else if (integer_zerop (step)) { warning_at (OMP_CLAUSE_LOCATION (t), 0, "ignoring zero linear step"); - args.release (); return NULL; } else @@ -263,7 +264,6 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses, warning_at (DECL_SOURCE_LOCATION (node->decl), 0, "ignoring %<#pragma omp declare simd%> on function " "with %<_Atomic%> qualified return type"); - args.release (); return NULL; } @@ -278,7 +278,6 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses, return NULL; } - args.release (); return clone_info; } @@ -303,14 +302,14 @@ simd_clone_compute_base_data_type (struct cgraph_node *node, such parameter. */ else { - vec map = simd_clone_vector_of_formal_parm_types (fndecl); + auto_vec map; + simd_clone_vector_of_formal_parm_types (&map, fndecl); for (unsigned int i = 0; i < clone_info->nargs; ++i) if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR) { type = map[i]; break; } - map.release (); } /* c) If the characteristic data type determined by a) or b) above @@ -441,7 +440,7 @@ simd_clone_create (struct cgraph_node *old_node) return NULL; old_node->get_body (); new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL, - false, NULL, NULL, + NULL, NULL, "simdclone"); } else @@ -561,31 +560,33 @@ create_tmp_simd_array (const char *prefix, tree type, int simdlen) NODE is the function whose arguments are to be adjusted. - Returns an adjustment vector that will be filled describing how the - argument types will be adjusted. */ + If NODE does not represent function definition, returns NULL. Otherwise + returns an adjustment class that will be filled describing how the argument + declarations will be remapped. New arguments which are not to be remapped + are marked with USER_FLAG. */ -static ipa_parm_adjustment_vec +static ipa_param_body_adjustments * simd_clone_adjust_argument_types (struct cgraph_node *node) { - vec args; - ipa_parm_adjustment_vec adjustments; + auto_vec args; if (node->definition) - args = ipa_get_vector_of_formal_parms (node->decl); + push_function_arg_decls (&args, node->decl); else - args = simd_clone_vector_of_formal_parm_types (node->decl); - adjustments.create (args.length ()); - unsigned i, j, veclen; - struct ipa_parm_adjustment adj; + simd_clone_vector_of_formal_parm_types (&args, node->decl); struct cgraph_simd_clone *sc = node->simdclone; + vec *new_params = NULL; + vec_safe_reserve (new_params, sc->nargs); + unsigned i, j, veclen; for (i = 0; i < sc->nargs; ++i) { + ipa_adjusted_param adj; memset (&adj, 0, sizeof (adj)); tree parm = args[i]; tree parm_type = node->definition ? TREE_TYPE (parm) : parm; adj.base_index = i; - adj.base = parm; + adj.prev_clone_index = i; sc->args[i].orig_arg = node->definition ? parm : NULL_TREE; sc->args[i].orig_type = parm_type; @@ -594,7 +595,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) { default: /* No adjustment necessary for scalar arguments. */ - adj.op = IPA_PARM_OP_COPY; + adj.op = IPA_PARAM_OP_COPY; break; case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP: @@ -603,7 +604,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)), TREE_TYPE (parm_type), sc->simdlen); - adj.op = IPA_PARM_OP_COPY; + adj.op = IPA_PARAM_OP_COPY; break; case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP: @@ -615,7 +616,8 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type)); if (veclen > sc->simdlen) veclen = sc->simdlen; - adj.arg_prefix = "simd"; + adj.op = IPA_PARAM_OP_NEW; + adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD; if (POINTER_TYPE_P (parm_type)) adj.type = build_vector_type (pointer_sized_int_node, veclen); else @@ -623,13 +625,15 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) sc->args[i].vector_type = adj.type; for (j = veclen; j < sc->simdlen; j += veclen) { - adjustments.safe_push (adj); + vec_safe_push (new_params, adj); if (j == veclen) { memset (&adj, 0, sizeof (adj)); - adj.op = IPA_PARM_OP_NEW; - adj.arg_prefix = "simd"; + adj.op = IPA_PARAM_OP_NEW; + adj.user_flag = 1; + adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD; adj.base_index = i; + adj.prev_clone_index = i; adj.type = sc->args[i].vector_type; } } @@ -640,18 +644,20 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) ? IDENTIFIER_POINTER (DECL_NAME (parm)) : NULL, parm_type, sc->simdlen); } - adjustments.safe_push (adj); + vec_safe_push (new_params, adj); } if (sc->inbranch) { tree base_type = simd_clone_compute_base_data_type (sc->origin, sc); - + ipa_adjusted_param adj; memset (&adj, 0, sizeof (adj)); - adj.op = IPA_PARM_OP_NEW; - adj.arg_prefix = "mask"; + adj.op = IPA_PARAM_OP_NEW; + adj.user_flag = 1; + adj.param_prefix_index = IPA_PARAM_PREFIX_MASK; adj.base_index = i; + adj.prev_clone_index = i; if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type)) veclen = sc->vecsize_int; else @@ -666,10 +672,10 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) adj.type = build_vector_type (pointer_sized_int_node, veclen); else adj.type = build_vector_type (base_type, veclen); - adjustments.safe_push (adj); + vec_safe_push (new_params, adj); for (j = veclen; j < sc->simdlen; j += veclen) - adjustments.safe_push (adj); + vec_safe_push (new_params, adj); /* We have previously allocated one extra entry for the mask. Use it and fill it. */ @@ -694,7 +700,13 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) } if (node->definition) - ipa_modify_formal_parameters (node->decl, adjustments); + { + ipa_param_body_adjustments *adjustments + = new ipa_param_body_adjustments (new_params, node->decl); + + adjustments->modify_formal_parameters (); + return adjustments; + } else { tree new_arg_types = NULL_TREE, new_reversed; @@ -703,12 +715,12 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) last_parm_void = true; gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl))); - j = adjustments.length (); + j = vec_safe_length (new_params); for (i = 0; i < j; i++) { - struct ipa_parm_adjustment *adj = &adjustments[i]; + struct ipa_adjusted_param *adj = &(*new_params)[i]; tree ptype; - if (adj->op == IPA_PARM_OP_COPY) + if (adj->op == IPA_PARAM_OP_COPY) ptype = args[adj->base_index]; else ptype = adj->type; @@ -723,10 +735,8 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) new_reversed = void_list_node; } TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed; - adjustments.release (); + return NULL; } - args.release (); - return adjustments; } /* Initialize and copy the function arguments in NODE to their @@ -735,7 +745,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node) static gimple_seq simd_clone_init_simd_arrays (struct cgraph_node *node, - ipa_parm_adjustment_vec adjustments) + ipa_param_body_adjustments *adjustments) { gimple_seq seq = NULL; unsigned i = 0, j = 0, k; @@ -744,7 +754,7 @@ simd_clone_init_simd_arrays (struct cgraph_node *node, arg; arg = DECL_CHAIN (arg), i++, j++) { - if (adjustments[j].op == IPA_PARM_OP_COPY + if ((*adjustments->m_adj_params)[j].op == IPA_PARAM_OP_COPY || POINTER_TYPE_P (TREE_TYPE (arg))) continue; @@ -809,7 +819,7 @@ simd_clone_init_simd_arrays (struct cgraph_node *node, /* Callback info for ipa_simd_modify_stmt_ops below. */ struct modify_stmt_info { - ipa_parm_adjustment_vec adjustments; + ipa_param_body_adjustments *adjustments; gimple *stmt; /* True if the parent statement was modified by ipa_simd_modify_stmt_ops. */ @@ -829,15 +839,26 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data) tree *orig_tp = tp; if (TREE_CODE (*tp) == ADDR_EXPR) tp = &TREE_OPERAND (*tp, 0); - struct ipa_parm_adjustment *cand = NULL; + + if (TREE_CODE (*tp) == BIT_FIELD_REF + || TREE_CODE (*tp) == IMAGPART_EXPR + || TREE_CODE (*tp) == REALPART_EXPR) + tp = &TREE_OPERAND (*tp, 0); + + tree repl = NULL_TREE; + ipa_param_body_replacement *pbr = NULL; + if (TREE_CODE (*tp) == PARM_DECL) - cand = ipa_get_adjustment_candidate (&tp, NULL, info->adjustments, true); + { + pbr = info->adjustments->get_expr_replacement (*tp, true); + if (pbr) + repl = pbr->repl; + } else if (TYPE_P (*tp)) *walk_subtrees = 0; - tree repl = NULL_TREE; - if (cand) - repl = unshare_expr (cand->new_decl); + if (repl) + repl = unshare_expr (repl); else { if (tp != orig_tp) @@ -861,13 +882,13 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data) if (tp != orig_tp) { if (gimple_code (info->stmt) == GIMPLE_PHI - && cand + && pbr && TREE_CODE (*orig_tp) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL - && cand->alias_ptr_type) + && pbr->dummy) { - gcc_assert (TREE_CODE (cand->alias_ptr_type) == SSA_NAME); - *orig_tp = cand->alias_ptr_type; + gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME); + *orig_tp = pbr->dummy; info->modified = true; return NULL_TREE; } @@ -893,10 +914,13 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data) { gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); /* Cache SSA_NAME for next time. */ - if (cand + if (pbr && TREE_CODE (*orig_tp) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL) - cand->alias_ptr_type = repl; + { + gcc_assert (!pbr->dummy); + pbr->dummy = repl; + } } else gsi = gsi_for_stmt (info->stmt); @@ -926,70 +950,56 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data) static void ipa_simd_modify_function_body (struct cgraph_node *node, - ipa_parm_adjustment_vec adjustments, + ipa_param_body_adjustments *adjustments, tree retval_array, tree iter) { basic_block bb; - unsigned int i, j, l; + unsigned int i, j; - /* Re-use the adjustments array, but this time use it to replace - every function argument use to an offset into the corresponding - simd_array. */ + + /* Register replacements for every function argument use to an offset into + the corresponding simd_array. */ for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j) { - if (!node->simdclone->args[i].vector_arg) + if (!node->simdclone->args[i].vector_arg + || (*adjustments->m_adj_params)[j].user_flag) continue; tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg); tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg); - adjustments[j].new_decl - = build4 (ARRAY_REF, - basetype, - node->simdclone->args[i].simd_array, - iter, - NULL_TREE, NULL_TREE); - if (adjustments[j].op == IPA_PARM_OP_NONE - && simd_clone_subparts (vectype) < node->simdclone->simdlen) + tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array, + iter, NULL_TREE, NULL_TREE); + adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r); + + if (simd_clone_subparts (vectype) < node->simdclone->simdlen) j += node->simdclone->simdlen / simd_clone_subparts (vectype) - 1; } - l = adjustments.length (); tree name; - FOR_EACH_SSA_NAME (i, name, cfun) { + tree base_var; if (SSA_NAME_VAR (name) - && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL) + && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL + && (base_var + = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name)))) { - for (j = 0; j < l; j++) - if (SSA_NAME_VAR (name) == adjustments[j].base - && adjustments[j].new_decl) - { - tree base_var; - if (adjustments[j].new_ssa_base == NULL_TREE) - { - base_var - = copy_var_decl (adjustments[j].base, - DECL_NAME (adjustments[j].base), - TREE_TYPE (adjustments[j].base)); - adjustments[j].new_ssa_base = base_var; - } - else - base_var = adjustments[j].new_ssa_base; - if (SSA_NAME_IS_DEFAULT_DEF (name)) - { - bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); - gimple_stmt_iterator gsi = gsi_after_labels (bb); - tree new_decl = unshare_expr (adjustments[j].new_decl); - set_ssa_default_def (cfun, adjustments[j].base, NULL_TREE); - SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var); - SSA_NAME_IS_DEFAULT_DEF (name) = 0; - gimple *stmt = gimple_build_assign (name, new_decl); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - } - else - SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var); - } + if (SSA_NAME_IS_DEFAULT_DEF (name)) + { + tree old_decl = SSA_NAME_VAR (name); + bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); + gimple_stmt_iterator gsi = gsi_after_labels (bb); + tree repl = adjustments->lookup_replacement (old_decl, 0); + gcc_checking_assert (repl); + repl = unshare_expr (repl); + set_ssa_default_def (cfun, old_decl, NULL_TREE); + SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var); + SSA_NAME_IS_DEFAULT_DEF (name) = 0; + gimple *stmt = gimple_build_assign (name, repl); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + } + else + SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var); } } @@ -1162,8 +1172,9 @@ simd_clone_adjust (struct cgraph_node *node) targetm.simd_clone.adjust (node); tree retval = simd_clone_adjust_return_type (node); - ipa_parm_adjustment_vec adjustments + ipa_param_body_adjustments *adjustments = simd_clone_adjust_argument_types (node); + gcc_assert (adjustments); push_gimplify_context (); @@ -1175,7 +1186,7 @@ simd_clone_adjust (struct cgraph_node *node) tree iter1 = make_ssa_name (iter); tree iter2 = NULL_TREE; ipa_simd_modify_function_body (node, adjustments, retval, iter1); - adjustments.release (); + delete adjustments; /* Initialize the iteration variable. */ basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); diff --git a/gcc/params.def b/gcc/params.def index 5fe3397..d2d957f 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -1062,6 +1062,13 @@ DEFPARAM (PARAM_IPA_SRA_PTR_GROWTH_FACTOR, "that ipa-sra replaces a pointer to an aggregate with.", 2, 0, 0) +DEFPARAM (PARAM_IPA_SRA_MAX_REPLACEMENTS, + "ipa-sra-max-replacements", + "Maximum pieces that IPA-SRA tracks per formal parameter, as " + "a consequence, also the maximum number of replacements of a formal " + "parameter.", + 8, 0, 16) + DEFPARAM (PARAM_TM_MAX_AGGREGATE_SIZE, "tm-max-aggregate-size", "Size in bytes after which thread-local aggregates should be " diff --git a/gcc/passes.def b/gcc/passes.def index 9387922..8999cee 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -89,7 +89,6 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_dse); NEXT_PASS (pass_cd_dce); NEXT_PASS (pass_phiopt, true /* early_p */); - NEXT_PASS (pass_early_ipa_sra); NEXT_PASS (pass_tail_recursion); NEXT_PASS (pass_convert_switch); NEXT_PASS (pass_cleanup_eh); @@ -148,6 +147,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_ipa_icf); NEXT_PASS (pass_ipa_devirt); NEXT_PASS (pass_ipa_cp); + NEXT_PASS (pass_ipa_sra); NEXT_PASS (pass_ipa_cdtor_merge); NEXT_PASS (pass_ipa_hsa); NEXT_PASS (pass_ipa_fn_summary); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c230b2a..a4323b4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,43 @@ +2019-09-20 Martin Jambor + + * g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan. + * gcc.dg/ipa/ipa-sra-1.c: Likewise. + * gcc.dg/ipa/ipa-sra-10.c: Likewise. + * gcc.dg/ipa/ipa-sra-11.c: Likewise. + * gcc.dg/ipa/ipa-sra-3.c: Likewise. + * gcc.dg/ipa/ipa-sra-4.c: Likewise. + * gcc.dg/ipa/ipa-sra-5.c: Likewise. + * gcc.dg/ipa/ipacost-2.c: Disable ipa-sra. + * gcc.dg/ipa/ipcp-agg-9.c: Likewise. + * gcc.dg/ipa/pr78121.c: Adjust scan pattern. + * gcc.dg/ipa/vrp1.c: Likewise. + * gcc.dg/ipa/vrp2.c: Likewise. + * gcc.dg/ipa/vrp3.c: Likewise. + * gcc.dg/ipa/vrp7.c: Likewise. + * gcc.dg/ipa/vrp8.c: Likewise. + * gcc.dg/noreorder.c: use noipa attribute instead of noinline. + * gcc.dg/ipa/20040703-wpa.c: New test. + * gcc.dg/ipa/ipa-sra-12.c: New test. + * gcc.dg/ipa/ipa-sra-13.c: Likewise. + * gcc.dg/ipa/ipa-sra-14.c: Likewise. + * gcc.dg/ipa/ipa-sra-15.c: Likewise. + * gcc.dg/ipa/ipa-sra-16.c: Likewise. + * gcc.dg/ipa/ipa-sra-17.c: Likewise. + * gcc.dg/ipa/ipa-sra-18.c: Likewise. + * gcc.dg/ipa/ipa-sra-19.c: Likewise. + * gcc.dg/ipa/ipa-sra-20.c: Likewise. + * gcc.dg/ipa/ipa-sra-21.c: Likewise. + * gcc.dg/ipa/ipa-sra-22.c: Likewise. + * gcc.dg/sso/ipa-sra-1.c: Likewise. + * g++.dg/ipa/ipa-sra-2.C: Likewise. + * g++.dg/ipa/ipa-sra-3.C: Likewise. + * gcc.dg/tree-ssa/ipa-cp-1.c: Make return value used. + * g++.dg/ipa/devirt-19.C: Add missing return, add -fipa-cp-clone + option. + * g++.dg/lto/devirt-19_0.C: Add -fipa-cp-clone option. + * gcc.dg/ipa/ipa-sra-2.c: Removed. + * gcc.dg/ipa/ipa-sra-6.c: Likewise. + 2019-09-19 Martin Sebor PR middle-end/91631 diff --git a/gcc/testsuite/g++.dg/ipa/devirt-19.C b/gcc/testsuite/g++.dg/ipa/devirt-19.C index 8277dea..f35bc32 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-19.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-19.C @@ -2,7 +2,7 @@ Previously we were failing by considering CLOBBER statement to be a type change. */ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-ipa-cp" } */ +/* { dg-options "-O2 -fdump-ipa-cp -fipa-cp-clone" } */ /* { dg-additional-options "-Wno-return-type" } */ struct A { @@ -23,9 +23,12 @@ public: C b; template const M &C::m_fn2(const T &) { + A a = _map.m_fn2(); a == _map.m_fn1(); m_fn1(); + static M m; + return m; } void fn1() { b.m_fn2(0); } diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-1.C b/gcc/testsuite/g++.dg/ipa/ipa-sra-1.C new file mode 100644 index 0000000..ef7d704 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-1.C @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fipa-sra" } */ + +void fn1(int *, int *, double *, int *, double *); +int a, c, d, e, f, g, k; +double *b; +double h, i; +void fn2(int *p1, int *p2, double *p3) { + int l = 0, j, q, r; + double m, n, o, p, s, t, u; + --p3; + for (; a;) { + if (c) { + ++*p2; + goto L170; + } + m = n = b[c]; + p = t = m; + for (; j; ++j) { + u = 1.; + if (k) { + s = o; + u = -1.; + } + } + i = u * p; + L60: + p3[1] = s; + for (; d;) + goto L60; + fn1(&f, &g, &h, &l, &p3[1]); + o = p3[1]; + L100: + o *= i; + if (e) + goto L100; + L170:; + } + if (*p1) + for (;;) { + if (r) + q = *p2; + d = q - j; + r = j; + } +} diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-2.C b/gcc/testsuite/g++.dg/ipa/ipa-sra-2.C new file mode 100644 index 0000000..17bd13a --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-2.C @@ -0,0 +1,19 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-options "-O2 -fipa-sra" } */ + +class a { + void b(); + char16_t c; + char16_t d; +}; +void e(a); +void g(); +void a::b() { + char16_t f = d; + e(*this); + for (;;) { + g(); + if (f) + break; + } +} diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-3.C b/gcc/testsuite/g++.dg/ipa/ipa-sra-3.C new file mode 100644 index 0000000..d15ae22 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-3.C @@ -0,0 +1,9 @@ +/* { dg-options "-O2 -fipa-sra -fno-inline -fno-ipa-cp" } */ + + +char *a() __attribute__((__malloc__)); +static char *b() { + char *c = a(); + return c; +} +int d() { b(); return 4; } diff --git a/gcc/testsuite/g++.dg/ipa/pr81248.C b/gcc/testsuite/g++.dg/ipa/pr81248.C index d7796ff..b79710f 100644 --- a/gcc/testsuite/g++.dg/ipa/pr81248.C +++ b/gcc/testsuite/g++.dg/ipa/pr81248.C @@ -1,5 +1,5 @@ // { dg-do compile { target c++17 } } -// { dg-options "-O2 -fdump-tree-eipa_sra" } +// { dg-options "-O2 -fdump-ipa-sra" } #include @@ -37,4 +37,4 @@ int main() { f(n2); } -// { dg-final { scan-tree-dump-times "Adjusting call" 2 "eipa_sra" } } +// { dg-final { scan-ipa-dump "Will split parameter 0" "sra" } } diff --git a/gcc/testsuite/g++.dg/lto/devirt-19_0.C b/gcc/testsuite/g++.dg/lto/devirt-19_0.C index b43527e..7d53651 100644 --- a/gcc/testsuite/g++.dg/lto/devirt-19_0.C +++ b/gcc/testsuite/g++.dg/lto/devirt-19_0.C @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options { "-O2 -fdump-ipa-cp -Wno-return-type -flto -r -nostdlib" } } */ +/* { dg-lto-options { "-O2 -fdump-ipa-cp -fipa-cp-clone -Wno-return-type -flto -r -nostdlib" } } */ /* { dg-extra-ld-options "-flinker-output=nolto-rel -flto=auto" } */ #include "../ipa/devirt-19.C" /* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/20040703-wpa.c b/gcc/testsuite/gcc.dg/ipa/20040703-wpa.c new file mode 100644 index 0000000..b1a318b --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/20040703-wpa.c @@ -0,0 +1,151 @@ +/* With -fwhole-program this is an excelent testcase for inlining IPA-SRAed + functions into each other. */ +/* { dg-do run } */ +/* { dg-options "-O2 -w -fno-ipa-cp -fwhole-program" } */ +/* { dg-require-effective-target int32plus } */ + +#define PART_PRECISION (sizeof (cpp_num_part) * 8) + +typedef unsigned int cpp_num_part; +typedef struct cpp_num cpp_num; +struct cpp_num +{ + cpp_num_part high; + cpp_num_part low; + int unsignedp; /* True if value should be treated as unsigned. */ + int overflow; /* True if the most recent calculation overflowed. */ +}; + +static int +num_positive (cpp_num num, unsigned int precision) +{ + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0; + } + + return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0; +} + +static cpp_num +num_trim (cpp_num num, unsigned int precision) +{ + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + if (precision < PART_PRECISION) + num.high &= ((cpp_num_part) 1 << precision) - 1; + } + else + { + if (precision < PART_PRECISION) + num.low &= ((cpp_num_part) 1 << precision) - 1; + num.high = 0; + } + + return num; +} + +/* Shift NUM, of width PRECISION, right by N bits. */ +static cpp_num +num_rshift (cpp_num num, unsigned int precision, unsigned int n) +{ + cpp_num_part sign_mask; + int x = num_positive (num, precision); + + if (num.unsignedp || x) + sign_mask = 0; + else + sign_mask = ~(cpp_num_part) 0; + + if (n >= precision) + num.high = num.low = sign_mask; + else + { + /* Sign-extend. */ + if (precision < PART_PRECISION) + num.high = sign_mask, num.low |= sign_mask << precision; + else if (precision < 2 * PART_PRECISION) + num.high |= sign_mask << (precision - PART_PRECISION); + + if (n >= PART_PRECISION) + { + n -= PART_PRECISION; + num.low = num.high; + num.high = sign_mask; + } + + if (n) + { + num.low = (num.low >> n) | (num.high << (PART_PRECISION - n)); + num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n)); + } + } + + num = num_trim (num, precision); + num.overflow = 0; + return num; +} + #define num_zerop(num) ((num.low | num.high) == 0) +#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high) + +cpp_num +num_lshift (cpp_num num, unsigned int precision, unsigned int n) +{ + if (n >= precision) + { + num.overflow = !num.unsignedp && !num_zerop (num); + num.high = num.low = 0; + } + else + { + cpp_num orig; + unsigned int m = n; + + orig = num; + if (m >= PART_PRECISION) + { + m -= PART_PRECISION; + num.high = num.low; + num.low = 0; + } + if (m) + { + num.high = (num.high << m) | (num.low >> (PART_PRECISION - m)); + num.low <<= m; + } + num = num_trim (num, precision); + + if (num.unsignedp) + num.overflow = 0; + else + { + cpp_num maybe_orig = num_rshift (num, precision, n); + num.overflow = !num_eq (orig, maybe_orig); + } + } + + return num; +} + +unsigned int precision = 64; +unsigned int n = 16; + +cpp_num num = { 0, 3, 0, 0 }; + +int main() +{ + cpp_num res = num_lshift (num, 64, n); + + if (res.low != 0x30000) + abort (); + + if (res.high != 0) + abort (); + + if (res.overflow != 0) + abort (); + + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c index 4db904b..4a22e39 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra-details" } */ struct bovid { @@ -36,4 +36,4 @@ main (int argc, char *argv[]) return 0; } -/* { dg-final { scan-tree-dump-times "About to replace expr" 2 "eipa_sra" } } */ +/* { dg-final { scan-ipa-dump "Will split parameter" "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-10.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-10.c index 24b64d1..b5535cf 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-10.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-10.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-options "-O2 -fno-ipa-cp -fipa-sra -fdump-ipa-sra" } */ extern void consume (int); extern int glob, glob1, glob2; @@ -31,4 +31,4 @@ bar (int a) return 0; } -/* { dg-final { scan-tree-dump-times "replacing an SSA name of a removed param" 4 "eipa_sra" } } */ +/* { dg-final { scan-ipa-dump "Will remove parameter 0" "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c index e91423a..61c02c1 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c @@ -1,5 +1,5 @@ -/* { dg-do run } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra-details" } */ struct bovid { @@ -36,4 +36,4 @@ main (int argc, char *argv[]) return 0; } -/* { dg-final { scan-tree-dump-not "About to replace expr" "eipa_sra" } } */ +/* { dg-final { scan-ipa-dump-not "Will split parameter" "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c new file mode 100644 index 0000000..689071e --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c @@ -0,0 +1,50 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */ + +/* Check of a simple and transitive structure split. */ + +struct S +{ + float red; + void *blue; + int green; +}; + + +void __attribute__((noipa)) +check (float r, int g, int g2) +{ + if (r < 7.39 || r > 7.41 + || g != 6 || g2 != 6) + __builtin_abort (); +} + +static void +__attribute__((noinline)) +foo (struct S s) +{ + check (s.red, s.green, s.green); +} + +static void +__attribute__((noinline)) +bar (struct S s) +{ + foo (s); +} + +int +main (int argc, char *argv[]) +{ + struct S s; + + s.red = 7.4; + s.green = 6; + s.blue = &s; + + bar (s); + return 0; +} + +/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */ +/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c new file mode 100644 index 0000000..4d4ed74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */ + +/* Check of a by-reference structure split. */ + +struct S +{ + float red; + void *blue; + int green; +}; + +void __attribute__((noipa)) +check (float r, int g, int g2) +{ + if (r < 7.39 || r > 7.41 + || g != 6 || g2 != 6) + __builtin_abort (); +} + +static void +__attribute__((noinline)) +foo (struct S *s) +{ + check (s->red, s->green, s->green); +} + +static void +__attribute__((noinline)) +bar (struct S *s) +{ + foo (s); +} + +int +main (int argc, char *argv[]) +{ + struct S s; + + s.red = 7.4; + s.green = 6; + s.blue = &s; + + bar (&s); + return 0; +} + +/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */ +/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c new file mode 100644 index 0000000..0188124 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c @@ -0,0 +1,60 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */ + +/* Check of a transitive recursive structure split. */ + +struct S +{ + float red; + void *blue; + int green; +}; + + +static int done = 0; + +void __attribute__((noipa)) +check (float r, int g, int g2) +{ + if (r < 7.39 || r > 7.41 + || g != 6 || g2 != 6) + __builtin_abort (); +} + +static void __attribute__((noinline)) bar (struct S s); + +static void +__attribute__((noinline)) +foo (struct S s) +{ + if (!done) + { + done = 1; + bar (s); + } + check (s.red, s.green, s.green); +} + +static void +__attribute__((noinline)) +bar (struct S s) +{ + foo (s); +} + +int +main (int argc, char *argv[]) +{ + struct S s; + + s.red = 7.4; + s.green = 6; + s.blue = &s; + + bar (s); + return 0; +} + + +/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */ +/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c new file mode 100644 index 0000000..6c57c7b --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c @@ -0,0 +1,61 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */ + +/* Check of a recursive by-reference structure split. The recursive functions + have to be pure right from the start, otherwise the current AA would detect + possible modification of data. */ + +struct S +{ + float red; + void *blue; + int green; +}; + +void __attribute__((noipa)) +check (float r, int g, int g2) +{ + if (r < 7.39 || r > 7.41 + || g != 6 || g2 != 6) + __builtin_abort (); + return; +} + +static int __attribute__((noinline, pure)) bar (struct S *s, int rec); + +static int +__attribute__((noinline, pure)) +foo (struct S *s , int rec) +{ + int t = 0; + if (rec) + t = bar (s, 0); + check (s->red, s->green, s->green); + return t; +} + +static int +__attribute__((noinline, pure)) +bar (struct S *s, int rec) +{ + int t = foo (s, rec); + return t + t; +} + +volatile int g; + +int +main (int argc, char *argv[]) +{ + struct S s; + + s.red = 7.4; + s.green = 6; + s.blue = &s; + + g = bar (&s, 1); + return 0; +} + +/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */ +/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c new file mode 100644 index 0000000..2bffe29 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra -fdump-tree-optimized" } */ + +/* Testing removal of unused parameters in recursive calls. */ + +extern int work_1 (int); +extern int work_2 (int); + +static int __attribute__((noinline)) +foo (int l, int w1, int w2, int useless, int useless2); + + +static int __attribute__((noinline)) +bar_1 (int l, int w1, int w2, int useless, int useless2) +{ + return work_1 (w1) + foo (l, w1, w2, useless2, useless); +} + +static int __attribute__((noinline)) +baz_1 (int useless, int useless2, int l, int w1, int w2) +{ + return bar_1 (l, w1, w2, useless, useless2); +} + +static int __attribute__((noinline)) +bax_1 (int l, int w1, int w2, int useless, int useless2) +{ + return baz_1 (useless, useless2, l, w1, w2); +} + + + +static int __attribute__((noinline)) +bar_2 (int l, int w1, int w2, int useless, int useless2) +{ + return foo (l, w1, w2, useless2 + 5, useless); +} + +static int __attribute__((noinline)) +baz_2 (int useless, int useless2, int l, int w1, int w2) +{ + return bar_2 (l, w1, w2, useless, useless2); +} + + +static int __attribute__((noinline)) +bax_2 (int l, int w1, int w2, int useless, int useless2) +{ + return work_2 (w2) + baz_2 (useless, useless2, l, w1, w2); +} + + +static int __attribute__((noinline)) + foo (int l, int w1, int w2, int useless, int useless2) +{ + int r = 0; + if (!l) + return r; + if (l % 2) + r = bax_1 (l - 1, w1, w2, useless, useless2); + else + r = bax_2 (l - 1, w1, w2, useless, useless2); + + return r; +} + +int +entry (int l, int w1, int w2, int noneed, int noneed2) +{ + return foo (l, w2, w2, noneed2, noneed2 + 4); +} + +/* { dg-final { scan-ipa-dump-times "Will remove parameter" 14 "sra" } } */ +/* { dg-final { scan-tree-dump-not "useless" "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c new file mode 100644 index 0000000..9cb6367 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c @@ -0,0 +1,102 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-ipa-sra -fdump-tree-optimized" } */ + +#define DOIT +#define DONT + + +extern int extern_leaf (int); + +/* ----- 1 ----- */ +#ifdef DOIT +static int __attribute__((noinline)) +whee_1 (int i, int j) +{ + return extern_leaf (i * j) + 1; +} + +static int foo_1 (int i, int j); + +static int __attribute__((noinline)) +baz_1 (int i, int j) +{ + int a = 5; + if (j) + a = foo_1 (i, j - 1); + return whee_1 (i, j) + a + 1; +} + +static int __attribute__((noinline)) +bar_1 (int i, int j) +{ + return baz_1 (i, j) + 1; +} + +static int __attribute__((noinline)) +foo_1 (int i, int j) +{ + return bar_1 (i, j) + 1; +} + +static int __attribute__((noinline)) +inter_1 (int i, int j) +{ + return foo_1 (i, j) + 1; +} +#endif + +/* ----- 2 ----- */ +#ifdef DONT +static int __attribute__((noinline)) +whee_2 (int i, int j) +{ + return extern_leaf (i * j) + 2; +} + +static int foo_2 (int i, int j); + +static int __attribute__((noinline)) +baz_2 (int i, int j) +{ + int a = 6; + if (j) + a = foo_2 (i, j - 1); + return whee_2 (i, j) + a + 2; +} + +static int __attribute__((noinline)) +bar_2 (int i, int j) +{ + return baz_2 (i, j) + 2; +} + +static int __attribute__((noinline)) +foo_2 (int i, int j) +{ + return bar_2 (i, j) + 2; +} +#endif + +/* ----- entries ----- */ +#ifdef DOIT +int +entry_1 (int i, int j) +{ + inter_1 (i, j); + return i + j + 1; +} +#endif + +#ifdef DONT +int +entry_2 (int i, int j) +{ +#ifdef DOIT + inter_1 (i, j); +#endif + return i + j + bar_2 (i, j); +} +#endif + +/* { dg-final { scan-ipa-dump-times "Will remove return value" 5 "sra" } } */ +/* { dg-final { scan-tree-dump-times "return;" 5 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c new file mode 100644 index 0000000..3217b61 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-ipa-sra" } */ + +struct S +{ + long a, b; +}; + +extern void leaf_a (int ); +extern void leaf_b (int, int); +extern void leaf_c (int, int); + +extern void leaf_sa (struct S); + +static void baz (int i, int j, int k, int l, struct S a, struct S b); + +extern int gi; + +static void __attribute__((noinline)) +foo (int i, int j, int k, int l, struct S a, struct S b) +{ + gi += l; + baz (i, j, k, l, a, b); +} + +static void __attribute__((noinline)) +bar (int i, int j, int k, int l, struct S a, struct S b) +{ + foo (i, j, k, l, a, b); + leaf_sa (b); +} + + +static void __attribute__((noinline)) +baz (int i, int j, int k, int l, struct S a, struct S b) +{ + if (--k) + bar (i, j, k, l, a, b); + leaf_b (i, k); +} + +void +entry (int i, int j, int k, int l, struct S a, struct S b) +{ + foo (i, j, k, l, a, b); +} + +/* { dg-final { scan-ipa-dump-times "Will remove parameter 1" 3 "sra" } } */ +/* { dg-final { scan-ipa-dump-times "Will remove parameter 4" 3 "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c new file mode 100644 index 0000000..adebaa5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef int __attribute__((__vector_size__(16))) vectype; + +vectype dk(); +vectype k(); + +int b; +vectype *j; +inline int c(vectype *d) { + vectype e; + vectype f; + vectype g = *d; + vectype h = g; + vectype i = h; + f = i == dk(); + e = f == b; + k(e); +} + +static void m(vectype *d) { + int l = c(d); + if (l) + c(j); +} + +void o(void) { + vectype n; + m(&n); +} diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-2.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-2.c deleted file mode 100644 index a31945c..0000000 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-2.c +++ /dev/null @@ -1,51 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ - -struct bovid -{ - float red; - int green; - void *blue; -}; - -static int -__attribute__((noinline)) -ox (struct bovid *cow) -{ - cow->red = cow->red + cow->green + cow->green; - return 0; -} - -int something; - -static int -__attribute__((noinline)) -ox_improved (struct bovid *calf) -{ - if (something > 0) - calf->red = calf->red + calf->green; - else - calf->red = calf->green + 87; - something = 77; - return 0; -} - - -int main (int argc, char *argv[]) -{ - struct bovid cow; - - cow.red = 7.4; - cow.green = 6; - cow.blue = &cow; - - ox (&cow); - - ox_improved (&cow); - return 0; -} - -/* { dg-final { scan-tree-dump "About to replace expr cow_.*D.->red with \\*ISRA" "eipa_sra" } } */ -/* { dg-final { scan-tree-dump "About to replace expr cow_.*D.->green with ISRA" "eipa_sra" } } */ -/* { dg-final { scan-tree-dump "About to replace expr calf_.*D.->red with \\*ISRA" "eipa_sra" } } */ -/* { dg-final { scan-tree-dump "About to replace expr calf_.*D.->green with ISRA" "eipa_sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c new file mode 100644 index 0000000..a47df4f --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fipa-sra" } */ + +typedef struct { + int a; +} b; +typedef struct { + double c; + double a; +} d; +typedef struct { + d e; + d f; +} g; +g h; +b i, m; +int j, k, l, n, o; +static b q(d s) { + int r = s.c ?: 0; + if (r) + if (j) + l = j - 2; + o = k; + n = l; + i = m; + return m; +} +static void t(g s) { + { + d p = s.e; + int r = p.c ?: 0; + if (r) { + l = j - 2; + } + } + b f = q(s.f); +} +void main() { t(h); } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c new file mode 100644 index 0000000..67806b8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef int a; +typedef int b; +int c, e; +void i(); +void n(d, ab, f, ae, af, action, ag, ah, ai, g, h, aj, ak, al, j, k, am, an, ao, + l, m) int action, + ag; +int f, ae, af; +int ah, ai; +int j, k; +int l, m; +a aj, am; +int ak, al, an, ao, g, h; +char d, ab; +{ + if (c) + i(e); +} +void o(d, ab, action, at, ag, g, h, aj, ak, al, au, av, am, an, ao, aw, ax, ay, + az, ba, bb, ai) int action, + ag; +int at, ai; +int au, av, aw, ax; +b ay, ba; +int az, bb; +int g, h; +int ak, al, an, ao; +a aj, am; +char d, ab; +{ n(); } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c new file mode 100644 index 0000000..0d6a353 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fipa-sra" } */ + +struct W +{ + int a, b; +}; + +union U +{ + struct W w; + long l; +}; + +struct Z +{ + int k; + union U u; +}; + +struct S +{ + int i, j; + struct Z z; + char buf[64]; +}; + +struct W gw; + + +static long +__attribute__((noinline)) +foo (struct Z z) +{ + return z.u.l; +} + +static long +__attribute__((noinline)) +bar (struct S s) +{ + if (s.i > 100) + return s.z.u.w.a; + else + return foo (s.z); +} + +volatile long g; + +long +entry (struct S *p) +{ + struct S s = *p; + + return bar (s) | 2; +} diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-3.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-3.c index 23dec2a..203650c 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-3.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-options "-O2 -fno-ipa-cp -fipa-sra -fdump-ipa-sra" } */ struct bovid { @@ -34,5 +34,6 @@ void caller (void) return; } -/* { dg-final { scan-tree-dump "base: z, remove_param" "eipa_sra" } } */ -/* { dg-final { scan-tree-dump "base: calf, remove_param" "eipa_sra" } } */ +/* { dg-final { scan-ipa-dump "Will split parameter 0" "sra" } } */ +/* { dg-final { scan-ipa-dump "Will remove parameter 1" "sra" } } */ +/* { dg-final { scan-ipa-dump "Will remove parameter 2" "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-4.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-4.c index 50ac179..fdbd5e5 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-4.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-options "-O2 -fipa-sra -fno-ipa-pure-const -fdump-ipa-sra" } */ static int __attribute__((noinline)) @@ -61,7 +61,5 @@ void caller (void) return; } -/* { dg-final { scan-tree-dump "About to replace expr \\*i_.*D. with ISRA" "eipa_sra" } } */ -/* { dg-final { scan-tree-dump "About to replace expr \\*l_.*D. with ISRA" "eipa_sra" } } */ -/* { dg-final { scan-tree-dump-times "About to replace expr \*j_.*D. with ISRA" 0 "eipa_sra" } } */ -/* { dg-final { scan-tree-dump-times "About to replace expr \*k_.*D. with ISRA" 0 "eipa_sra" } } */ +/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */ + diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-5.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-5.c index 3310a6d..8a75681 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-5.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-5.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */ static int * __attribute__((noinline,used)) @@ -16,4 +16,4 @@ int *caller (void) return ox (&a, &b); } -/* { dg-final { scan-tree-dump-times "base: j, remove_param" 0 "eipa_sra" } } */ +/* { dg-final { scan-ipa-dump-times "Will split parameter" 0 "sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-6.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-6.c deleted file mode 100644 index 89909f0..0000000 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-6.c +++ /dev/null @@ -1,33 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-slim" } */ -/* { dg-require-effective-target non_strict_align } */ - -struct bovid -{ - float a; - int b; - struct bovid *next; -}; - -static int -__attribute__((noinline)) -foo (struct bovid *cow, int i) -{ - i++; - if (cow->next) - foo (cow->next, i); - return i; -} - -int main (int argc, char *argv[]) -{ - struct bovid cow; - - cow.a = 7.4; - cow.b = 6; - cow.next = (struct bovid *) 0; - - return foo (&cow, 0); -} - -/* { dg-final { scan-tree-dump-times "foo " 1 "eipa_sra" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipacost-2.c b/gcc/testsuite/gcc.dg/ipa/ipacost-2.c index 43f0114..e0501db 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipacost-2.c +++ b/gcc/testsuite/gcc.dg/ipa/ipacost-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-ipa-cp -fno-early-inlining -fdump-tree-optimized -fno-ipa-icf" } */ +/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-ipa-cp -fno-early-inlining -fno-ipa-sra -fdump-tree-optimized -fno-ipa-icf" } */ /* { dg-add-options bind_pic_locally } */ int array[100]; @@ -72,7 +72,7 @@ main() } /* { dg-final { scan-ipa-dump-times "Creating a specialized node of i_can_be_propagated_fully2" 1 "cp" } } */ -/* { dg-final { scan-ipa-dump-times "Creating a specialized node of i_can_be_propagated_fully/" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Creating a specialized node of i_can_be_propagated_fully\[./\]" 1 "cp" } } */ /* { dg-final { scan-ipa-dump-not "Creating a specialized node of i_can_not_be_propagated_fully2" "cp" } } */ /* { dg-final { scan-ipa-dump-not "Creating a specialized node of i_can_not_be_propagated_fully/" "cp" } } */ /* { dg-final { scan-tree-dump-not "i_can_be_propagated_fully \\(" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c index 2005a10..c69a285 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c +++ b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c @@ -1,6 +1,6 @@ /* Verify that IPA-CP can make edges direct based on aggregate contents. */ /* { dg-do compile } */ -/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp -fdump-ipa-inline" } */ +/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp -fdump-ipa-inline" } */ struct S { diff --git a/gcc/testsuite/gcc.dg/ipa/pr78121.c b/gcc/testsuite/gcc.dg/ipa/pr78121.c index 4a0ae18..19d6eda 100644 --- a/gcc/testsuite/gcc.dg/ipa/pr78121.c +++ b/gcc/testsuite/gcc.dg/ipa/pr78121.c @@ -13,4 +13,4 @@ static void fn1(c) unsigned char c; void fn3() { fn1 (267); } -/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[11, 35\\\]" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[11, 35\\\]" "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/vrp1.c b/gcc/testsuite/gcc.dg/ipa/vrp1.c index 72a3139..e32a13c 100644 --- a/gcc/testsuite/gcc.dg/ipa/vrp1.c +++ b/gcc/testsuite/gcc.dg/ipa/vrp1.c @@ -28,5 +28,5 @@ int main () return 0; } -/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[6," "cp" } } */ -/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 999\\\]" "cp" } } */ +/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[6," "cp" } } */ +/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[0, 999\\\]" "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/vrp2.c b/gcc/testsuite/gcc.dg/ipa/vrp2.c index c720e5c..31909bd 100644 --- a/gcc/testsuite/gcc.dg/ipa/vrp2.c +++ b/gcc/testsuite/gcc.dg/ipa/vrp2.c @@ -31,5 +31,5 @@ int main () return 0; } -/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[4," "cp" } } */ -/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 11\\\]" "cp" } } */ +/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[4," "cp" } } */ +/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[0, 11\\\]" "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/vrp3.c b/gcc/testsuite/gcc.dg/ipa/vrp3.c index fb5d54a..9b1dcf9 100644 --- a/gcc/testsuite/gcc.dg/ipa/vrp3.c +++ b/gcc/testsuite/gcc.dg/ipa/vrp3.c @@ -27,4 +27,4 @@ int main () return 0; } -/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[0, 9\\\]" 2 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\(now 0\\) \\\[0, 9\\\]" 2 "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/vrp7.c b/gcc/testsuite/gcc.dg/ipa/vrp7.c index e4e0bc6..ca5aa29 100644 --- a/gcc/testsuite/gcc.dg/ipa/vrp7.c +++ b/gcc/testsuite/gcc.dg/ipa/vrp7.c @@ -29,4 +29,4 @@ int main () return 0; } -/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[-10, 9\\\]" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\(now 0\\) \\\[-10, 9\\\]" 1 "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/vrp8.c b/gcc/testsuite/gcc.dg/ipa/vrp8.c index 55832b0..0ac5fb5 100644 --- a/gcc/testsuite/gcc.dg/ipa/vrp8.c +++ b/gcc/testsuite/gcc.dg/ipa/vrp8.c @@ -39,4 +39,4 @@ main () return 0; } -/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[-10, 9\\\]" 1 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\(now 0\\) \\\[-10, 9\\\]" 1 "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/noreorder.c b/gcc/testsuite/gcc.dg/noreorder.c index 7d40a29..e413b68 100644 --- a/gcc/testsuite/gcc.dg/noreorder.c +++ b/gcc/testsuite/gcc.dg/noreorder.c @@ -13,7 +13,7 @@ static int func2(void); asm("firstasm"); -NOREORDER __attribute__((noinline)) int bozo(void) +NOREORDER __attribute__((noipa)) int bozo(void) { f2(3); func2(); @@ -21,14 +21,14 @@ NOREORDER __attribute__((noinline)) int bozo(void) asm("jukjuk"); -NOREORDER __attribute__((noinline)) static int func1(void) +NOREORDER __attribute__((noipa)) static int func1(void) { f2(1); } asm("barbar"); -NOREORDER __attribute__((noinline)) static int func2(void) +NOREORDER __attribute__((noipa)) static int func2(void) { func1(); } diff --git a/gcc/testsuite/gcc.dg/sso/ipa-sra-1.c b/gcc/testsuite/gcc.dg/sso/ipa-sra-1.c new file mode 100644 index 0000000..6712141 --- /dev/null +++ b/gcc/testsuite/gcc.dg/sso/ipa-sra-1.c @@ -0,0 +1,57 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fipa-sra" } */ + + +struct __attribute__((scalar_storage_order("little-endian"))) LE +{ + int i; + int j; +}; + +struct __attribute__((scalar_storage_order("big-endian"))) BE +{ + int i; + int j; +}; + +struct LE gle; +struct BE gbe; + +#define VAL 0x12345678 + +void __attribute__((noipa)) +fill (void) +{ + gle.i = VAL; + gle.j = 0xdeadbeef; + gbe.i = VAL; + gbe.j = 0x11223344; +} + +static int __attribute__((noinline)) +readLE (struct LE p) +{ + return p.i; +} + +static int __attribute__((noinline)) +readBE (struct BE p) +{ + return p.i; +} + +int +main (int argc, char *argv[]) +{ + int r; + fill (); + + r = readLE (gle); + if (r != VAL) + __builtin_abort (); + r = readBE (gbe); + if (r != VAL) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ipa-cp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ipa-cp-1.c index 61878b7..56b7f9f 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ipa-cp-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ipa-cp-1.c @@ -14,7 +14,7 @@ very_long_function(int a) int blah () { - very_long_function (1); + return very_long_function (1); } /* One appearance for dump, one self recursive call and one call from main. */ /* { dg-final { scan-tree-dump-times "very_long_function.constprop \\(\\)" 3 "optimized"} } */ diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c index c39d6d0..4a3f130 100644 --- a/gcc/trans-mem.c +++ b/gcc/trans-mem.c @@ -5009,8 +5009,7 @@ ipa_tm_create_version (struct cgraph_node *old_node) } tree_function_versioning (old_decl, new_decl, - NULL, false, NULL, - false, NULL, NULL); + NULL, NULL, false, NULL, NULL); } record_tm_clone_pair (old_decl, new_decl); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index b9c1a3b..e4ae1b0 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -130,7 +130,6 @@ static void copy_bind_expr (tree *, int *, copy_body_data *); static void declare_inline_vars (tree, tree); static void remap_save_expr (tree *, hash_map *, int *); static void prepend_lexical_block (tree current_block, tree new_block); -static tree copy_decl_to_var (tree, copy_body_data *); static tree copy_result_decl_to_var (tree, copy_body_data *); static tree copy_decl_maybe_to_var (tree, copy_body_data *); static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *); @@ -192,7 +191,21 @@ remap_ssa_name (tree name, copy_body_data *id) n = id->decl_map->get (name); if (n) - return unshare_expr (*n); + { + /* WHen we perform edge redirection as part of CFG copy, IPA-SRA can + remove an unused LHS from a call statement. Such LHS can however + still appear in debug statements, but their value is lost in this + function and we do not want to map them. */ + if (id->killed_new_ssa_names + && id->killed_new_ssa_names->contains (*n)) + { + gcc_assert (processing_debug_stmt); + processing_debug_stmt = -1; + return name; + } + + return unshare_expr (*n); + } if (processing_debug_stmt) { @@ -1902,6 +1915,21 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) gcc_assert (n); gimple_set_block (copy, *n); } + if (id->param_body_adjs) + { + gimple_seq extra_stmts = NULL; + id->param_body_adjs->modify_gimple_stmt (©, &extra_stmts); + if (!gimple_seq_empty_p (extra_stmts)) + { + memset (&wi, 0, sizeof (wi)); + wi.info = id; + for (gimple_stmt_iterator egsi = gsi_start (extra_stmts); + !gsi_end_p (egsi); + gsi_next (&egsi)) + walk_gimple_op (gsi_stmt (egsi), remap_gimple_op_r, &wi); + gimple_seq_add_seq (&stmts, extra_stmts); + } + } if (id->reset_location) gimple_set_location (copy, input_location); @@ -2865,10 +2893,24 @@ redirect_all_calls (copy_body_data * id, basic_block bb) gimple *stmt = gsi_stmt (si); if (is_gimple_call (stmt)) { + tree old_lhs = gimple_call_lhs (stmt); struct cgraph_edge *edge = id->dst_node->get_edge (stmt); if (edge) { - edge->redirect_call_stmt_to_callee (); + gimple *new_stmt = edge->redirect_call_stmt_to_callee (); + /* If IPA-SRA transformation, run as part of edge redirection, + removed the LHS because it is unused, save it to + killed_new_ssa_names so that we can prune it from debug + statements. */ + if (old_lhs + && TREE_CODE (old_lhs) == SSA_NAME + && !gimple_call_lhs (new_stmt)) + { + if (!id->killed_new_ssa_names) + id->killed_new_ssa_names = new hash_set (16); + id->killed_new_ssa_names->add (old_lhs); + } + if (stmt == last && id->call_stmt && maybe_clean_eh_stmt (stmt)) gimple_purge_dead_eh_edges (bb); } @@ -3189,6 +3231,8 @@ copy_body (copy_body_data *id, body = copy_cfg_body (id, entry_block_map, exit_block_map, new_entry); copy_debug_stmts (id); + delete id->killed_new_ssa_names; + id->killed_new_ssa_names = NULL; return body; } @@ -4908,6 +4952,38 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id) /* Add local vars in this inlined callee to caller. */ add_local_variables (id->src_cfun, cfun, id); + if (id->src_node->clone.performed_splits) + { + /* Any calls from the inlined function will be turned into calls from the + function we inline into. We must preserve notes about how to split + parameters such calls should be redirected/updated. */ + unsigned len = vec_safe_length (id->src_node->clone.performed_splits); + for (unsigned i = 0; i < len; i++) + { + ipa_param_performed_split ps + = (*id->src_node->clone.performed_splits)[i]; + ps.dummy_decl = remap_decl (ps.dummy_decl, id); + vec_safe_push (id->dst_node->clone.performed_splits, ps); + } + + if (flag_checking) + { + len = vec_safe_length (id->dst_node->clone.performed_splits); + for (unsigned i = 0; i < len; i++) + { + ipa_param_performed_split *ps1 + = &(*id->dst_node->clone.performed_splits)[i]; + for (unsigned j = i + 1; j < len; j++) + { + ipa_param_performed_split *ps2 + = &(*id->dst_node->clone.performed_splits)[j]; + gcc_assert (ps1->dummy_decl != ps2->dummy_decl + || ps1->unit_offset != ps2->unit_offset); + } + } + } + } + if (dump_enabled_p ()) { char buf[128]; @@ -5733,7 +5809,11 @@ copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy) return copy; } -static tree +/* Create a new VAR_DECL that is indentical in all respect to DECL except that + DECL can be either a VAR_DECL, a PARM_DECL or RESULT_DECL. The original + DECL must come from ID->src_fn and the copy will be part of ID->dst_fn. */ + +tree copy_decl_to_var (tree decl, copy_body_data *id) { tree copy, type; @@ -5816,38 +5896,24 @@ copy_decl_maybe_to_var (tree decl, copy_body_data *id) return copy_decl_no_change (decl, id); } -/* Return a copy of the function's argument tree. */ +/* Return a copy of the function's argument tree without any modifications. */ + static tree -copy_arguments_for_versioning (tree orig_parm, copy_body_data * id, - bitmap args_to_skip, tree *vars) +copy_arguments_nochange (tree orig_parm, copy_body_data * id) { tree arg, *parg; tree new_parm = NULL; - int i = 0; parg = &new_parm; - - for (arg = orig_parm; arg; arg = DECL_CHAIN (arg), i++) - if (!args_to_skip || !bitmap_bit_p (args_to_skip, i)) - { - tree new_tree = remap_decl (arg, id); - if (TREE_CODE (new_tree) != PARM_DECL) - new_tree = id->copy_decl (arg, id); - lang_hooks.dup_lang_specific_decl (new_tree); - *parg = new_tree; - parg = &DECL_CHAIN (new_tree); - } - else if (!id->decl_map->get (arg)) - { - /* Make an equivalent VAR_DECL. If the argument was used - as temporary variable later in function, the uses will be - replaced by local variable. */ - tree var = copy_decl_to_var (arg, id); - insert_decl_map (id, arg, var); - /* Declare this new variable. */ - DECL_CHAIN (var) = *vars; - *vars = var; - } + for (arg = orig_parm; arg; arg = DECL_CHAIN (arg)) + { + tree new_tree = remap_decl (arg, id); + if (TREE_CODE (new_tree) != PARM_DECL) + new_tree = id->copy_decl (arg, id); + lang_hooks.dup_lang_specific_decl (new_tree); + *parg = new_tree; + parg = &DECL_CHAIN (new_tree); + } return new_parm; } @@ -5883,6 +5949,18 @@ tree_versionable_function_p (tree fndecl) static void update_clone_info (copy_body_data * id) { + vec *cur_performed_splits + = id->dst_node->clone.performed_splits; + if (cur_performed_splits) + { + unsigned len = cur_performed_splits->length (); + for (unsigned i = 0; i < len; i++) + { + ipa_param_performed_split *ps = &(*cur_performed_splits)[i]; + ps->dummy_decl = remap_decl (ps->dummy_decl, id); + } + } + struct cgraph_node *node; if (!id->dst_node->clones) return; @@ -5896,10 +5974,55 @@ update_clone_info (copy_body_data * id) { struct ipa_replace_map *replace_info; replace_info = (*node->clone.tree_map)[i]; - walk_tree (&replace_info->old_tree, copy_tree_body_r, id, NULL); walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL); } } + if (node->clone.performed_splits) + { + unsigned len = vec_safe_length (node->clone.performed_splits); + for (unsigned i = 0; i < len; i++) + { + ipa_param_performed_split *ps + = &(*node->clone.performed_splits)[i]; + ps->dummy_decl = remap_decl (ps->dummy_decl, id); + } + } + if (unsigned len = vec_safe_length (cur_performed_splits)) + { + /* We do not want to add current performed splits when we are saving + a copy of function body for later during inlining, that would just + duplicate all entries. So let's have a look whether anything + referring to the first dummy_decl is present. */ + unsigned dst_len = vec_safe_length (node->clone.performed_splits); + ipa_param_performed_split *first = &(*cur_performed_splits)[0]; + for (unsigned i = 0; i < dst_len; i++) + if ((*node->clone.performed_splits)[i].dummy_decl + == first->dummy_decl) + { + len = 0; + break; + } + + for (unsigned i = 0; i < len; i++) + vec_safe_push (node->clone.performed_splits, + (*cur_performed_splits)[i]); + if (flag_checking) + { + for (unsigned i = 0; i < dst_len; i++) + { + ipa_param_performed_split *ps1 + = &(*node->clone.performed_splits)[i]; + for (unsigned j = i + 1; j < dst_len; j++) + { + ipa_param_performed_split *ps2 + = &(*node->clone.performed_splits)[j]; + gcc_assert (ps1->dummy_decl != ps2->dummy_decl + || ps1->unit_offset != ps2->unit_offset); + } + } + } + } + if (node->clones) node = node->clones; else if (node->next_sibling_clone) @@ -5921,19 +6044,18 @@ update_clone_info (copy_body_data * id) tree with another tree while duplicating the function's body, TREE_MAP represents the mapping between these trees. If UPDATE_CLONES is set, the call_stmt fields - of edges of clones of the function will be updated. + of edges of clones of the function will be updated. - If non-NULL ARGS_TO_SKIP determine function parameters to remove - from new version. - If SKIP_RETURN is true, the new version will return void. - If non-NULL BLOCK_TO_COPY determine what basic blocks to copy. + If non-NULL PARAM_ADJUSTMENTS determines how function prototype (i.e. the + function parameters and return value) should be modified). + If non-NULL BLOCKS_TO_COPY determine what basic blocks to copy. If non_NULL NEW_ENTRY determine new entry BB of the clone. */ void tree_function_versioning (tree old_decl, tree new_decl, vec *tree_map, - bool update_clones, bitmap args_to_skip, - bool skip_return, bitmap blocks_to_copy, + ipa_param_adjustments *param_adjustments, + bool update_clones, bitmap blocks_to_copy, basic_block new_entry) { struct cgraph_node *old_version_node; @@ -5945,7 +6067,6 @@ tree_function_versioning (tree old_decl, tree new_decl, basic_block old_entry_block, bb; auto_vec init_stmts; tree vars = NULL_TREE; - bitmap debug_args_to_skip = args_to_skip; gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL && TREE_CODE (new_decl) == FUNCTION_DECL); @@ -6021,96 +6142,78 @@ tree_function_versioning (tree old_decl, tree new_decl, DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl = copy_static_chain (p, &id); + auto_vec new_param_indices; + ipa_param_adjustments *old_param_adjustments + = old_version_node->clone.param_adjustments; + if (old_param_adjustments) + old_param_adjustments->get_updated_indices (&new_param_indices); + /* If there's a tree_map, prepare for substitution. */ if (tree_map) for (i = 0; i < tree_map->length (); i++) { gimple *init; replace_info = (*tree_map)[i]; - if (replace_info->replace_p) + + int p = replace_info->parm_num; + if (old_param_adjustments) + p = new_param_indices[p]; + + tree parm; + tree req_type, new_type; + + for (parm = DECL_ARGUMENTS (old_decl); p; + parm = DECL_CHAIN (parm)) + p--; + tree old_tree = parm; + req_type = TREE_TYPE (parm); + new_type = TREE_TYPE (replace_info->new_tree); + if (!useless_type_conversion_p (req_type, new_type)) { - int parm_num = -1; - if (!replace_info->old_tree) - { - int p = replace_info->parm_num; - tree parm; - tree req_type, new_type; - - for (parm = DECL_ARGUMENTS (old_decl); p; - parm = DECL_CHAIN (parm)) - p--; - replace_info->old_tree = parm; - parm_num = replace_info->parm_num; - req_type = TREE_TYPE (parm); - new_type = TREE_TYPE (replace_info->new_tree); - if (!useless_type_conversion_p (req_type, new_type)) - { - if (fold_convertible_p (req_type, replace_info->new_tree)) - replace_info->new_tree - = fold_build1 (NOP_EXPR, req_type, - replace_info->new_tree); - else if (TYPE_SIZE (req_type) == TYPE_SIZE (new_type)) - replace_info->new_tree - = fold_build1 (VIEW_CONVERT_EXPR, req_type, - replace_info->new_tree); - else - { - if (dump_file) - { - fprintf (dump_file, " const "); - print_generic_expr (dump_file, - replace_info->new_tree); - fprintf (dump_file, - " can't be converted to param "); - print_generic_expr (dump_file, parm); - fprintf (dump_file, "\n"); - } - replace_info->old_tree = NULL; - } - } - } + if (fold_convertible_p (req_type, replace_info->new_tree)) + replace_info->new_tree + = fold_build1 (NOP_EXPR, req_type, replace_info->new_tree); + else if (TYPE_SIZE (req_type) == TYPE_SIZE (new_type)) + replace_info->new_tree + = fold_build1 (VIEW_CONVERT_EXPR, req_type, + replace_info->new_tree); else - gcc_assert (TREE_CODE (replace_info->old_tree) == PARM_DECL); - if (replace_info->old_tree) { - init = setup_one_parameter (&id, replace_info->old_tree, - replace_info->new_tree, id.src_fn, - NULL, - &vars); - if (init) - init_stmts.safe_push (init); - if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip) + if (dump_file) { - if (parm_num == -1) - { - tree parm; - int p; - for (parm = DECL_ARGUMENTS (old_decl), p = 0; parm; - parm = DECL_CHAIN (parm), p++) - if (parm == replace_info->old_tree) - { - parm_num = p; - break; - } - } - if (parm_num != -1) - { - if (debug_args_to_skip == args_to_skip) - { - debug_args_to_skip = BITMAP_ALLOC (NULL); - bitmap_copy (debug_args_to_skip, args_to_skip); - } - bitmap_clear_bit (debug_args_to_skip, parm_num); - } + fprintf (dump_file, " const "); + print_generic_expr (dump_file, + replace_info->new_tree); + fprintf (dump_file, + " can't be converted to param "); + print_generic_expr (dump_file, parm); + fprintf (dump_file, "\n"); } + old_tree = NULL; } } + + if (old_tree) + { + init = setup_one_parameter (&id, old_tree, replace_info->new_tree, + id.src_fn, NULL, &vars); + if (init) + init_stmts.safe_push (init); + } } - /* Copy the function's arguments. */ - if (DECL_ARGUMENTS (old_decl) != NULL_TREE) + + ipa_param_body_adjustments *param_body_adjs = NULL; + if (param_adjustments) + { + param_body_adjs = new ipa_param_body_adjustments (param_adjustments, + new_decl, old_decl, + &id, &vars, tree_map); + id.param_body_adjs = param_body_adjs; + DECL_ARGUMENTS (new_decl) = param_body_adjs->get_new_param_chain (); + } + else if (DECL_ARGUMENTS (old_decl) != NULL_TREE) DECL_ARGUMENTS (new_decl) - = copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id, - args_to_skip, &vars); + = copy_arguments_nochange (DECL_ARGUMENTS (old_decl), &id); DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id); BLOCK_SUPERCONTEXT (DECL_INITIAL (new_decl)) = new_decl; @@ -6123,12 +6226,19 @@ tree_function_versioning (tree old_decl, tree new_decl, if (DECL_RESULT (old_decl) == NULL_TREE) ; - else if (skip_return && !VOID_TYPE_P (TREE_TYPE (DECL_RESULT (old_decl)))) + else if (param_adjustments && param_adjustments->m_skip_return + && !VOID_TYPE_P (TREE_TYPE (DECL_RESULT (old_decl)))) { + tree resdecl_repl = copy_result_decl_to_var (DECL_RESULT (old_decl), + &id); + declare_inline_vars (NULL, resdecl_repl); + insert_decl_map (&id, DECL_RESULT (old_decl), resdecl_repl); + DECL_RESULT (new_decl) = build_decl (DECL_SOURCE_LOCATION (DECL_RESULT (old_decl)), RESULT_DECL, NULL_TREE, void_type_node); DECL_CONTEXT (DECL_RESULT (new_decl)) = new_decl; + DECL_IS_MALLOC (new_decl) = false; cfun->returns_struct = 0; cfun->returns_pcc_struct = 0; } @@ -6221,29 +6331,30 @@ tree_function_versioning (tree old_decl, tree new_decl, } } - if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS) + if (param_body_adjs && MAY_HAVE_DEBUG_BIND_STMTS) { - tree parm; vec **debug_args = NULL; unsigned int len = 0; - for (parm = DECL_ARGUMENTS (old_decl), i = 0; - parm; parm = DECL_CHAIN (parm), i++) - if (bitmap_bit_p (debug_args_to_skip, i) && is_gimple_reg (parm)) - { - tree ddecl; + unsigned reset_len = param_body_adjs->m_reset_debug_decls.length (); - if (debug_args == NULL) - { - debug_args = decl_debug_args_insert (new_decl); - len = vec_safe_length (*debug_args); - } - ddecl = make_node (DEBUG_EXPR_DECL); - DECL_ARTIFICIAL (ddecl) = 1; - TREE_TYPE (ddecl) = TREE_TYPE (parm); - SET_DECL_MODE (ddecl, DECL_MODE (parm)); - vec_safe_push (*debug_args, DECL_ORIGIN (parm)); - vec_safe_push (*debug_args, ddecl); - } + for (i = 0; i < reset_len; i++) + { + tree parm = param_body_adjs->m_reset_debug_decls[i]; + gcc_assert (is_gimple_reg (parm)); + tree ddecl; + + if (debug_args == NULL) + { + debug_args = decl_debug_args_insert (new_decl); + len = vec_safe_length (*debug_args); + } + ddecl = make_node (DEBUG_EXPR_DECL); + DECL_ARTIFICIAL (ddecl) = 1; + TREE_TYPE (ddecl) = TREE_TYPE (parm); + SET_DECL_MODE (ddecl, DECL_MODE (parm)); + vec_safe_push (*debug_args, DECL_ORIGIN (parm)); + vec_safe_push (*debug_args, ddecl); + } if (debug_args != NULL) { /* On the callee side, add @@ -6269,7 +6380,7 @@ tree_function_versioning (tree old_decl, tree new_decl, if (var == NULL_TREE) break; vexpr = make_node (DEBUG_EXPR_DECL); - parm = (**debug_args)[i]; + tree parm = (**debug_args)[i]; DECL_ARTIFICIAL (vexpr) = 1; TREE_TYPE (vexpr) = TREE_TYPE (parm); SET_DECL_MODE (vexpr, DECL_MODE (parm)); @@ -6281,9 +6392,7 @@ tree_function_versioning (tree old_decl, tree new_decl, while (i > len); } } - - if (debug_args_to_skip && debug_args_to_skip != args_to_skip) - BITMAP_FREE (debug_args_to_skip); + delete param_body_adjs; free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h index 3ede89e..87a149c 100644 --- a/gcc/tree-inline.h +++ b/gcc/tree-inline.h @@ -172,6 +172,15 @@ struct copy_body_data outside of the inlined function, this should be the number of basic blocks in the caller before inlining. Zero otherwise. */ int add_clobbers_to_eh_landing_pads; + + /* Class managing changes to function parameters and return value planned + during IPA stage. */ + class ipa_param_body_adjustments *param_body_adjs; + + /* Hash set of SSA names that have been killed during call graph edge + redirection and should not be introduced into debug statements or NULL if no + SSA_NAME was deleted during redirections happened. */ + hash_set *killed_new_ssa_names; }; /* Weights of constructions for estimate_num_insns. */ @@ -240,6 +249,7 @@ extern bool debug_find_tree (tree, tree); extern tree copy_fn (tree, tree&, tree&); extern const char *copy_forbidden (struct function *fun); extern tree copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy); +extern tree copy_decl_to_var (tree, copy_body_data *); /* This is in tree-inline.c since the routine uses data structures from the inliner. */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 7106eba..85b1c828 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -355,7 +355,6 @@ extern gimple_opt_pass *make_pass_early_tree_profile (gcc::context *ctxt); extern gimple_opt_pass *make_pass_cleanup_eh (gcc::context *ctxt); extern gimple_opt_pass *make_pass_sra (gcc::context *ctxt); extern gimple_opt_pass *make_pass_sra_early (gcc::context *ctxt); -extern gimple_opt_pass *make_pass_early_ipa_sra (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tail_recursion (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tail_calls (gcc::context *ctxt); extern gimple_opt_pass *make_pass_fix_loops (gcc::context *ctxt); @@ -500,6 +499,7 @@ extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt); +extern ipa_opt_pass_d *make_pass_ipa_sra (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_icf (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 1505ce5..4858932 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -96,15 +96,10 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "tree-dfa.h" #include "tree-ssa.h" -#include "symbol-summary.h" -#include "ipa-param-manipulation.h" -#include "ipa-prop.h" #include "params.h" #include "dbgcnt.h" -#include "tree-inline.h" -#include "ipa-fnsummary.h" -#include "ipa-utils.h" #include "builtins.h" +#include "tree-sra.h" /* Enumeration of all aggregate reductions we can do. */ @@ -169,8 +164,7 @@ struct access struct access *first_child; /* In intraprocedural SRA, pointer to the next sibling in the access tree as - described above. In IPA-SRA this is a pointer to the next access - belonging to the same group (having the same representative). */ + described above. */ struct access *next_sibling; /* Pointers to the first and last element in the linked list of assign @@ -185,9 +179,6 @@ struct access when grp_to_be_replaced flag is set. */ tree replacement_decl; - /* Is this access an access to a non-addressable field? */ - unsigned non_addressable : 1; - /* Is this access made in reverse storage order? */ unsigned reverse : 1; @@ -260,19 +251,6 @@ struct access /* Should TREE_NO_WARNING of a replacement be set? */ unsigned grp_no_warning : 1; - - /* Is it possible that the group refers to data which might be (directly or - otherwise) modified? */ - unsigned grp_maybe_modified : 1; - - /* Set when this is a representative of a pointer to scalar (i.e. by - reference) parameter which we consider for turning into a plain scalar - (i.e. a by value parameter). */ - unsigned grp_scalar_ptr : 1; - - /* Set when we discover that this pointer is not safe to dereference in the - caller. */ - unsigned grp_not_necessarilly_dereferenced : 1; }; typedef struct access *access_p; @@ -349,29 +327,6 @@ static struct obstack name_obstack; propagated to their assignment counterparts. */ static struct access *work_queue_head; -/* Number of parameters of the analyzed function when doing early ipa SRA. */ -static int func_param_count; - -/* scan_function sets the following to true if it encounters a call to - __builtin_apply_args. */ -static bool encountered_apply_args; - -/* Set by scan_function when it finds a recursive call. */ -static bool encountered_recursive_call; - -/* Set by scan_function when it finds a recursive call with less actual - arguments than formal parameters.. */ -static bool encountered_unchangable_recursive_call; - -/* This is a table in which for each basic block and parameter there is a - distance (offset + size) in that parameter which is dereferenced and - accessed in that BB. */ -static HOST_WIDE_INT *bb_dereferences; -/* Bitmap of BBs that can cause the function to "stop" progressing by - returning, throwing externally, looping infinitely or calling a function - which might abort etc.. */ -static bitmap final_bbs; - /* Representative of no accesses at all. */ static struct access no_accesses_representant; @@ -440,8 +395,7 @@ dump_access (FILE *f, struct access *access, bool grp) print_generic_expr (f, access->expr); fprintf (f, ", type = "); print_generic_expr (f, access->type); - fprintf (f, ", non_addressable = %d, reverse = %d", - access->non_addressable, access->reverse); + fprintf (f, ", reverse = %d", access->reverse); if (grp) fprintf (f, ", grp_read = %d, grp_write = %d, grp_assignment_read = %d, " "grp_assignment_write = %d, grp_scalar_read = %d, " @@ -449,18 +403,14 @@ dump_access (FILE *f, struct access *access, bool grp) "grp_hint = %d, grp_covered = %d, " "grp_unscalarizable_region = %d, grp_unscalarized_data = %d, " "grp_same_access_path = %d, grp_partial_lhs = %d, " - "grp_to_be_replaced = %d, grp_to_be_debug_replaced = %d, " - "grp_maybe_modified = %d, " - "grp_not_necessarilly_dereferenced = %d\n", + "grp_to_be_replaced = %d, grp_to_be_debug_replaced = %d\n", access->grp_read, access->grp_write, access->grp_assignment_read, access->grp_assignment_write, access->grp_scalar_read, access->grp_scalar_write, access->grp_total_scalarization, access->grp_hint, access->grp_covered, access->grp_unscalarizable_region, access->grp_unscalarized_data, access->grp_same_access_path, access->grp_partial_lhs, - access->grp_to_be_replaced, access->grp_to_be_debug_replaced, - access->grp_maybe_modified, - access->grp_not_necessarilly_dereferenced); + access->grp_to_be_replaced, access->grp_to_be_debug_replaced); else fprintf (f, ", write = %d, grp_total_scalarization = %d, " "grp_partial_lhs = %d\n", @@ -672,9 +622,6 @@ sra_initialize (void) gcc_obstack_init (&name_obstack); base_access_vec = new hash_map >; memset (&sra_stats, 0, sizeof (sra_stats)); - encountered_apply_args = false; - encountered_recursive_call = false; - encountered_unchangable_recursive_call = false; } /* Deallocate all general structures. */ @@ -722,14 +669,20 @@ disqualify_candidate (tree decl, const char *reason) } /* Return true iff the type contains a field or an element which does not allow - scalarization. */ + scalarization. Use VISITED_TYPES to avoid re-checking already checked + (sub-)types. */ static bool -type_internals_preclude_sra_p (tree type, const char **msg) +type_internals_preclude_sra_p_1 (tree type, const char **msg, + hash_set *visited_types) { tree fld; tree et; + if (visited_types->contains (type)) + return false; + visited_types->add (type); + switch (TREE_CODE (type)) { case RECORD_TYPE: @@ -738,6 +691,8 @@ type_internals_preclude_sra_p (tree type, const char **msg) for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld)) if (TREE_CODE (fld) == FIELD_DECL) { + if (TREE_CODE (fld) == FUNCTION_DECL) + continue; tree ft = TREE_TYPE (fld); if (TREE_THIS_VOLATILE (fld)) @@ -777,7 +732,8 @@ type_internals_preclude_sra_p (tree type, const char **msg) return true; } - if (AGGREGATE_TYPE_P (ft) && type_internals_preclude_sra_p (ft, msg)) + if (AGGREGATE_TYPE_P (ft) + && type_internals_preclude_sra_p_1 (ft, msg, visited_types)) return true; } @@ -792,7 +748,8 @@ type_internals_preclude_sra_p (tree type, const char **msg) return true; } - if (AGGREGATE_TYPE_P (et) && type_internals_preclude_sra_p (et, msg)) + if (AGGREGATE_TYPE_P (et) + && type_internals_preclude_sra_p_1 (et, msg, visited_types)) return true; return false; @@ -802,47 +759,16 @@ type_internals_preclude_sra_p (tree type, const char **msg) } } -/* If T is an SSA_NAME, return NULL if it is not a default def or return its - base variable if it is. Return T if it is not an SSA_NAME. */ +/* Return true iff the type contains a field or an element which does not allow + scalarization. */ -static tree -get_ssa_base_param (tree t) +bool +type_internals_preclude_sra_p (tree type, const char **msg) { - if (TREE_CODE (t) == SSA_NAME) - { - if (SSA_NAME_IS_DEFAULT_DEF (t)) - return SSA_NAME_VAR (t); - else - return NULL_TREE; - } - return t; + hash_set visited_types; + return type_internals_preclude_sra_p_1 (type, msg, &visited_types); } -/* Mark a dereference of BASE of distance DIST in a basic block tht STMT - belongs to, unless the BB has already been marked as a potentially - final. */ - -static void -mark_parm_dereference (tree base, HOST_WIDE_INT dist, gimple *stmt) -{ - basic_block bb = gimple_bb (stmt); - int idx, parm_index = 0; - tree parm; - - if (bitmap_bit_p (final_bbs, bb->index)) - return; - - for (parm = DECL_ARGUMENTS (current_function_decl); - parm && parm != base; - parm = DECL_CHAIN (parm)) - parm_index++; - - gcc_assert (parm_index < func_param_count); - - idx = bb->index * func_param_count + parm_index; - if (bb_dereferences[idx] < dist) - bb_dereferences[idx] = dist; -} /* Allocate an access structure for BASE, OFFSET and SIZE, clear it, fill in the three fields. Also add it to the vector of accesses corresponding to @@ -876,7 +802,7 @@ create_access (tree expr, gimple *stmt, bool write) poly_int64 poffset, psize, pmax_size; HOST_WIDE_INT offset, size, max_size; tree base = expr; - bool reverse, ptr, unscalarizable_region = false; + bool reverse, unscalarizable_region = false; base = get_ref_base_and_extent (expr, &poffset, &psize, &pmax_size, &reverse); @@ -888,20 +814,8 @@ create_access (tree expr, gimple *stmt, bool write) return NULL; } - if (sra_mode == SRA_MODE_EARLY_IPA - && TREE_CODE (base) == MEM_REF) - { - base = get_ssa_base_param (TREE_OPERAND (base, 0)); - if (!base) - return NULL; - ptr = true; - } - else - ptr = false; - /* For constant-pool entries, check we can substitute the constant value. */ - if (constant_decl_p (base) - && (sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA)) + if (constant_decl_p (base)) { gcc_assert (!bitmap_bit_p (disqualified_constants, DECL_UID (base))); if (expr != base @@ -921,36 +835,15 @@ create_access (tree expr, gimple *stmt, bool write) if (!DECL_P (base) || !bitmap_bit_p (candidate_bitmap, DECL_UID (base))) return NULL; - if (sra_mode == SRA_MODE_EARLY_IPA) + if (size != max_size) { - if (size < 0 || size != max_size) - { - disqualify_candidate (base, "Encountered a variable sized access."); - return NULL; - } - if (TREE_CODE (expr) == COMPONENT_REF - && DECL_BIT_FIELD (TREE_OPERAND (expr, 1))) - { - disqualify_candidate (base, "Encountered a bit-field access."); - return NULL; - } - gcc_checking_assert ((offset % BITS_PER_UNIT) == 0); - - if (ptr) - mark_parm_dereference (base, offset + size, stmt); + size = max_size; + unscalarizable_region = true; } - else + if (size < 0) { - if (size != max_size) - { - size = max_size; - unscalarizable_region = true; - } - if (size < 0) - { - disqualify_candidate (base, "Encountered an unconstrained access."); - return NULL; - } + disqualify_candidate (base, "Encountered an unconstrained access."); + return NULL; } access = create_access_1 (base, offset, size); @@ -961,10 +854,6 @@ create_access (tree expr, gimple *stmt, bool write) access->stmt = stmt; access->reverse = reverse; - if (TREE_CODE (expr) == COMPONENT_REF - && DECL_NONADDRESSABLE_P (TREE_OPERAND (expr, 1))) - access->non_addressable = 1; - return access; } @@ -1198,10 +1087,6 @@ static void disqualify_base_of_expr (tree t, const char *reason) { t = get_base_address (t); - if (sra_mode == SRA_MODE_EARLY_IPA - && TREE_CODE (t) == MEM_REF) - t = get_ssa_base_param (TREE_OPERAND (t, 0)); - if (t && DECL_P (t)) disqualify_candidate (t, reason); } @@ -1254,8 +1139,7 @@ build_access_from_expr_1 (tree expr, gimple *stmt, bool write) switch (TREE_CODE (expr)) { case MEM_REF: - if (TREE_CODE (TREE_OPERAND (expr, 0)) != ADDR_EXPR - && sra_mode != SRA_MODE_EARLY_IPA) + if (TREE_CODE (TREE_OPERAND (expr, 0)) != ADDR_EXPR) return NULL; /* fall through */ case VAR_DECL: @@ -1329,8 +1213,7 @@ single_non_eh_succ (basic_block bb) static bool disqualify_if_bad_bb_terminating_stmt (gimple *stmt, tree lhs, tree rhs) { - if ((sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA) - && stmt_ends_bb_p (stmt)) + if (stmt_ends_bb_p (stmt)) { if (single_non_eh_succ (gimple_bb (stmt))) return false; @@ -1454,29 +1337,6 @@ asm_visit_addr (gimple *, tree op, tree, void *) return false; } -/* Return true iff callsite CALL has at least as many actual arguments as there - are formal parameters of the function currently processed by IPA-SRA and - that their types match. */ - -static inline bool -callsite_arguments_match_p (gimple *call) -{ - if (gimple_call_num_args (call) < (unsigned) func_param_count) - return false; - - tree parm; - int i; - for (parm = DECL_ARGUMENTS (current_function_decl), i = 0; - parm; - parm = DECL_CHAIN (parm), i++) - { - tree arg = gimple_call_arg (call, i); - if (!useless_type_conversion_p (TREE_TYPE (parm), TREE_TYPE (arg))) - return false; - } - return true; -} - /* Scan function and look for interesting expressions and create access structures for them. Return true iff any access is created. */ @@ -1495,16 +1355,12 @@ scan_function (void) tree t; unsigned i; - if (final_bbs && stmt_can_throw_external (cfun, stmt)) - bitmap_set_bit (final_bbs, bb->index); switch (gimple_code (stmt)) { case GIMPLE_RETURN: t = gimple_return_retval (as_a (stmt)); if (t != NULL_TREE) ret |= build_access_from_expr (t, stmt, false); - if (final_bbs) - bitmap_set_bit (final_bbs, bb->index); break; case GIMPLE_ASSIGN: @@ -1516,28 +1372,6 @@ scan_function (void) ret |= build_access_from_expr (gimple_call_arg (stmt, i), stmt, false); - if (sra_mode == SRA_MODE_EARLY_IPA) - { - tree dest = gimple_call_fndecl (stmt); - int flags = gimple_call_flags (stmt); - - if (dest) - { - if (fndecl_built_in_p (dest, BUILT_IN_APPLY_ARGS)) - encountered_apply_args = true; - if (recursive_call_p (current_function_decl, dest)) - { - encountered_recursive_call = true; - if (!callsite_arguments_match_p (stmt)) - encountered_unchangable_recursive_call = true; - } - } - - if (final_bbs - && (flags & (ECF_CONST | ECF_PURE)) == 0) - bitmap_set_bit (final_bbs, bb->index); - } - t = gimple_call_lhs (stmt); if (t && !disqualify_if_bad_bb_terminating_stmt (stmt, t, NULL)) ret |= build_access_from_expr (t, stmt, true); @@ -1548,9 +1382,6 @@ scan_function (void) gasm *asm_stmt = as_a (stmt); walk_stmt_load_store_addr_ops (asm_stmt, NULL, NULL, NULL, asm_visit_addr); - if (final_bbs) - bitmap_set_bit (final_bbs, bb->index); - for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++) { t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i)); @@ -2002,14 +1833,6 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset, } } -/* Return true iff TYPE is stdarg va_list type. */ - -static inline bool -is_va_list_type (tree type) -{ - return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node); -} - /* Print message to dump file why a variable was rejected. */ static void @@ -2037,10 +1860,8 @@ maybe_add_sra_candidate (tree var) reject (var, "not aggregate"); return false; } - /* Allow constant-pool entries (that "need to live in memory") - unless we are doing IPA SRA. */ - if (needs_to_live_in_memory (var) - && (sra_mode == SRA_MODE_EARLY_IPA || !constant_decl_p (var))) + /* Allow constant-pool entries that "need to live in memory". */ + if (needs_to_live_in_memory (var) && !constant_decl_p (var)) { reject (var, "needs to live in memory"); return false; @@ -4184,1609 +4005,3 @@ make_pass_sra (gcc::context *ctxt) { return new pass_sra (ctxt); } - - -/* Return true iff PARM (which must be a parm_decl) is an unused scalar - parameter. */ - -static bool -is_unused_scalar_param (tree parm) -{ - tree name; - return (is_gimple_reg (parm) - && (!(name = ssa_default_def (cfun, parm)) - || has_zero_uses (name))); -} - -/* Scan immediate uses of a default definition SSA name of a parameter PARM and - examine whether there are any direct or otherwise infeasible ones. If so, - return true, otherwise return false. PARM must be a gimple register with a - non-NULL default definition. */ - -static bool -ptr_parm_has_direct_uses (tree parm) -{ - imm_use_iterator ui; - gimple *stmt; - tree name = ssa_default_def (cfun, parm); - bool ret = false; - - FOR_EACH_IMM_USE_STMT (stmt, ui, name) - { - int uses_ok = 0; - use_operand_p use_p; - - if (is_gimple_debug (stmt)) - continue; - - /* Valid uses include dereferences on the lhs and the rhs. */ - if (gimple_has_lhs (stmt)) - { - tree lhs = gimple_get_lhs (stmt); - while (handled_component_p (lhs)) - lhs = TREE_OPERAND (lhs, 0); - if (TREE_CODE (lhs) == MEM_REF - && TREE_OPERAND (lhs, 0) == name - && integer_zerop (TREE_OPERAND (lhs, 1)) - && types_compatible_p (TREE_TYPE (lhs), - TREE_TYPE (TREE_TYPE (name))) - && !TREE_THIS_VOLATILE (lhs)) - uses_ok++; - } - if (gimple_assign_single_p (stmt)) - { - tree rhs = gimple_assign_rhs1 (stmt); - while (handled_component_p (rhs)) - rhs = TREE_OPERAND (rhs, 0); - if (TREE_CODE (rhs) == MEM_REF - && TREE_OPERAND (rhs, 0) == name - && integer_zerop (TREE_OPERAND (rhs, 1)) - && types_compatible_p (TREE_TYPE (rhs), - TREE_TYPE (TREE_TYPE (name))) - && !TREE_THIS_VOLATILE (rhs)) - uses_ok++; - } - else if (is_gimple_call (stmt)) - { - unsigned i; - for (i = 0; i < gimple_call_num_args (stmt); ++i) - { - tree arg = gimple_call_arg (stmt, i); - while (handled_component_p (arg)) - arg = TREE_OPERAND (arg, 0); - if (TREE_CODE (arg) == MEM_REF - && TREE_OPERAND (arg, 0) == name - && integer_zerop (TREE_OPERAND (arg, 1)) - && types_compatible_p (TREE_TYPE (arg), - TREE_TYPE (TREE_TYPE (name))) - && !TREE_THIS_VOLATILE (arg)) - uses_ok++; - } - } - - /* If the number of valid uses does not match the number of - uses in this stmt there is an unhandled use. */ - FOR_EACH_IMM_USE_ON_STMT (use_p, ui) - --uses_ok; - - if (uses_ok != 0) - ret = true; - - if (ret) - BREAK_FROM_IMM_USE_STMT (ui); - } - - return ret; -} - -/* Identify candidates for reduction for IPA-SRA based on their type and mark - them in candidate_bitmap. Note that these do not necessarily include - parameter which are unused and thus can be removed. Return true iff any - such candidate has been found. */ - -static bool -find_param_candidates (void) -{ - tree parm; - int count = 0; - bool ret = false; - const char *msg; - - for (parm = DECL_ARGUMENTS (current_function_decl); - parm; - parm = DECL_CHAIN (parm)) - { - tree type = TREE_TYPE (parm); - tree_node **slot; - - count++; - - if (TREE_THIS_VOLATILE (parm) - || TREE_ADDRESSABLE (parm) - || (!is_gimple_reg_type (type) && is_va_list_type (type))) - continue; - - if (is_unused_scalar_param (parm)) - { - ret = true; - continue; - } - - if (POINTER_TYPE_P (type)) - { - type = TREE_TYPE (type); - - if (TREE_CODE (type) == FUNCTION_TYPE - || TYPE_VOLATILE (type) - || (TREE_CODE (type) == ARRAY_TYPE - && TYPE_NONALIASED_COMPONENT (type)) - || !is_gimple_reg (parm) - || is_va_list_type (type) - || ptr_parm_has_direct_uses (parm)) - continue; - } - else if (!AGGREGATE_TYPE_P (type)) - continue; - - if (!COMPLETE_TYPE_P (type) - || !tree_fits_uhwi_p (TYPE_SIZE (type)) - || tree_to_uhwi (TYPE_SIZE (type)) == 0 - || (AGGREGATE_TYPE_P (type) - && type_internals_preclude_sra_p (type, &msg))) - continue; - - bitmap_set_bit (candidate_bitmap, DECL_UID (parm)); - slot = candidates->find_slot_with_hash (parm, DECL_UID (parm), INSERT); - *slot = parm; - - ret = true; - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Candidate (%d): ", DECL_UID (parm)); - print_generic_expr (dump_file, parm); - fprintf (dump_file, "\n"); - } - } - - func_param_count = count; - return ret; -} - -/* Callback of walk_aliased_vdefs, marks the access passed as DATA as - maybe_modified. */ - -static bool -mark_maybe_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED, - void *data) -{ - struct access *repr = (struct access *) data; - - repr->grp_maybe_modified = 1; - return true; -} - -/* Analyze what representatives (in linked lists accessible from - REPRESENTATIVES) can be modified by side effects of statements in the - current function. */ - -static void -analyze_modified_params (vec representatives) -{ - int i; - - for (i = 0; i < func_param_count; i++) - { - struct access *repr; - - for (repr = representatives[i]; - repr; - repr = repr->next_grp) - { - struct access *access; - bitmap visited; - ao_ref ar; - - if (no_accesses_p (repr)) - continue; - if (!POINTER_TYPE_P (TREE_TYPE (repr->base)) - || repr->grp_maybe_modified) - continue; - - ao_ref_init (&ar, repr->expr); - visited = BITMAP_ALLOC (NULL); - for (access = repr; access; access = access->next_sibling) - { - /* All accesses are read ones, otherwise grp_maybe_modified would - be trivially set. */ - walk_aliased_vdefs (&ar, gimple_vuse (access->stmt), - mark_maybe_modified, repr, &visited); - if (repr->grp_maybe_modified) - break; - } - BITMAP_FREE (visited); - } - } -} - -/* Propagate distances in bb_dereferences in the opposite direction than the - control flow edges, in each step storing the maximum of the current value - and the minimum of all successors. These steps are repeated until the table - stabilizes. Note that BBs which might terminate the functions (according to - final_bbs bitmap) never updated in this way. */ - -static void -propagate_dereference_distances (void) -{ - basic_block bb; - - auto_vec queue (last_basic_block_for_fn (cfun)); - queue.quick_push (ENTRY_BLOCK_PTR_FOR_FN (cfun)); - FOR_EACH_BB_FN (bb, cfun) - { - queue.quick_push (bb); - bb->aux = bb; - } - - while (!queue.is_empty ()) - { - edge_iterator ei; - edge e; - bool change = false; - int i; - - bb = queue.pop (); - bb->aux = NULL; - - if (bitmap_bit_p (final_bbs, bb->index)) - continue; - - for (i = 0; i < func_param_count; i++) - { - int idx = bb->index * func_param_count + i; - bool first = true; - HOST_WIDE_INT inh = 0; - - FOR_EACH_EDGE (e, ei, bb->succs) - { - int succ_idx = e->dest->index * func_param_count + i; - - if (e->src == EXIT_BLOCK_PTR_FOR_FN (cfun)) - continue; - - if (first) - { - first = false; - inh = bb_dereferences [succ_idx]; - } - else if (bb_dereferences [succ_idx] < inh) - inh = bb_dereferences [succ_idx]; - } - - if (!first && bb_dereferences[idx] < inh) - { - bb_dereferences[idx] = inh; - change = true; - } - } - - if (change && !bitmap_bit_p (final_bbs, bb->index)) - FOR_EACH_EDGE (e, ei, bb->preds) - { - if (e->src->aux) - continue; - - e->src->aux = e->src; - queue.quick_push (e->src); - } - } -} - -/* Dump a dereferences TABLE with heading STR to file F. */ - -static void -dump_dereferences_table (FILE *f, const char *str, HOST_WIDE_INT *table) -{ - basic_block bb; - - fprintf (dump_file, "%s", str); - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), - EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb) - { - fprintf (f, "%4i %i ", bb->index, bitmap_bit_p (final_bbs, bb->index)); - if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) - { - int i; - for (i = 0; i < func_param_count; i++) - { - int idx = bb->index * func_param_count + i; - fprintf (f, " %4" HOST_WIDE_INT_PRINT "d", table[idx]); - } - } - fprintf (f, "\n"); - } - fprintf (dump_file, "\n"); -} - -/* Determine what (parts of) parameters passed by reference that are not - assigned to are not certainly dereferenced in this function and thus the - dereferencing cannot be safely moved to the caller without potentially - introducing a segfault. Mark such REPRESENTATIVES as - grp_not_necessarilly_dereferenced. - - The dereferenced maximum "distance," i.e. the offset + size of the accessed - part is calculated rather than simple booleans are calculated for each - pointer parameter to handle cases when only a fraction of the whole - aggregate is allocated (see testsuite/gcc.c-torture/execute/ipa-sra-2.c for - an example). - - The maximum dereference distances for each pointer parameter and BB are - already stored in bb_dereference. This routine simply propagates these - values upwards by propagate_dereference_distances and then compares the - distances of individual parameters in the ENTRY BB to the equivalent - distances of each representative of a (fraction of a) parameter. */ - -static void -analyze_caller_dereference_legality (vec representatives) -{ - int i; - - if (dump_file && (dump_flags & TDF_DETAILS)) - dump_dereferences_table (dump_file, - "Dereference table before propagation:\n", - bb_dereferences); - - propagate_dereference_distances (); - - if (dump_file && (dump_flags & TDF_DETAILS)) - dump_dereferences_table (dump_file, - "Dereference table after propagation:\n", - bb_dereferences); - - for (i = 0; i < func_param_count; i++) - { - struct access *repr = representatives[i]; - int idx = ENTRY_BLOCK_PTR_FOR_FN (cfun)->index * func_param_count + i; - - if (!repr || no_accesses_p (repr)) - continue; - - do - { - if ((repr->offset + repr->size) > bb_dereferences[idx]) - repr->grp_not_necessarilly_dereferenced = 1; - repr = repr->next_grp; - } - while (repr); - } -} - -/* Return the representative access for the parameter declaration PARM if it is - a scalar passed by reference which is not written to and the pointer value - is not used directly. Thus, if it is legal to dereference it in the caller - and we can rule out modifications through aliases, such parameter should be - turned into one passed by value. Return NULL otherwise. */ - -static struct access * -unmodified_by_ref_scalar_representative (tree parm) -{ - int i, access_count; - struct access *repr; - vec *access_vec; - - access_vec = get_base_access_vector (parm); - gcc_assert (access_vec); - repr = (*access_vec)[0]; - if (repr->write) - return NULL; - repr->group_representative = repr; - - access_count = access_vec->length (); - for (i = 1; i < access_count; i++) - { - struct access *access = (*access_vec)[i]; - if (access->write) - return NULL; - access->group_representative = repr; - access->next_sibling = repr->next_sibling; - repr->next_sibling = access; - } - - repr->grp_read = 1; - repr->grp_scalar_ptr = 1; - return repr; -} - -/* Return true iff this ACCESS precludes IPA-SRA of the parameter it is - associated with. REQ_ALIGN is the minimum required alignment. */ - -static bool -access_precludes_ipa_sra_p (struct access *access, unsigned int req_align) -{ - unsigned int exp_align; - /* Avoid issues such as the second simple testcase in PR 42025. The problem - is incompatible assign in a call statement (and possibly even in asm - statements). This can be relaxed by using a new temporary but only for - non-TREE_ADDRESSABLE types and is probably not worth the complexity. (In - intraprocedural SRA we deal with this by keeping the old aggregate around, - something we cannot do in IPA-SRA.) */ - if (access->write - && (is_gimple_call (access->stmt) - || gimple_code (access->stmt) == GIMPLE_ASM)) - return true; - - exp_align = get_object_alignment (access->expr); - if (exp_align < req_align) - return true; - - return false; -} - - -/* Sort collected accesses for parameter PARM, identify representatives for - each accessed region and link them together. Return NULL if there are - different but overlapping accesses, return the special ptr value meaning - there are no accesses for this parameter if that is the case and return the - first representative otherwise. Set *RO_GRP if there is a group of accesses - with only read (i.e. no write) accesses. */ - -static struct access * -splice_param_accesses (tree parm, bool *ro_grp) -{ - int i, j, access_count, group_count; - int total_size = 0; - struct access *access, *res, **prev_acc_ptr = &res; - vec *access_vec; - - access_vec = get_base_access_vector (parm); - if (!access_vec) - return &no_accesses_representant; - access_count = access_vec->length (); - - access_vec->qsort (compare_access_positions); - - i = 0; - total_size = 0; - group_count = 0; - while (i < access_count) - { - bool modification; - tree a1_alias_type; - access = (*access_vec)[i]; - modification = access->write; - if (access_precludes_ipa_sra_p (access, TYPE_ALIGN (access->type))) - return NULL; - a1_alias_type = reference_alias_ptr_type (access->expr); - - /* Access is about to become group representative unless we find some - nasty overlap which would preclude us from breaking this parameter - apart. */ - - j = i + 1; - while (j < access_count) - { - struct access *ac2 = (*access_vec)[j]; - if (ac2->offset != access->offset) - { - /* All or nothing law for parameters. */ - if (access->offset + access->size > ac2->offset) - return NULL; - else - break; - } - else if (ac2->size != access->size) - return NULL; - - if (access_precludes_ipa_sra_p (ac2, TYPE_ALIGN (access->type)) - || (ac2->type != access->type - && (TREE_ADDRESSABLE (ac2->type) - || TREE_ADDRESSABLE (access->type))) - || (reference_alias_ptr_type (ac2->expr) != a1_alias_type)) - return NULL; - - modification |= ac2->write; - ac2->group_representative = access; - ac2->next_sibling = access->next_sibling; - access->next_sibling = ac2; - j++; - } - - group_count++; - access->grp_maybe_modified = modification; - if (!modification) - *ro_grp = true; - *prev_acc_ptr = access; - prev_acc_ptr = &access->next_grp; - total_size += access->size; - i = j; - } - - gcc_assert (group_count > 0); - return res; -} - -/* Decide whether parameters with representative accesses given by REPR should - be reduced into components. */ - -static int -decide_one_param_reduction (struct access *repr) -{ - HOST_WIDE_INT total_size, cur_parm_size; - bool by_ref; - tree parm; - - parm = repr->base; - cur_parm_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (parm))); - gcc_assert (cur_parm_size > 0); - - if (POINTER_TYPE_P (TREE_TYPE (parm))) - by_ref = true; - else - by_ref = false; - - if (dump_file) - { - struct access *acc; - fprintf (dump_file, "Evaluating PARAM group sizes for "); - print_generic_expr (dump_file, parm); - fprintf (dump_file, " (UID: %u): \n", DECL_UID (parm)); - for (acc = repr; acc; acc = acc->next_grp) - dump_access (dump_file, acc, true); - } - - total_size = 0; - int new_param_count = 0; - - for (; repr; repr = repr->next_grp) - { - gcc_assert (parm == repr->base); - - /* Taking the address of a non-addressable field is verboten. */ - if (by_ref && repr->non_addressable) - return 0; - - /* Do not decompose a non-BLKmode param in a way that would - create BLKmode params. Especially for by-reference passing - (thus, pointer-type param) this is hardly worthwhile. */ - if (DECL_MODE (parm) != BLKmode - && TYPE_MODE (repr->type) == BLKmode) - return 0; - - if (!by_ref || (!repr->grp_maybe_modified - && !repr->grp_not_necessarilly_dereferenced)) - total_size += repr->size; - else - total_size += cur_parm_size; - - new_param_count++; - } - - gcc_assert (new_param_count > 0); - - if (!by_ref) - { - if (total_size >= cur_parm_size) - return 0; - } - else - { - int parm_num_limit; - if (optimize_function_for_size_p (cfun)) - parm_num_limit = 1; - else - parm_num_limit = PARAM_VALUE (PARAM_IPA_SRA_PTR_GROWTH_FACTOR); - - if (new_param_count > parm_num_limit - || total_size > (parm_num_limit * cur_parm_size)) - return 0; - } - - if (dump_file) - fprintf (dump_file, " ....will be split into %i components\n", - new_param_count); - return new_param_count; -} - -/* The order of the following enums is important, we need to do extra work for - UNUSED_PARAMS, BY_VAL_ACCESSES and UNMODIF_BY_REF_ACCESSES. */ -enum ipa_splicing_result { NO_GOOD_ACCESS, UNUSED_PARAMS, BY_VAL_ACCESSES, - MODIF_BY_REF_ACCESSES, UNMODIF_BY_REF_ACCESSES }; - -/* Identify representatives of all accesses to all candidate parameters for - IPA-SRA. Return result based on what representatives have been found. */ - -static enum ipa_splicing_result -splice_all_param_accesses (vec &representatives) -{ - enum ipa_splicing_result result = NO_GOOD_ACCESS; - tree parm; - struct access *repr; - - representatives.create (func_param_count); - - for (parm = DECL_ARGUMENTS (current_function_decl); - parm; - parm = DECL_CHAIN (parm)) - { - if (is_unused_scalar_param (parm)) - { - representatives.quick_push (&no_accesses_representant); - if (result == NO_GOOD_ACCESS) - result = UNUSED_PARAMS; - } - else if (POINTER_TYPE_P (TREE_TYPE (parm)) - && is_gimple_reg_type (TREE_TYPE (TREE_TYPE (parm))) - && bitmap_bit_p (candidate_bitmap, DECL_UID (parm))) - { - repr = unmodified_by_ref_scalar_representative (parm); - representatives.quick_push (repr); - if (repr) - result = UNMODIF_BY_REF_ACCESSES; - } - else if (bitmap_bit_p (candidate_bitmap, DECL_UID (parm))) - { - bool ro_grp = false; - repr = splice_param_accesses (parm, &ro_grp); - representatives.quick_push (repr); - - if (repr && !no_accesses_p (repr)) - { - if (POINTER_TYPE_P (TREE_TYPE (parm))) - { - if (ro_grp) - result = UNMODIF_BY_REF_ACCESSES; - else if (result < MODIF_BY_REF_ACCESSES) - result = MODIF_BY_REF_ACCESSES; - } - else if (result < BY_VAL_ACCESSES) - result = BY_VAL_ACCESSES; - } - else if (no_accesses_p (repr) && (result == NO_GOOD_ACCESS)) - result = UNUSED_PARAMS; - } - else - representatives.quick_push (NULL); - } - - if (result == NO_GOOD_ACCESS) - { - representatives.release (); - return NO_GOOD_ACCESS; - } - - return result; -} - -/* Return the index of BASE in PARMS. Abort if it is not found. */ - -static inline int -get_param_index (tree base, vec parms) -{ - int i, len; - - len = parms.length (); - for (i = 0; i < len; i++) - if (parms[i] == base) - return i; - gcc_unreachable (); -} - -/* Convert the decisions made at the representative level into compact - parameter adjustments. REPRESENTATIVES are pointers to first - representatives of each param accesses, ADJUSTMENTS_COUNT is the expected - final number of adjustments. */ - -static ipa_parm_adjustment_vec -turn_representatives_into_adjustments (vec representatives, - int adjustments_count) -{ - vec parms; - ipa_parm_adjustment_vec adjustments; - tree parm; - int i; - - gcc_assert (adjustments_count > 0); - parms = ipa_get_vector_of_formal_parms (current_function_decl); - adjustments.create (adjustments_count); - parm = DECL_ARGUMENTS (current_function_decl); - for (i = 0; i < func_param_count; i++, parm = DECL_CHAIN (parm)) - { - struct access *repr = representatives[i]; - - if (!repr || no_accesses_p (repr)) - { - struct ipa_parm_adjustment adj; - - memset (&adj, 0, sizeof (adj)); - adj.base_index = get_param_index (parm, parms); - adj.base = parm; - if (!repr) - adj.op = IPA_PARM_OP_COPY; - else - adj.op = IPA_PARM_OP_REMOVE; - adj.arg_prefix = "ISRA"; - adjustments.quick_push (adj); - } - else - { - struct ipa_parm_adjustment adj; - int index = get_param_index (parm, parms); - - for (; repr; repr = repr->next_grp) - { - memset (&adj, 0, sizeof (adj)); - gcc_assert (repr->base == parm); - adj.base_index = index; - adj.base = repr->base; - adj.type = repr->type; - adj.alias_ptr_type = reference_alias_ptr_type (repr->expr); - adj.offset = repr->offset; - adj.reverse = repr->reverse; - adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base)) - && (repr->grp_maybe_modified - || repr->grp_not_necessarilly_dereferenced)); - adj.arg_prefix = "ISRA"; - adjustments.quick_push (adj); - } - } - } - parms.release (); - return adjustments; -} - -/* Analyze the collected accesses and produce a plan what to do with the - parameters in the form of adjustments, NULL meaning nothing. */ - -static ipa_parm_adjustment_vec -analyze_all_param_acesses (void) -{ - enum ipa_splicing_result repr_state; - bool proceed = false; - int i, adjustments_count = 0; - vec representatives; - ipa_parm_adjustment_vec adjustments; - - repr_state = splice_all_param_accesses (representatives); - if (repr_state == NO_GOOD_ACCESS) - return ipa_parm_adjustment_vec (); - - /* If there are any parameters passed by reference which are not modified - directly, we need to check whether they can be modified indirectly. */ - if (repr_state == UNMODIF_BY_REF_ACCESSES) - { - analyze_caller_dereference_legality (representatives); - analyze_modified_params (representatives); - } - - for (i = 0; i < func_param_count; i++) - { - struct access *repr = representatives[i]; - - if (repr && !no_accesses_p (repr)) - { - if (repr->grp_scalar_ptr) - { - adjustments_count++; - if (repr->grp_not_necessarilly_dereferenced - || repr->grp_maybe_modified) - representatives[i] = NULL; - else - { - proceed = true; - sra_stats.scalar_by_ref_to_by_val++; - } - } - else - { - int new_components = decide_one_param_reduction (repr); - - if (new_components == 0) - { - representatives[i] = NULL; - adjustments_count++; - } - else - { - adjustments_count += new_components; - sra_stats.aggregate_params_reduced++; - sra_stats.param_reductions_created += new_components; - proceed = true; - } - } - } - else - { - if (no_accesses_p (repr)) - { - proceed = true; - sra_stats.deleted_unused_parameters++; - } - adjustments_count++; - } - } - - if (!proceed && dump_file) - fprintf (dump_file, "NOT proceeding to change params.\n"); - - if (proceed) - adjustments = turn_representatives_into_adjustments (representatives, - adjustments_count); - else - adjustments = ipa_parm_adjustment_vec (); - - representatives.release (); - return adjustments; -} - -/* If a parameter replacement identified by ADJ does not yet exist in the form - of declaration, create it and record it, otherwise return the previously - created one. */ - -static tree -get_replaced_param_substitute (struct ipa_parm_adjustment *adj) -{ - tree repl; - if (!adj->new_ssa_base) - { - char *pretty_name = make_fancy_name (adj->base); - - repl = create_tmp_reg (TREE_TYPE (adj->base), "ISR"); - DECL_NAME (repl) = get_identifier (pretty_name); - DECL_NAMELESS (repl) = 1; - obstack_free (&name_obstack, pretty_name); - - adj->new_ssa_base = repl; - } - else - repl = adj->new_ssa_base; - return repl; -} - -/* Find the first adjustment for a particular parameter BASE in a vector of - ADJUSTMENTS which is not a copy_param. Return NULL if there is no such - adjustment. */ - -static struct ipa_parm_adjustment * -get_adjustment_for_base (ipa_parm_adjustment_vec adjustments, tree base) -{ - int i, len; - - len = adjustments.length (); - for (i = 0; i < len; i++) - { - struct ipa_parm_adjustment *adj; - - adj = &adjustments[i]; - if (adj->op != IPA_PARM_OP_COPY && adj->base == base) - return adj; - } - - return NULL; -} - -/* If OLD_NAME, which is being defined by statement STMT, is an SSA_NAME of a - parameter which is to be removed because its value is not used, create a new - SSA_NAME relating to a replacement VAR_DECL, replace all uses of the - original with it and return it. If there is no need to re-map, return NULL. - ADJUSTMENTS is a pointer to a vector of IPA-SRA adjustments. */ - -static tree -replace_removed_params_ssa_names (tree old_name, gimple *stmt, - ipa_parm_adjustment_vec adjustments) -{ - struct ipa_parm_adjustment *adj; - tree decl, repl, new_name; - - if (TREE_CODE (old_name) != SSA_NAME) - return NULL; - - decl = SSA_NAME_VAR (old_name); - if (decl == NULL_TREE - || TREE_CODE (decl) != PARM_DECL) - return NULL; - - adj = get_adjustment_for_base (adjustments, decl); - if (!adj) - return NULL; - - repl = get_replaced_param_substitute (adj); - new_name = make_ssa_name (repl, stmt); - SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_name) - = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (old_name); - - if (dump_file) - { - fprintf (dump_file, "replacing an SSA name of a removed param "); - print_generic_expr (dump_file, old_name); - fprintf (dump_file, " with "); - print_generic_expr (dump_file, new_name); - fprintf (dump_file, "\n"); - } - - replace_uses_by (old_name, new_name); - return new_name; -} - -/* If the statement STMT contains any expressions that need to replaced with a - different one as noted by ADJUSTMENTS, do so. Handle any potential type - incompatibilities (GSI is used to accommodate conversion statements and must - point to the statement). Return true iff the statement was modified. */ - -static bool -sra_ipa_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi, - ipa_parm_adjustment_vec adjustments) -{ - tree *lhs_p, *rhs_p; - bool any; - - if (!gimple_assign_single_p (stmt)) - return false; - - rhs_p = gimple_assign_rhs1_ptr (stmt); - lhs_p = gimple_assign_lhs_ptr (stmt); - - any = ipa_modify_expr (rhs_p, false, adjustments); - any |= ipa_modify_expr (lhs_p, false, adjustments); - if (any) - { - tree new_rhs = NULL_TREE; - - if (!useless_type_conversion_p (TREE_TYPE (*lhs_p), TREE_TYPE (*rhs_p))) - { - if (TREE_CODE (*rhs_p) == CONSTRUCTOR) - { - /* V_C_Es of constructors can cause trouble (PR 42714). */ - if (is_gimple_reg_type (TREE_TYPE (*lhs_p))) - *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); - else - *rhs_p = build_constructor (TREE_TYPE (*lhs_p), - NULL); - } - else - new_rhs = fold_build1_loc (gimple_location (stmt), - VIEW_CONVERT_EXPR, TREE_TYPE (*lhs_p), - *rhs_p); - } - else if (REFERENCE_CLASS_P (*rhs_p) - && is_gimple_reg_type (TREE_TYPE (*lhs_p)) - && !is_gimple_reg (*lhs_p)) - /* This can happen when an assignment in between two single field - structures is turned into an assignment in between two pointers to - scalars (PR 42237). */ - new_rhs = *rhs_p; - - if (new_rhs) - { - tree tmp = force_gimple_operand_gsi (gsi, new_rhs, true, NULL_TREE, - true, GSI_SAME_STMT); - - gimple_assign_set_rhs_from_tree (gsi, tmp); - } - - return true; - } - - return false; -} - -/* Traverse the function body and all modifications as described in - ADJUSTMENTS. Return true iff the CFG has been changed. */ - -bool -ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments) -{ - bool cfg_changed = false; - basic_block bb; - - FOR_EACH_BB_FN (bb, cfun) - { - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gphi *phi = as_a (gsi_stmt (gsi)); - tree new_lhs, old_lhs = gimple_phi_result (phi); - new_lhs = replace_removed_params_ssa_names (old_lhs, phi, adjustments); - if (new_lhs) - { - gimple_phi_set_result (phi, new_lhs); - release_ssa_name (old_lhs); - } - } - - gsi = gsi_start_bb (bb); - while (!gsi_end_p (gsi)) - { - gimple *stmt = gsi_stmt (gsi); - bool modified = false; - tree *t; - unsigned i; - - switch (gimple_code (stmt)) - { - case GIMPLE_RETURN: - t = gimple_return_retval_ptr (as_a (stmt)); - if (*t != NULL_TREE) - modified |= ipa_modify_expr (t, true, adjustments); - break; - - case GIMPLE_ASSIGN: - modified |= sra_ipa_modify_assign (stmt, &gsi, adjustments); - break; - - case GIMPLE_CALL: - /* Operands must be processed before the lhs. */ - for (i = 0; i < gimple_call_num_args (stmt); i++) - { - t = gimple_call_arg_ptr (stmt, i); - modified |= ipa_modify_expr (t, true, adjustments); - } - - if (gimple_call_lhs (stmt)) - { - t = gimple_call_lhs_ptr (stmt); - modified |= ipa_modify_expr (t, false, adjustments); - } - break; - - case GIMPLE_ASM: - { - gasm *asm_stmt = as_a (stmt); - for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++) - { - t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i)); - modified |= ipa_modify_expr (t, true, adjustments); - } - for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++) - { - t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i)); - modified |= ipa_modify_expr (t, false, adjustments); - } - } - break; - - default: - break; - } - - def_operand_p defp; - ssa_op_iter iter; - FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_DEF) - { - tree old_def = DEF_FROM_PTR (defp); - if (tree new_def = replace_removed_params_ssa_names (old_def, stmt, - adjustments)) - { - SET_DEF (defp, new_def); - release_ssa_name (old_def); - modified = true; - } - } - - if (modified) - { - update_stmt (stmt); - if (maybe_clean_eh_stmt (stmt) - && gimple_purge_dead_eh_edges (gimple_bb (stmt))) - cfg_changed = true; - } - gsi_next (&gsi); - } - } - - return cfg_changed; -} - -/* Call gimple_debug_bind_reset_value on all debug statements describing - gimple register parameters that are being removed or replaced. */ - -static void -sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments) -{ - int i, len; - gimple_stmt_iterator *gsip = NULL, gsi; - - if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun))) - { - gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - gsip = &gsi; - } - len = adjustments.length (); - for (i = 0; i < len; i++) - { - struct ipa_parm_adjustment *adj; - imm_use_iterator ui; - gimple *stmt; - gdebug *def_temp; - tree name, vexpr, copy = NULL_TREE; - use_operand_p use_p; - - adj = &adjustments[i]; - if (adj->op == IPA_PARM_OP_COPY || !is_gimple_reg (adj->base)) - continue; - name = ssa_default_def (cfun, adj->base); - vexpr = NULL; - if (name) - FOR_EACH_IMM_USE_STMT (stmt, ui, name) - { - if (gimple_clobber_p (stmt)) - { - gimple_stmt_iterator cgsi = gsi_for_stmt (stmt); - unlink_stmt_vdef (stmt); - gsi_remove (&cgsi, true); - release_defs (stmt); - continue; - } - /* All other users must have been removed by - ipa_sra_modify_function_body. */ - gcc_assert (is_gimple_debug (stmt)); - if (vexpr == NULL && gsip != NULL) - { - gcc_assert (TREE_CODE (adj->base) == PARM_DECL); - vexpr = make_node (DEBUG_EXPR_DECL); - def_temp = gimple_build_debug_source_bind (vexpr, adj->base, - NULL); - DECL_ARTIFICIAL (vexpr) = 1; - TREE_TYPE (vexpr) = TREE_TYPE (name); - SET_DECL_MODE (vexpr, DECL_MODE (adj->base)); - gsi_insert_before (gsip, def_temp, GSI_SAME_STMT); - } - if (vexpr) - { - FOR_EACH_IMM_USE_ON_STMT (use_p, ui) - SET_USE (use_p, vexpr); - } - else - gimple_debug_bind_reset_value (stmt); - update_stmt (stmt); - } - /* Create a VAR_DECL for debug info purposes. */ - if (!DECL_IGNORED_P (adj->base)) - { - copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl), - VAR_DECL, DECL_NAME (adj->base), - TREE_TYPE (adj->base)); - if (DECL_PT_UID_SET_P (adj->base)) - SET_DECL_PT_UID (copy, DECL_PT_UID (adj->base)); - TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (adj->base); - TREE_READONLY (copy) = TREE_READONLY (adj->base); - TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (adj->base); - DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (adj->base); - DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (adj->base); - DECL_IGNORED_P (copy) = DECL_IGNORED_P (adj->base); - DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (adj->base); - DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; - SET_DECL_RTL (copy, 0); - TREE_USED (copy) = 1; - DECL_CONTEXT (copy) = current_function_decl; - add_local_decl (cfun, copy); - DECL_CHAIN (copy) = - BLOCK_VARS (DECL_INITIAL (current_function_decl)); - BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy; - } - if (gsip != NULL && copy && target_for_debug_bind (adj->base)) - { - gcc_assert (TREE_CODE (adj->base) == PARM_DECL); - if (vexpr) - def_temp = gimple_build_debug_bind (copy, vexpr, NULL); - else - def_temp = gimple_build_debug_source_bind (copy, adj->base, - NULL); - gsi_insert_before (gsip, def_temp, GSI_SAME_STMT); - } - } -} - -/* Return false if all callers have at least as many actual arguments as there - are formal parameters in the current function and that their types - match. */ - -static bool -some_callers_have_mismatched_arguments_p (struct cgraph_node *node, - void *data ATTRIBUTE_UNUSED) -{ - struct cgraph_edge *cs; - for (cs = node->callers; cs; cs = cs->next_caller) - if (!cs->call_stmt || !callsite_arguments_match_p (cs->call_stmt)) - return true; - - return false; -} - -/* Return false if all callers have vuse attached to a call statement. */ - -static bool -some_callers_have_no_vuse_p (struct cgraph_node *node, - void *data ATTRIBUTE_UNUSED) -{ - struct cgraph_edge *cs; - for (cs = node->callers; cs; cs = cs->next_caller) - if (!cs->call_stmt || !gimple_vuse (cs->call_stmt)) - return true; - - return false; -} - -/* Convert all callers of NODE. */ - -static bool -convert_callers_for_node (struct cgraph_node *node, - void *data) -{ - ipa_parm_adjustment_vec *adjustments = (ipa_parm_adjustment_vec *) data; - bitmap recomputed_callers = BITMAP_ALLOC (NULL); - struct cgraph_edge *cs; - - for (cs = node->callers; cs; cs = cs->next_caller) - { - push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl)); - - if (dump_file) - fprintf (dump_file, "Adjusting call %s -> %s\n", - cs->caller->dump_name (), cs->callee->dump_name ()); - - ipa_modify_call_arguments (cs, cs->call_stmt, *adjustments); - - pop_cfun (); - } - - for (cs = node->callers; cs; cs = cs->next_caller) - if (bitmap_set_bit (recomputed_callers, cs->caller->get_uid ()) - && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl))) - compute_fn_summary (cs->caller, true); - BITMAP_FREE (recomputed_callers); - - return true; -} - -/* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS. */ - -static void -convert_callers (struct cgraph_node *node, tree old_decl, - ipa_parm_adjustment_vec adjustments) -{ - basic_block this_block; - - node->call_for_symbol_and_aliases (convert_callers_for_node, - &adjustments, false); - - if (!encountered_recursive_call) - return; - - FOR_EACH_BB_FN (this_block, cfun) - { - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gcall *stmt; - tree call_fndecl; - stmt = dyn_cast (gsi_stmt (gsi)); - if (!stmt) - continue; - call_fndecl = gimple_call_fndecl (stmt); - if (call_fndecl == old_decl) - { - if (dump_file) - fprintf (dump_file, "Adjusting recursive call"); - gimple_call_set_fndecl (stmt, node->decl); - ipa_modify_call_arguments (NULL, stmt, adjustments); - } - } - } - - return; -} - -/* Perform all the modification required in IPA-SRA for NODE to have parameters - as given in ADJUSTMENTS. Return true iff the CFG has been changed. */ - -static bool -modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) -{ - struct cgraph_node *new_node; - bool cfg_changed; - - cgraph_edge::rebuild_edges (); - free_dominance_info (CDI_DOMINATORS); - pop_cfun (); - - /* This must be done after rebuilding cgraph edges for node above. - Otherwise any recursive calls to node that are recorded in - redirect_callers will be corrupted. */ - vec redirect_callers = node->collect_callers (); - new_node = node->create_version_clone_with_body (redirect_callers, NULL, - NULL, false, NULL, NULL, - "isra"); - redirect_callers.release (); - - push_cfun (DECL_STRUCT_FUNCTION (new_node->decl)); - ipa_modify_formal_parameters (current_function_decl, adjustments); - cfg_changed = ipa_sra_modify_function_body (adjustments); - sra_ipa_reset_debug_stmts (adjustments); - convert_callers (new_node, node->decl, adjustments); - new_node->make_local (); - return cfg_changed; -} - -/* Means of communication between ipa_sra_check_caller and - ipa_sra_preliminary_function_checks. */ - -struct ipa_sra_check_caller_data -{ - bool has_callers; - bool bad_arg_alignment; - bool has_thunk; -}; - -/* If NODE has a caller, mark that fact in DATA which is pointer to - ipa_sra_check_caller_data. Also check all aggregate arguments in all known - calls if they are unit aligned and if not, set the appropriate flag in DATA - too. */ - -static bool -ipa_sra_check_caller (struct cgraph_node *node, void *data) -{ - if (!node->callers) - return false; - - struct ipa_sra_check_caller_data *iscc; - iscc = (struct ipa_sra_check_caller_data *) data; - iscc->has_callers = true; - - for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) - { - if (cs->caller->thunk.thunk_p) - { - iscc->has_thunk = true; - return true; - } - gimple *call_stmt = cs->call_stmt; - unsigned count = gimple_call_num_args (call_stmt); - for (unsigned i = 0; i < count; i++) - { - tree arg = gimple_call_arg (call_stmt, i); - if (is_gimple_reg (arg)) - continue; - - tree offset; - poly_int64 bitsize, bitpos; - machine_mode mode; - int unsignedp, reversep, volatilep = 0; - get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode, - &unsignedp, &reversep, &volatilep); - if (!multiple_p (bitpos, BITS_PER_UNIT)) - { - iscc->bad_arg_alignment = true; - return true; - } - } - } - - return false; -} - -/* Return false the function is apparently unsuitable for IPA-SRA based on it's - attributes, return true otherwise. NODE is the cgraph node of the current - function. */ - -static bool -ipa_sra_preliminary_function_checks (struct cgraph_node *node) -{ - if (!node->can_be_local_p ()) - { - if (dump_file) - fprintf (dump_file, "Function not local to this compilation unit.\n"); - return false; - } - - if (!node->local.can_change_signature) - { - if (dump_file) - fprintf (dump_file, "Function cannot change signature.\n"); - return false; - } - - if (!tree_versionable_function_p (node->decl)) - { - if (dump_file) - fprintf (dump_file, "Function is not versionable.\n"); - return false; - } - - if (!opt_for_fn (node->decl, optimize) - || !opt_for_fn (node->decl, flag_ipa_sra)) - { - if (dump_file) - fprintf (dump_file, "Function not optimized.\n"); - return false; - } - - if (DECL_VIRTUAL_P (current_function_decl)) - { - if (dump_file) - fprintf (dump_file, "Function is a virtual method.\n"); - return false; - } - - if ((DECL_ONE_ONLY (node->decl) || DECL_EXTERNAL (node->decl)) - && ipa_fn_summaries->get (node) - && ipa_fn_summaries->get (node)->size >= MAX_INLINE_INSNS_AUTO) - { - if (dump_file) - fprintf (dump_file, "Function too big to be made truly local.\n"); - return false; - } - - if (cfun->stdarg) - { - if (dump_file) - fprintf (dump_file, "Function uses stdarg. \n"); - return false; - } - - if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) - return false; - - if (DECL_DISREGARD_INLINE_LIMITS (node->decl)) - { - if (dump_file) - fprintf (dump_file, "Always inline function will be inlined " - "anyway. \n"); - return false; - } - - struct ipa_sra_check_caller_data iscc; - memset (&iscc, 0, sizeof(iscc)); - node->call_for_symbol_and_aliases (ipa_sra_check_caller, &iscc, true); - if (!iscc.has_callers) - { - if (dump_file) - fprintf (dump_file, - "Function has no callers in this compilation unit.\n"); - return false; - } - - if (iscc.bad_arg_alignment) - { - if (dump_file) - fprintf (dump_file, - "A function call has an argument with non-unit alignment.\n"); - return false; - } - - if (iscc.has_thunk) - { - if (dump_file) - fprintf (dump_file, - "A has thunk.\n"); - return false; - } - - return true; -} - -/* Perform early interprocedural SRA. */ - -static unsigned int -ipa_early_sra (void) -{ - struct cgraph_node *node = cgraph_node::get (current_function_decl); - ipa_parm_adjustment_vec adjustments; - int ret = 0; - - if (!ipa_sra_preliminary_function_checks (node)) - return 0; - - sra_initialize (); - sra_mode = SRA_MODE_EARLY_IPA; - - if (!find_param_candidates ()) - { - if (dump_file) - fprintf (dump_file, "Function has no IPA-SRA candidates.\n"); - goto simple_out; - } - - if (node->call_for_symbol_and_aliases - (some_callers_have_mismatched_arguments_p, NULL, true)) - { - if (dump_file) - fprintf (dump_file, "There are callers with insufficient number of " - "arguments or arguments with type mismatches.\n"); - goto simple_out; - } - - if (node->call_for_symbol_and_aliases - (some_callers_have_no_vuse_p, NULL, true)) - { - if (dump_file) - fprintf (dump_file, "There are callers with no VUSE attached " - "to a call stmt.\n"); - goto simple_out; - } - - bb_dereferences = XCNEWVEC (HOST_WIDE_INT, - func_param_count - * last_basic_block_for_fn (cfun)); - final_bbs = BITMAP_ALLOC (NULL); - - scan_function (); - if (encountered_apply_args) - { - if (dump_file) - fprintf (dump_file, "Function calls __builtin_apply_args().\n"); - goto out; - } - - if (encountered_unchangable_recursive_call) - { - if (dump_file) - fprintf (dump_file, "Function calls itself with insufficient " - "number of arguments.\n"); - goto out; - } - - adjustments = analyze_all_param_acesses (); - if (!adjustments.exists ()) - goto out; - if (dump_file) - ipa_dump_param_adjustments (dump_file, adjustments, current_function_decl); - - if (modify_function (node, adjustments)) - ret = TODO_update_ssa | TODO_cleanup_cfg; - else - ret = TODO_update_ssa; - adjustments.release (); - - statistics_counter_event (cfun, "Unused parameters deleted", - sra_stats.deleted_unused_parameters); - statistics_counter_event (cfun, "Scalar parameters converted to by-value", - sra_stats.scalar_by_ref_to_by_val); - statistics_counter_event (cfun, "Aggregate parameters broken up", - sra_stats.aggregate_params_reduced); - statistics_counter_event (cfun, "Aggregate parameter components created", - sra_stats.param_reductions_created); - - out: - BITMAP_FREE (final_bbs); - free (bb_dereferences); - simple_out: - sra_deinitialize (); - return ret; -} - -namespace { - -const pass_data pass_data_early_ipa_sra = -{ - GIMPLE_PASS, /* type */ - "eipa_sra", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_IPA_SRA, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_symtab, /* todo_flags_finish */ -}; - -class pass_early_ipa_sra : public gimple_opt_pass -{ -public: - pass_early_ipa_sra (gcc::context *ctxt) - : gimple_opt_pass (pass_data_early_ipa_sra, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) { return flag_ipa_sra && dbg_cnt (eipa_sra); } - virtual unsigned int execute (function *) { return ipa_early_sra (); } - -}; // class pass_early_ipa_sra - -} // anon namespace - -gimple_opt_pass * -make_pass_early_ipa_sra (gcc::context *ctxt) -{ - return new pass_early_ipa_sra (ctxt); -} diff --git a/gcc/tree-sra.h b/gcc/tree-sra.h new file mode 100644 index 0000000..8baf09f --- /dev/null +++ b/gcc/tree-sra.h @@ -0,0 +1,31 @@ +/* Scalar Replacement of Aggregates (SRA) converts some structure + references into scalar references, exposing them to the scalar + optimizers. + Copyright (C) 2019 Free Software Foundation, Inc. + +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 +. */ + +bool type_internals_preclude_sra_p (tree type, const char **msg); + +/* Return true iff TYPE is stdarg va_list type (which early SRA and IPA-SRA + should leave alone). */ + +static inline bool +is_va_list_type (tree type) +{ + return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node); +} -- cgit v1.1 From c3ff46a5185b69d3022edb28d3f7e6dfe9f1c351 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 20 Sep 2019 00:16:15 +0000 Subject: Daily bump. From-SVN: r275986 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index c8a46c1..0fc3d8d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190919 +20190920 -- cgit v1.1 From d865ed7227a98bc1229d6e42bca35f605d6f4f75 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 20 Sep 2019 06:42:39 +0000 Subject: re PR target/91767 (After r274953, clang-compiled xgcc segfaults during RTL pass: stv) 2019-09-20 Richard Biener PR target/91767 * config/i386/i386-features.c (general_scalar_chain::convert_registers): Ensure there's a sequence point between allocating the new register and passing a reference to a reg via regno_reg_rtx. From-SVN: r275989 --- gcc/ChangeLog | 7 +++++++ gcc/config/i386/i386-features.c | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6f34d1a..31dd206 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-20 Richard Biener + + PR target/91767 + * config/i386/i386-features.c (general_scalar_chain::convert_registers): + Ensure there's a sequence point between allocating the new register + and passing a reference to a reg via regno_reg_rtx. + 2019-09-20 Martin Jambor * coretypes.h (cgraph_edge): Declare. diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index f57a555..546d78d 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -1210,7 +1210,10 @@ general_scalar_chain::convert_registers () bitmap_iterator bi; unsigned id; EXECUTE_IF_SET_IN_BITMAP (defs_conv, 0, id, bi) - defs_map.put (regno_reg_rtx[id], gen_reg_rtx (smode)); + { + rtx chain_reg = gen_reg_rtx (smode); + defs_map.put (regno_reg_rtx[id], chain_reg); + } EXECUTE_IF_SET_IN_BITMAP (insns_conv, 0, id, bi) for (df_ref ref = DF_INSN_UID_DEFS (id); ref; ref = DF_REF_NEXT_LOC (ref)) if (bitmap_bit_p (defs_conv, DF_REF_REGNO (ref))) -- cgit v1.1 From 6e222b2a3aede20f3093802d1649e75848e3bd2b Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 20 Sep 2019 08:35:59 +0000 Subject: re PR tree-optimization/91822 (FAIL: gcc.dg/pr88031.c (internal compiler error)) 2019-09-20 Richard Biener PR tree-optimization/91822 * tree-vectorizer.h (vectorizable_condition): Restore for_reduction parameter. * tree-vect-loop.c (vectorizable_reduction): Adjust asserts for reduc_index in nested cycles, adjust vectorizable_condition calls. * tree-vect-stmts.c (vectorizable_condition): Restore for_reduction parameter. (vect_analyze_stmt): Adjust. (vect_transform_stmt): Likewise. From-SVN: r275990 --- gcc/ChangeLog | 13 +++++++++++++ gcc/tree-vect-loop.c | 11 ++++++----- gcc/tree-vect-stmts.c | 10 +++++----- gcc/tree-vectorizer.h | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 31dd206..bda334b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2019-09-20 Richard Biener + PR tree-optimization/91822 + * tree-vectorizer.h (vectorizable_condition): Restore for_reduction + parameter. + * tree-vect-loop.c (vectorizable_reduction): Adjust asserts + for reduc_index in nested cycles, adjust vectorizable_condition + calls. + * tree-vect-stmts.c (vectorizable_condition): Restore for_reduction + parameter. + (vect_analyze_stmt): Adjust. + (vect_transform_stmt): Likewise. + +2019-09-20 Richard Biener + PR target/91767 * config/i386/i386-features.c (general_scalar_chain::convert_registers): Ensure there's a sequence point between allocating the new register diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 9a4d960d..7e13986 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -6534,9 +6534,10 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, { /* Only call during the analysis stage, otherwise we'll lose STMT_VINFO_TYPE. */ - gcc_assert (reduc_index > 0); + gcc_assert (nested_cycle || reduc_index > 0); if (!vec_stmt && !vectorizable_condition (stmt_info, gsi, NULL, - reduc_index, NULL, cost_vec)) + true, reduc_index, + NULL, cost_vec)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6991,7 +6992,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, { gcc_assert (!slp_node && reduc_index > 0); return vectorizable_condition (stmt_info, gsi, vec_stmt, - reduc_index, NULL, NULL); + true, reduc_index, NULL, NULL); } /* Create the destination vector */ @@ -7021,8 +7022,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, { if (code == COND_EXPR) { - gcc_assert (!slp_node && reduc_index > 0); - vectorizable_condition (stmt_info, gsi, vec_stmt, + gcc_assert (!slp_node && (nested_cycle || reduc_index > 0)); + vectorizable_condition (stmt_info, gsi, vec_stmt, true, reduc_index, NULL, NULL); break; } diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 0636e5c..b1e97f8 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -9778,7 +9778,8 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, bool vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, - stmt_vec_info *vec_stmt, int reduc_index, + stmt_vec_info *vec_stmt, bool for_reduction, + int reduc_index, slp_tree slp_node, stmt_vector_for_cost *cost_vec) { vec_info *vinfo = stmt_info->vinfo; @@ -9807,7 +9808,6 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vec vec_oprnds3 = vNULL; tree vec_cmp_type; bool masked = false; - bool for_reduction = (reduc_index > 0); if (for_reduction && STMT_SLP_TYPE (stmt_info)) return false; @@ -10668,7 +10668,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize, node_instance, cost_vec) || vectorizable_induction (stmt_info, NULL, NULL, node, cost_vec) || vectorizable_shift (stmt_info, NULL, NULL, node, cost_vec) - || vectorizable_condition (stmt_info, NULL, NULL, 0, node, + || vectorizable_condition (stmt_info, NULL, NULL, false, -1, node, cost_vec) || vectorizable_comparison (stmt_info, NULL, NULL, node, cost_vec)); @@ -10687,7 +10687,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize, || vectorizable_load (stmt_info, NULL, NULL, node, node_instance, cost_vec) || vectorizable_store (stmt_info, NULL, NULL, node, cost_vec) - || vectorizable_condition (stmt_info, NULL, NULL, 0, node, + || vectorizable_condition (stmt_info, NULL, NULL, false, -1, node, cost_vec) || vectorizable_comparison (stmt_info, NULL, NULL, node, cost_vec)); @@ -10792,7 +10792,7 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, break; case condition_vec_info_type: - done = vectorizable_condition (stmt_info, gsi, &vec_stmt, 0, + done = vectorizable_condition (stmt_info, gsi, &vec_stmt, false, -1, slp_node, NULL); gcc_assert (done); break; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index aef0ff8..a514c77 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1534,7 +1534,7 @@ extern void vect_remove_stores (stmt_vec_info); extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree, slp_instance, stmt_vector_for_cost *); extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *, - stmt_vec_info *, int, slp_tree, + stmt_vec_info *, bool, int, slp_tree, stmt_vector_for_cost *); extern bool vectorizable_shift (stmt_vec_info, gimple_stmt_iterator *, stmt_vec_info *, slp_tree, -- cgit v1.1 From 522da4c233cb626f66e413dabb86a0a78adaafce Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 20 Sep 2019 09:11:20 +0000 Subject: re PR c/91815 (questionable error on type definition at file scope) PR c/91815 * c-decl.c (pushdecl): In C detect duplicate declarations across scopes of identifiers in the external scope only for variables and functions. From-SVN: r275992 --- gcc/c/ChangeLog | 6 ++++++ gcc/c/c-decl.c | 7 +++++-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/typedef-var-1.c | 14 ++++++++++++++ gcc/testsuite/gcc.dg/typedef-var-2.c | 15 +++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/typedef-var-1.c create mode 100644 gcc/testsuite/gcc.dg/typedef-var-2.c (limited to 'gcc') diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 285ea18..9665549 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2019-09-20 Eric Botcazou + + PR c/91815 + * c-decl.c (pushdecl): In C detect duplicate declarations across scopes + of identifiers in the external scope only for variables and functions. + 2019-09-04 Prathamesh Kulkarni PR c/78736 diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 31116b2..132fa3e 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -3130,8 +3130,11 @@ pushdecl (tree x) detecting duplicate declarations of the same object, no matter what scope they are in; this is what we do here. (C99 6.2.7p2: All declarations that refer to the same object or function shall - have compatible type; otherwise, the behavior is undefined.) */ - if (DECL_EXTERNAL (x) || scope == file_scope) + have compatible type; otherwise, the behavior is undefined.) + However, in Objective-C, we also want to detect declarations + conflicting with those of the basic types. */ + if ((DECL_EXTERNAL (x) || scope == file_scope) + && (VAR_OR_FUNCTION_DECL_P (x) || c_dialect_objc ())) { tree type = TREE_TYPE (x); tree vistype = NULL_TREE; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a4323b4..59c6b79 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-20 Eric Botcazou + + * gcc.dg/typedef-var-1.c: New test. + * gcc.dg/typedef-var-2.c: Likewise. + 2019-09-20 Martin Jambor * g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan. diff --git a/gcc/testsuite/gcc.dg/typedef-var-1.c b/gcc/testsuite/gcc.dg/typedef-var-1.c new file mode 100644 index 0000000..2cda92d --- /dev/null +++ b/gcc/testsuite/gcc.dg/typedef-var-1.c @@ -0,0 +1,14 @@ +/* PR c/91815 */ +/* { dg-do compile } */ + +int f (void) +{ + extern int t; + extern float v; + + return (v > 0.0f); +} + +typedef float t; + +t v = 4.5f; diff --git a/gcc/testsuite/gcc.dg/typedef-var-2.c b/gcc/testsuite/gcc.dg/typedef-var-2.c new file mode 100644 index 0000000..716d29c --- /dev/null +++ b/gcc/testsuite/gcc.dg/typedef-var-2.c @@ -0,0 +1,15 @@ +/* PR c/91815 */ +/* { dg-do compile } */ + +int f (void) +{ + extern float v; + + return (v > 0.0f); +} + +extern int t; + +typedef float t; /* { dg-error "redeclared as different kind of symbol" } */ + +t v = 4.5f; -- cgit v1.1 From 9ba4312712a96eba938c9d280e57f71929cdef41 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 20 Sep 2019 09:42:40 +0000 Subject: re PR target/91269 (unaligned floating-point register with -mcpu=niagara4 -fcall-used-g6) PR target/91269 * config/sparc/sparc.h (HARD_REGNO_CALLER_SAVE_MODE): Define. From-SVN: r275994 --- gcc/ChangeLog | 5 +++ gcc/config/sparc/sparc.h | 7 +++++ gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.dg/pr91269.c | 70 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr91269.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bda334b..c841fff 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-20 Eric Botcazou + + PR target/91269 + * config/sparc/sparc.h (HARD_REGNO_CALLER_SAVE_MODE): Define. + 2019-09-20 Richard Biener PR tree-optimization/91822 diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index defcba8..d147418 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -711,6 +711,13 @@ along with GCC; see the file COPYING3. If not see register window instruction in the prologue. */ #define HARD_REGNO_RENAME_OK(FROM, TO) ((FROM) != 1) +/* Select a register mode required for caller save of hard regno REGNO. + Contrary to what is documented, the default is not the smallest suitable + mode but the largest suitable mode for the given (REGNO, NREGS) pair and + it quickly creates paradoxical subregs that can be problematic. */ +#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ + ((MODE) == VOIDmode ? choose_hard_reg_mode (REGNO, NREGS, false) : (MODE)) + /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 59c6b79..8e1b4be 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2019-09-20 Eric Botcazou + * gcc.dg/pr91269.c: New test. + +2019-09-20 Eric Botcazou + * gcc.dg/typedef-var-1.c: New test. * gcc.dg/typedef-var-2.c: Likewise. diff --git a/gcc/testsuite/gcc.dg/pr91269.c b/gcc/testsuite/gcc.dg/pr91269.c new file mode 100644 index 0000000..8c03ba8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr91269.c @@ -0,0 +1,70 @@ +/* PR target/91269 */ +/* Testcase by Sergei Trofimovich */ + +/* { dg-do assemble } */ +/* { dg-options "-O2 -Wno-int-conversion" } */ +/* { dg-additional-options "-fcall-used-g6 -fPIE -mcpu=niagara4" { target sparc*-*-* } } */ + +struct m; + +enum { a = 2 }; +int b[1]; +int d[2715]; +int e, f, h; +enum { i = 2 } j; +inline int c(int k) { + char *cp; + if (k >= 62 && k <= 247) + cp = b[k]; + if (cp) + return 65533; + return 2; +} +inline int g(int k) { + if (k < sizeof(d)) + return e; + return 0; +} + +int u(struct m*, char*, char*); + +int l(struct m *k, char n, long o, int *p) { + int q, flags = j, r, s, lasttwo = *p; + char inptr, outptr; + while (inptr) { + if (__builtin_expect(h, 0)) + break; + unsigned ch = inptr; + if (lasttwo) { + long need = lasttwo >> 3; + if (__builtin_expect(need > n, 0)) + break; + } else if (s == i) { + long t = c(ch); + if (t != 65533) { + int jch = g(ch); + if (jch & 8) + continue; + } + } + if (ch <= 5) + ; + else { + long t = c(ch); + if (t != 65533) + ; + else { + switch (f >> 8) + case 79: + q = f == 20308 || f == 20350; + if (q) + if (j) + r = u(k, &inptr, &outptr); + s = *p; + if (r) + if (o && flags & a) + break; + } + } + } +} -- cgit v1.1 From d63eadac7db10d4846bdffa93fd164cb035fb102 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 20 Sep 2019 09:54:54 +0000 Subject: re PR testsuite/91821 (r275928 breaks gcc.target/powerpc/sad-vectorize-2.c) 2019-09-20 Richard Biener PR tree-optimization/91821 * tree-vect-loop.c (check_reduction_path): Check we can compute reduc_idx. (vect_is_simple_reduction): Set STMT_VINFO_REDUC_IDX. * tree-vect-patterns.c (vect_reassociating_reduction_p): Return operands in canonical order. * tree-vectorizer.c (vec_info::new_stmt_vec_info): Initialize STMT_VINFO_REDUC_IDX. * tree-vectorizer.h (_stmt_vec_info::reduc_idx): New. (STMT_VINFO_REDUC_IDX): Likewise. From-SVN: r275996 --- gcc/ChangeLog | 13 +++++++++++++ gcc/tree-vect-loop.c | 22 ++++++++++++++++------ gcc/tree-vect-patterns.c | 2 ++ gcc/tree-vectorizer.c | 1 + gcc/tree-vectorizer.h | 5 +++++ 5 files changed, 37 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c841fff..756b4d4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-09-20 Richard Biener + + PR tree-optimization/91821 + * tree-vect-loop.c (check_reduction_path): Check we can compute + reduc_idx. + (vect_is_simple_reduction): Set STMT_VINFO_REDUC_IDX. + * tree-vect-patterns.c (vect_reassociating_reduction_p): Return + operands in canonical order. + * tree-vectorizer.c (vec_info::new_stmt_vec_info): Initialize + STMT_VINFO_REDUC_IDX. + * tree-vectorizer.h (_stmt_vec_info::reduc_idx): New. + (STMT_VINFO_REDUC_IDX): Likewise. + 2019-09-20 Eric Botcazou PR target/91269 diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 7e13986..e952713 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -2658,7 +2658,13 @@ pop: gimple *use_stmt = USE_STMT (path[i].second); tree op = USE_FROM_PTR (path[i].second); if (! has_single_use (op) - || ! is_gimple_assign (use_stmt)) + || ! is_gimple_assign (use_stmt) + /* The following make sure we can compute the operand index + easily plus it mostly disallows chaining via COND_EXPR condition + operands. */ + || (gimple_assign_rhs1 (use_stmt) != op + && gimple_assign_rhs2 (use_stmt) != op + && gimple_assign_rhs3 (use_stmt) != op)) { fail = true; break; @@ -3058,6 +3064,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, || !flow_bb_inside_loop_p (loop, gimple_bb (def1_info->stmt)) || vect_valid_reduction_input_p (def1_info))) { + STMT_VINFO_REDUC_IDX (def_stmt_info) = 1; if (dump_enabled_p ()) report_vect_op (MSG_NOTE, def_stmt, "detected reduction: "); return def_stmt_info; @@ -3070,6 +3077,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, || !flow_bb_inside_loop_p (loop, gimple_bb (def2_info->stmt)) || vect_valid_reduction_input_p (def2_info))) { + STMT_VINFO_REDUC_IDX (def_stmt_info) = 0; if (dump_enabled_p ()) report_vect_op (MSG_NOTE, def_stmt, "detected reduction: "); return def_stmt_info; @@ -3084,16 +3092,18 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, restriction is that all operations in the chain are the same. */ auto_vec reduc_chain; unsigned i; + bool is_slp_reduc = !nested_in_vect_loop && code != COND_EXPR; for (i = path.length () - 1; i >= 1; --i) { gimple *stmt = USE_STMT (path[i].second); if (gimple_assign_rhs_code (stmt) != code) - break; - reduc_chain.safe_push (loop_info->lookup_stmt (stmt)); + is_slp_reduc = false; + stmt_vec_info stmt_info = loop_info->lookup_stmt (stmt); + STMT_VINFO_REDUC_IDX (stmt_info) + = path[i].second->use - gimple_assign_rhs1_ptr (stmt); + reduc_chain.safe_push (stmt_info); } - if (i == 0 - && ! nested_in_vect_loop - && code != COND_EXPR) + if (is_slp_reduc) { for (unsigned i = 0; i < reduc_chain.length () - 1; ++i) { diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 2f86f9e..baa9a4c 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -868,6 +868,8 @@ vect_reassociating_reduction_p (stmt_vec_info stmt_info, tree_code code, *op0_out = gimple_assign_rhs1 (assign); *op1_out = gimple_assign_rhs2 (assign); + if (commutative_tree_code (code) && STMT_VINFO_REDUC_IDX (stmt_info) == 0) + std::swap (*op0_out, *op1_out); return true; } diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index dc18152..da4330c 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -639,6 +639,7 @@ vec_info::new_stmt_vec_info (gimple *stmt) STMT_VINFO_VECTORIZABLE (res) = true; STMT_VINFO_VEC_REDUCTION_TYPE (res) = TREE_CODE_REDUCTION; STMT_VINFO_VEC_CONST_COND_REDUC_CODE (res) = ERROR_MARK; + STMT_VINFO_REDUC_IDX (res) = -1; STMT_VINFO_SLP_VECT_ONLY (res) = false; if (gimple_code (stmt) == GIMPLE_PHI diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index a514c77..09d31ec 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -941,6 +941,10 @@ public: vect_force_simple_reduction. */ enum vect_reduction_type reduc_type; + /* On a stmt participating in the reduction the index of the operand + on the reduction SSA cycle. */ + int reduc_idx; + /* On a reduction PHI the def returned by vect_force_simple_reduction. On the def returned by vect_force_simple_reduction the corresponding PHI. */ @@ -1030,6 +1034,7 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) #define STMT_VINFO_SIMD_LANE_ACCESS_P(S) (S)->simd_lane_access_p #define STMT_VINFO_VEC_REDUCTION_TYPE(S) (S)->v_reduc_type #define STMT_VINFO_VEC_CONST_COND_REDUC_CODE(S) (S)->const_cond_reduc_code +#define STMT_VINFO_REDUC_IDX(S) (S)->reduc_idx #define STMT_VINFO_DR_WRT_VEC_LOOP(S) (S)->dr_wrt_vec_loop #define STMT_VINFO_DR_BASE_ADDRESS(S) (S)->dr_wrt_vec_loop.base_address -- cgit v1.1 From b049c26955642f80c1c3a84782d20c36b858d7d3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 20 Sep 2019 11:14:34 +0000 Subject: re PR target/91814 (ICE in elimination_costs_in_insn, at reload1.c:3549 since r274926) 2019-09-20 Richard Biener Uros Bizjak PR target/91814 * config/i386/i386-features.c (gen_gpr_to_xmm_move_src): Revert previous change. (general_scalar_chain::convert_op): Force not suitable memory operands to a register. Co-Authored-By: Uros Bizjak From-SVN: r275998 --- gcc/ChangeLog | 9 +++++++++ gcc/config/i386/i386-features.c | 11 +++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 756b4d4..76269e1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,13 @@ 2019-09-20 Richard Biener + Uros Bizjak + + PR target/91814 + * config/i386/i386-features.c (gen_gpr_to_xmm_move_src): Revert + previous change. + (general_scalar_chain::convert_op): Force not suitable memory + operands to a register. + +2019-09-20 Richard Biener PR tree-optimization/91821 * tree-vect-loop.c (check_reduction_path): Check we can compute diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index 546d78d..9b297ba 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -668,8 +668,6 @@ scalar_chain::emit_conversion_insns (rtx insns, rtx_insn *after) static rtx gen_gpr_to_xmm_move_src (enum machine_mode vmode, rtx gpr) { - if (!nonimmediate_operand (gpr, GET_MODE_INNER (vmode))) - gpr = force_reg (GET_MODE_INNER (vmode), gpr); switch (GET_MODE_NUNITS (vmode)) { case 1: @@ -835,6 +833,15 @@ general_scalar_chain::convert_op (rtx *op, rtx_insn *insn) { rtx tmp = gen_reg_rtx (GET_MODE (*op)); + /* Handle movabs. */ + if (!memory_operand (*op, GET_MODE (*op))) + { + rtx tmp2 = gen_reg_rtx (GET_MODE (*op)); + + emit_insn_before (gen_rtx_SET (tmp2, *op), insn); + *op = tmp2; + } + emit_insn_before (gen_rtx_SET (gen_rtx_SUBREG (vmode, tmp, 0), gen_gpr_to_xmm_move_src (vmode, *op)), insn); -- cgit v1.1 From 264c073993e2887308144fc8e27e2bf4a3bcd353 Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Fri, 20 Sep 2019 12:17:20 +0000 Subject: Restrict gnat.dg/system_info1.adb to Linux and Windows hosts Where it is know to work, still covering the original test intent. From-SVN: r275999 --- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gnat.dg/system_info1.adb | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8e1b4be..8868ad1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-20 Olivier Hainque + + * gnat.dg/system_info1.adb: Restrict to *-*-linux* and *-*-mingw*. + 2019-09-20 Eric Botcazou * gcc.dg/pr91269.c: New test. diff --git a/gcc/testsuite/gnat.dg/system_info1.adb b/gcc/testsuite/gnat.dg/system_info1.adb index 493a18e..e299bc4 100644 --- a/gcc/testsuite/gnat.dg/system_info1.adb +++ b/gcc/testsuite/gnat.dg/system_info1.adb @@ -1,4 +1,9 @@ --- { dg-do run } +-- A basic test initially intended to check that +-- System.Task_Info.Number_Of_Processors yields sensible results on +-- both 32bit and 64bit Windows. Additional configurations where the +-- feature was verified to work can opt-in. + +-- { dg-do run { target *-*-mingw* *-*-linux* } } with System.Multiprocessors; with System.Task_Info; @@ -20,4 +25,4 @@ begin if Nprocs /= Integer (Ncpus) then raise Program_Error; end if; -end; \ No newline at end of file +end; -- cgit v1.1 From ac4a783640162ed734c538ce1ff516b40431834b Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Fri, 20 Sep 2019 18:05:06 +0200 Subject: re PR fortran/78260 (ICE in gimplify_expr, at gimplify.c:11939) 2019-09-20 Tobias Burnus PR fortran/78260 * openmp.c (gfc_resolve_oacc_declare): Reject all non variables but accept function result variables. * trans-openmp.c (gfc_trans_omp_clauses): Handle function-result variables for remaing cases. 2019-09-20 Tobias Burnus PR fortran/78260 * gfortran.dg/goacc/parameter.f95: Change dg-error as it is now detected earlier. * gfortran.dg/goacc/pr85701.f90: Modify to use a separate result variable. * gfortran.dg/goacc/pr78260.f90: New. * gfortran.dg/goacc/pr78260-2.f90: New. * gfortran.dg/gomp/pr78260.f90: New. * gfortran.dg/gomp/pr78260-2.f90: New. * gfortran.dg/gomp/pr78260-3.f90: New. From-SVN: r276002 --- gcc/fortran/ChangeLog | 8 +++ gcc/fortran/openmp.c | 10 ++-- gcc/fortran/trans-openmp.c | 6 +-- gcc/testsuite/ChangeLog | 47 +++++++++++------ gcc/testsuite/gfortran.dg/goacc/parameter.f95 | 2 +- gcc/testsuite/gfortran.dg/goacc/pr78260-2.f90 | 20 ++++++++ gcc/testsuite/gfortran.dg/goacc/pr78260.f90 | 36 +++++++++++++ gcc/testsuite/gfortran.dg/goacc/pr85701.f90 | 4 +- gcc/testsuite/gfortran.dg/gomp/pr78260-2.f90 | 59 +++++++++++++++++++++ gcc/testsuite/gfortran.dg/gomp/pr78260-3.f90 | 74 +++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/gomp/pr78260.f90 | 33 ++++++++++++ 11 files changed, 269 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/goacc/pr78260-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/goacc/pr78260.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr78260-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr78260-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr78260.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 853bd32..7435a22 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,11 @@ +2019-09-20 Tobias Burnus + + PR fortran/78260 + * openmp.c (gfc_resolve_oacc_declare): Reject all + non variables but accept function result variables. + * trans-openmp.c (gfc_trans_omp_clauses): Handle + function-result variables for remaing cases. + 2019-09-17 Paul Thomas PR fortran/91588 diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 44fcb9d..bda7f28 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -6048,18 +6048,14 @@ gfc_resolve_oacc_declare (gfc_namespace *ns) for (n = oc->clauses->lists[list]; n; n = n->next) { n->sym->mark = 0; - if (n->sym->attr.function || n->sym->attr.subroutine) + if (n->sym->attr.flavor != FL_VARIABLE + && (n->sym->attr.flavor != FL_PROCEDURE + || n->sym->result != n->sym)) { gfc_error ("Object %qs is not a variable at %L", n->sym->name, &oc->loc); continue; } - if (n->sym->attr.flavor == FL_PARAMETER) - { - gfc_error ("PARAMETER object %qs is not allowed at %L", - n->sym->name, &oc->loc); - continue; - } if (n->expr && n->expr->ref->type == REF_ARRAY) { diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 8eae7bc..b4c77ae 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -2075,7 +2075,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree node = build_omp_clause (input_location, OMP_CLAUSE_DEPEND); if (n->expr == NULL || n->expr->ref->u.ar.type == AR_FULL) { - tree decl = gfc_get_symbol_decl (n->sym); + tree decl = gfc_trans_omp_variable (n->sym, false); if (gfc_omp_privatize_by_reference (decl)) decl = build_fold_indirect_ref (decl); if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) @@ -2136,7 +2136,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree node2 = NULL_TREE; tree node3 = NULL_TREE; tree node4 = NULL_TREE; - tree decl = gfc_get_symbol_decl (n->sym); + tree decl = gfc_trans_omp_variable (n->sym, false); if (DECL_P (decl)) TREE_ADDRESSABLE (decl) = 1; if (n->expr == NULL || n->expr->ref->u.ar.type == AR_FULL) @@ -2398,7 +2398,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree node = build_omp_clause (input_location, clause_code); if (n->expr == NULL || n->expr->ref->u.ar.type == AR_FULL) { - tree decl = gfc_get_symbol_decl (n->sym); + tree decl = gfc_trans_omp_variable (n->sym, false); if (gfc_omp_privatize_by_reference (decl)) decl = build_fold_indirect_ref (decl); else if (DECL_P (decl)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8868ad1..f46b109 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2019-09-20 Tobias Burnus + + PR fortran/78260 + * gfortran.dg/goacc/parameter.f95: Change + dg-error as it is now detected earlier. + * gfortran.dg/goacc/pr85701.f90: Modify to + use a separate result variable. + * gfortran.dg/goacc/pr78260.f90: New. + * gfortran.dg/goacc/pr78260-2.f90: New. + * gfortran.dg/gomp/pr78260.f90: New. + * gfortran.dg/gomp/pr78260-2.f90: New. + * gfortran.dg/gomp/pr78260-3.f90: New. + 2019-09-20 Olivier Hainque * gnat.dg/system_info1.adb: Restrict to *-*-linux* and *-*-mingw*. @@ -13,23 +26,23 @@ 2019-09-20 Martin Jambor - * g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan. - * gcc.dg/ipa/ipa-sra-1.c: Likewise. - * gcc.dg/ipa/ipa-sra-10.c: Likewise. - * gcc.dg/ipa/ipa-sra-11.c: Likewise. - * gcc.dg/ipa/ipa-sra-3.c: Likewise. - * gcc.dg/ipa/ipa-sra-4.c: Likewise. - * gcc.dg/ipa/ipa-sra-5.c: Likewise. - * gcc.dg/ipa/ipacost-2.c: Disable ipa-sra. - * gcc.dg/ipa/ipcp-agg-9.c: Likewise. - * gcc.dg/ipa/pr78121.c: Adjust scan pattern. - * gcc.dg/ipa/vrp1.c: Likewise. - * gcc.dg/ipa/vrp2.c: Likewise. - * gcc.dg/ipa/vrp3.c: Likewise. - * gcc.dg/ipa/vrp7.c: Likewise. - * gcc.dg/ipa/vrp8.c: Likewise. - * gcc.dg/noreorder.c: use noipa attribute instead of noinline. - * gcc.dg/ipa/20040703-wpa.c: New test. + * g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan. + * gcc.dg/ipa/ipa-sra-1.c: Likewise. + * gcc.dg/ipa/ipa-sra-10.c: Likewise. + * gcc.dg/ipa/ipa-sra-11.c: Likewise. + * gcc.dg/ipa/ipa-sra-3.c: Likewise. + * gcc.dg/ipa/ipa-sra-4.c: Likewise. + * gcc.dg/ipa/ipa-sra-5.c: Likewise. + * gcc.dg/ipa/ipacost-2.c: Disable ipa-sra. + * gcc.dg/ipa/ipcp-agg-9.c: Likewise. + * gcc.dg/ipa/pr78121.c: Adjust scan pattern. + * gcc.dg/ipa/vrp1.c: Likewise. + * gcc.dg/ipa/vrp2.c: Likewise. + * gcc.dg/ipa/vrp3.c: Likewise. + * gcc.dg/ipa/vrp7.c: Likewise. + * gcc.dg/ipa/vrp8.c: Likewise. + * gcc.dg/noreorder.c: use noipa attribute instead of noinline. + * gcc.dg/ipa/20040703-wpa.c: New test. * gcc.dg/ipa/ipa-sra-12.c: New test. * gcc.dg/ipa/ipa-sra-13.c: Likewise. * gcc.dg/ipa/ipa-sra-14.c: Likewise. diff --git a/gcc/testsuite/gfortran.dg/goacc/parameter.f95 b/gcc/testsuite/gfortran.dg/goacc/parameter.f95 index 8427461..cbe67db 100644 --- a/gcc/testsuite/gfortran.dg/goacc/parameter.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/parameter.f95 @@ -6,7 +6,7 @@ contains implicit none integer :: i integer, parameter :: a = 1 - !$acc declare device_resident (a) ! { dg-error "PARAMETER" } + !$acc declare device_resident (a) ! { dg-error "is not a variable" } !$acc data copy (a) ! { dg-error "not a variable" } !$acc end data !$acc data deviceptr (a) ! { dg-error "not a variable" } diff --git a/gcc/testsuite/gfortran.dg/goacc/pr78260-2.f90 b/gcc/testsuite/gfortran.dg/goacc/pr78260-2.f90 new file mode 100644 index 0000000..e28564d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/pr78260-2.f90 @@ -0,0 +1,20 @@ +! { dg-do compile } +! { dg-options "-fopenacc -fdump-tree-original" } +! { dg-require-effective-target fopenacc } + +! PR fortran/78260 + +module m + implicit none + integer :: n = 0 +contains + integer function f1() + !$acc declare present(f1) + !$acc kernels copyin(f1) + f1 = 5 + !$acc end kernels + end function f1 +end module m +! { dg-final { scan-tree-dump-times "#pragma acc data map\\(force_present:__result_f1\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma acc data map\\(force_present:__result_f1\\)" 1 "original" } } + diff --git a/gcc/testsuite/gfortran.dg/goacc/pr78260.f90 b/gcc/testsuite/gfortran.dg/goacc/pr78260.f90 new file mode 100644 index 0000000..21bde85 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/pr78260.f90 @@ -0,0 +1,36 @@ +! { dg-do compile } +! { dg-options "-fopenacc" } +! { dg-require-effective-target fopenacc } + +! PR fortran/78260 +! Contributed by Gerhard Steinmetz + +module m + implicit none + integer :: n = 0 +contains + subroutine s + !$acc declare present(m) ! { dg-error "Object .m. is not a variable" } + !$acc kernels copyin(m) ! { dg-error "Object .m. is not a variable" } + n = n + 1 + !$acc end kernels + end subroutine s + subroutine s2 + !$acc declare present(s2) ! { dg-error "Object .s2. is not a variable" } + !$acc kernels copyin(s2) ! { dg-error "Object .s2. is not a variable" } + n = n + 1 + !$acc end kernels + end subroutine s2 + integer function f1() + !$acc declare present(f1) ! OK, f1 is also the result variable + !$acc kernels copyin(f1) ! OK, f1 is also the result variable + f1 = 5 + !$acc end kernels + end function f1 + integer function f2() result(res) + !$acc declare present(f2) ! { dg-error "Object .f2. is not a variable" } + !$acc kernels copyin(f2) ! { dg-error "Object .f2. is not a variable" } + res = 5 + !$acc end kernels + end function f2 +end module m diff --git a/gcc/testsuite/gfortran.dg/goacc/pr85701.f90 b/gcc/testsuite/gfortran.dg/goacc/pr85701.f90 index 9c201b8..bae09de 100644 --- a/gcc/testsuite/gfortran.dg/goacc/pr85701.f90 +++ b/gcc/testsuite/gfortran.dg/goacc/pr85701.f90 @@ -9,11 +9,11 @@ subroutine s2 !$acc declare present(s2) ! { dg-error "is not a variable" } end -function f1 () +function f1 () result(res) !$acc declare copy(f1) ! { dg-error "is not a variable" } end -function f2 () +function f2 () result(res) !$acc declare present(f2) ! { dg-error "is not a variable" } end diff --git a/gcc/testsuite/gfortran.dg/gomp/pr78260-2.f90 b/gcc/testsuite/gfortran.dg/gomp/pr78260-2.f90 new file mode 100644 index 0000000..c58ad93 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/pr78260-2.f90 @@ -0,0 +1,59 @@ +! { dg-do compile } +! { dg-options "-fopenmp -fdump-tree-original" } + +! PR fortran/78260 + +module m + implicit none + integer :: n = 0 +contains + integer function f1() + !$omp target data map(f1) + !$omp target update to(f1) + f1 = 5 + !$omp end target data + end function f1 + + integer function f2() + dimension :: f2(1) + !$omp target data map(f2) + !$omp target update to(f2) + f2(1) = 5 + !$omp end target data + end function f2 + + integer function f3() result(res) + dimension :: res(1) + !$omp target data map(res) + !$omp target update to(res) + res(1) = 5 + !$omp end target data + end function f3 + + integer function f4() result(res) + allocatable :: res + dimension :: res(:) + !$omp target data map(res) + !$omp target update to(res) + res = [5] + !$omp end target data + end function f4 + + subroutine sub() + integer, allocatable :: arr(:) + !$omp target data map(arr) + !$omp target update to(arr) + arr = [5] + !$omp end target data + end subroutine sub +end module m + +! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:\\*\\(c_char \\*\\) arr.data \\\[len: D.\[0-9\]+ \\* 4\\\]\\) map\\(to:arr \\\[pointer set, len: ..\\\]\\) map\\(alloc:\\(integer\\(kind=4\\)\\\[0:\\\] \\* restrict\\) arr.data \\\[pointer assign, bias: 0\\\]\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target update to\\(\\*\\(c_char \\*\\) arr.data \\\[len: D.\[0-9\]+ \\* 4\\\]\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:\\*\\(c_char \\*\\) __result->data \\\[len: D.\[0-9\]+ \\* 4\\\]\\) map\\(to:\\*__result \\\[pointer set, len: ..\\\]\\) map\\(alloc:\\(integer\\(kind=4\\)\\\[0:\\\] \\* restrict\\) __result->data \\\[pointer assign, bias: 0\\\]\\) map\\(alloc:__result \\\[pointer assign, bias: 0\\\]\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target update to\\(\\*\\(c_char \\*\\) __result->data \\\[len: D.\[0-9\]+ \\* 4\\\]\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:\\*__result.0\\) map\\(alloc:__result.0 \\\[pointer assign, bias: 0\\\]\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target update to\\(\\*__result.0\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:__result_f1\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target update to\\(__result_f1\\)" 1 "original" } } + diff --git a/gcc/testsuite/gfortran.dg/gomp/pr78260-3.f90 b/gcc/testsuite/gfortran.dg/gomp/pr78260-3.f90 new file mode 100644 index 0000000..4ca3e36 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/pr78260-3.f90 @@ -0,0 +1,74 @@ +! { dg-do compile } +! { dg-options "-fopenmp -fdump-tree-original" } + +! PR fortran/78260 + +integer function f1() + implicit none + + f1 = 0 + + !$omp task depend(inout:f1) + !$omp end task + + !$omp task depend(inout:f1) + !$omp end task +end function f1 + +integer function f2() + implicit none + dimension :: f2(1) + + f2(1) = 0 + + !$omp task depend(inout:f2) + !$omp end task + + !$omp task depend(inout:f2) + !$omp end task +end function f2 + +integer function f3() result(res) + implicit none + dimension :: res(1) + + res(1) = 0 + + !$omp task depend(inout:res) + !$omp end task + + !$omp task depend(inout:res) + !$omp end task +end function f3 + +integer function f4() result(res) + implicit none + allocatable :: res + dimension :: res(:) + + res = [0] + + !$omp task depend(inout:res) + !$omp end task + + !$omp task depend(inout:res) + !$omp end task +end function f4 + +subroutine sub() + implicit none + integer, allocatable :: arr(:) + + arr = [3] + + !$omp task depend(inout:arr) + !$omp end task + + !$omp task depend(inout:arr) + !$omp end task +end subroutine sub + +! { dg-final { scan-tree-dump-times "#pragma omp task depend\\(inout:__result_f1\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp task depend\\(inout:\\*__result.0\\)" 4 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp task depend\\(inout:\\*\\(c_char \\*\\) __result->data\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp task depend\\(inout:\\*\\(c_char \\*\\) arr.data\\)" 2 "original" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/pr78260.f90 b/gcc/testsuite/gfortran.dg/gomp/pr78260.f90 new file mode 100644 index 0000000..23acd4c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/pr78260.f90 @@ -0,0 +1,33 @@ +! { dg-do compile } + +! PR fortran/78260 + +module m + implicit none + integer :: n = 0 +contains + subroutine s + !$omp target data map(m) ! { dg-error "Object .m. is not a variable" } + !$omp target update to(m) ! { dg-error "Object .m. is not a variable" } + n = n + 1 + !$omp end target data + end subroutine s + subroutine s2 + !$omp target data map(s2) ! { dg-error "Object .s2. is not a variable" } + !$omp target update to(s2) ! { dg-error "Object .s2. is not a variable" } + n = n + 1 + !$omp end target data + end subroutine s2 + integer function f1() + !$omp target data map(f1) ! OK, f1 is also the result variable + !$omp target update to(f1) ! OK, f1 is also the result variable + f1 = 5 + !$omp end target data + end function f1 + integer function f2() result(res) + !$omp target data map(f2) ! { dg-error "Object .f2. is not a variable" } + !$omp target update to(f2) ! { dg-error "Object .f2. is not a variable" } + res = 5 + !$omp end target data + end function f2 +end module m -- cgit v1.1 From 1fa153b0ef29796df55dd64ff45f622840a13301 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 20 Sep 2019 18:52:05 +0000 Subject: [Darwin, X86, testsuite] Fix naked-1.c fail. This fails at m32 because the scan-asm is looking for an absence of "ret". Darwin is generating the correct code for the function but the picbase thunk has a 'ret' insn. Fixed by making the test use -mdynamic-no-pic for m32. gcc/testsuite/ChangeLog: 2019-09-20 Iain Sandoe * gcc.target/i386/naked-1.c: Alter options to use non- PIC codegen for m32 Darwin. From-SVN: r276004 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/i386/naked-1.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f46b109..05c25ee2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-20 Iain Sandoe + + * gcc.target/i386/naked-1.c: Alter options to use non- + PIC codegen for m32 Darwin. + 2019-09-20 Tobias Burnus PR fortran/78260 diff --git a/gcc/testsuite/gcc.target/i386/naked-1.c b/gcc/testsuite/gcc.target/i386/naked-1.c index 07bb10e..f51773c 100644 --- a/gcc/testsuite/gcc.target/i386/naked-1.c +++ b/gcc/testsuite/gcc.target/i386/naked-1.c @@ -1,5 +1,7 @@ /* { dg-do compile } */ -/* { dg-options "-O0 -fno-pic" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ +/* { dg-additional-options "-mdynamic-no-pic" { target { *-*-darwin* && ia32 } } } */ /* Verify that __attribute__((naked)) produces a naked function that does not use ret to return but traps at the end. */ -- cgit v1.1 From 0fc7d9e3d1272682b8ad2c274b820a0419d98bb7 Mon Sep 17 00:00:00 2001 From: Maya Rashish Date: Fri, 20 Sep 2019 20:23:29 +0000 Subject: re PR target/86811 (Vax port needs updating for CVE-2017-5753) PR target/86811 * config/vax/vax.c (TARGET_HAVE_SPECULATION_SAFE_VALUE): Define to speculation_safe_value_not_needed. From-SVN: r276006 --- gcc/ChangeLog | 6 ++++++ gcc/config/vax/vax.c | 3 +++ 2 files changed, 9 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 76269e1..1943260 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-20 Maya Rashish + + PR target/86811 + * config/vax/vax.c (TARGET_HAVE_SPECULATION_SAFE_VALUE): + Define to speculation_safe_value_not_needed. + 2019-09-20 Richard Biener Uros Bizjak diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c index 7a8c86d..a971687 100644 --- a/gcc/config/vax/vax.c +++ b/gcc/config/vax/vax.c @@ -121,6 +121,9 @@ static HOST_WIDE_INT vax_starting_frame_offset (void); #undef TARGET_STARTING_FRAME_OFFSET #define TARGET_STARTING_FRAME_OFFSET vax_starting_frame_offset +#undef TARGET_HAVE_SPECULATION_SAFE_VALUE +#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed + struct gcc_target targetm = TARGET_INITIALIZER; /* Set global variables as needed for the options enabled. */ -- cgit v1.1 From bd7a5c5dc082707dd62083514bbb88c6f78e5bdb Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Fri, 20 Sep 2019 21:47:56 +0000 Subject: pa.c (pa_trampoline_init): Remove spurious extended character. * config/pa/pa.c (pa_trampoline_init): Remove spurious extended character. From-SVN: r276007 --- gcc/ChangeLog | 5 +++++ gcc/config/pa/pa.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1943260..d8d5490 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-20 John David Anglin + + * config/pa/pa.c (pa_trampoline_init): Remove spurious extended + character. + 2019-09-20 Maya Rashish PR target/86811 diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 80a0ea0..55637df 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -10197,7 +10197,7 @@ pa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) } #ifdef HAVE_ENABLE_EXECUTE_STACK -  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"), + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"), LCT_NORMAL, VOIDmode, XEXP (m_tramp, 0), Pmode); #endif } -- cgit v1.1 From 6b5596d5fcb28569707f97ef86af6a5cf9bc172f Mon Sep 17 00:00:00 2001 From: Jonas Pfeil Date: Fri, 20 Sep 2019 22:50:42 +0000 Subject: microblaze.h (ASM_OUTPUT_SKIP): Use HOST_WIDE_PRINT_UNSIGNED. * config/microblaze/microblaze.h (ASM_OUTPUT_SKIP): Use HOST_WIDE_PRINT_UNSIGNED. From-SVN: r276011 --- gcc/ChangeLog | 5 +++++ gcc/config/microblaze/microblaze.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d8d5490..7b77316 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-20 Jonas Pfeil + + * config/microblaze/microblaze.h (ASM_OUTPUT_SKIP): Use + HOST_WIDE_PRINT_UNSIGNED. + 2019-09-20 John David Anglin * config/pa/pa.c (pa_trampoline_init): Remove spurious extended diff --git a/gcc/config/microblaze/microblaze.h b/gcc/config/microblaze/microblaze.h index fa0806e..4551ddd 100644 --- a/gcc/config/microblaze/microblaze.h +++ b/gcc/config/microblaze/microblaze.h @@ -695,7 +695,7 @@ do { \ fprintf (STREAM, "\t.align\t%d\n", (LOG)) #define ASM_OUTPUT_SKIP(STREAM,SIZE) \ - fprintf (STREAM, "\t.space\t%lu\n", (SIZE)) + fprintf (STREAM, "\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED "\n", (SIZE)) #define ASCII_DATA_ASM_OP "\t.ascii\t" #define STRING_ASM_OP "\t.asciz\t" -- cgit v1.1 From b2addbf403fe60091ed4d2363cb36938b75b4892 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 21 Sep 2019 00:16:17 +0000 Subject: Daily bump. From-SVN: r276015 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 0fc3d8d..6108a45 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190920 +20190921 -- cgit v1.1 From 681fc0fa40cc4f018cb691d796aa819a24257774 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sat, 21 Sep 2019 12:56:50 +0000 Subject: Extend neg_const_int simplifications to other const rtxes This patch generalises some neg_const_int-based rtx simplifications so that they handle all CONST_SCALAR_INTs and also CONST_POLY_INT. This actually simplifies things a bit, since we no longer have to treat HOST_WIDE_INT_MIN specially. This is tested by later SVE patches. 2019-09-21 Richard Sandiford gcc/ * simplify-rtx.c (neg_const_int): Replace with... (neg_poly_int_rtx): ...this new function. (simplify_binary_operation_1): Extend (minus x C) -> (plus X -C) to all CONST_SCALAR_INTs and to CONST_POLY_INT. (simplify_plus_minus): Likewise for constant terms here. From-SVN: r276017 --- gcc/ChangeLog | 8 ++++++++ gcc/simplify-rtx.c | 31 +++++++++++++------------------ 2 files changed, 21 insertions(+), 18 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7b77316..ca23b27 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-21 Richard Sandiford + + * simplify-rtx.c (neg_const_int): Replace with... + (neg_poly_int_rtx): ...this new function. + (simplify_binary_operation_1): Extend (minus x C) -> (plus X -C) + to all CONST_SCALAR_INTs and to CONST_POLY_INT. + (simplify_plus_minus): Likewise for constant terms here. + 2019-09-20 Jonas Pfeil * config/microblaze/microblaze.h (ASM_OUTPUT_SKIP): Use diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 87ba337..9a70720 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -46,7 +46,6 @@ along with GCC; see the file COPYING3. If not see #define HWI_SIGN_EXTEND(low) \ ((((HOST_WIDE_INT) low) < 0) ? HOST_WIDE_INT_M1 : HOST_WIDE_INT_0) -static rtx neg_const_int (machine_mode, const_rtx); static bool plus_minus_operand_p (const_rtx); static rtx simplify_plus_minus (enum rtx_code, machine_mode, rtx, rtx); static rtx simplify_associative_operation (enum rtx_code, machine_mode, @@ -57,17 +56,12 @@ static rtx simplify_unary_operation_1 (enum rtx_code, machine_mode, rtx); static rtx simplify_binary_operation_1 (enum rtx_code, machine_mode, rtx, rtx, rtx, rtx); -/* Negate a CONST_INT rtx. */ +/* Negate I, which satisfies poly_int_rtx_p. MODE is the mode of I. */ + static rtx -neg_const_int (machine_mode mode, const_rtx i) +neg_poly_int_rtx (machine_mode mode, const_rtx i) { - unsigned HOST_WIDE_INT val = -UINTVAL (i); - - if (!HWI_COMPUTABLE_MODE_P (mode) - && val == UINTVAL (i)) - return simplify_const_unary_operation (NEG, mode, CONST_CAST_RTX (i), - mode); - return gen_int_mode (val, mode); + return immed_wide_int_const (-wi::to_poly_wide (i, mode), mode); } /* Test whether expression, X, is an immediate constant that represents @@ -2547,10 +2541,10 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode, return plus_constant (mode, op0, trunc_int_for_mode (-offset, mode)); /* Don't let a relocatable value get a negative coeff. */ - if (CONST_INT_P (op1) && GET_MODE (op0) != VOIDmode) + if (poly_int_rtx_p (op1) && GET_MODE (op0) != VOIDmode) return simplify_gen_binary (PLUS, mode, op0, - neg_const_int (mode, op1)); + neg_poly_int_rtx (mode, op1)); /* (x - (x & y)) -> (x & ~y) */ if (INTEGRAL_MODE_P (mode) && GET_CODE (op1) == AND) @@ -4619,11 +4613,12 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, } break; - case CONST_INT: + CASE_CONST_SCALAR_INT: + case CONST_POLY_INT: n_constants++; if (this_neg) { - ops[i].op = neg_const_int (mode, this_op); + ops[i].op = neg_poly_int_rtx (mode, this_op); ops[i].neg = 0; changed = 1; canonicalized = 1; @@ -4748,8 +4743,8 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, lneg &= rneg; if (GET_CODE (tem) == NEG) tem = XEXP (tem, 0), lneg = !lneg; - if (CONST_INT_P (tem) && lneg) - tem = neg_const_int (mode, tem), lneg = 0; + if (poly_int_rtx_p (tem) && lneg) + tem = neg_poly_int_rtx (mode, tem), lneg = 0; ops[i].op = tem; ops[i].neg = lneg; @@ -4808,12 +4803,12 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, in the array and that any other constant will be next-to-last. */ if (n_ops > 1 - && CONST_INT_P (ops[n_ops - 1].op) + && poly_int_rtx_p (ops[n_ops - 1].op) && CONSTANT_P (ops[n_ops - 2].op)) { rtx value = ops[n_ops - 1].op; if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg) - value = neg_const_int (mode, value); + value = neg_poly_int_rtx (mode, value); if (CONST_INT_P (value)) { ops[n_ops - 2].op = plus_constant (mode, ops[n_ops - 2].op, -- cgit v1.1 From 9f635bd13fe9e85872e441b6f3618947f989909a Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sat, 21 Sep 2019 12:57:13 +0000 Subject: Avoid adding impossible copies in ira-conflicts.c:process_reg_shuffles If an insn requires two operands to be tied, and the input operand dies in the insn, IRA acts as though there were a copy from the input to the output with the same execution frequency as the insn. Allocating the same register to the input and the output then saves the cost of a move. If there is no such tie, but an input operand nevertheless dies in the insn, IRA creates a similar move, but with an eighth of the frequency. This helps to ensure that chains of instructions reuse registers in a natural way, rather than using arbitrarily different registers for no reason. This heuristic seems to work well in the vast majority of cases. However, for SVE, the handling of untied operands ends up creating copies between dying predicate registers and vector outputs, even though vector and predicate registers are distinct classes and can never be tied. This is a particular problem because the dying predicate tends to be the loop control predicate, which is used by most instructions in a vector loop and so (rightly) has a very high allocation priority. Any copies involving the loop predicate therefore tend to get processed before copies involving only vector registers. The end result is that we tend to allocate the output of the last vector instruction in a loop ahead of its natural place in the allocation order and don't benefit from chains created between vector registers. This patch tries to avoid the problem by not adding register shuffle copies if there appears to be no chance that the two operands could be allocated to the same register. 2019-09-21 Richard Sandiford gcc/ * ira-conflicts.c (can_use_same_reg_p): New function. (process_reg_shuffles): Take an insn parameter. Ignore cases in which input operand op_num could seemingly never be allocated to the same register as the destination. (add_insn_allocno_copies): Update call to process_reg_shuffles. gcc/testsuite/ * gcc.target/aarch64/sve/cond_convert_1.c: Remove XFAILs. * gcc.target/aarch64/sve/cond_convert_4.c: Likewise. * gcc.target/aarch64/sve/cond_unary_2.c: Likewise. From-SVN: r276018 --- gcc/ChangeLog | 8 +++++ gcc/ira-conflicts.c | 42 +++++++++++++++++++--- gcc/testsuite/ChangeLog | 6 ++++ .../gcc.target/aarch64/sve/cond_convert_1.c | 3 +- .../gcc.target/aarch64/sve/cond_convert_4.c | 3 +- .../gcc.target/aarch64/sve/cond_unary_2.c | 5 +-- 6 files changed, 54 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ca23b27..f22714e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2019-09-21 Richard Sandiford + * ira-conflicts.c (can_use_same_reg_p): New function. + (process_reg_shuffles): Take an insn parameter. Ignore cases + in which input operand op_num could seemingly never be allocated + to the same register as the destination. + (add_insn_allocno_copies): Update call to process_reg_shuffles. + +2019-09-21 Richard Sandiford + * simplify-rtx.c (neg_const_int): Replace with... (neg_poly_int_rtx): ...this new function. (simplify_binary_operation_1): Extend (minus x C) -> (plus X -C) diff --git a/gcc/ira-conflicts.c b/gcc/ira-conflicts.c index afbc2ec..c199309 100644 --- a/gcc/ira-conflicts.c +++ b/gcc/ira-conflicts.c @@ -325,12 +325,37 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p, return true; } -/* Process all of the output registers of the current insn which are - not bound (BOUND_P) and the input register REG (its operand number +/* Return true if output operand OUTPUT and input operand INPUT of + INSN can use the same register class for at least one alternative. + INSN is already described in recog_data and recog_op_alt. */ +static bool +can_use_same_reg_p (rtx_insn *insn, int output, int input) +{ + alternative_mask preferred = get_preferred_alternatives (insn); + for (int nalt = 0; nalt < recog_data.n_alternatives; nalt++) + { + if (!TEST_BIT (preferred, nalt)) + continue; + + const operand_alternative *op_alt + = &recog_op_alt[nalt * recog_data.n_operands]; + if (op_alt[input].matches == output) + return true; + + if (ira_reg_class_intersect[op_alt[input].cl][op_alt[output].cl] + != NO_REGS) + return true; + } + return false; +} + +/* Process all of the output registers of the current insn (INSN) which + are not bound (BOUND_P) and the input register REG (its operand number OP_NUM) which dies in the insn as if there were a move insn between them with frequency FREQ. */ static void -process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p) +process_reg_shuffles (rtx_insn *insn, rtx reg, int op_num, int freq, + bool *bound_p) { int i; rtx another_reg; @@ -342,7 +367,13 @@ process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p) if (!REG_SUBREG_P (another_reg) || op_num == i || recog_data.operand_type[i] != OP_OUT - || bound_p[i]) + || bound_p[i] + || (!can_use_same_reg_p (insn, i, op_num) + && (recog_data.constraints[op_num][0] != '%' + || !can_use_same_reg_p (insn, i, op_num + 1)) + && (op_num == 0 + || recog_data.constraints[op_num - 1][0] != '%' + || !can_use_same_reg_p (insn, i, op_num - 1)))) continue; process_regs_for_copy (reg, another_reg, false, NULL, freq); @@ -412,7 +443,8 @@ add_insn_allocno_copies (rtx_insn *insn) the corresponding allocno copies. The cost will not correspond to a real move insn cost, so make the frequency smaller. */ - process_reg_shuffles (operand, i, freq < 8 ? 1 : freq / 8, bound_p); + process_reg_shuffles (insn, operand, i, freq < 8 ? 1 : freq / 8, + bound_p); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 05c25ee2..d0c01e3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-09-21 Richard Sandiford + + * gcc.target/aarch64/sve/cond_convert_1.c: Remove XFAILs. + * gcc.target/aarch64/sve/cond_convert_4.c: Likewise. + * gcc.target/aarch64/sve/cond_unary_2.c: Likewise. + 2019-09-20 Iain Sandoe * gcc.target/i386/naked-1.c: Alter options to use non- diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_1.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_1.c index 69468eb..dcc3076 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_1.c @@ -32,6 +32,5 @@ TEST_ALL (DEF_LOOP) /* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.d, p[0-7]/m,} 1 } } */ /* { dg-final { scan-assembler-not {\tmov\tz} } } */ -/* At the moment we don't manage to avoid using MOVPRFX. */ -/* { dg-final { scan-assembler-not {\tmovprfx\t} { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ /* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_4.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_4.c index 55b535f..7e5f2a7 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_4.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_convert_4.c @@ -32,6 +32,5 @@ TEST_ALL (DEF_LOOP) /* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.d, p[0-7]/m,} 1 } } */ /* { dg-final { scan-assembler-not {\tmov\tz} } } */ -/* At the moment we don't manage to avoid using MOVPRFX. */ -/* { dg-final { scan-assembler-not {\tmovprfx\t} { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ /* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_unary_2.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_unary_2.c index adf8283..991ccf0 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_unary_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_unary_2.c @@ -54,8 +54,5 @@ TEST_ALL (DEF_LOOP) /* { dg-final { scan-assembler-times {\tfneg\tz[0-9]+\.d, p[0-7]/m,} 1 } } */ /* { dg-final { scan-assembler-not {\tmov\tz} } } */ -/* At the moment we don't manage to avoid using MOVPRFX for the - floating-point functions. */ -/* { dg-final { scan-assembler-not {\tmovprfx\t} { xfail *-*-* } } } */ -/* { dg-final { scan-assembler-times {\tmovprfx\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ /* { dg-final { scan-assembler-not {\tsel\t} } } */ -- cgit v1.1 From 296580b640a8161ae25037b01cc4f8e45bc73a30 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Sat, 21 Sep 2019 13:59:29 +0000 Subject: DR 2345 - Jumping across initializers in init-statements and conditions. * g++.dg/cpp1z/init-statement10.C: New test. From-SVN: r276019 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp1z/init-statement10.C | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1z/init-statement10.C (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0c01e3..36e0b2b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-21 Marek Polacek + + DR 2345 - Jumping across initializers in init-statements and conditions. + * g++.dg/cpp1z/init-statement10.C: New test. + 2019-09-21 Richard Sandiford * gcc.target/aarch64/sve/cond_convert_1.c: Remove XFAILs. diff --git a/gcc/testsuite/g++.dg/cpp1z/init-statement10.C b/gcc/testsuite/g++.dg/cpp1z/init-statement10.C new file mode 100644 index 0000000..d13d135 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/init-statement10.C @@ -0,0 +1,14 @@ +// DR 2345 - Jumping across initializers in init-statements and conditions. +// { dg-do compile { target c++17 } } + +int +fn () +{ + goto X; + if (int i = 42; i == 42) + { +X: // { dg-error "jump to label" } + return i; + } + return -1; +} -- cgit v1.1 From 6bd2a4f3d173deaa06680904dd368292208cb95e Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sat, 21 Sep 2019 19:48:27 +0000 Subject: [Darwin] Update machopic_legitimize_pic_address. Some changes were missed here in the transition to LRA. The Darwin archs are all using LRA now. gcc/ChangeLog: 2019-09-21 Iain Sandoe * config/darwin.c (machopic_legitimize_pic_address): Check for lra not reload. From-SVN: r276020 --- gcc/ChangeLog | 5 +++++ gcc/config/darwin.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f22714e..014dd8d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-21 Iain Sandoe + + * config/darwin.c (machopic_legitimize_pic_address): Check + for lra not reload. + 2019-09-21 Richard Sandiford * ira-conflicts.c (can_use_same_reg_p): New function. diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index e1017be..3e4bbff 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -842,7 +842,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) { if (reg == 0) { - gcc_assert (!reload_in_progress); + gcc_assert (!lra_in_progress); reg = gen_reg_rtx (Pmode); } @@ -926,7 +926,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) emit_use (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)); #endif - if (reload_in_progress) + if (lra_in_progress) df_set_regs_ever_live (REGNO (pic), true); pic_ref = gen_rtx_PLUS (Pmode, pic, machopic_gen_offset (XEXP (orig, 0))); @@ -950,7 +950,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) if (reg == 0) { - gcc_assert (!reload_in_progress); + gcc_assert (!lra_in_progress); reg = gen_reg_rtx (Pmode); } @@ -996,7 +996,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) #if 0 emit_use (pic_offset_table_rtx); #endif - if (reload_in_progress) + if (lra_in_progress) df_set_regs_ever_live (REGNO (pic), true); pic_ref = gen_rtx_PLUS (Pmode, pic, -- cgit v1.1 From e4df9be4e2bb9f379d2737282f765f1ef6d8d2dd Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 21 Sep 2019 23:54:38 +0200 Subject: re PR c++/30277 (bit-field: wrong overload resolution) PR c++/30277 * g++.dg/expr/bitfield14.C (struct S): Use signed long long instead of signed long. (foo): Use long long instead of long. From-SVN: r276021 --- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/g++.dg/expr/bitfield14.C | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 36e0b2b..e7e62bf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-09-21 Jakub Jelinek + + PR c++/30277 + * g++.dg/expr/bitfield14.C (struct S): Use signed long long instead + of signed long. + (foo): Use long long instead of long. + 2019-09-21 Marek Polacek DR 2345 - Jumping across initializers in init-statements and conditions. diff --git a/gcc/testsuite/g++.dg/expr/bitfield14.C b/gcc/testsuite/g++.dg/expr/bitfield14.C index 546af85..4bd6f12 100644 --- a/gcc/testsuite/g++.dg/expr/bitfield14.C +++ b/gcc/testsuite/g++.dg/expr/bitfield14.C @@ -3,10 +3,10 @@ struct S { - signed long l: 32; + signed long long l: 32; }; -void foo(long) = delete; +void foo(long long) = delete; void foo(int) {} int main() -- cgit v1.1 From 810118592aaa82a6dc460cf6234aa738bf9bbbea Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sat, 21 Sep 2019 22:32:59 +0000 Subject: PR middle-end/91830 - Bogus -Warray-bounds on strcpy into a member PR middle-end/91830 - Bogus -Warray-bounds on strcpy into a member of a subobject compiling binutils gcc/ChangeLog: * gcc/gimple-ssa-warn-restrict.c (builtin_memref::set_base_and_offset): Simplify computation of the offset of the referenced subobject. gcc/testsuite/ChangeLog: * gcc/testsuite/gcc.dg/Warray-bounds-47.c: New test. From-SVN: r276022 --- gcc/ChangeLog | 6 + gcc/gimple-ssa-warn-restrict.c | 10 +- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/Warray-bounds-47.c | 429 ++++++++++++++++++++++++++++++++ 4 files changed, 442 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-47.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 014dd8d..72b2151 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-21 Martin Sebor + + PR middle-end/91830 + * gcc/gimple-ssa-warn-restrict.c (builtin_memref::set_base_and_offset): + Simplify computation of the offset of the referenced subobject. + 2019-09-21 Iain Sandoe * config/darwin.c (machopic_legitimize_pic_address): Check diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 4f6e535..f452deb 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -517,14 +517,8 @@ builtin_memref::set_base_and_offset (tree expr) struct S { char a, b[3]; } s[2]; strcpy (s[1].b, "1234"); REFOFF is set to s[1].b - (char*)s. */ - tree basetype = TREE_TYPE (TREE_TYPE (base)); - if (tree basesize = TYPE_SIZE_UNIT (basetype)) - if (TREE_CODE (basesize) == INTEGER_CST) - { - offset_int size = wi::to_offset (basesize); - offset_int off = tree_to_shwi (memrefoff); - refoff += size * (off / size); - } + offset_int off = tree_to_shwi (memrefoff); + refoff += off; } if (!integer_zerop (memrefoff)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e7e62bf..412616d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-21 Martin Sebor + + PR middle-end/91830 + * gcc/testsuite/gcc.dg/Warray-bounds-47.c: New test. + 2019-09-21 Jakub Jelinek PR c++/30277 diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-47.c b/gcc/testsuite/gcc.dg/Warray-bounds-47.c new file mode 100644 index 0000000..06ad488 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-47.c @@ -0,0 +1,429 @@ +/* PR middle-end/91830 - Bogus -Warray-bounds on strcpy into a member + of a subobject compiling binutils + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +extern char* strcpy (char*, const char*); +extern void sink (void*); + +#define S36 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +#define S(N) (S36 + sizeof (S36) - N - 1) + +/* In the test macro, prevent the strcpy to memcpy transformation + by using a local array initialized with the string literal. Without + it, GCC transforms the strcpy call with memcpy which (unfortunately) + permits accesses that cross subobject boundaries. */ +#define T(obj, mem, n) \ + do { \ + struct A *pa = &obj; \ + const char a[] = S36; \ + strcpy (pa->mem, a + sizeof a - n - 1); \ + sink (&obj); \ + } while (0) + + +struct A { char a[3]; char b[5]; }; +struct B { char c[7]; struct A a; struct A a2[2]; }; + +extern struct B b[]; + +void array_nowarn (int i) +{ + struct B *pb = b; + + T (pb[0].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[1].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[123].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[i].a, a, 0); + T (pb[i].a, a, 1); + T (pb[i].a, a, 2); + + + T (pb[0].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[1].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[123].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[i].a, b, 0); + T (pb[i].a, b, 1); + T (pb[i].a, b, 2); + T (pb[i].a, b, 3); + T (pb[i].a, b, 4); + + + T (pb[0].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[1].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[123].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[123].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[i].a2[0], b, 0); + T (pb[i].a2[0], b, 1); + T (pb[i].a2[0], b, 2); + T (pb[i].a2[0], b, 3); + T (pb[i].a2[0], b, 4); + + T (pb[i].a2[1], b, 0); + T (pb[i].a2[1], b, 1); + T (pb[i].a2[1], b, 2); + T (pb[i].a2[1], b, 3); + T (pb[i].a2[1], b, 4); +} + +void array_warn (int i) +{ + struct B *pb = b; + + T (pb[0].a, a, 3); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a, a, 4); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a, a, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a, a, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a, a, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a, a, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a, a, 7); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a, a, 8); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + + T (pb[0].a, b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a, b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a, b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a, b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a, b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a, b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a, b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a, b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + + T (pb[0].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + T (pb[0].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } +} + +void ptr_nowarn (struct B *pb, int i) +{ + T (pb[-123].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[-123].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[-123].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[-2].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[-2].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[-2].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[-1].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[-1].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[-1].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[0].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[1].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[123].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a, a, 2); // { dg-bogus "\\\[-W" } + + T (pb[i].a, a, 0); // { dg-bogus "\\\[-W" } + T (pb[i].a, a, 1); // { dg-bogus "\\\[-W" } + T (pb[i].a, a, 2); // { dg-bogus "\\\[-W" } + + + T (pb[-123].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[-123].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[-123].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[-123].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[-123].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[-2].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[-2].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[-2].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[-2].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[-2].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[-1].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[-1].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[-1].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[-1].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[-1].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[0].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[0].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[1].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[1].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[123].a, b, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 2); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 3); // { dg-bogus "\\\[-W" } + T (pb[123].a, b, 4); // { dg-bogus "\\\[-W" } + + T (pb[i].a, b, 0); + T (pb[i].a, b, 1); + T (pb[i].a, b, 2); + T (pb[i].a, b, 3); + T (pb[i].a, b, 4); + + + T (pb[-123].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[-2].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[-1].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[0].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[0].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[1].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[1].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[123].a2[0], b, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 2); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 3); // { dg-bogus "\\\[-W" } + T (pb[123].a2[0], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[i].a2[0], b, 0); + T (pb[i].a2[0], b, 1); + T (pb[i].a2[0], b, 2); + T (pb[i].a2[0], b, 3); + T (pb[i].a2[0], b, 4); + + T (pb[-123].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[-123].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[-2].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[-2].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[-1].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[-1].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[0].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[0].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[0].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[0].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[0].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[1].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[1].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[1].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[1].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[1].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[123].a2[1], b, 0); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 1); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 2); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 3); // { dg-bogus "\\\[-W" } + T (pb[123].a2[1], b, 4); // { dg-bogus "\\\[-W" } + + T (pb[i].a2[1], b, 0); + T (pb[i].a2[1], b, 1); + T (pb[i].a2[1], b, 2); + T (pb[i].a2[1], b, 3); + T (pb[i].a2[1], b, 4); + + T (pb[i].a2[i], b, 0); + T (pb[i].a2[i], b, 1); + T (pb[i].a2[i], b, 2); + T (pb[i].a2[i], b, 3); + T (pb[i].a2[i], b, 4); +} + +void ptr_warn (struct B *pb, int i) +{ + T (pb[-987].a, a, 8); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-654].a, a, 7); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-2].a, a, 6); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-2].a, a, 5); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-1].a, a, 3); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-1].a, a, 4); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[0].a, a, 3); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a, a, 4); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a, a, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a, a, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a, a, 7); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a, a, 8); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a, a, 3); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a, a, 4); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a, a, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + + T (pb[-987].a, b, 10); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-654].a, b, 9); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-2].a, b, 8); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-2].a, b, 7); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-1].a, b, 6); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-1].a, b, 5); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[0].a, b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a, b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a, b, 7); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a, b, 8); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a, b, 9); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a, b, 10); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a, b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a, b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a, b, 7); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + + T (pb[-987].a2[0], b, 10); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-654].a2[0], b, 9); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-2].a2[0], b, 8); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-2].a2[0], b, 7); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-1].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-1].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[0].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a2[0], b, 7); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a2[0], b, 8); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a2[0], b, 9); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a2[0], b, 10); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a2[0], b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[0], b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[0], b, 7); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + T (pb[-987].a2[1], b, 10); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-654].a2[1], b, 9); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-2].a2[1], b, 8); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-2].a2[1], b, 7); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[-1].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" } + T (pb[-1].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[0].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" } + T (pb[0].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[1].a2[1], b, 7); // { dg-warning "\\\[-Warray-bounds" } + T (pb[1].a2[1], b, 8); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[789].a2[1], b, 9); // { dg-warning "\\\[-Warray-bounds" } + T (pb[789].a2[1], b, 10); // { dg-warning "\\\[-Warray-bounds" } + + T (pb[i].a2[1], b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[1], b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[1], b, 7); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + + T (pb[i].a2[i], b, 5); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[i], b, 6); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } + T (pb[i].a2[i], b, 7); // { dg-warning "\\\[-Warray-bounds" "pr91848" { xfail *-*-* } } +} -- cgit v1.1 From dcb786e59eb7ec2ad32357673f138bd5d9242ea9 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 22 Sep 2019 00:16:15 +0000 Subject: Daily bump. From-SVN: r276026 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 6108a45..088b92f 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190921 +20190922 -- cgit v1.1 From 0968003dd08a9e9f83bee955bbdc259a781f044f Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Sun, 22 Sep 2019 12:35:00 +0000 Subject: PR c++/91819 - ICE with operator++ and enum. * call.c (build_new_op_1): Set arg2_type. * g++.dg/other/operator4.C: New test. From-SVN: r276027 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/call.c | 5 ++++- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/other/operator4.C | 22 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/other/operator4.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3015d68..4420d8f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-09-22 Marek Polacek + + PR c++/91819 - ICE with operator++ and enum. + * call.c (build_new_op_1): Set arg2_type. + 2019-09-17 Jason Merrill * parser.c (cp_parser_statement): Handle [[likely]] on diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e613d8a..2dad699 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5878,7 +5878,10 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, goto builtin; if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) - arg2 = integer_zero_node; + { + arg2 = integer_zero_node; + arg2_type = integer_type_node; + } vec_alloc (arglist, 3); arglist->quick_push (arg1); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 412616d..cbf0eff 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-22 Marek Polacek + + PR c++/91819 - ICE with operator++ and enum. + * g++.dg/other/operator4.C: New test. + 2019-09-21 Martin Sebor PR middle-end/91830 diff --git a/gcc/testsuite/g++.dg/other/operator4.C b/gcc/testsuite/g++.dg/other/operator4.C new file mode 100644 index 0000000..e7a41c0 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/operator4.C @@ -0,0 +1,22 @@ +// PR c++/91819 - ICE with operator++ and enum. +// { dg-do compile } + +enum Foo +{ + a, + b +}; + +inline Foo operator++(Foo &f, int) +{ + return f = (Foo)(f + 1); +} + +int main() +{ + int count = 0; + for (Foo f = a; f <= b; f++) { + count++; + } + return count; +} -- cgit v1.1 From f1c22d660bc467c1816817d1240a0be5a42d1c56 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 22 Sep 2019 19:24:14 +0000 Subject: [Darwin, PPC] Clean up symbol stubs code. Remove dead code for the the TARGET_LINK_STACK which is not applicable to Darwin. Use MACHOPIC_PURE instead of a hard-wired PIC level to determine the stub kind. Merge common code blocks. gcc/ChangeLog: 2019-09-22 Iain Sandoe * config/rs6000/rs6000.c (machopic_output_stub): Remove dead code. Merge code blocks with common conditionals. Use declared macro instead of a magic number for PIC level. From-SVN: r276030 --- gcc/ChangeLog | 6 ++++++ gcc/config/rs6000/rs6000.c | 26 ++++++-------------------- 2 files changed, 12 insertions(+), 20 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 72b2151..2030879 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-22 Iain Sandoe + + * config/rs6000/rs6000.c (machopic_output_stub): Remove dead + code. Merge code blocks with common conditionals. Use declared + macro instead of a magic number for PIC level. + 2019-09-21 Martin Sebor PR middle-end/91830 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c2834bd..81aec9c 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -19499,7 +19499,6 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) /* Lose our funky encoding stuff so it doesn't contaminate the stub. */ symb = (*targetm.strip_name_encoding) (symb); - length = strlen (symb); symbol_name = XALLOCAVEC (char, length + 32); GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length); @@ -19507,13 +19506,9 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) lazy_ptr_name = XALLOCAVEC (char, length + 32); GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length); - if (flag_pic == 2) - switch_to_section (darwin_sections[machopic_picsymbol_stub1_section]); - else - switch_to_section (darwin_sections[machopic_symbol_stub1_section]); - - if (flag_pic == 2) + if (MACHOPIC_PURE) { + switch_to_section (darwin_sections[machopic_picsymbol_stub1_section]); fprintf (file, "\t.align 5\n"); fprintf (file, "%s:\n", stub); @@ -19524,18 +19519,8 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) sprintf (local_label_0, "L%u$spb", label); fprintf (file, "\tmflr r0\n"); - if (TARGET_LINK_STACK) - { - char name[32]; - get_ppc476_thunk_name (name); - fprintf (file, "\tbl %s\n", name); - fprintf (file, "%s:\n\tmflr r11\n", local_label_0); - } - else - { - fprintf (file, "\tbcl 20,31,%s\n", local_label_0); - fprintf (file, "%s:\n\tmflr r11\n", local_label_0); - } + fprintf (file, "\tbcl 20,31,%s\n", local_label_0); + fprintf (file, "%s:\n\tmflr r11\n", local_label_0); fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n", lazy_ptr_name, local_label_0); fprintf (file, "\tmtlr r0\n"); @@ -19545,8 +19530,9 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) fprintf (file, "\tmtctr r12\n"); fprintf (file, "\tbctr\n"); } - else + else /* mdynamic-no-pic or mkernel. */ { + switch_to_section (darwin_sections[machopic_symbol_stub1_section]); fprintf (file, "\t.align 4\n"); fprintf (file, "%s:\n", stub); -- cgit v1.1 From 2d814ac2f7b4200c2f47c562bb3b0cfc7b4f2325 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 23 Sep 2019 00:16:24 +0000 Subject: Daily bump. From-SVN: r276035 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 088b92f..0bff5aa 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190922 +20190923 -- cgit v1.1 From fdfa0e44b7e5bbf319634a2d51cc7fbfb7aae27a Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 23 Sep 2019 07:45:58 +0000 Subject: decl.c (components_to_record): Do not reorder fields in packed record types if... * gcc-interface/decl.c (components_to_record): Do not reorder fields in packed record types if they contain fixed-size fields that cannot be laid out in a packed manner. From-SVN: r276036 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/gcc-interface/decl.c | 15 +++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 94b32fb..79e6326 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2019-09-23 Eric Botcazou + + * gcc-interface/decl.c (components_to_record): Do not reorder fields + in packed record types if they contain fixed-size fields that cannot + be laid out in a packed manner. + 2019-09-19 Tom Tromey * gcc-interface/misc.c (gnat_get_type_bias): Return the bias diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index d1082ee..67b938e 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -7521,6 +7521,7 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, bool all_rep_and_size = all_rep && TYPE_SIZE (gnu_record_type); bool variants_have_rep = all_rep; bool layout_with_rep = false; + bool has_non_packed_fixed_size_field = false; bool has_self_field = false; bool has_aliased_after_self_field = false; Entity_Id gnat_component_decl, gnat_variant_part; @@ -7577,6 +7578,10 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, has_self_field = true; else if (has_self_field && DECL_ALIASED_P (gnu_field)) has_aliased_after_self_field = true; + else if (!DECL_FIELD_OFFSET (gnu_field) + && !DECL_PACKED (gnu_field) + && !field_has_variable_size (gnu_field)) + has_non_packed_fixed_size_field = true; } } @@ -7868,8 +7873,9 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, self-referential/variable offset or misaligned. Note, in the latter case, that this can only happen in packed record types so the alignment is effectively capped to the byte for the whole record. But we don't - do it for non-packed record types if pragma Optimize_Alignment (Space) - is specified because this can prevent alignment gaps from being filled. + do it for packed record types if not all fixed-size fiels can be packed + and for non-packed record types if pragma Optimize_Alignment (Space) is + specified, because this can prevent alignment gaps from being filled. Optionally, if the layout warning is enabled, keep track of the above 4 different kinds of fields and issue a warning if some of them would be @@ -7880,8 +7886,9 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, const bool do_reorder = (Convention (gnat_record_type) == Convention_Ada && !No_Reordering (gnat_record_type) - && (!Optimize_Alignment_Space (gnat_record_type) - || Is_Packed (gnat_record_type)) + && !(Is_Packed (gnat_record_type) + ? has_non_packed_fixed_size_field + : Optimize_Alignment_Space (gnat_record_type)) && !debug__debug_flag_dot_r); const bool w_reorder = (Convention (gnat_record_type) == Convention_Ada -- cgit v1.1 From ef5a9557bdfeef1d7941ec52702a25f2de9abcdc Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 23 Sep 2019 08:08:08 +0000 Subject: trans.c (Attribute_to_gnu): Test Can_Use_Internal_Rep on the underlying type of the node. * gcc-interface/trans.c (Attribute_to_gnu): Test Can_Use_Internal_Rep on the underlying type of the node. (Call_to_gnu): Likewise with the type of the prefix. From-SVN: r276041 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/gcc-interface/trans.c | 48 +++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 79e6326..f74e8bb 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,11 @@ 2019-09-23 Eric Botcazou + * gcc-interface/trans.c (Attribute_to_gnu): Test Can_Use_Internal_Rep + on the underlying type of the node. + (Call_to_gnu): Likewise with the type of the prefix. + +2019-09-23 Eric Botcazou + * gcc-interface/decl.c (components_to_record): Do not reorder fields in packed record types if they contain fixed-size fields that cannot be laid out in a packed manner. diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index fe02dc4..1af477f 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -2254,32 +2254,29 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) /* For other address attributes applied to a nested function, find an inner ADDR_EXPR and annotate it so that we can issue a useful warning with -Wtrampolines. */ - else if (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (gnu_prefix))) + else if (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (gnu_prefix)) + && (gnu_expr = remove_conversions (gnu_result, false)) + && TREE_CODE (gnu_expr) == ADDR_EXPR + && decl_function_context (TREE_OPERAND (gnu_expr, 0))) { - gnu_expr = remove_conversions (gnu_result, false); + set_expr_location_from_node (gnu_expr, gnat_node); - if (TREE_CODE (gnu_expr) == ADDR_EXPR - && decl_function_context (TREE_OPERAND (gnu_expr, 0))) - { - set_expr_location_from_node (gnu_expr, gnat_node); - - /* Also check the inlining status. */ - check_inlining_for_nested_subprog (TREE_OPERAND (gnu_expr, 0)); - - /* Moreover, for 'Access or 'Unrestricted_Access with non- - foreign-compatible representation, mark the ADDR_EXPR so - that we can build a descriptor instead of a trampoline. */ - if ((attribute == Attr_Access - || attribute == Attr_Unrestricted_Access) - && targetm.calls.custom_function_descriptors > 0 - && Can_Use_Internal_Rep (Etype (gnat_node))) - FUNC_ADDR_BY_DESCRIPTOR (gnu_expr) = 1; - - /* Otherwise, we need to check that we are not violating the - No_Implicit_Dynamic_Code restriction. */ - else if (targetm.calls.custom_function_descriptors != 0) - Check_Implicit_Dynamic_Code_Allowed (gnat_node); - } + /* Also check the inlining status. */ + check_inlining_for_nested_subprog (TREE_OPERAND (gnu_expr, 0)); + + /* Moreover, for 'Access or 'Unrestricted_Access with non- + foreign-compatible representation, mark the ADDR_EXPR so + that we can build a descriptor instead of a trampoline. */ + if ((attribute == Attr_Access + || attribute == Attr_Unrestricted_Access) + && targetm.calls.custom_function_descriptors > 0 + && Can_Use_Internal_Rep (Underlying_Type (Etype (gnat_node)))) + FUNC_ADDR_BY_DESCRIPTOR (gnu_expr) = 1; + + /* Otherwise, we need to check that we are not violating the + No_Implicit_Dynamic_Code restriction. */ + else if (targetm.calls.custom_function_descriptors != 0) + Check_Implicit_Dynamic_Code_Allowed (gnat_node); } break; @@ -5111,7 +5108,8 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, /* If the access type doesn't require foreign-compatible representation, be prepared for descriptors. */ if (targetm.calls.custom_function_descriptors > 0 - && Can_Use_Internal_Rep (Etype (Prefix (Name (gnat_node))))) + && Can_Use_Internal_Rep + (Underlying_Type (Etype (Prefix (Name (gnat_node)))))) by_descriptor = true; } else if (Nkind (Name (gnat_node)) == N_Attribute_Reference) -- cgit v1.1 From ec4a0d837764aa230aab3b5c8d1567c3fdd170d7 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 23 Sep 2019 08:27:40 +0000 Subject: trans.c (gnat_compile_time_expr_list): New variable. * gcc-interface/trans.c (gnat_compile_time_expr_list): New variable. (Pragma_to_gnu): Rename local variable. Save the (first) expression of pragma Compile_Time_{Error|Warning} for later processing. (Compilation_Unit_to_gnu): Process the expressions saved above. From-SVN: r276045 --- gcc/ada/ChangeLog | 7 ++++ gcc/ada/gcc-interface/trans.c | 44 ++++++++++++++++------- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gnat.dg/specs/compile_time1.ads | 9 +++++ gcc/testsuite/gnat.dg/specs/compile_time1_pkg.ads | 7 ++++ 5 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/specs/compile_time1.ads create mode 100644 gcc/testsuite/gnat.dg/specs/compile_time1_pkg.ads (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index f74e8bb..898ae38 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,12 @@ 2019-09-23 Eric Botcazou + * gcc-interface/trans.c (gnat_compile_time_expr_list): New variable. + (Pragma_to_gnu): Rename local variable. Save the (first) expression + of pragma Compile_Time_{Error|Warning} for later processing. + (Compilation_Unit_to_gnu): Process the expressions saved above. + +2019-09-23 Eric Botcazou + * gcc-interface/trans.c (Attribute_to_gnu): Test Can_Use_Internal_Rep on the underlying type of the node. (Call_to_gnu): Likewise with the type of the prefix. diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 1af477f..d9cd84d 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -95,6 +95,9 @@ bool type_annotate_only; /* List of N_Validate_Unchecked_Conversion nodes in the unit. */ static vec gnat_validate_uc_list; +/* List of expressions of pragma Compile_Time_{Error|Warning} in the unit. */ +static vec gnat_compile_time_expr_list; + /* When not optimizing, we cache the 'First, 'Last and 'Length attributes of unconstrained array IN parameters to avoid emitting a great deal of redundant instructions to recompute them each time. */ @@ -1508,17 +1511,28 @@ static tree Pragma_to_gnu (Node_Id gnat_node) { tree gnu_result = alloc_stmt_list (); - unsigned char pragma_id; Node_Id gnat_temp; - /* Do nothing if we are just annotating types and check for (and ignore) - unrecognized pragmas. */ - if (type_annotate_only - || !Is_Pragma_Name (Chars (Pragma_Identifier (gnat_node)))) + /* Check for (and ignore) unrecognized pragmas. */ + if (!Is_Pragma_Name (Chars (Pragma_Identifier (gnat_node)))) + return gnu_result; + + const unsigned char id + = Get_Pragma_Id (Chars (Pragma_Identifier (gnat_node))); + + /* Save the expression of pragma Compile_Time_{Error|Warning} for later. */ + if (id == Pragma_Compile_Time_Error || id == Pragma_Compile_Time_Warning) + { + gnat_temp = First (Pragma_Argument_Associations (gnat_node)); + gnat_compile_time_expr_list.safe_push (Expression (gnat_temp)); + return gnu_result; + } + + /* Stop there if we are just annotating types. */ + if (type_annotate_only) return gnu_result; - pragma_id = Get_Pragma_Id (Chars (Pragma_Identifier (gnat_node))); - switch (pragma_id) + switch (id) { case Pragma_Inspection_Point: /* Do nothing at top level: all such variables are already viewable. */ @@ -1670,11 +1684,11 @@ Pragma_to_gnu (Node_Id gnat_node) break; tree gnu_clauses = gnu_loop_stack->last ()->omp_construct_clauses; - if (pragma_id == Pragma_Acc_Data) + if (id == Pragma_Acc_Data) gnu_loop_stack->last ()->omp_code = OACC_DATA; - else if (pragma_id == Pragma_Acc_Kernels) + else if (id == Pragma_Acc_Kernels) gnu_loop_stack->last ()->omp_code = OACC_KERNELS; - else if (pragma_id == Pragma_Acc_Parallel) + else if (id == Pragma_Acc_Parallel) gnu_loop_stack->last ()->omp_code = OACC_PARALLEL; else gcc_unreachable (); @@ -1914,7 +1928,7 @@ Pragma_to_gnu (Node_Id gnat_node) /* This is the String form: pragma Warning{s|_As_Error}(String). */ if (Nkind (Expression (gnat_temp)) == N_String_Literal) { - switch (pragma_id) + switch (id) { case Pragma_Warning_As_Error: kind = DK_ERROR; @@ -6319,7 +6333,7 @@ Compilation_Unit_to_gnu (Node_Id gnat_node) || Nkind (gnat_unit) == N_Subprogram_Body); const Entity_Id gnat_unit_entity = Defining_Entity (gnat_unit); Entity_Id gnat_entity; - Node_Id gnat_pragma; + Node_Id gnat_pragma, gnat_iter; /* Make the decl for the elaboration procedure. Emit debug info for it, so that users can break into their elaboration code in debuggers. Kludge: don't consider it as a definition so that we have a line map for its @@ -6415,6 +6429,12 @@ Compilation_Unit_to_gnu (Node_Id gnat_node) add_stmt_list (Actions (Aux_Decls_Node (gnat_node))); finalize_from_limited_with (); + /* Then process the expressions of pragma Compile_Time_{Error|Warning} to + annotate types referenced therein if they have not been annotated. */ + for (int i = 0; gnat_compile_time_expr_list.iterate (i, &gnat_iter); i++) + (void) gnat_to_gnu_external (gnat_iter); + gnat_compile_time_expr_list.release (); + /* Save away what we've made so far and finish it up. */ set_current_block_context (gnu_elab_proc_decl); gnat_poplevel (); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cbf0eff..3e64e58 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-23 Eric Botcazou + + * gnat.dg/specs/compile_time1.ads: New test. + * gnat.dg/specs/compile_time1_pkg.ads! New helper. + 2019-09-22 Marek Polacek PR c++/91819 - ICE with operator++ and enum. diff --git a/gcc/testsuite/gnat.dg/specs/compile_time1.ads b/gcc/testsuite/gnat.dg/specs/compile_time1.ads new file mode 100644 index 0000000..f28d4e6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/specs/compile_time1.ads @@ -0,0 +1,9 @@ +-- { dg-do compile } + +with Compile_Time1_Pkg; use Compile_Time1_Pkg; + +package Compile_Time1 is + + pragma Compile_Time_Error (Rec'Size /= Integer'Size, "wrong record size"); + +end Compile_Time1; diff --git a/gcc/testsuite/gnat.dg/specs/compile_time1_pkg.ads b/gcc/testsuite/gnat.dg/specs/compile_time1_pkg.ads new file mode 100644 index 0000000..c0345c2 --- /dev/null +++ b/gcc/testsuite/gnat.dg/specs/compile_time1_pkg.ads @@ -0,0 +1,7 @@ +package Compile_Time1_Pkg is + + type Rec is record + I : Integer; + end record; + +end Compile_Time1_Pkg; -- cgit v1.1 From 8082999eb2e01e16beca9722664f7575185b0e61 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 23 Sep 2019 08:28:36 +0000 Subject: Fix typo From-SVN: r276046 --- gcc/testsuite/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3e64e58..02462fc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,7 +1,7 @@ 2019-09-23 Eric Botcazou * gnat.dg/specs/compile_time1.ads: New test. - * gnat.dg/specs/compile_time1_pkg.ads! New helper. + * gnat.dg/specs/compile_time1_pkg.ads: New helper. 2019-09-22 Marek Polacek -- cgit v1.1 From 09248547abd5cce9eee57b07b8ee788f45f002ee Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 23 Sep 2019 08:31:52 +0000 Subject: trans.c (Regular_Loop_to_gnu): Do not rotate the loop if -Og is enabled. * gcc-interface/trans.c (Regular_Loop_to_gnu): Do not rotate the loop if -Og is enabled. (build_return_expr): Do not perform NRV if -Og is enabled. (Subprogram_Body_to_gnu): Likewise. (gnat_to_gnu) : Likewise. (Handled_Sequence_Of_Statements_to_gnu): Do not inline finalizers if -Og is enabled. * gcc-interface/utils.c (convert_to_index_type): Return early if -Og is enabled. From-SVN: r276047 --- gcc/ada/ChangeLog | 12 ++++++++++++ gcc/ada/gcc-interface/trans.c | 11 +++++++---- gcc/ada/gcc-interface/utils.c | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 898ae38..c0bc883 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,17 @@ 2019-09-23 Eric Botcazou + * gcc-interface/trans.c (Regular_Loop_to_gnu): Do not rotate the loop + if -Og is enabled. + (build_return_expr): Do not perform NRV if -Og is enabled. + (Subprogram_Body_to_gnu): Likewise. + (gnat_to_gnu) : Likewise. + (Handled_Sequence_Of_Statements_to_gnu): Do not inline finalizers if + -Og is enabled. + * gcc-interface/utils.c (convert_to_index_type): Return early if -Og + is enabled. + +2019-09-23 Eric Botcazou + * gcc-interface/trans.c (gnat_compile_time_expr_list): New variable. (Pragma_to_gnu): Rename local variable. Save the (first) expression of pragma Compile_Time_{Error|Warning} for later processing. diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index d9cd84d..7b842d4 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -3653,7 +3653,7 @@ Regular_Loop_to_gnu (Node_Id gnat_node, tree *gnu_cond_expr_p) which works in all cases. */ - if (optimize) + if (optimize && !optimize_debug) { /* We can use the do-while form directly if GNU_FIRST-1 doesn't overflow. */ @@ -4436,6 +4436,7 @@ build_return_expr (tree ret_obj, tree ret_val) a candidate for Named Return Value. If so, record it. Otherwise, if this is an expression of some kind, record it elsewhere. */ if (optimize + && !optimize_debug && AGGREGATE_TYPE_P (operation_type) && !TYPE_IS_FAT_POINTER_P (operation_type) && TYPE_MODE (operation_type) == BLKmode @@ -4773,7 +4774,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) /* If the function returns an aggregate type and we have candidates for a Named Return Value, finalize the optimization. */ - if (optimize && gnu_subprog_language->named_ret_val) + if (optimize && !optimize_debug && gnu_subprog_language->named_ret_val) { finalize_nrv (gnu_subprog_decl, gnu_subprog_language->named_ret_val, @@ -5893,7 +5894,7 @@ Handled_Sequence_Of_Statements_to_gnu (Node_Id gnat_node) /* When not optimizing, disable inlining of finalizers as this can create a more complex CFG in the parent function. */ - if (!optimize) + if (!optimize || optimize_debug) DECL_DECLARED_INLINE_P (proc_decl) = 0; /* If there is no end label attached, we use the location of the At_End @@ -8050,7 +8051,9 @@ gnat_to_gnu (Node_Id gnat_node) /* And find out whether this is a candidate for Named Return Value. If so, record it. */ - if (!TYPE_CI_CO_LIST (gnu_subprog_type) && optimize) + if (optimize + && !optimize_debug + && !TYPE_CI_CO_LIST (gnu_subprog_type)) { tree ret_val = gnu_ret_val; diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 8a38b34..b9d5af7 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5023,7 +5023,7 @@ convert_to_index_type (tree expr) /* If the type is unsigned, overflow is allowed so we cannot be sure that EXPR doesn't overflow. Keep it simple if optimization is disabled. */ - if (TYPE_UNSIGNED (type) || !optimize) + if (TYPE_UNSIGNED (type) || !optimize || optimize_debug) return convert (sizetype, expr); switch (code) -- cgit v1.1 From e25427723608118c1441aac4c4808e2360eb0b6c Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Mon, 23 Sep 2019 09:13:21 +0000 Subject: Provide Task_Info.Number_Of_Processors on Solaris gcc/ada: * libgnarl/s-osinte__solaris.ads (sysconf): Declare. (SC_NPROCESSORS_ONLN): Define. * libgnarl/s-tasinf__solaris.ads (Number_Of_Processors): Declare. * libgnarl/s-tasinf__solaris.adb (N_CPU): New variable. (Number_Of_Processors): New function. gcc/testsuite: * gnat.dg/system_info1.adb: Sort dg-do target list. Add *-*-solaris2.*. From-SVN: r276049 --- gcc/ada/ChangeLog | 8 ++++++++ gcc/ada/libgnarl/s-osinte__solaris.ads | 5 +++++ gcc/ada/libgnarl/s-tasinf__solaris.adb | 19 +++++++++++++++++++ gcc/ada/libgnarl/s-tasinf__solaris.ads | 3 +++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gnat.dg/system_info1.adb | 2 +- 6 files changed, 41 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index c0bc883..08244e8 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,11 @@ +2019-09-23 Rainer Orth + + * libgnarl/s-osinte__solaris.ads (sysconf): Declare. + (SC_NPROCESSORS_ONLN): Define. + * libgnarl/s-tasinf__solaris.ads (Number_Of_Processors): Declare. + * libgnarl/s-tasinf__solaris.adb (N_CPU): New variable. + (Number_Of_Processors): New function. + 2019-09-23 Eric Botcazou * gcc-interface/trans.c (Regular_Loop_to_gnu): Do not rotate the loop diff --git a/gcc/ada/libgnarl/s-osinte__solaris.ads b/gcc/ada/libgnarl/s-osinte__solaris.ads index 2543225..be242ba 100644 --- a/gcc/ada/libgnarl/s-osinte__solaris.ads +++ b/gcc/ada/libgnarl/s-osinte__solaris.ads @@ -259,6 +259,11 @@ package System.OS_Interface is function To_Timespec (D : Duration) return timespec; pragma Inline (To_Timespec); + function sysconf (name : int) return long; + pragma Import (C, sysconf); + + SC_NPROCESSORS_ONLN : constant := 15; + ------------- -- Process -- ------------- diff --git a/gcc/ada/libgnarl/s-tasinf__solaris.adb b/gcc/ada/libgnarl/s-tasinf__solaris.adb index 9744d01..44a9115 100644 --- a/gcc/ada/libgnarl/s-tasinf__solaris.adb +++ b/gcc/ada/libgnarl/s-tasinf__solaris.adb @@ -84,4 +84,23 @@ package body System.Task_Info is return (False, False); end Unbound_Thread_Attributes; + N_CPU : Natural := 0; + pragma Atomic (N_CPU); + -- Cache CPU number. Use pragma Atomic to avoid a race condition when + -- setting N_CPU in Number_Of_Processors below. + + -------------------------- + -- Number_Of_Processors -- + -------------------------- + + function Number_Of_Processors return Positive is + begin + if N_CPU = 0 then + N_CPU := Natural + (OS_Interface.sysconf (OS_Interface.SC_NPROCESSORS_ONLN)); + end if; + + return N_CPU; + end Number_Of_Processors; + end System.Task_Info; diff --git a/gcc/ada/libgnarl/s-tasinf__solaris.ads b/gcc/ada/libgnarl/s-tasinf__solaris.ads index c3dc0f1..0d2cbfd 100644 --- a/gcc/ada/libgnarl/s-tasinf__solaris.ads +++ b/gcc/ada/libgnarl/s-tasinf__solaris.ads @@ -139,4 +139,7 @@ package System.Task_Info is Unspecified_Task_Info : constant Task_Info_Type := null; + function Number_Of_Processors return Positive; + -- Returns the number of processors on the running host + end System.Task_Info; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 02462fc..815aee0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-23 Rainer Orth + + * gnat.dg/system_info1.adb: Sort dg-do target list. + Add *-*-solaris2.*. + 2019-09-23 Eric Botcazou * gnat.dg/specs/compile_time1.ads: New test. diff --git a/gcc/testsuite/gnat.dg/system_info1.adb b/gcc/testsuite/gnat.dg/system_info1.adb index e299bc4..fedcc22 100644 --- a/gcc/testsuite/gnat.dg/system_info1.adb +++ b/gcc/testsuite/gnat.dg/system_info1.adb @@ -3,7 +3,7 @@ -- both 32bit and 64bit Windows. Additional configurations where the -- feature was verified to work can opt-in. --- { dg-do run { target *-*-mingw* *-*-linux* } } +-- { dg-do run { target *-*-linux* *-*-mingw* *-*-solaris2.* } } with System.Multiprocessors; with System.Task_Info; -- cgit v1.1 From b7bb3d35804f1d50d7dcfa18aacf1f91d898bb1f Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Mon, 23 Sep 2019 09:17:57 +0000 Subject: Use underscore in IPA-SRA LTO section name (PR ipa/91835) PR ipa/91835 * lto-section-in.c (lto_section_name): Use "ipa_sra" instead of "ipa-sra". From-SVN: r276050 --- gcc/ChangeLog | 6 ++++++ gcc/lto-section-in.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2030879..de8f50e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-23 Rainer Orth + + PR ipa/91835 + * lto-section-in.c (lto_section_name): Use "ipa_sra" instead of + "ipa-sra". + 2019-09-22 Iain Sandoe * config/rs6000/rs6000.c (machopic_output_stub): Remove dead diff --git a/gcc/lto-section-in.c b/gcc/lto-section-in.c index d5feebf..60f111f 100644 --- a/gcc/lto-section-in.c +++ b/gcc/lto-section-in.c @@ -54,7 +54,7 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] = "mode_table", "hsa", "lto", - "ipa-sra" + "ipa_sra" }; /* Hooks so that the ipa passes can call into the lto front end to get -- cgit v1.1 From 158ab204321cfa5fe5466faa5a12b3c38c45125a Mon Sep 17 00:00:00 2001 From: Paul Thomas Date: Mon, 23 Sep 2019 09:19:10 +0000 Subject: re PR fortran/91729 (ICE in gfc_match_select_rank, at fortran/match.c:6586) 2019-09-23 Paul Thomas PR fortran/91729 * match.c (gfc_match_select_rank): Initialise 'as' to NULL. Check for a symtree in the selector expression before trying to assign a value to 'as'. Revert to gfc_error and go to cleanup after setting a MATCH_ERROR. 2019-09-23 Paul Thomas PR fortran/91729 * gfortran.dg/select_rank_2.f90 : Add two more errors in foo2. * gfortran.dg/select_rank_3.f90 : New test. From-SVN: r276051 --- gcc/fortran/ChangeLog | 8 +++++++ gcc/fortran/match.c | 34 +++++++++++++++++++++-------- gcc/testsuite/ChangeLog | 6 +++++ gcc/testsuite/gfortran.dg/select_rank_2.f90 | 4 ++-- gcc/testsuite/gfortran.dg/select_rank_3.f90 | 21 ++++++++++++++++++ 5 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/select_rank_3.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 7435a22..cd1ca75 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,11 @@ +2019-09-23 Paul Thomas + + PR fortran/91729 + * match.c (gfc_match_select_rank): Initialise 'as' to NULL. + Check for a symtree in the selector expression before trying to + assign a value to 'as'. Revert to gfc_error and go to cleanup + after setting a MATCH_ERROR. + 2019-09-20 Tobias Burnus PR fortran/78260 diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index 56d9af0..9b9dbf1 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -6510,7 +6510,7 @@ gfc_match_select_rank (void) char name[GFC_MAX_SYMBOL_LEN]; gfc_symbol *sym, *sym2; gfc_namespace *ns = gfc_current_ns; - gfc_array_spec *as; + gfc_array_spec *as = NULL; m = gfc_match_label (); if (m == MATCH_ERROR) @@ -6538,13 +6538,21 @@ gfc_match_select_rank (void) } sym = expr1->symtree->n.sym; - sym2 = expr2->symtree->n.sym; - as = sym2->ts.type == BT_CLASS ? CLASS_DATA (sym2)->as : sym2->as; + if (expr2->symtree) + { + sym2 = expr2->symtree->n.sym; + as = sym2->ts.type == BT_CLASS ? CLASS_DATA (sym2)->as : sym2->as; + } + if (expr2->expr_type != EXPR_VARIABLE || !(as && as->type == AS_ASSUMED_RANK)) - gfc_error_now ("The SELECT RANK selector at %C must be an assumed " - "rank variable"); + { + gfc_error ("The SELECT RANK selector at %C must be an assumed " + "rank variable"); + m = MATCH_ERROR; + goto cleanup; + } if (expr2->ts.type == BT_CLASS) { @@ -6583,12 +6591,20 @@ gfc_match_select_rank (void) return m; } - sym = expr1->symtree->n.sym; - as = sym->ts.type == BT_CLASS ? CLASS_DATA (sym)->as : sym->as; + if (expr1->symtree) + { + sym = expr1->symtree->n.sym; + as = sym->ts.type == BT_CLASS ? CLASS_DATA (sym)->as : sym->as; + } + if (expr1->expr_type != EXPR_VARIABLE || !(as && as->type == AS_ASSUMED_RANK)) - gfc_error_now ("The SELECT RANK selector at %C must be an assumed " - "rank variable"); + { + gfc_error("The SELECT RANK selector at %C must be an assumed " + "rank variable"); + m = MATCH_ERROR; + goto cleanup; + } } m = gfc_match (" )%t"); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 815aee0..cd7ee8d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-09-23 Paul Thomas + + PR fortran/91729 + * gfortran.dg/select_rank_2.f90 : Add two more errors in foo2. + * gfortran.dg/select_rank_3.f90 : New test. + 2019-09-23 Rainer Orth * gnat.dg/system_info1.adb: Sort dg-do target list. diff --git a/gcc/testsuite/gfortran.dg/select_rank_2.f90 b/gcc/testsuite/gfortran.dg/select_rank_2.f90 index 2415fdf..184027f 100644 --- a/gcc/testsuite/gfortran.dg/select_rank_2.f90 +++ b/gcc/testsuite/gfortran.dg/select_rank_2.f90 @@ -8,9 +8,9 @@ subroutine foo1 (arg) integer :: i integer, dimension(3) :: arg select rank (arg) ! { dg-error "must be an assumed rank variable" } - rank (3) + rank (3) ! { dg-error "Unexpected RANK statement" } print *, arg - end select + end select ! { dg-error "Expecting END SUBROUTINE" } end subroutine foo2 (arg) diff --git a/gcc/testsuite/gfortran.dg/select_rank_3.f90 b/gcc/testsuite/gfortran.dg/select_rank_3.f90 new file mode 100644 index 0000000..35cd8cd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/select_rank_3.f90 @@ -0,0 +1,21 @@ +! { dg-do compile } +! +! Test the fix for PR91729 +! +! Contributed by Gerhardt Steinmetz +! +subroutine s(x) + integer :: x(..) + select rank (-x) ! { dg-error "must be an assumed rank" } + rank (1) ! { dg-error "Unexpected RANK statement" } + print *, x ! { dg-error "may only be used as actual argument" } + end select ! { dg-error "Expecting END SUBROUTINE" } +end + +subroutine t(x) + integer :: x(..) + select rank (z => -x) ! { dg-error "must be an assumed rank" } + rank (1) ! { dg-error "Unexpected RANK statement" } + print *, z + end select ! { dg-error "Expecting END SUBROUTINE" } +end -- cgit v1.1 From 3a30d2558b3a199fe346479e6140cddae7fba5ed Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 23 Sep 2019 09:24:03 +0000 Subject: [AArch64] Fix memmodel index in aarch64_store_exclusive_pair Found via an rtx checking failure. 2019-09-23 Richard Sandiford gcc/ * config/aarch64/atomics.md (aarch64_store_exclusive_pair): Fix memmodel index. From-SVN: r276052 --- gcc/ChangeLog | 5 +++++ gcc/config/aarch64/atomics.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index de8f50e..79b331a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-23 Richard Sandiford + + * config/aarch64/atomics.md (aarch64_store_exclusive_pair): Fix + memmodel index. + 2019-09-23 Rainer Orth PR ipa/91835 diff --git a/gcc/config/aarch64/atomics.md b/gcc/config/aarch64/atomics.md index 2e59b86..4111721 100644 --- a/gcc/config/aarch64/atomics.md +++ b/gcc/config/aarch64/atomics.md @@ -752,7 +752,7 @@ UNSPECV_SX))] "" { - enum memmodel model = memmodel_from_int (INTVAL (operands[3])); + enum memmodel model = memmodel_from_int (INTVAL (operands[4])); if (is_mm_relaxed (model) || is_mm_consume (model) || is_mm_acquire (model)) return "stxp\t%w0, %x2, %x3, %1"; else -- cgit v1.1 From 4d411f1ff79a4cf60f4700ea0f1fec104687f20e Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Mon, 23 Sep 2019 09:29:21 +0000 Subject: Skip gcc.dg/ucnid-5-utf8.c unless ucn is supported * gcc.dg/ucnid-5-utf8.c: Skip unless ucn is supported. From-SVN: r276053 --- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gcc.dg/ucnid-5-utf8.c | 1 + 2 files changed, 5 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cd7ee8d..39fc50b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-23 Rainer Orth + + * gcc.dg/ucnid-5-utf8.c: Skip unless ucn is supported. + 2019-09-23 Paul Thomas PR fortran/91729 diff --git a/gcc/testsuite/gcc.dg/ucnid-5-utf8.c b/gcc/testsuite/gcc.dg/ucnid-5-utf8.c index f4473e1..8e10467 100644 --- a/gcc/testsuite/gcc.dg/ucnid-5-utf8.c +++ b/gcc/testsuite/gcc.dg/ucnid-5-utf8.c @@ -1,5 +1,6 @@ /* { dg-do run } */ /* { dg-skip-if "No dollar in identfiers" { avr-*-* powerpc-ibm-aix* } } */ +/* { dg-skip-if "" { ! ucn } } */ /* { dg-options "-std=c99 -fdollars-in-identifiers -g" } */ void abort (void); -- cgit v1.1 From d469a71e5a0eb512b522248841c56496abca8cd6 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 23 Sep 2019 10:21:45 +0000 Subject: tree-vect-loop.c (get_initial_def_for_reduction): Simplify, avoid adjusting by + 0 or * 1. 2019-09-23 Richard Biener * tree-vect-loop.c (get_initial_def_for_reduction): Simplify, avoid adjusting by + 0 or * 1. (vect_create_epilog_for_reduction): Get reduction code only when necessary. Deal with adjustment_def only when necessary. From-SVN: r276054 --- gcc/ChangeLog | 7 ++++++ gcc/tree-vect-loop.c | 60 ++++++++++++++++++++++------------------------------ 2 files changed, 32 insertions(+), 35 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 79b331a..9392b8f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-23 Richard Biener + + * tree-vect-loop.c (get_initial_def_for_reduction): Simplify, + avoid adjusting by + 0 or * 1. + (vect_create_epilog_for_reduction): Get reduction code only + when necessary. Deal with adjustment_def only when necessary. + 2019-09-23 Richard Sandiford * config/aarch64/atomics.md (aarch64_store_exclusive_pair): Fix diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index e952713..9e399cd 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -4003,8 +4003,10 @@ get_initial_def_for_reduction (stmt_vec_info stmt_vinfo, tree init_val, gcc_assert (nested_in_vect_loop_p (loop, stmt_vinfo) || loop == (gimple_bb (stmt_vinfo->stmt))->loop_father); - vect_reduction_type reduction_type - = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_vinfo); + /* ADJUSTMENT_DEF is NULL when called from + vect_create_epilog_for_reduction to vectorize double reduction. */ + if (adjustment_def) + *adjustment_def = NULL; switch (code) { @@ -4018,11 +4020,6 @@ get_initial_def_for_reduction (stmt_vec_info stmt_vinfo, tree init_val, case MULT_EXPR: case BIT_AND_EXPR: { - /* ADJUSTMENT_DEF is NULL when called from - vect_create_epilog_for_reduction to vectorize double reduction. */ - if (adjustment_def) - *adjustment_def = init_val; - if (code == MULT_EXPR) { real_init_val = dconst1; @@ -4037,10 +4034,14 @@ get_initial_def_for_reduction (stmt_vec_info stmt_vinfo, tree init_val, else def_for_init = build_int_cst (scalar_type, int_init_val); - if (adjustment_def) - /* Option1: the first element is '0' or '1' as well. */ - init_def = gimple_build_vector_from_val (&stmts, vectype, - def_for_init); + if (adjustment_def || operand_equal_p (def_for_init, init_val, 0)) + { + /* Option1: the first element is '0' or '1' as well. */ + if (!operand_equal_p (def_for_init, init_val, 0)) + *adjustment_def = init_val; + init_def = gimple_build_vector_from_val (&stmts, vectype, + def_for_init); + } else if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()) { /* Option2 (variable length): the first element is INIT_VAL. */ @@ -4064,16 +4065,6 @@ get_initial_def_for_reduction (stmt_vec_info stmt_vinfo, tree init_val, case MAX_EXPR: case COND_EXPR: { - if (adjustment_def) - { - *adjustment_def = NULL_TREE; - if (reduction_type != COND_REDUCTION - && reduction_type != EXTRACT_LAST_REDUCTION) - { - init_def = vect_get_vec_def_for_operand (init_val, stmt_vinfo); - break; - } - } init_val = gimple_convert (&stmts, TREE_TYPE (vectype), init_val); init_def = gimple_build_vector_from_val (&stmts, vectype, init_val); } @@ -4304,7 +4295,6 @@ vect_create_epilog_for_reduction (vec vect_defs, tree vec_dest; tree new_temp = NULL_TREE, new_dest, new_name, new_scalar_dest; gimple *epilog_stmt = NULL; - enum tree_code code = gimple_assign_rhs_code (stmt_info->stmt); gimple *exit_phi; tree bitsize; tree adjustment_def = NULL; @@ -4645,12 +4635,6 @@ vect_create_epilog_for_reduction (vec vect_defs, gcc_assert (STMT_VINFO_IN_PATTERN_P (orig_stmt_info)); gcc_assert (STMT_VINFO_RELATED_STMT (orig_stmt_info) == stmt_info); } - - code = gimple_assign_rhs_code (orig_stmt_info->stmt); - /* For MINUS_EXPR the initial vector is [init_val,0,...,0], therefore, - partial results are added and not subtracted. */ - if (code == MINUS_EXPR) - code = PLUS_EXPR; scalar_dest = gimple_assign_lhs (orig_stmt_info->stmt); scalar_type = TREE_TYPE (scalar_dest); @@ -4665,7 +4649,14 @@ vect_create_epilog_for_reduction (vec vect_defs, in the vectorized outer-loop, or reduced to a scalar result at the end of the outer-loop. */ if (nested_in_vect_loop && !double_reduc) - goto vect_finalize_reduction; + ; + else + { + enum tree_code code = gimple_assign_rhs_code (orig_stmt_info->stmt); + /* For MINUS_EXPR the initial vector is [init_val,0,...,0], therefore, + partial results are added and not subtracted. */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; /* SLP reduction without reduction chain, e.g., # a1 = phi @@ -5352,12 +5343,7 @@ vect_create_epilog_for_reduction (vec vect_defs, scalar_results[0] = tmp; } } - -vect_finalize_reduction: - - if (double_reduc) - loop = loop->inner; - + /* 2.5 Adjust the final result by the initial value of the reduction variable. (When such adjustment is not needed, then 'adjustment_def' is zero). For example, if code is PLUS we create: @@ -5401,6 +5387,10 @@ vect_finalize_reduction: new_phis[0] = epilog_stmt; } + } + + if (double_reduc) + loop = loop->inner; /* 2.6 Handle the loop-exit phis. Replace the uses of scalar loop-exit phis with new adjusted scalar results, i.e., replace use -- cgit v1.1 From fa87544ca13000e62982d3005edb47a53401cfe7 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 23 Sep 2019 11:56:47 +0000 Subject: Fix non-canonical CONST_INTs in altivec_copysign_v4sf3 (PR91823) The pattern was generating zero-extended rather than sign-extended CONST_INTs. 2019-09-23 Richard Sandiford gcc/ PR target/91823 * config/rs6000/altivec.md (altivec_copysign_v4sf3): Generate canonical CONST_INTs. Use gen_rtvec. From-SVN: r276055 --- gcc/ChangeLog | 6 ++++++ gcc/config/rs6000/altivec.md | 9 ++------- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9392b8f..30a55da 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-23 Richard Sandiford + + PR target/91823 + * config/rs6000/altivec.md (altivec_copysign_v4sf3): Generate + canonical CONST_INTs. Use gen_rtvec. + 2019-09-23 Richard Biener * tree-vect-loop.c (get_initial_def_for_reduction): Simplify, diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index 6fa4d80..dc34528 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -2198,13 +2198,8 @@ "VECTOR_UNIT_ALTIVEC_P (V4SFmode)" { rtx mask = gen_reg_rtx (V4SImode); - rtvec v = rtvec_alloc (4); - unsigned HOST_WIDE_INT mask_val = ((unsigned HOST_WIDE_INT)1) << 31; - - RTVEC_ELT (v, 0) = GEN_INT (mask_val); - RTVEC_ELT (v, 1) = GEN_INT (mask_val); - RTVEC_ELT (v, 2) = GEN_INT (mask_val); - RTVEC_ELT (v, 3) = GEN_INT (mask_val); + rtx mask_val = gen_int_mode (HOST_WIDE_INT_1U << 31, SImode); + rtvec v = gen_rtvec (4, mask_val, mask_val, mask_val, mask_val); emit_insn (gen_vec_initv4sisi (mask, gen_rtx_PARALLEL (V4SImode, v))); emit_insn (gen_vector_select_v4sf (operands[0], operands[1], operands[2], -- cgit v1.1 From ba2b30dc9fa9190101b3eb7ae10415b54ca25e7a Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Mon, 23 Sep 2019 16:28:09 +0000 Subject: [arm] Add missing Makefile dependency on arm_acle_builtins.def arm-builtins.o is missing a Makefile dependency on arm_acle_builtins.def which can cause inconsistent rebuilds when adding builtins in there. This patch adds the right Makefile-foo to fix that. * config/arm/t-arm (arm-builtins.o): Add dependency on arm_acle_builtins.def. From-SVN: r276057 --- gcc/ChangeLog | 5 +++++ gcc/config/arm/t-arm | 1 + 2 files changed, 6 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 30a55da..91efa76 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-23 Kyrylo Tkachov + + * config/arm/t-arm (arm-builtins.o): Add dependency on + arm_acle_builtins.def. + 2019-09-23 Richard Sandiford PR target/91823 diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm index f49ee72..af60c8f 100644 --- a/gcc/config/arm/t-arm +++ b/gcc/config/arm/t-arm @@ -141,6 +141,7 @@ arm-builtins.o: $(srcdir)/config/arm/arm-builtins.c $(CONFIG_H) \ $(RTL_H) $(TREE_H) expr.h $(TM_P_H) $(RECOG_H) langhooks.h \ $(DIAGNOSTIC_CORE_H) $(OPTABS_H) \ $(srcdir)/config/arm/arm-protos.h \ + $(srcdir)/config/arm/arm_acle_builtins.def \ $(srcdir)/config/arm/arm_neon_builtins.def \ $(srcdir)/config/arm/arm_vfp_builtins.def \ $(srcdir)/config/arm/arm-simd-builtin-types.def -- cgit v1.1 From 1a09197cb1bc05a71d1866d1220937289da02c5e Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 23 Sep 2019 17:37:54 +0000 Subject: PR c++/91844 - Implement CWG 2352, Similar types and reference binding. * call.c (reference_related_p): Use similar_type_p instead of same_type_p. (reference_compatible_p): Update implementation to match CWG 2352. * cp-tree.h (similar_type_p): Declare. * typeck.c (similar_type_p): New. * g++.dg/cpp0x/pr33930.C: Add dg-error. * g++.dg/cpp0x/ref-bind1.C: New test. * g++.dg/cpp0x/ref-bind2.C: New test. * g++.dg/cpp0x/ref-bind3.C: New test. * g++.old-deja/g++.pt/spec35.C: Remove dg-error. From-SVN: r276058 --- gcc/cp/ChangeLog | 9 ++++++ gcc/cp/call.c | 22 +++++++-------- gcc/cp/cp-tree.h | 1 + gcc/cp/typeck.c | 27 ++++++++++++++++++ gcc/testsuite/ChangeLog | 9 ++++++ gcc/testsuite/g++.dg/cpp0x/pr33930.C | 2 +- gcc/testsuite/g++.dg/cpp0x/ref-bind1.C | 44 ++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/ref-bind2.C | 15 ++++++++++ gcc/testsuite/g++.dg/cpp0x/ref-bind3.C | 22 +++++++++++++++ gcc/testsuite/g++.old-deja/g++.pt/spec35.C | 8 +++--- 10 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind3.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4420d8f..7ccc7cd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-09-23 Marek Polacek + + PR c++/91844 - Implement CWG 2352, Similar types and reference binding. + * call.c (reference_related_p): Use similar_type_p instead of + same_type_p. + (reference_compatible_p): Update implementation to match CWG 2352. + * cp-tree.h (similar_type_p): Declare. + * typeck.c (similar_type_p): New. + 2019-09-22 Marek Polacek PR c++/91819 - ICE with operator++ and enum. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 2dad699..28b3f33 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1530,9 +1530,8 @@ reference_related_p (tree t1, tree t2) /* [dcl.init.ref] Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related - to "cv2 T2" if T1 is the same type as T2, or T1 is a base class - of T2. */ - return (same_type_p (t1, t2) + to "cv2 T2" if T1 is similar to T2, or T1 is a base class of T2. */ + return (similar_type_p (t1, t2) || (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2) && DERIVED_FROM_P (t1, t2))); } @@ -1545,14 +1544,15 @@ reference_compatible_p (tree t1, tree t2) /* [dcl.init.ref] "cv1 T1" is reference compatible with "cv2 T2" if - * T1 is reference-related to T2 or - * T2 is "noexcept function" and T1 is "function", where the - function types are otherwise the same, - and cv1 is the same cv-qualification as, or greater cv-qualification - than, cv2. */ - return ((reference_related_p (t1, t2) - || fnptr_conv_p (t1, t2)) - && at_least_as_qualified_p (t1, t2)); + a prvalue of type "pointer to cv2 T2" can be converted to the type + "pointer to cv1 T1" via a standard conversion sequence. */ + tree ptype1 = build_pointer_type (t1); + tree ptype2 = build_pointer_type (t2); + conversion *conv = standard_conversion (ptype1, ptype2, NULL_TREE, + /*c_cast_p=*/false, 0, tf_none); + if (!conv || conv->bad_p) + return false; + return true; } /* A reference of the indicated TYPE is being bound directly to the diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6d217fc..9c0f394 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7361,6 +7361,7 @@ enum { ce_derived, ce_type, ce_normal, ce_exact }; extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); +extern bool similar_type_p (tree, tree); extern bool compparms (const_tree, const_tree); extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qualification (int, int); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d85e547..f427c4f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1530,6 +1530,33 @@ same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2) return same_type_p (type1, type2); } +/* Returns nonzero iff TYPE1 and TYPE2 are similar, as per [conv.qual]. */ + +bool +similar_type_p (tree type1, tree type2) +{ + if (type1 == error_mark_node || type2 == error_mark_node) + return false; + + /* Informally, two types are similar if, ignoring top-level cv-qualification: + * they are the same type; or + * they are both pointers, and the pointed-to types are similar; or + * they are both pointers to member of the same class, and the types of + the pointed-to members are similar; or + * they are both arrays of the same size or both arrays of unknown bound, + and the array element types are similar. */ + + if (same_type_ignoring_top_level_qualifiers_p (type1, type2)) + return true; + + /* FIXME This ought to handle ARRAY_TYPEs too. */ + if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2)) + || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))) + return comp_ptr_ttypes_const (type1, type2); + + return false; +} + /* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ bool diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 39fc50b..f381bb2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-09-23 Marek Polacek + + PR c++/91844 - Implement CWG 2352, Similar types and reference binding. + * g++.dg/cpp0x/pr33930.C: Add dg-error. + * g++.dg/cpp0x/ref-bind1.C: New test. + * g++.dg/cpp0x/ref-bind2.C: New test. + * g++.dg/cpp0x/ref-bind3.C: New test. + * g++.old-deja/g++.pt/spec35.C: Remove dg-error. + 2019-09-23 Rainer Orth * gcc.dg/ucnid-5-utf8.c: Skip unless ucn is supported. diff --git a/gcc/testsuite/g++.dg/cpp0x/pr33930.C b/gcc/testsuite/g++.dg/cpp0x/pr33930.C index 8d9312c..ba5b4b9 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr33930.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr33930.C @@ -6,5 +6,5 @@ int& foo( type&& ggg ); void bar( int* someptr ) { - int& x = foo( someptr ); + int& x = foo( someptr ); // { dg-error "cannot bind non-const lvalue reference" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind1.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind1.C new file mode 100644 index 0000000..af6140a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind1.C @@ -0,0 +1,44 @@ +// PR c++/91844 - Implement CWG 2352, Similar types and reference binding. +// { dg-do compile { target c++11 } } + +// These should bind directly to ptr, so no -Wreturn-local-addr warnings. +int *ptr; + +const int *const & +fn1 () +{ + return ptr; +} + +int **const ptr2 = nullptr; +const int *const *const & +fn2 () +{ + return ptr2; +} + +int (*ptr3)[10]; +using T = const int (*const)[10]; + +T& +fn3 () +{ + return ptr3; +} + +int (**ptr4)[5] = nullptr; +using T2 = const int (*const *const)[5]; + +T2& +fn4 () +{ + return ptr4; +} + +const int **ptr5 = nullptr; + +const int *const *const & +fn5 () +{ + return ptr5; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind2.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind2.C new file mode 100644 index 0000000..967c59e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind2.C @@ -0,0 +1,15 @@ +// PR c++/91844 - Implement CWG 2352, Similar types and reference binding. +// { dg-do compile { target c++11 } } + +// "const int *" and "int *" are reference-related, and 5.4.4. +// says that in that case, if the reference is an rvalue reference, +// the initializer expression shall not be an lvalue. + +int &f (const int *&&); + +void +fn (int *p) +{ + const int *&&r = p; // { dg-error "cannot bind rvalue reference" } + f (p); // { dg-error "cannot bind rvalue reference" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C new file mode 100644 index 0000000..16e1bfe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C @@ -0,0 +1,22 @@ +// PR c++/91844 - Implement CWG 2352, Similar types and reference binding. +// { dg-do compile { target c++11 } } + +template int f (const T *const &); // (1) +template int f (T *const &); // (2) +template int f (T *); // (3) + +/* Before CWG 2352, (2) was a better match than (1), but (2) and (3) were + equally good, so there was an ambiguity. (2) was better than (1) because + (1) required a qualification conversion whereas (2) didn't. But with this + CWG, (1) no longer requires a qualification conversion, because the types + "const int* const" and "int *" are now considered reference-related and we + bind directly, and (1) is more specialized than (2). And (1) is also a + better match than (3). */ + +void +g (int *p, const int *q, const int *const r) +{ + f (p); // calls (1) + f (q); // calls (1) + f (r); // calls (1) +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C index 581bb8e..93e953d 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C @@ -14,9 +14,9 @@ template int Foo (T &); // { dg-message "note" } candidate template int Qux (T); // { dg-message "note" } template int Qux (T const &); // { dg-message "note" } candidate -template int Bar (T const *const &); // { dg-message "note" } -template int Bar (T *const &); // { dg-message "note" } candidate -template int Bar (T *); // { dg-message "note" } candidate +template int Bar (T const *const &); +template int Bar (T *const &); +template int Bar (T *); template int Baz (T *const &); // { dg-message "note" } template int Baz (T *); // { dg-message "note" } candidate @@ -24,7 +24,7 @@ template int Baz (T *); // { dg-message "note" } candi int Baz (int const *ptr, int *ptr2) { Baz (ptr2); // { dg-error "ambiguous" } - Bar (ptr2); // { dg-error "ambiguous" } + Bar (ptr2); Foo (ptr2); // { dg-error "ambiguous" } Qux (ptr2); // { dg-error "ambiguous" } return 0; -- cgit v1.1 From 33ba6ac3912614d2e2c5bb1bad2f4f069525e700 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 23 Sep 2019 13:48:00 -0400 Subject: PR c++/91809 - bit-field and ellipsis. decay_conversion converts a bit-field access to its declared type, which isn't what we want here; it even has a comment that the caller is expected to have already used default_conversion to perform integral promotion. This function handles arithmetic promotion differently, but we still don't want to call decay_conversion before that happens. * call.c (convert_arg_to_ellipsis): Don't call decay_conversion for arithmetic arguments. From-SVN: r276059 --- gcc/cp/ChangeLog | 6 ++++++ gcc/cp/call.c | 14 +++++++------- gcc/testsuite/g++.dg/overload/ellipsis4.C | 12 ++++++++++++ 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/overload/ellipsis4.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7ccc7cd..541d018 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-09-23 Jason Merrill + + PR c++/91809 - bit-field and ellipsis. + * call.c (convert_arg_to_ellipsis): Don't call decay_conversion for + arithmetic arguments. + 2019-09-23 Marek Polacek PR c++/91844 - Implement CWG 2352, Similar types and reference binding. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 28b3f33..77f10a9 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7485,17 +7485,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, tree convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) { - tree arg_type; + tree arg_type = TREE_TYPE (arg); location_t loc = cp_expr_loc_or_input_loc (arg); /* [expr.call] - The lvalue-to-rvalue, array-to-pointer, and function-to-pointer - standard conversions are performed. */ - arg = decay_conversion (arg, complain); - arg_type = TREE_TYPE (arg); - /* [expr.call] - If the argument has integral or enumeration type that is subject to the integral promotions (_conv.prom_), or a floating-point type that is subject to the floating-point promotion @@ -7536,6 +7530,12 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) else arg = cp_perform_integral_promotions (arg, complain); } + else + /* [expr.call] + + The lvalue-to-rvalue, array-to-pointer, and function-to-pointer + standard conversions are performed. */ + arg = decay_conversion (arg, complain); arg = require_complete_type_sfinae (arg, complain); arg_type = TREE_TYPE (arg); diff --git a/gcc/testsuite/g++.dg/overload/ellipsis4.C b/gcc/testsuite/g++.dg/overload/ellipsis4.C new file mode 100644 index 0000000..9bade5a --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/ellipsis4.C @@ -0,0 +1,12 @@ +// { dg-additional-options "-Wformat" } + +extern "C" int printf (const char *, ...); + +struct X { + unsigned long long a: 1; +} x; + +void foo() +{ + printf("%d", x.a); +} -- cgit v1.1 From 7926a220d853e7c28576e69f90eab1aff684c5ad Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Mon, 23 Sep 2019 15:28:10 -0400 Subject: 2019-09-23 Sandra Loosemore gcc/testsuite/ * lib/target-supports.exp (check_effective_target_arm_vfp_ok_nocache): New. (check_effective_target_arm_vfp_ok): Rewrite. (add_options_for_arm_vfp): New. (add_options_for_sqrt_insn): Add options for arm. * gcc.target/arm/attr-neon-builtin-fail2.c: Use dg-add-options. * gcc.target/arm/short-vfp-1.c: Likewise. From-SVN: r276063 --- gcc/testsuite/ChangeLog | 10 +++++ .../gcc.target/arm/attr-neon-builtin-fail2.c | 3 +- gcc/testsuite/gcc.target/arm/short-vfp-1.c | 2 +- gcc/testsuite/lib/target-supports.exp | 46 +++++++++++++++++----- 4 files changed, 50 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f381bb2..a9b108d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2019-09-23 Sandra Loosemore + + * lib/target-supports.exp + (check_effective_target_arm_vfp_ok_nocache): New. + (check_effective_target_arm_vfp_ok): Rewrite. + (add_options_for_arm_vfp): New. + (add_options_for_sqrt_insn): Add options for arm. + * gcc.target/arm/attr-neon-builtin-fail2.c: Use dg-add-options. + * gcc.target/arm/short-vfp-1.c: Likewise. + 2019-09-23 Marek Polacek PR c++/91844 - Implement CWG 2352, Similar types and reference binding. diff --git a/gcc/testsuite/gcc.target/arm/attr-neon-builtin-fail2.c b/gcc/testsuite/gcc.target/arm/attr-neon-builtin-fail2.c index 0f8ac1b..9cb5a2e 100644 --- a/gcc/testsuite/gcc.target/arm/attr-neon-builtin-fail2.c +++ b/gcc/testsuite/gcc.target/arm/attr-neon-builtin-fail2.c @@ -1,7 +1,8 @@ /* Check that calling a neon builtin from a function compiled with vfp fails. */ /* { dg-do compile } */ /* { dg-require-effective-target arm_vfp_ok } */ -/* { dg-options "-O2 -mfloat-abi=softfp" } */ +/* { dg-options "-O2" } */ +/* { dg-add-options arm_vfp } */ extern __simd64_int8_t a, b; diff --git a/gcc/testsuite/gcc.target/arm/short-vfp-1.c b/gcc/testsuite/gcc.target/arm/short-vfp-1.c index d96c763..3ca1ffc 100644 --- a/gcc/testsuite/gcc.target/arm/short-vfp-1.c +++ b/gcc/testsuite/gcc.target/arm/short-vfp-1.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target arm_vfp_ok } -/* { dg-options "-mfpu=vfp" } */ +/* { dg-add-options arm_vfp } */ int test_sisf (float x) diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 414bf80..6a1aaca 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -3489,18 +3489,43 @@ proc check_effective_target_arm_soft_ok { } { } } -# Return 1 if this is an ARM target supporting -mfpu=vfp -# -mfloat-abi=softfp. Some multilibs may be incompatible with these -# options. +# Return 1 if this is an ARM target supporting -mfpu=vfp with an +# appropriate abi. -proc check_effective_target_arm_vfp_ok { } { +proc check_effective_target_arm_vfp_ok_nocache { } { + global et_arm_vfp_flags + set et_arm_vfp_flags "" if { [check_effective_target_arm32] } { - return [check_no_compiler_messages arm_vfp_ok object { - int dummy; - } "-mfpu=vfp -mfloat-abi=softfp"] - } else { - return 0 + foreach flags {"-mfpu=vfp" "-mfpu=vfp -mfloat-abi=softfp" "-mpu=vfp -mfloat-abi=hard"} { + if { [check_no_compiler_messages_nocache arm_fp_ok object { + #ifndef __ARM_FP + #error __ARM_FP not defined + #endif + } "$flags"] } { + set et_arm_vfp_flags $flags + return 1 + } + } } + + return 0 +} + +proc check_effective_target_arm_vfp_ok { } { + return [check_cached_effective_target arm_vfp_ok \ + check_effective_target_arm_vfp_ok_nocache] +} + +# Add the options needed to compile code with -mfpu=vfp. We need either +# -mfloat-abi=softfp or -mfloat-abi=hard, but if one is already +# specified by the multilib, use it. + +proc add_options_for_arm_vfp { flags } { + if { ! [check_effective_target_arm_vfp_ok] } { + return "$flags" + } + global et_arm_vfp_flags + return "$flags $et_arm_vfp_flags" } # Return 1 if this is an ARM target supporting -mfpu=vfp3 @@ -6678,6 +6703,9 @@ proc add_options_for_sqrt_insn { flags } { if { [istarget amdgcn*-*-*] } { return "$flags -ffast-math" } + if { [istarget arm*-*-*] } { + return [add_options_for_arm_vfp "$flags"] + } return $flags } -- cgit v1.1 From 0788210f804a2ba451bc9cbda26c256ad9f7c5f3 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Mon, 23 Sep 2019 19:29:55 +0000 Subject: pt.c (check_explicit_specialization): Use cp_expr_loc_or_input_loc. /cp 2019-09-23 Paolo Carlini * pt.c (check_explicit_specialization): Use cp_expr_loc_or_input_loc. (process_partial_specialization): Likewise. (convert_nontype_argument_function): Likewise. (invalid_tparm_referent_p): Likewise. (convert_template_argument): Likewise. (check_valid_ptrmem_cst_expr): Tidy. /testsuite 2019-09-23 Paolo Carlini * g++.dg/cpp0x/pr68724.C: Check location(s) too. * g++.dg/cpp0x/variadic38.C: Likewise. * g++.dg/cpp1z/nontype2.C: Likewise. * g++.dg/parse/explicit1.C: Likewise. * g++.dg/template/crash11.C: Likewise. * g++.dg/template/non-dependent8.C: Likewise. * g++.dg/template/nontype-array1.C: Likewise. * g++.dg/template/nontype3.C: Likewise. * g++.dg/template/nontype8.C: Likewise. * g++.dg/template/partial5.C: Likewise. * g++.dg/template/spec33.C: Likewise. * g++.old-deja/g++.pt/memtemp64.C: Likewise. * g++.old-deja/g++.pt/spec20.C: Likewise. * g++.old-deja/g++.pt/spec21.C: Likewise. * g++.old-deja/g++.robertl/eb103.C: Likewise. From-SVN: r276064 --- gcc/cp/ChangeLog | 9 ++++ gcc/cp/pt.c | 71 +++++++++++++++----------- gcc/testsuite/ChangeLog | 18 +++++++ gcc/testsuite/g++.dg/cpp0x/pr68724.C | 2 +- gcc/testsuite/g++.dg/cpp0x/variadic38.C | 2 +- gcc/testsuite/g++.dg/cpp1z/nontype2.C | 2 +- gcc/testsuite/g++.dg/parse/explicit1.C | 2 +- gcc/testsuite/g++.dg/template/crash11.C | 4 +- gcc/testsuite/g++.dg/template/non-dependent8.C | 3 +- gcc/testsuite/g++.dg/template/nontype-array1.C | 4 +- gcc/testsuite/g++.dg/template/nontype3.C | 2 +- gcc/testsuite/g++.dg/template/nontype8.C | 6 ++- gcc/testsuite/g++.dg/template/partial5.C | 2 +- gcc/testsuite/g++.dg/template/spec33.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/memtemp64.C | 3 +- gcc/testsuite/g++.old-deja/g++.pt/spec20.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/spec21.C | 4 +- gcc/testsuite/g++.old-deja/g++.robertl/eb103.C | 3 +- 18 files changed, 93 insertions(+), 48 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 541d018..5b561e6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-09-23 Paolo Carlini + + * pt.c (check_explicit_specialization): Use cp_expr_loc_or_input_loc. + (process_partial_specialization): Likewise. + (convert_nontype_argument_function): Likewise. + (invalid_tparm_referent_p): Likewise. + (convert_template_argument): Likewise. + (check_valid_ptrmem_cst_expr): Tidy. + 2019-09-23 Jason Merrill PR c++/91809 - bit-field and ellipsis. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4b3993c..e5d6498 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2808,8 +2808,9 @@ check_explicit_specialization (tree declarator, /* This case handles bogus declarations like template <> template void f(); */ - error ("template-id %qD in declaration of primary template", - declarator); + error_at (cp_expr_loc_or_input_loc (declarator), + "template-id %qE in declaration of primary template", + declarator); return decl; } } @@ -2867,8 +2868,9 @@ check_explicit_specialization (tree declarator, template void f(); */ if (!uses_template_parms (TREE_OPERAND (declarator, 1))) - error ("template-id %qD in declaration of primary template", - declarator); + error_at (cp_expr_loc_or_input_loc (declarator), + "template-id %qE in declaration of primary template", + declarator); else if (variable_template_p (TREE_OPERAND (declarator, 0))) { /* Partial specialization of variable template. */ @@ -2877,11 +2879,13 @@ check_explicit_specialization (tree declarator, goto ok; } else if (cxx_dialect < cxx14) - error ("non-type partial specialization %qD " - "is not allowed", declarator); + error_at (cp_expr_loc_or_input_loc (declarator), + "non-type partial specialization %qE " + "is not allowed", declarator); else - error ("non-class, non-variable partial specialization %qD " - "is not allowed", declarator); + error_at (cp_expr_loc_or_input_loc (declarator), + "non-class, non-variable partial specialization %qE " + "is not allowed", declarator); return decl; ok:; } @@ -4958,8 +4962,9 @@ process_partial_specialization (tree decl) { if ((!packed_args && tpd.arg_uses_template_parms[i]) || (packed_args && uses_template_parms (arg))) - error ("template argument %qE involves template parameter(s)", - arg); + error_at (cp_expr_loc_or_input_loc (arg), + "template argument %qE involves template " + "parameter(s)", arg); else { /* Look at the corresponding template parameter, @@ -6258,13 +6263,14 @@ convert_nontype_argument_function (tree type, tree expr, { if (complain & tf_error) { - error ("%qE is not a valid template argument for type %qT", - expr, type); + location_t loc = cp_expr_loc_or_input_loc (expr); + error_at (loc, "%qE is not a valid template argument for type %qT", + expr, type); if (TYPE_PTR_P (type)) - inform (input_location, "it must be the address of a function " + inform (loc, "it must be the address of a function " "with external linkage"); else - inform (input_location, "it must be the name of a function with " + inform (loc, "it must be the name of a function with " "external linkage"); } return NULL_TREE; @@ -6275,14 +6281,15 @@ convert_nontype_argument_function (tree type, tree expr, { if (complain & tf_error) { + location_t loc = cp_expr_loc_or_input_loc (expr); if (cxx_dialect >= cxx11) - error ("%qE is not a valid template argument for type %qT " - "because %qD has no linkage", - expr, type, fn_no_ptr); + error_at (loc, "%qE is not a valid template argument for type " + "%qT because %qD has no linkage", + expr, type, fn_no_ptr); else - error ("%qE is not a valid template argument for type %qT " - "because %qD does not have external linkage", - expr, type, fn_no_ptr); + error_at (loc, "%qE is not a valid template argument for type " + "%qT because %qD does not have external linkage", + expr, type, fn_no_ptr); } return NULL_TREE; } @@ -6309,7 +6316,6 @@ static bool check_valid_ptrmem_cst_expr (tree type, tree expr, tsubst_flags_t complain) { - location_t loc = cp_expr_loc_or_input_loc (expr); tree orig_expr = expr; STRIP_NOPS (expr); if (null_ptr_cst_p (expr)) @@ -6326,6 +6332,7 @@ check_valid_ptrmem_cst_expr (tree type, tree expr, return true; if (complain & tf_error) { + location_t loc = cp_expr_loc_or_input_loc (orig_expr); error_at (loc, "%qE is not a valid template argument for type %qT", orig_expr, type); if (TREE_CODE (expr) != PTRMEM_CST) @@ -6623,24 +6630,27 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) if (!VAR_P (decl)) { if (complain & tf_error) - error ("%qE is not a valid template argument of type %qT " - "because %qE is not a variable", expr, type, decl); + error_at (cp_expr_loc_or_input_loc (expr), + "%qE is not a valid template argument of type %qT " + "because %qE is not a variable", expr, type, decl); return true; } else if (cxx_dialect < cxx11 && !DECL_EXTERNAL_LINKAGE_P (decl)) { if (complain & tf_error) - error ("%qE is not a valid template argument of type %qT " - "in C++98 because %qD does not have external linkage", - expr, type, decl); + error_at (cp_expr_loc_or_input_loc (expr), + "%qE is not a valid template argument of type %qT " + "in C++98 because %qD does not have external linkage", + expr, type, decl); return true; } else if ((cxx_dialect >= cxx11 && cxx_dialect < cxx17) && decl_linkage (decl) == lk_none) { if (complain & tf_error) - error ("%qE is not a valid template argument of type %qT " - "because %qD has no linkage", expr, type, decl); + error_at (cp_expr_loc_or_input_loc (expr), + "%qE is not a valid template argument of type %qT " + "because %qD has no linkage", expr, type, decl); return true; } /* C++17: For a non-type template-parameter of reference or pointer @@ -8129,8 +8139,9 @@ convert_template_argument (tree parm, if (val == NULL_TREE) val = error_mark_node; else if (val == error_mark_node && (complain & tf_error)) - error ("could not convert template argument %qE from %qT to %qT", - orig_arg, TREE_TYPE (orig_arg), t); + error_at (cp_expr_loc_or_input_loc (orig_arg), + "could not convert template argument %qE from %qT to %qT", + orig_arg, TREE_TYPE (orig_arg), t); if (INDIRECT_REF_P (val)) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a9b108d..6d84a01 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2019-09-23 Paolo Carlini + + * g++.dg/cpp0x/pr68724.C: Check location(s) too. + * g++.dg/cpp0x/variadic38.C: Likewise. + * g++.dg/cpp1z/nontype2.C: Likewise. + * g++.dg/parse/explicit1.C: Likewise. + * g++.dg/template/crash11.C: Likewise. + * g++.dg/template/non-dependent8.C: Likewise. + * g++.dg/template/nontype-array1.C: Likewise. + * g++.dg/template/nontype3.C: Likewise. + * g++.dg/template/nontype8.C: Likewise. + * g++.dg/template/partial5.C: Likewise. + * g++.dg/template/spec33.C: Likewise. + * g++.old-deja/g++.pt/memtemp64.C: Likewise. + * g++.old-deja/g++.pt/spec20.C: Likewise. + * g++.old-deja/g++.pt/spec21.C: Likewise. + * g++.old-deja/g++.robertl/eb103.C: Likewise. + 2019-09-23 Sandra Loosemore * lib/target-supports.exp diff --git a/gcc/testsuite/g++.dg/cpp0x/pr68724.C b/gcc/testsuite/g++.dg/cpp0x/pr68724.C index ff6d84d..4e99d53 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr68724.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr68724.C @@ -9,7 +9,7 @@ struct integral_constant integral_constant inst; template -struct integral_constant // { dg-error "" } +struct integral_constant // { dg-error "32:template argument" } { }; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic38.C b/gcc/testsuite/g++.dg/cpp0x/variadic38.C index 62031a3..b569404 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic38.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic38.C @@ -3,4 +3,4 @@ template struct int_vec {}; template -struct int_vec<0, (Values+1)...> {}; // { dg-error "involves template parameter" } +struct int_vec<0, (Values+1)...> {}; // { dg-error "26:template argument" } diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype2.C b/gcc/testsuite/g++.dg/cpp1z/nontype2.C index 393c833..75dc760 100644 --- a/gcc/testsuite/g++.dg/cpp1z/nontype2.C +++ b/gcc/testsuite/g++.dg/cpp1z/nontype2.C @@ -8,7 +8,7 @@ template class X { }; template class Y {}; template class Z {}; -X<&s.m> x7; // { dg-error "" } +X<&s.m> x7; // { dg-error "3:.& s.S::m. is not a valid template argument" } Y<"foo"> y1; // { dg-error "string literal" } Z z1; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/parse/explicit1.C b/gcc/testsuite/g++.dg/parse/explicit1.C index 3535874..23c8264 100644 --- a/gcc/testsuite/g++.dg/parse/explicit1.C +++ b/gcc/testsuite/g++.dg/parse/explicit1.C @@ -7,5 +7,5 @@ struct foo { template void bar (T &t) {} - template<> void bar(double &t) {} // { dg-error "non-namespace|template|function" } + template<> void bar(double &t) {} // { dg-error "25:template-id .bar. in declaration|explicit specialization" } }; diff --git a/gcc/testsuite/g++.dg/template/crash11.C b/gcc/testsuite/g++.dg/template/crash11.C index 3c69514..229aec9 100644 --- a/gcc/testsuite/g++.dg/template/crash11.C +++ b/gcc/testsuite/g++.dg/template/crash11.C @@ -6,4 +6,6 @@ // substitution. template void foo(T, U) {} -template void foo(T, void) {} // { dg-error "incomplete|invalid|partial" } +template void foo(T, void) {} // { dg-error "40:invalid use of type .void." } +// { dg-error "25:non-class, non-variable partial specialization" "" { target c++14 } .-1 } +// { dg-error "25:non-type partial specialization" "" { target c++11_down } .-2 } diff --git a/gcc/testsuite/g++.dg/template/non-dependent8.C b/gcc/testsuite/g++.dg/template/non-dependent8.C index 369e137..f99691b 100644 --- a/gcc/testsuite/g++.dg/template/non-dependent8.C +++ b/gcc/testsuite/g++.dg/template/non-dependent8.C @@ -17,5 +17,6 @@ struct X template struct Foo { - X<&S::i> x; // { dg-error "convert|no type" } + X<&S::i> x; // { dg-error "5:could not convert" "" { target c++17 } } + // { dg-error "could not convert" "" { target c++14_down } .-1 } }; diff --git a/gcc/testsuite/g++.dg/template/nontype-array1.C b/gcc/testsuite/g++.dg/template/nontype-array1.C index f22551b..2a227b9 100644 --- a/gcc/testsuite/g++.dg/template/nontype-array1.C +++ b/gcc/testsuite/g++.dg/template/nontype-array1.C @@ -26,14 +26,14 @@ int main() Message m2; // OK for clang since C++14, for gcc since C++17 Message m3; // OK for clang/gcc since C++11 - A a1; // { dg-error "" "" { target c++14_down } } + A a1; // { dg-error "7:.f2\\(\\). is not a valid template argument" "" { target c++14_down } } static char const s4[] = "hi"; static constexpr char const s5[] = "hi"; // OK since C++11 Message m4; // { dg-error "no linkage" "" { target c++14_down } } Message m5; // { dg-error "no linkage" "" { target c++14_down } } Message m6; // { dg-error "" "" { target c++14_down } } - Message m7; // { dg-error "" "" { target c++14_down } } + Message m7; // { dg-error "11:could not convert template argument" "" { target c++14_down } } char const s8[] = "hi"; diff --git a/gcc/testsuite/g++.dg/template/nontype3.C b/gcc/testsuite/g++.dg/template/nontype3.C index 2269e0f..0f5accf 100644 --- a/gcc/testsuite/g++.dg/template/nontype3.C +++ b/gcc/testsuite/g++.dg/template/nontype3.C @@ -16,7 +16,7 @@ template void dep6(bar *); // { dg-error "" "integral or enumeration" } template -void dep7(bar *); // { dg-error "" } +void dep7(bar *); // { dg-error "16:could not convert template argument" } template void dep8(foo< *PI > *); // { dg-error "" "integral or enumeration" } diff --git a/gcc/testsuite/g++.dg/template/nontype8.C b/gcc/testsuite/g++.dg/template/nontype8.C index 86d39f3..b4fbeae 100644 --- a/gcc/testsuite/g++.dg/template/nontype8.C +++ b/gcc/testsuite/g++.dg/template/nontype8.C @@ -6,8 +6,10 @@ template class X { }; int a[10]; struct S { int m; static int s; } s; -X<&a[2]> x3; // { dg-error "" } address of array element -X<&s.m> x4; // { dg-error "" } address of non-static member +X<&a[2]> x3; // { dg-error "3:.& a\\\[2\\\]. is not a valid template argument" "" { target c++17 } } +// { dg-error "" "" { target c++14_down } .-1 } +X<&s.m> x4; // { dg-error "3:.& s.S::m. is not a valid template argument" "" { target c++17 } } +// { dg-error "" "" { target c++14_down } .-1 } X<&s.s> x5; // { dg-error "" "" { target { ! c++17 } } } &S::s must be used X<&S::s> x6; // OK: address of static member diff --git a/gcc/testsuite/g++.dg/template/partial5.C b/gcc/testsuite/g++.dg/template/partial5.C index 464408e..a562297 100644 --- a/gcc/testsuite/g++.dg/template/partial5.C +++ b/gcc/testsuite/g++.dg/template/partial5.C @@ -21,4 +21,4 @@ template struct Z { }; template -struct Z { }; // { dg-error "involves template parameter" } +struct Z { }; // { dg-error "13:template argument" } diff --git a/gcc/testsuite/g++.dg/template/spec33.C b/gcc/testsuite/g++.dg/template/spec33.C index 7b7a751..2cdf85b 100644 --- a/gcc/testsuite/g++.dg/template/spec33.C +++ b/gcc/testsuite/g++.dg/template/spec33.C @@ -3,5 +3,5 @@ struct A { template static void foo () {} - template<> static void foo<0>() {} // { dg-error "explicit|template" } + template<> static void foo<0>() {} // { dg-error "31:template-id .foo<0>. in declaration|explicit specialization" } }; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp64.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp64.C index dda0a63..47b4ded 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/memtemp64.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp64.C @@ -10,7 +10,8 @@ template struct S2 { template - void f >(T) {} // { dg-error "" } bad specialization. + void f >(T) {} // { dg-error "8:non-class, non-variable partial specialization" "" { target c++14 } } + // { dg-error "8:non-type partial specialization" "" { target c++11_down } .-1 } }; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec20.C b/gcc/testsuite/g++.old-deja/g++.pt/spec20.C index b6148e5..610e6c7 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec20.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec20.C @@ -8,7 +8,7 @@ template struct S { template void f(U); - template <> void f(int); // { dg-error "" } invalid specialization + template <> void f(int); // { dg-error "20:template-id .f. in declaration|explicit specialization" } template struct I {}; // { dg-error "template" } template struct I {}; // { dg-error "template" } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec21.C b/gcc/testsuite/g++.old-deja/g++.pt/spec21.C index 4107306..cf89d6b 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec21.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec21.C @@ -4,8 +4,8 @@ template struct S {}; template struct S {}; // { dg-error "" } default argument template struct A {}; -template struct A {}; // { dg-error "" } argument involves parameter - +template struct A {}; // { dg-error "28:template argument" } +// { dg-error "33:template argument" "" { target *-*-* } .-1 } template struct C {}; template struct C; // { dg-error "" } type depends on parameter int i; diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C index ffc51ee..de181ab 100644 --- a/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C +++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C @@ -4,7 +4,8 @@ template inline unsigned f (unsigned* ptr); template -inline unsigned f (unsigned* ptr) // { dg-error "partial specialization" } +inline unsigned f (unsigned* ptr) // { dg-error "17:non-class, non-variable partial specialization" "" { target c++14 } } +// { dg-error "17:non-type partial specialization" "" { target c++11_down } .-1 } { return 1; } -- cgit v1.1 From a8cea25c734906e622113369704101617ef34c31 Mon Sep 17 00:00:00 2001 From: Carl Love Date: Mon, 23 Sep 2019 20:08:13 +0000 Subject: RS6000, add xxswapd support gcc/ChangeLog: 2019-09-23 Carl Love * config/rs6000/vsx.md (xxswapd_v4si, xxswapd_v8hi, xxswapd_v16qi): New define_insn. (vsx_xxpermdi4_le_ for VSX_W, vsx_xxpermdi8_le_V8HI, vsx_xxpermdi16_le_V16QI): Removed define_insn. From-SVN: r276065 --- gcc/config/rs6000/vsx.md | 62 ++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 28 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 7633171..91f5fed 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -2941,41 +2941,47 @@ "xxpermdi %x0,%x1,%x1,2" [(set_attr "type" "vecperm")]) -(define_insn "*vsx_xxpermdi4_le_" - [(set (match_operand:VSX_W 0 "vsx_register_operand" "=wa") - (vec_select:VSX_W - (match_operand:VSX_W 1 "vsx_register_operand" "wa") - (parallel [(const_int 2) (const_int 3) - (const_int 0) (const_int 1)])))] - "!BYTES_BIG_ENDIAN && VECTOR_MEM_VSX_P (mode)" +(define_insn "xxswapd_v16qi" + [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa") + (vec_select:V16QI + (match_operand:V16QI 1 "vsx_register_operand" "wa") + (parallel [(const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15) + (const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)])))] + "TARGET_VSX" +;; AIX does not support the extended mnemonic xxswapd. Use the basic +;; mnemonic xxpermdi instead. "xxpermdi %x0,%x1,%x1,2" [(set_attr "type" "vecperm")]) -(define_insn "*vsx_xxpermdi8_le_V8HI" +(define_insn "xxswapd_v8hi" [(set (match_operand:V8HI 0 "vsx_register_operand" "=wa") - (vec_select:V8HI - (match_operand:V8HI 1 "vsx_register_operand" "wa") - (parallel [(const_int 4) (const_int 5) - (const_int 6) (const_int 7) - (const_int 0) (const_int 1) - (const_int 2) (const_int 3)])))] - "!BYTES_BIG_ENDIAN && VECTOR_MEM_VSX_P (V8HImode)" + (vec_select:V8HI + (match_operand:V8HI 1 "vsx_register_operand" "wa") + (parallel [(const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 0) (const_int 1) + (const_int 2) (const_int 3)])))] + "TARGET_VSX" +;; AIX does not support the extended mnemonic xxswapd. Use the basic +;; mnemonic xxpermdi instead. "xxpermdi %x0,%x1,%x1,2" [(set_attr "type" "vecperm")]) -(define_insn "*vsx_xxpermdi16_le_V16QI" - [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa") - (vec_select:V16QI - (match_operand:V16QI 1 "vsx_register_operand" "wa") - (parallel [(const_int 8) (const_int 9) - (const_int 10) (const_int 11) - (const_int 12) (const_int 13) - (const_int 14) (const_int 15) - (const_int 0) (const_int 1) - (const_int 2) (const_int 3) - (const_int 4) (const_int 5) - (const_int 6) (const_int 7)])))] - "!BYTES_BIG_ENDIAN && VECTOR_MEM_VSX_P (V16QImode)" +(define_insn "xxswapd_" + [(set (match_operand:VSX_W 0 "vsx_register_operand" "=wa") + (vec_select:VSX_W + (match_operand:VSX_W 1 "vsx_register_operand" "wa") + (parallel [(const_int 2) (const_int 3) + (const_int 0) (const_int 1)])))] + "TARGET_VSX" +;; AIX does not support extended mnemonic xxswapd. Use the basic +;; mnemonic xxpermdi instead. "xxpermdi %x0,%x1,%x1,2" [(set_attr "type" "vecperm")]) -- cgit v1.1 From 0ca2b1f3d8d2943425c79983330a64ebaf582937 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 23 Sep 2019 23:19:29 +0000 Subject: GNAT/testsuite: Pass the `ada' option to target compilation Pass the `ada' option to DejaGNU's `target_compile' procedure, which by default calls `default_target_compile', so that it arranges for an Ada compilation rather the default of C. We set the compiler to `gnatmake' manually here, so that part of the logic in `default_target_compile' is not used, but it affects other settings, such as the use of `adaflags'. gcc/testsuite/ * lib/gnat.exp (gnat_target_compile): Pass the `ada' option to `target_compile'. From-SVN: r276085 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/lib/gnat.exp | 2 ++ 2 files changed, 7 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6d84a01..d4ec00e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-23 Maciej W. Rozycki + + * lib/gnat.exp (gnat_target_compile): Pass the `ada' option to + `target_compile'. + 2019-09-23 Paolo Carlini * g++.dg/cpp0x/pr68724.C: Check location(s) too. diff --git a/gcc/testsuite/lib/gnat.exp b/gcc/testsuite/lib/gnat.exp index 5559220..b6b56b4 100644 --- a/gcc/testsuite/lib/gnat.exp +++ b/gcc/testsuite/lib/gnat.exp @@ -167,6 +167,8 @@ proc gnat_target_compile { source dest type options } { set options [concat "additional_flags=$TOOL_OPTIONS" $options] } + set options [concat "{ada}" $options] + return [target_compile $source $dest $type $options] } -- cgit v1.1 From 18b86eda6f2be355dfc34c32b36605356ae46fb9 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 24 Sep 2019 00:16:40 +0000 Subject: Daily bump. From-SVN: r276089 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 0bff5aa..1012279 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190923 +20190924 -- cgit v1.1 From 3f9e08f57e1de90de5bc9d2a00815ea38064c733 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 24 Sep 2019 10:10:49 +0000 Subject: tree-ssa-sccvn.c (vn_reference_lookup_3): Valueize MEM_REF base. 2019-09-24 Richard Biener * tree-ssa-sccvn.c (vn_reference_lookup_3): Valueize MEM_REF base. * gcc.dg/torture/20190924-1.c: New testcase. From-SVN: r276092 --- gcc/ChangeLog | 5 +++++ gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gcc.dg/torture/20190924-1.c | 17 +++++++++++++++++ gcc/tree-ssa-sccvn.c | 5 +++-- 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/20190924-1.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 91efa76..bd6f541 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Richard Biener + + * tree-ssa-sccvn.c (vn_reference_lookup_3): Valueize MEM_REF + base. + 2019-09-23 Kyrylo Tkachov * config/arm/t-arm (arm-builtins.o): Add dependency on diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d4ec00e..600901d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-24 Richard Biener + + * gcc.dg/torture/20190924-1.c: New testcase. + 2019-09-23 Maciej W. Rozycki * lib/gnat.exp (gnat_target_compile): Pass the `ada' option to diff --git a/gcc/testsuite/gcc.dg/torture/20190924-1.c b/gcc/testsuite/gcc.dg/torture/20190924-1.c new file mode 100644 index 0000000..13b46ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20190924-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +struct acct_gather_energy { + int base_consumed_energy; + int consumed_energy; + int previous_consumed_energy; +}; +static struct acct_gather_energy xcc_energy; +struct acct_gather_energy *new; +int _get_joules_task(int first) +{ + if (!first && new->previous_consumed_energy) + first = 1; + new->base_consumed_energy = new->consumed_energy; + __builtin_memcpy(&xcc_energy, new, sizeof(struct acct_gather_energy)); + return xcc_energy.base_consumed_energy; +} diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index c29e2de..44b8c67 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -2935,8 +2935,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, else return (void *)-1; } - if (TREE_CODE (rhs) != SSA_NAME - && TREE_CODE (rhs) != ADDR_EXPR) + if (TREE_CODE (rhs) == SSA_NAME) + rhs = SSA_VAL (rhs); + else if (TREE_CODE (rhs) != ADDR_EXPR) return (void *)-1; /* The bases of the destination and the references have to agree. */ -- cgit v1.1 From 5a4d0da4f5840b9829316e93710b4bd4269b9366 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Tue, 24 Sep 2019 13:16:57 +0200 Subject: [PR 91832] Do not ICE on negative offsets in ipa-sra Hi, IPA-SRA asserts that an offset obtained from get_ref_base_and_extent is non-negative (after it verifies it is based on a parameter). That assumption is invalid as the testcase shows. One could probably also write a testcase with defined behavior, but unless I see a reasonable one where the transformation is really desirable, I'd like to just punt on those cases. Bootstrapped and tested on x86_64-linux. OK for trunk? Thanks, Martin 2019-09-24 Martin Jambor PR ipa/91832 * ipa-sra.c (scan_expr_access): Check that offset is non-negative. testsuite/ * gcc.dg/ipa/pr91832.c: New test. From-SVN: r276093 --- gcc/ChangeLog | 5 +++++ gcc/ipa-sra.c | 7 ++++++- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/ipa/pr91832.c | 12 ++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/pr91832.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bd6f541..2d7e280 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Martin Jambor + + PR ipa/91832 + * ipa-sra.c (scan_expr_access): Check that offset is non-negative. + 2019-09-24 Richard Biener * tree-ssa-sccvn.c (vn_reference_lookup_3): Valueize MEM_REF diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c index a32defb..0ccebbd 100644 --- a/gcc/ipa-sra.c +++ b/gcc/ipa-sra.c @@ -1692,7 +1692,12 @@ scan_expr_access (tree expr, gimple *stmt, isra_scan_context ctx, disqualify_split_candidate (desc, "Encountered a bit-field access."); return; } - gcc_assert (offset >= 0); + if (offset < 0) + { + disqualify_split_candidate (desc, "Encountered an access at a " + "negative offset."); + return; + } gcc_assert ((offset % BITS_PER_UNIT) == 0); gcc_assert ((size % BITS_PER_UNIT) == 0); if ((offset / BITS_PER_UNIT) >= (UINT_MAX - ISRA_ARG_SIZE_LIMIT) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 600901d..83acf8e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Martin Jambor + + PR ipa/91832 + * gcc.dg/ipa/pr91832.c: New test. + 2019-09-24 Richard Biener * gcc.dg/torture/20190924-1.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/ipa/pr91832.c b/gcc/testsuite/gcc.dg/ipa/pr91832.c new file mode 100644 index 0000000..4a0d62e --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr91832.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct A1 { + char a1[1]; +}; + +void fn2(char a); + +void fn1(struct A1 *p1) { + fn2(p1->a1[-1]); +} -- cgit v1.1 From 231f75463c25e2a27c21c19f31bfbda421e12f49 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Tue, 24 Sep 2019 13:20:57 +0200 Subject: [PR 91831] Copy PARM_DECLs of artificial thunks Hi, I am quite surprised I did not catch this before but the new ipa-param-manipulation does not copy PARM_DECLs when creating artificial thinks (I think it originally did but then I somehow removed during one cleanups). Fixed by adding the capability at the natural place. It is triggered whenever context of the PARM_DECL that is just taken from the original function does not match the target fndecl rather than by some constructor parameter because in such situation it is always the correct thing to do. Bootstrapped and tested on x86_64-linux. OK for trunk? Thanks, Martin 2019-09-24 Martin Jambor PR ipa/91831 * ipa-param-manipulation.c (carry_over_param): Make a method of ipa_param_body_adjustments, remove now unnecessary argument. Also copy in case of a context mismatch. (ipa_param_body_adjustments::common_initialization): Adjust call to carry_over_param. * ipa-param-manipulation.h (class ipa_param_body_adjustments): Add private method carry_over_param. testsuite/ * g++.dg/ipa/pr91831.C: New test. From-SVN: r276094 --- gcc/ChangeLog | 11 +++++++++++ gcc/ipa-param-manipulation.c | 22 ++++++++++++++-------- gcc/ipa-param-manipulation.h | 1 + gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/ipa/pr91831.C | 19 +++++++++++++++++++ 5 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/pr91831.C (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2d7e280..a44f4db 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2019-09-24 Martin Jambor + PR ipa/91831 + * ipa-param-manipulation.c (carry_over_param): Make a method of + ipa_param_body_adjustments, remove now unnecessary argument. Also copy + in case of a context mismatch. + (ipa_param_body_adjustments::common_initialization): Adjust call to + carry_over_param. + * ipa-param-manipulation.h (class ipa_param_body_adjustments): Add + private method carry_over_param. + +2019-09-24 Martin Jambor + PR ipa/91832 * ipa-sra.c (scan_expr_access): Check that offset is non-negative. diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index 7f52e9c..913b96f 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -906,18 +906,24 @@ ipa_param_body_adjustments::register_replacement (ipa_adjusted_param *apm, m_replacements.safe_push (psr); } -/* Copy or not, as appropriate given ID, a pre-existing PARM_DECL T so that - it can be included in the parameters of the modified function. */ +/* Copy or not, as appropriate given m_id and decl context, a pre-existing + PARM_DECL T so that it can be included in the parameters of the modified + function. */ -static tree -carry_over_param (tree t, struct copy_body_data *id) +tree +ipa_param_body_adjustments::carry_over_param (tree t) { tree new_parm; - if (id) + if (m_id) { - new_parm = remap_decl (t, id); + new_parm = remap_decl (t, m_id); if (TREE_CODE (new_parm) != PARM_DECL) - new_parm = id->copy_decl (t, id); + new_parm = m_id->copy_decl (t, m_id); + } + else if (DECL_CONTEXT (t) != m_fndecl) + { + new_parm = copy_node (t); + DECL_CONTEXT (new_parm) = m_fndecl; } else new_parm = t; @@ -982,7 +988,7 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl, || apm->prev_clone_adjustment) { kept[prev_index] = true; - new_parm = carry_over_param (m_oparms[prev_index], m_id); + new_parm = carry_over_param (m_oparms[prev_index]); m_new_decls.quick_push (new_parm); } else if (apm->op == IPA_PARAM_OP_NEW diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h index 34477da..8e95545 100644 --- a/gcc/ipa-param-manipulation.h +++ b/gcc/ipa-param-manipulation.h @@ -370,6 +370,7 @@ public: private: void common_initialization (tree old_fndecl, tree *vars, vec *tree_map); + tree carry_over_param (tree t); unsigned get_base_index (ipa_adjusted_param *apm); ipa_param_body_replacement *lookup_replacement_1 (tree base, unsigned unit_offset); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 83acf8e..11710ba 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-09-24 Martin Jambor + PR ipa/91831 + * g++.dg/ipa/pr91831.C: New test. + +2019-09-24 Martin Jambor + PR ipa/91832 * gcc.dg/ipa/pr91832.c: New test. diff --git a/gcc/testsuite/g++.dg/ipa/pr91831.C b/gcc/testsuite/g++.dg/ipa/pr91831.C new file mode 100644 index 0000000..66e4b69 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/pr91831.C @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 --param uninlined-thunk-insns=1000" } */ + +struct A { + virtual void m_fn1(); +}; +struct B { + virtual void *m_fn2(int, int) = 0; +}; +struct C : A, B { + void *m_fn2(int, int) { return this; } +}; +void *fn1(B &p1) { return p1.m_fn2(0, 0); } + +int main() { + C c; + fn1(c); + return 0; +} -- cgit v1.1 From 90acd49f6ba247e4549224c2178910aee95a2617 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 24 Sep 2019 13:38:29 +0200 Subject: Use more switch statements. 2019-09-24 Martin Liska * cfgexpand.c (gimple_assign_rhs_to_tree): Use switch statement instead of if-elseif-elseif-... * gimple-expr.c (extract_ops_from_tree): Likewise. * gimple.c (get_gimple_rhs_num_ops): Likewise. * tree-ssa-forwprop.c (rhs_to_tree): Likewise. From-SVN: r276095 --- gcc/ChangeLog | 8 +++++++ gcc/cfgexpand.c | 62 ++++++++++++++++++++++++------------------------- gcc/gimple-expr.c | 59 ++++++++++++++++++++++++---------------------- gcc/gimple.c | 22 ++++++++++-------- gcc/tree-ssa-forwprop.c | 29 ++++++++++++----------- 5 files changed, 98 insertions(+), 82 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a44f4db..1c4c016 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-24 Martin Liska + + * cfgexpand.c (gimple_assign_rhs_to_tree): Use switch statement + instead of if-elseif-elseif-... + * gimple-expr.c (extract_ops_from_tree): Likewise. + * gimple.c (get_gimple_rhs_num_ops): Likewise. + * tree-ssa-forwprop.c (rhs_to_tree): Likewise. + 2019-09-24 Martin Jambor PR ipa/91831 diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 5a93447..a2f9623 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -104,38 +104,38 @@ tree gimple_assign_rhs_to_tree (gimple *stmt) { tree t; - enum gimple_rhs_class grhs_class; - - grhs_class = get_gimple_rhs_class (gimple_expr_code (stmt)); - - if (grhs_class == GIMPLE_TERNARY_RHS) - t = build3 (gimple_assign_rhs_code (stmt), - TREE_TYPE (gimple_assign_lhs (stmt)), - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - gimple_assign_rhs3 (stmt)); - else if (grhs_class == GIMPLE_BINARY_RHS) - t = build2 (gimple_assign_rhs_code (stmt), - TREE_TYPE (gimple_assign_lhs (stmt)), - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt)); - else if (grhs_class == GIMPLE_UNARY_RHS) - t = build1 (gimple_assign_rhs_code (stmt), - TREE_TYPE (gimple_assign_lhs (stmt)), - gimple_assign_rhs1 (stmt)); - else if (grhs_class == GIMPLE_SINGLE_RHS) - { - t = gimple_assign_rhs1 (stmt); - /* Avoid modifying this tree in place below. */ - if ((gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (t) - && gimple_location (stmt) != EXPR_LOCATION (t)) - || (gimple_block (stmt) - && currently_expanding_to_rtl - && EXPR_P (t))) - t = copy_node (t); + switch (get_gimple_rhs_class (gimple_expr_code (stmt))) + { + case GIMPLE_TERNARY_RHS: + t = build3 (gimple_assign_rhs_code (stmt), + TREE_TYPE (gimple_assign_lhs (stmt)), + gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt), + gimple_assign_rhs3 (stmt)); + break; + case GIMPLE_BINARY_RHS: + t = build2 (gimple_assign_rhs_code (stmt), + TREE_TYPE (gimple_assign_lhs (stmt)), + gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt)); + break; + case GIMPLE_UNARY_RHS: + t = build1 (gimple_assign_rhs_code (stmt), + TREE_TYPE (gimple_assign_lhs (stmt)), + gimple_assign_rhs1 (stmt)); + break; + case GIMPLE_SINGLE_RHS: + { + t = gimple_assign_rhs1 (stmt); + /* Avoid modifying this tree in place below. */ + if ((gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (t) + && gimple_location (stmt) != EXPR_LOCATION (t)) + || (gimple_block (stmt) && currently_expanding_to_rtl + && EXPR_P (t))) + t = copy_node (t); + break; + } + default: + gcc_unreachable (); } - else - gcc_unreachable (); if (gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (t)) SET_EXPR_LOCATION (t, gimple_location (stmt)); diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c index b0c9f9b..4082828 100644 --- a/gcc/gimple-expr.c +++ b/gcc/gimple-expr.c @@ -528,37 +528,40 @@ void extract_ops_from_tree (tree expr, enum tree_code *subcode_p, tree *op1_p, tree *op2_p, tree *op3_p) { - enum gimple_rhs_class grhs_class; - *subcode_p = TREE_CODE (expr); - grhs_class = get_gimple_rhs_class (*subcode_p); - - if (grhs_class == GIMPLE_TERNARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); - *op3_p = TREE_OPERAND (expr, 2); - } - else if (grhs_class == GIMPLE_BINARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); - *op3_p = NULL_TREE; - } - else if (grhs_class == GIMPLE_UNARY_RHS) - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = NULL_TREE; - *op3_p = NULL_TREE; - } - else if (grhs_class == GIMPLE_SINGLE_RHS) + switch (get_gimple_rhs_class (*subcode_p)) { - *op1_p = expr; - *op2_p = NULL_TREE; - *op3_p = NULL_TREE; + case GIMPLE_TERNARY_RHS: + { + *op1_p = TREE_OPERAND (expr, 0); + *op2_p = TREE_OPERAND (expr, 1); + *op3_p = TREE_OPERAND (expr, 2); + break; + } + case GIMPLE_BINARY_RHS: + { + *op1_p = TREE_OPERAND (expr, 0); + *op2_p = TREE_OPERAND (expr, 1); + *op3_p = NULL_TREE; + break; + } + case GIMPLE_UNARY_RHS: + { + *op1_p = TREE_OPERAND (expr, 0); + *op2_p = NULL_TREE; + *op3_p = NULL_TREE; + break; + } + case GIMPLE_SINGLE_RHS: + { + *op1_p = expr; + *op2_p = NULL_TREE; + *op3_p = NULL_TREE; + break; + } + default: + gcc_unreachable (); } - else - gcc_unreachable (); } /* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND. */ diff --git a/gcc/gimple.c b/gcc/gimple.c index 88250ca..af62c8b 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -2225,16 +2225,18 @@ dump_gimple_statistics (void) unsigned get_gimple_rhs_num_ops (enum tree_code code) { - enum gimple_rhs_class rhs_class = get_gimple_rhs_class (code); - - if (rhs_class == GIMPLE_UNARY_RHS || rhs_class == GIMPLE_SINGLE_RHS) - return 1; - else if (rhs_class == GIMPLE_BINARY_RHS) - return 2; - else if (rhs_class == GIMPLE_TERNARY_RHS) - return 3; - else - gcc_unreachable (); + switch (get_gimple_rhs_class (code)) + { + case GIMPLE_UNARY_RHS: + case GIMPLE_SINGLE_RHS: + return 1; + case GIMPLE_BINARY_RHS: + return 2; + case GIMPLE_TERNARY_RHS: + return 3; + default: + gcc_unreachable (); + } } #define DEFTREECODE(SYM, STRING, TYPE, NARGS) \ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index c464c89..221f140 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -347,19 +347,22 @@ rhs_to_tree (tree type, gimple *stmt) { location_t loc = gimple_location (stmt); enum tree_code code = gimple_assign_rhs_code (stmt); - if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS) - return fold_build3_loc (loc, code, type, gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - gimple_assign_rhs3 (stmt)); - else if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS) - return fold_build2_loc (loc, code, type, gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt)); - else if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS) - return build1 (code, type, gimple_assign_rhs1 (stmt)); - else if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS) - return gimple_assign_rhs1 (stmt); - else - gcc_unreachable (); + switch (get_gimple_rhs_class (code)) + { + case GIMPLE_TERNARY_RHS: + return fold_build3_loc (loc, code, type, gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt), + gimple_assign_rhs3 (stmt)); + case GIMPLE_BINARY_RHS: + return fold_build2_loc (loc, code, type, gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt)); + case GIMPLE_UNARY_RHS: + return build1 (code, type, gimple_assign_rhs1 (stmt)); + case GIMPLE_SINGLE_RHS: + return gimple_assign_rhs1 (stmt); + default: + gcc_unreachable (); + } } /* Combine OP0 CODE OP1 in the context of a COND_EXPR. Returns -- cgit v1.1 From 81b405828fd0d3dca3eaf715e2008e7a95686b5c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 24 Sep 2019 14:45:13 +0200 Subject: re PR middle-end/91866 (Sign extend of an int is not recognized) PR middle-end/91866 * match.pd (((T)(A)) + CST -> (T)(A + CST)): Formatting fix. (((T)(A + CST1)) + CST2 -> (T)(A) + (T)CST1 + CST2): New optimization. * gcc.dg/tree-ssa/pr91866.c: New test. From-SVN: r276096 --- gcc/ChangeLog | 6 ++++++ gcc/match.pd | 19 +++++++++++++++++-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/tree-ssa/pr91866.c | 12 ++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr91866.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1c4c016..ec00174 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-24 Jakub Jelinek + + PR middle-end/91866 + * match.pd (((T)(A)) + CST -> (T)(A + CST)): Formatting fix. + (((T)(A + CST1)) + CST2 -> (T)(A) + (T)CST1 + CST2): New optimization. + 2019-09-24 Martin Liska * cfgexpand.c (gimple_assign_rhs_to_tree): Use switch statement diff --git a/gcc/match.pd b/gcc/match.pd index 4fd7590..23ce3768 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2265,8 +2265,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) max_ovf = wi::OVF_OVERFLOW; tree inner_type = TREE_TYPE (@0); - wide_int w1 = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type), - TYPE_SIGN (inner_type)); + wide_int w1 + = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type), + TYPE_SIGN (inner_type)); wide_int wmin0, wmax0; if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE) @@ -2280,6 +2281,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) ))) #endif +/* ((T)(A + CST1)) + CST2 -> (T)(A) + (T)CST1 + CST2 */ +#if GIMPLE + (for op (plus minus) + (simplify + (plus (convert:s (op:s @0 INTEGER_CST@1)) INTEGER_CST@2) + (if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE + && TREE_CODE (type) == INTEGER_TYPE + && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0)) + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)) + && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)) + && TYPE_OVERFLOW_WRAPS (type)) + (plus (convert @0) (op @2 (convert @1)))))) +#endif + /* ~A + A -> -1 */ (simplify (plus:c (bit_not @0) @0) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 11710ba..582a2a4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Jakub Jelinek + + PR middle-end/91866 + * gcc.dg/tree-ssa/pr91866.c: New test. + 2019-09-24 Martin Jambor PR ipa/91831 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr91866.c b/gcc/testsuite/gcc.dg/tree-ssa/pr91866.c new file mode 100644 index 0000000..9f5bf19 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr91866.c @@ -0,0 +1,12 @@ +/* PR middle-end/91866 */ +/* { dg-do compile { target { ilp32 || lp64 } } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } * / +/* { dg-final { scan-tree-dump-times " \\+ 11;" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \[+-] \[0-9-]\[0-9]*;" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\\(long long unsigned int\\) x_" 5 "optimized" } } */ + +unsigned long long f1 (int x) { return (x + 1) - 1ULL; } +unsigned long long f2 (int x) { return (x - 5) + 5ULL; } +unsigned long long f3 (int x) { return (x - 15) + 26ULL; } +unsigned long long f4 (int x) { return (x + 6) + 5ULL; } +unsigned long long f5 (int x) { return (x - (-1 - __INT_MAX__)) + 10ULL - __INT_MAX__; } -- cgit v1.1 From 937960dfd7f324316e9b9d5a685d25799b8e5523 Mon Sep 17 00:00:00 2001 From: Stam Markianos-Wright Date: Tue, 24 Sep 2019 13:31:04 +0000 Subject: [GCC][PATCH][AArch64] Update hwcap string for fp16fml in aarch64-option-extensions.def This is a minor patch that fixes the entry for the fp16fml feature in GCC's aarch64-option-extensions.def. As can be seen in the Linux sources here https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/cpuinfo.c#L69 the correct string is "asimdfhm", not "asimdfml". Cross-compiled and tested on aarch64-none-linux-gnu. 2019-09-24 Stamatis Markianos-Wright * config/aarch64/aarch64-option-extensions.def (fp16fml): Update hwcap string for fp16fml. From-SVN: r276097 --- gcc/ChangeLog | 5 +++++ gcc/config/aarch64/aarch64-option-extensions.def | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ec00174..0f8c0b0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Stamatis Markianos-Wright + + * config/aarch64/aarch64-option-extensions.def (fp16fml): + Update hwcap string for fp16fml. + 2019-09-24 Jakub Jelinek PR middle-end/91866 diff --git a/gcc/config/aarch64/aarch64-option-extensions.def b/gcc/config/aarch64/aarch64-option-extensions.def index de91550..d3ae1b2 100644 --- a/gcc/config/aarch64/aarch64-option-extensions.def +++ b/gcc/config/aarch64/aarch64-option-extensions.def @@ -135,7 +135,7 @@ AARCH64_OPT_EXTENSION("sm4", AARCH64_FL_SM4, AARCH64_FL_SIMD, \ /* Enabling "fp16fml" also enables "fp" and "fp16". Disabling "fp16fml" just disables "fp16fml". */ AARCH64_OPT_EXTENSION("fp16fml", AARCH64_FL_F16FML, \ - AARCH64_FL_FP | AARCH64_FL_F16, 0, false, "asimdfml") + AARCH64_FL_FP | AARCH64_FL_F16, 0, false, "asimdfhm") /* Enabling "sve" also enables "fp16", "fp" and "simd". Disabling "sve" disables "sve", "sve2", "sve2-aes", "sve2-sha3", "sve2-sm4" -- cgit v1.1 From 01b9402c483365acb15aec42d1277467711e9e11 Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Tue, 24 Sep 2019 13:39:40 +0000 Subject: [AArch64] Don't split 64-bit constant stores to volatile location The optimisation to optimise: typedef unsigned long long u64; void bar(u64 *x) { *x = 0xabcdef10abcdef10; } from: mov x1, 61200 movk x1, 0xabcd, lsl 16 movk x1, 0xef10, lsl 32 movk x1, 0xabcd, lsl 48 str x1, [x0] into: mov w1, 61200 movk w1, 0xabcd, lsl 16 stp w1, w1, [x0] ends up producing two distinct stores if the destination is volatile: void bar(u64 *x) { *(volatile u64 *)x = 0xabcdef10abcdef10; } mov w1, 61200 movk w1, 0xabcd, lsl 16 str w1, [x0] str w1, [x0, 4] because we end up not merging the strs into an stp. It's questionable whether the use of STP is valid for volatile in the first place. To avoid unnecessary pain in a context where it's unlikely to be performance critical [1] (use of volatile), this patch avoids this transformation for volatile destinations, so we produce the original single STR-X. Bootstrapped and tested on aarch64-none-linux-gnu. [1] https://lore.kernel.org/lkml/20190821103200.kpufwtviqhpbuv2n@willie-the-truck/ * config/aarch64/aarch64.md (mov): Don't call aarch64_split_dimode_const_store on volatile MEM. * gcc.target/aarch64/nosplit-di-const-volatile_1.c: New test. From-SVN: r276098 --- gcc/ChangeLog | 5 +++++ gcc/config/aarch64/aarch64.md | 4 ++-- gcc/testsuite/ChangeLog | 4 ++++ .../gcc.target/aarch64/nosplit-di-const-volatile_1.c | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/nosplit-di-const-volatile_1.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0f8c0b0..c163e61 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Kyrylo Tkachov + + * config/aarch64/aarch64.md (mov): Don't call + aarch64_split_dimode_const_store on volatile MEM. + 2019-09-24 Stamatis Markianos-Wright * config/aarch64/aarch64-option-extensions.def (fp16fml): diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index e4f9005..edeaa6f 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -1104,8 +1104,8 @@ (match_operand:GPI 1 "general_operand"))] "" " - if (MEM_P (operands[0]) && CONST_INT_P (operands[1]) - && mode == DImode + if (MEM_P (operands[0]) && !MEM_VOLATILE_P (operands[0]) + && CONST_INT_P (operands[1]) && mode == DImode && aarch64_split_dimode_const_store (operands[0], operands[1])) DONE; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 582a2a4..55b3bab 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-24 Kyrylo Tkachov + + * gcc.target/aarch64/nosplit-di-const-volatile_1.c: New test. + 2019-09-24 Jakub Jelinek PR middle-end/91866 diff --git a/gcc/testsuite/gcc.target/aarch64/nosplit-di-const-volatile_1.c b/gcc/testsuite/gcc.target/aarch64/nosplit-di-const-volatile_1.c new file mode 100644 index 0000000..da5975a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/nosplit-di-const-volatile_1.c @@ -0,0 +1,15 @@ +/* Check that storing the 64-bit immediate to a volatile location is done + with a single store. */ + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef unsigned long long u64; + +void bar (u64 *x) +{ + *(volatile u64 *)x = 0xabcdef10abcdef10ULL; +} + +/* { dg-final { scan-assembler-times "str\tx..?, .*" 1 } } */ +/* { dg-final { scan-assembler-not "str\tw..?, .*" } } */ -- cgit v1.1 From a7701dd16103048432ec8051e4773760c0e2cf90 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 24 Sep 2019 13:43:07 +0000 Subject: tree-vectorizer.h (_stmt_vec_info::const_cond_reduc_code): Rename to... 2019-09-24 Richard Biener * tree-vectorizer.h (_stmt_vec_info::const_cond_reduc_code): Rename to... (_stmt_vec_info::cond_reduc_code): ... this. (_stmt_vec_info::induc_cond_initial_val): Add. (STMT_VINFO_VEC_CONST_COND_REDUC_CODE): Rename to... (STMT_VINFO_VEC_COND_REDUC_CODE): ... this. (STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL): Add. * tree-vectorizer.c (vec_info::new_stmt_vec_info): Adjust. * tree-vect-loop.c (get_initial_def_for_reduction): Pass in the reduction code. (vect_create_epilog_for_reduction): Drop special induction condition reduction params, pass in reduction code and simplify. (vectorizable_reduction): Perform condition reduction kind selection only at analysis time. Adjust passing on state. From-SVN: r276099 --- gcc/ChangeLog | 18 +++++++ gcc/tree-vect-loop.c | 130 ++++++++++++++++++-------------------------------- gcc/tree-vectorizer.c | 2 +- gcc/tree-vectorizer.h | 11 +++-- 4 files changed, 74 insertions(+), 87 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c163e61..47f3a00 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2019-09-24 Richard Biener + + * tree-vectorizer.h (_stmt_vec_info::const_cond_reduc_code): + Rename to... + (_stmt_vec_info::cond_reduc_code): ... this. + (_stmt_vec_info::induc_cond_initial_val): Add. + (STMT_VINFO_VEC_CONST_COND_REDUC_CODE): Rename to... + (STMT_VINFO_VEC_COND_REDUC_CODE): ... this. + (STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL): Add. + * tree-vectorizer.c (vec_info::new_stmt_vec_info): Adjust. + * tree-vect-loop.c (get_initial_def_for_reduction): Pass in + the reduction code. + (vect_create_epilog_for_reduction): Drop special + induction condition reduction params, pass in reduction code + and simplify. + (vectorizable_reduction): Perform condition reduction kind + selection only at analysis time. Adjust passing on state. + 2019-09-24 Kyrylo Tkachov * config/aarch64/aarch64.md (mov): Don't call diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 9e399cd..bc705d8 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -3981,14 +3981,14 @@ vect_model_induction_cost (stmt_vec_info stmt_info, int ncopies, A cost model should help decide between these two schemes. */ static tree -get_initial_def_for_reduction (stmt_vec_info stmt_vinfo, tree init_val, +get_initial_def_for_reduction (stmt_vec_info stmt_vinfo, + enum tree_code code, tree init_val, tree *adjustment_def) { loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo); class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); tree scalar_type = TREE_TYPE (init_val); tree vectype = get_vectype_for_scalar_type (scalar_type); - enum tree_code code = gimple_assign_rhs_code (stmt_vinfo->stmt); tree def_for_init; tree init_def; REAL_VALUE_TYPE real_init_val = dconst0; @@ -4273,14 +4273,15 @@ static void vect_create_epilog_for_reduction (vec vect_defs, stmt_vec_info stmt_info, gimple *reduc_def_stmt, + enum tree_code code, int ncopies, internal_fn reduc_fn, vec reduction_phis, bool double_reduc, slp_tree slp_node, slp_instance slp_node_instance, - tree induc_val, enum tree_code induc_code, tree neutral_op) { + tree induc_val = NULL_TREE; stmt_vec_info prev_phi_info; tree vectype; machine_mode mode; @@ -4370,17 +4371,22 @@ vect_create_epilog_for_reduction (vec vect_defs, /* Optimize: if initial_def is for REDUC_MAX smaller than the base and we can't use zero for induc_val, use initial_def. Similarly for REDUC_MIN and initial_def larger than the base. */ - if (TREE_CODE (initial_def) == INTEGER_CST - && (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) - == INTEGER_INDUC_COND_REDUCTION) - && !integer_zerop (induc_val) - && ((induc_code == MAX_EXPR - && tree_int_cst_lt (initial_def, induc_val)) - || (induc_code == MIN_EXPR - && tree_int_cst_lt (induc_val, initial_def)))) - induc_val = initial_def; - - if (double_reduc) + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + { + induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info); + if (TREE_CODE (initial_def) == INTEGER_CST + && (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + && !integer_zerop (induc_val) + && ((code == MAX_EXPR + && tree_int_cst_lt (initial_def, induc_val)) + || (code == MIN_EXPR + && tree_int_cst_lt (induc_val, initial_def)))) + induc_val = initial_def; + vec_initial_def = build_vector_from_val (vectype, induc_val); + } + else if (double_reduc) /* In case of double reduction we only create a vector variable to be put in the reduction phi node. The actual statement creation is done later in this function. */ @@ -4394,7 +4400,7 @@ vect_create_epilog_for_reduction (vec vect_defs, } else vec_initial_def - = get_initial_def_for_reduction (stmt_info, initial_def, + = get_initial_def_for_reduction (stmt_info, code, initial_def, &adjustment_def); vec_initial_defs.create (1); vec_initial_defs.quick_push (vec_initial_def); @@ -4418,24 +4424,8 @@ vect_create_epilog_for_reduction (vec vect_defs, /* Set the loop-entry arg of the reduction-phi. */ gphi *phi = as_a (phi_info->stmt); - if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) - == INTEGER_INDUC_COND_REDUCTION) - { - /* Initialise the reduction phi to zero. This prevents initial - values of non-zero interferring with the reduction op. */ - gcc_assert (ncopies == 1); - gcc_assert (i == 0); - - tree vec_init_def_type = TREE_TYPE (vec_init_def); - tree induc_val_vec - = build_vector_from_val (vec_init_def_type, induc_val); - - add_phi_arg (phi, induc_val_vec, loop_preheader_edge (loop), - UNKNOWN_LOCATION); - } - else - add_phi_arg (phi, vec_init_def, loop_preheader_edge (loop), - UNKNOWN_LOCATION); + add_phi_arg (phi, vec_init_def, loop_preheader_edge (loop), + UNKNOWN_LOCATION); /* Set the loop-latch arg for the reduction-phi. */ if (j > 0) @@ -4652,12 +4642,6 @@ vect_create_epilog_for_reduction (vec vect_defs, ; else { - enum tree_code code = gimple_assign_rhs_code (orig_stmt_info->stmt); - /* For MINUS_EXPR the initial vector is [init_val,0,...,0], therefore, - partial results are added and not subtracted. */ - if (code == MINUS_EXPR) - code = PLUS_EXPR; - /* SLP reduction without reduction chain, e.g., # a1 = phi # b1 = phi @@ -5049,20 +5033,6 @@ vect_create_epilog_for_reduction (vec vect_defs, bool reduce_with_shift; tree vec_temp; - /* COND reductions all do the final reduction with MAX_EXPR - or MIN_EXPR. */ - if (code == COND_EXPR) - { - if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) - == INTEGER_INDUC_COND_REDUCTION) - code = induc_code; - else if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) - == CONST_COND_REDUCTION) - code = STMT_VINFO_VEC_CONST_COND_REDUC_CODE (stmt_info); - else - code = MAX_EXPR; - } - /* See if the target wants to do the final (shift) reduction in a vector mode of smaller size and first reduce upper/lower halves against each other. */ @@ -5543,7 +5513,7 @@ vect_create_epilog_for_reduction (vec vect_defs, preheader_arg = PHI_ARG_DEF_FROM_EDGE (use_stmt, loop_preheader_edge (outer_loop)); vect_phi_init = get_initial_def_for_reduction - (stmt_info, preheader_arg, NULL); + (stmt_info, code, preheader_arg, NULL); /* Update phi node arguments with vs0 and vs2. */ add_phi_arg (vect_phi, vect_phi_init, @@ -6021,7 +5991,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, tree vectype_in = NULL_TREE; loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); - enum tree_code code, orig_code; + enum tree_code code; internal_fn reduc_fn; machine_mode vec_mode; int op_type; @@ -6029,7 +5999,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, tree new_temp = NULL_TREE; enum vect_def_type dt, cond_reduc_dt = vect_unknown_def_type; stmt_vec_info cond_stmt_vinfo = NULL; - enum tree_code cond_reduc_op_code = ERROR_MARK; tree scalar_type; bool is_simple_use; int i; @@ -6362,9 +6331,11 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, = STMT_VINFO_REDUC_TYPE (reduc_def_info); stmt_vec_info tmp = STMT_VINFO_REDUC_DEF (reduc_def_info); - STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = v_reduc_type; + if (!vec_stmt) + STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = v_reduc_type; /* If we have a condition reduction, see if we can simplify it further. */ - if (v_reduc_type == COND_REDUCTION) + if (v_reduc_type == COND_REDUCTION + && !vec_stmt) { /* TODO: We can't yet handle reduction chains, since we need to treat each COND_EXPR in the chain specially, not just the last one. @@ -6386,20 +6357,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, return false; } - /* Loop peeling modifies initial value of reduction PHI, which - makes the reduction stmt to be transformed different to the - original stmt analyzed. We need to record reduction code for - CONST_COND_REDUCTION type reduction at analyzing stage, thus - it can be used directly at transform stage. */ - if (STMT_VINFO_VEC_CONST_COND_REDUC_CODE (stmt_info) == MAX_EXPR - || STMT_VINFO_VEC_CONST_COND_REDUC_CODE (stmt_info) == MIN_EXPR) - { - /* Also set the reduction type to CONST_COND_REDUCTION. */ - gcc_assert (cond_reduc_dt == vect_constant_def); - STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = CONST_COND_REDUCTION; - } - else if (direct_internal_fn_supported_p (IFN_FOLD_EXTRACT_LAST, - vectype_in, OPTIMIZE_FOR_SPEED)) + if (direct_internal_fn_supported_p (IFN_FOLD_EXTRACT_LAST, + vectype_in, OPTIMIZE_FOR_SPEED)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6416,6 +6375,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, gcc_assert (TREE_CODE (base) == INTEGER_CST && TREE_CODE (step) == INTEGER_CST); cond_reduc_val = NULL_TREE; + enum tree_code cond_reduc_op_code = ERROR_MARK; tree res = PHI_RESULT (STMT_VINFO_STMT (cond_stmt_vinfo)); if (!types_compatible_p (TREE_TYPE (res), TREE_TYPE (base))) ; @@ -6444,10 +6404,10 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } if (cond_reduc_val) { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "condition expression based on " - "integer induction.\n"); + STMT_VINFO_VEC_COND_REDUC_CODE (stmt_info) + = cond_reduc_op_code; + STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info) + = cond_reduc_val; STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = INTEGER_INDUC_COND_REDUCTION; } @@ -6474,7 +6434,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, "condition expression based on " "compile time constant.\n"); /* Record reduction code at analysis stage. */ - STMT_VINFO_VEC_CONST_COND_REDUC_CODE (stmt_info) + STMT_VINFO_VEC_COND_REDUC_CODE (stmt_info) = integer_onep (e) ? MAX_EXPR : MIN_EXPR; STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) = CONST_COND_REDUCTION; @@ -6482,6 +6442,11 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } } } + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION + && dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "condition expression based on " + "integer induction.\n"); if (orig_stmt_info) gcc_assert (tmp == orig_stmt_info @@ -6637,6 +6602,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, (and also the same tree-code) when generating the epilog code and when generating the code inside the loop. */ + enum tree_code orig_code; if (orig_stmt_info && (reduction_type == TREE_CODE_REDUCTION || reduction_type == FOLD_LEFT_REDUCTION)) @@ -6658,13 +6624,12 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, /* For simple condition reductions, replace with the actual expression we want to base our reduction around. */ - if (reduction_type == CONST_COND_REDUCTION) + if (reduction_type == CONST_COND_REDUCTION + || reduction_type == INTEGER_INDUC_COND_REDUCTION) { - orig_code = STMT_VINFO_VEC_CONST_COND_REDUC_CODE (stmt_info); + orig_code = STMT_VINFO_VEC_COND_REDUC_CODE (stmt_info); gcc_assert (orig_code == MAX_EXPR || orig_code == MIN_EXPR); } - else if (reduction_type == INTEGER_INDUC_COND_REDUCTION) - orig_code = cond_reduc_op_code; } reduc_fn = IFN_LAST; @@ -7171,9 +7136,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vect_defs[0] = gimple_get_lhs ((*vec_stmt)->stmt); vect_create_epilog_for_reduction (vect_defs, stmt_info, reduc_def_phi, - epilog_copies, reduc_fn, phis, + orig_code, epilog_copies, reduc_fn, phis, double_reduc, slp_node, slp_node_instance, - cond_reduc_val, cond_reduc_op_code, neutral_op); return true; diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index da4330c..c3004f6 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -638,7 +638,7 @@ vec_info::new_stmt_vec_info (gimple *stmt) STMT_VINFO_RELEVANT (res) = vect_unused_in_scope; STMT_VINFO_VECTORIZABLE (res) = true; STMT_VINFO_VEC_REDUCTION_TYPE (res) = TREE_CODE_REDUCTION; - STMT_VINFO_VEC_CONST_COND_REDUC_CODE (res) = ERROR_MARK; + STMT_VINFO_VEC_COND_REDUC_CODE (res) = ERROR_MARK; STMT_VINFO_REDUC_IDX (res) = -1; STMT_VINFO_SLP_VECT_ONLY (res) = false; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 09d31ec..370ce13 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -934,8 +934,12 @@ public: /* For reduction loops, this is the type of reduction. */ enum vect_reduction_type v_reduc_type; - /* For CONST_COND_REDUCTION, record the reduc code. */ - enum tree_code const_cond_reduc_code; + /* For CONST_COND_REDUCTION and INTEGER_INDUC_COND_REDUCTION, the + reduction code. */ + enum tree_code cond_reduc_code; + + /* For INTEGER_INDUC_COND_REDUCTION, the initial value to be used. */ + tree induc_cond_initial_val; /* On a reduction PHI the reduction type as detected by vect_force_simple_reduction. */ @@ -1033,7 +1037,8 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) #define STMT_VINFO_MEMORY_ACCESS_TYPE(S) (S)->memory_access_type #define STMT_VINFO_SIMD_LANE_ACCESS_P(S) (S)->simd_lane_access_p #define STMT_VINFO_VEC_REDUCTION_TYPE(S) (S)->v_reduc_type -#define STMT_VINFO_VEC_CONST_COND_REDUC_CODE(S) (S)->const_cond_reduc_code +#define STMT_VINFO_VEC_COND_REDUC_CODE(S) (S)->cond_reduc_code +#define STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL(S) (S)->induc_cond_initial_val #define STMT_VINFO_REDUC_IDX(S) (S)->reduc_idx #define STMT_VINFO_DR_WRT_VEC_LOOP(S) (S)->dr_wrt_vec_loop -- cgit v1.1 From fea3397e56a3662a9b2361c14e427c9786042ebf Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 24 Sep 2019 14:38:53 +0000 Subject: PR c++/91845 - ICE with invalid pointer-to-member. * expr.c (mark_use): Use error_operand_p. * typeck2.c (build_m_component_ref): Check error_operand_p after calling mark_[lr]value_use. * g++.dg/cpp1y/pr91845.C: New test. From-SVN: r276102 --- gcc/cp/ChangeLog | 7 +++++++ gcc/cp/expr.c | 2 +- gcc/cp/typeck2.c | 6 +++--- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp1y/pr91845.C | 14 ++++++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr91845.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5b561e6..1cd2a63 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2019-09-24 Marek Polacek + + PR c++/91845 - ICE with invalid pointer-to-member. + * expr.c (mark_use): Use error_operand_p. + * typeck2.c (build_m_component_ref): Check error_operand_p after + calling mark_[lr]value_use. + 2019-09-23 Paolo Carlini * pt.c (check_explicit_specialization): Use cp_expr_loc_or_input_loc. diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 212a7f9..d488912 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -96,7 +96,7 @@ mark_use (tree expr, bool rvalue_p, bool read_p, { #define RECUR(t) mark_use ((t), rvalue_p, read_p, loc, reject_builtin) - if (expr == NULL_TREE || expr == error_mark_node) + if (expr == NULL_TREE || error_operand_p (expr)) return expr; if (reject_builtin && reject_gcc_builtin (expr, loc)) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index d5098fa..58fa54f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -2068,12 +2068,12 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) tree binfo; tree ctype; - if (error_operand_p (datum) || error_operand_p (component)) - return error_mark_node; - datum = mark_lvalue_use (datum); component = mark_rvalue_use (component); + if (error_operand_p (datum) || error_operand_p (component)) + return error_mark_node; + ptrmem_type = TREE_TYPE (component); if (!TYPE_PTRMEM_P (ptrmem_type)) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 55b3bab..a38a057 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Marek Polacek + + PR c++/91845 - ICE with invalid pointer-to-member. + * g++.dg/cpp1y/pr91845.C: New test. + 2019-09-24 Kyrylo Tkachov * gcc.target/aarch64/nosplit-di-const-volatile_1.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp1y/pr91845.C b/gcc/testsuite/g++.dg/cpp1y/pr91845.C new file mode 100644 index 0000000..cb80dd7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr91845.C @@ -0,0 +1,14 @@ +// PR c++/91845 - ICE with invalid pointer-to-member. +// { dg-do compile { target c++14 } } + +void non_const_mem_ptr() { + struct A { + }; + constexpr A a = {1, 2}; // { dg-error "too many initializers" } + struct B { + int A::*p; + constexpr int g() const { + return a.*p; // { dg-error "use of local variable" } + }; + }; +} -- cgit v1.1 From a0aedc7a41c6756a30669632d3df22e05b174401 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 24 Sep 2019 14:40:24 +0000 Subject: PR c++/91868 - improve -Wshadow location. * name-lookup.c (check_local_shadow): Use DECL_SOURCE_LOCATION instead of input_location. * g++.dg/warn/Wshadow-16.C: New test. From-SVN: r276103 --- gcc/cp/ChangeLog | 4 ++++ gcc/cp/name-lookup.c | 6 +++--- gcc/testsuite/ChangeLog | 3 +++ gcc/testsuite/g++.dg/warn/Wshadow-16.C | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wshadow-16.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1cd2a63..f4c87c5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2019-09-24 Marek Polacek + PR c++/91868 - improve -Wshadow location. + * name-lookup.c (check_local_shadow): Use DECL_SOURCE_LOCATION + instead of input_location. + PR c++/91845 - ICE with invalid pointer-to-member. * expr.c (mark_use): Use error_operand_p. * typeck2.c (build_m_component_ref): Check error_operand_p after diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 8bbb92d..74f1072 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2771,7 +2771,7 @@ check_local_shadow (tree decl) msg = "declaration of %qD shadows a previous local"; auto_diagnostic_group d; - if (warning_at (input_location, warning_code, msg, decl)) + if (warning_at (DECL_SOURCE_LOCATION (decl), warning_code, msg, decl)) inform_shadowed (old); return; } @@ -2798,7 +2798,7 @@ check_local_shadow (tree decl) || TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))) { auto_diagnostic_group d; - if (warning_at (input_location, OPT_Wshadow, + if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wshadow, "declaration of %qD shadows a member of %qT", decl, current_nonlambda_class_type ()) && DECL_P (member)) @@ -2818,7 +2818,7 @@ check_local_shadow (tree decl) /* XXX shadow warnings in outer-more namespaces */ { auto_diagnostic_group d; - if (warning_at (input_location, OPT_Wshadow, + if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wshadow, "declaration of %qD shadows a global declaration", decl)) inform_shadowed (old); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a38a057..b90eb6d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2019-09-24 Marek Polacek + PR c++/91868 - improve -Wshadow location. + * g++.dg/warn/Wshadow-16.C: New test. + PR c++/91845 - ICE with invalid pointer-to-member. * g++.dg/cpp1y/pr91845.C: New test. diff --git a/gcc/testsuite/g++.dg/warn/Wshadow-16.C b/gcc/testsuite/g++.dg/warn/Wshadow-16.C new file mode 100644 index 0000000..bbf3a46 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wshadow-16.C @@ -0,0 +1,24 @@ +// PR c++/91868 - improve -Wshadow location. +// { dg-options "-Wshadow" } + +int global; // { dg-message "shadowed declaration" } + +struct S +{ + static int bar; // { dg-message "shadowed declaration" } + S (int i) { int bar // { dg-warning "19:declaration of .bar. shadows a member" } + (1); + int global // { dg-warning "9:declaration of .global. shadows a global declaration" } + (42); + } +}; + +void +foo () +{ + int xx; // { dg-message "shadowed declaration" } + { + S xx // { dg-warning "7:declaration of .xx. shadows a previous local" } + (42); + } +} -- cgit v1.1 From 931631924b3726db31f2f723e6c7d2d0d9de084f Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 24 Sep 2019 19:04:54 +0000 Subject: PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on a conditional PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on a conditional of two strings gcc/Changelog: * tree-ssa-strlen.c (get_range_strlen_dynamic): Handle null and non-constant minlen, maxlen and maxbound. gcc/testsuite/Changelog: * gcc.dg/pr91570.c: New test. From-SVN: r276105 --- gcc/ChangeLog | 6 ++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/pr91570.c | 30 ++++++++++++++++++++++++++++++ gcc/tree-ssa-strlen.c | 26 ++++++++++++++++++-------- 4 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr91570.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 47f3a00..ab0cef7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-23 Martin Sebor + + PR tree-optimization/91570 + * tree-ssa-strlen.c (get_range_strlen_dynamic): Handle null and + non-constant minlen, maxlen and maxbound. + 2019-09-24 Richard Biener * tree-vectorizer.h (_stmt_vec_info::const_cond_reduc_code): diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b90eb6d..f1f670b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-23 Martin Sebor + + PR tree-optimization/91570 + * gcc.dg/pr91570.c: New test. + 2019-09-24 Marek Polacek PR c++/91868 - improve -Wshadow location. diff --git a/gcc/testsuite/gcc.dg/pr91570.c b/gcc/testsuite/gcc.dg/pr91570.c new file mode 100644 index 0000000..03f2686 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr91570.c @@ -0,0 +1,30 @@ +/* PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on + a conditional of two strings + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +extern char a[], b[]; + +/* Test case from comment #0 on the bug. */ + +void comment_0 (int i) +{ + a[0] = 0; + b[0] = '1'; + + const char *p = i ? b : a; + + if (__builtin_snprintf (0, 0, "%s", p) < 4) + __builtin_abort (); +} + + +/* Test case from comment #2 on the bug. */ + +void comment_2 (char *s) +{ + char *t = __builtin_strrchr (s, '/'); + __builtin_strcat (s, ".SIF"); + t = t ? t : s; + __builtin_printf ("%s", t); +} diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index 5e1054b..c82bc7c 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -896,7 +896,8 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, if (!argdata.minlen || (integer_zerop (argdata.minlen) - && integer_all_onesp (argdata.maxbound) + && (!argdata.maxbound + || integer_all_onesp (argdata.maxbound)) && integer_all_onesp (argdata.maxlen))) { /* Set the upper bound of the length to unbounded. */ @@ -910,11 +911,13 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, || tree_int_cst_lt (argdata.minlen, pdata->minlen)) pdata->minlen = argdata.minlen; if (!pdata->maxlen - || tree_int_cst_lt (pdata->maxlen, argdata.maxlen)) + || (argdata.maxlen + && tree_int_cst_lt (pdata->maxlen, argdata.maxlen))) pdata->maxlen = argdata.maxlen; if (!pdata->maxbound - || (tree_int_cst_lt (pdata->maxbound, - argdata.maxbound) + || (argdata.maxbound + && tree_int_cst_lt (pdata->maxbound, + argdata.maxbound) && !integer_all_onesp (argdata.maxbound))) pdata->maxbound = argdata.maxbound; } @@ -944,8 +947,7 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, if (strinfo *si = get_strinfo (idx)) { pdata->minlen = get_string_length (si); - if (!pdata->minlen - && si->nonzero_chars) + if (!pdata->minlen && si->nonzero_chars) { if (TREE_CODE (si->nonzero_chars) == INTEGER_CST) pdata->minlen = si->nonzero_chars; @@ -989,7 +991,7 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, else pdata->maxlen = build_all_ones_cst (size_type_node); } - else if (TREE_CODE (pdata->minlen) == SSA_NAME) + else if (pdata->minlen && TREE_CODE (pdata->minlen) == SSA_NAME) { const value_range *vr = CONST_CAST (class vr_values *, rvals) @@ -1007,11 +1009,19 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, pdata->maxlen = build_all_ones_cst (size_type_node); } } - else + else if (pdata->minlen && TREE_CODE (pdata->minlen) == INTEGER_CST) { pdata->maxlen = pdata->minlen; pdata->maxbound = pdata->minlen; } + else + { + /* For PDATA->MINLEN that's a non-constant expression such + as PLUS_EXPR whose value range is unknown, set the bounds + to zero and SIZE_MAX. */ + pdata->minlen = build_zero_cst (size_type_node); + pdata->maxlen = build_all_ones_cst (size_type_node); + } return true; } -- cgit v1.1 From 42eb48017d5cf2a7c76b73cb829871e67635536a Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Tue, 24 Sep 2019 19:15:01 +0000 Subject: [Darwin, PPC, Mode Iterators 0/n] Make iterators visible to darwin.md. As a clean-up, we want to be able to use mode iterators in darwin.md. This patch moves the include point for the Darwin include until after the definition of the mode iterators and attrs. No functional change intended. gcc/ChangeLog: 2019-09-24 Iain Sandoe * config/rs6000/rs6000.md: Move darwin.md include until after the definition of the mode iterators. From-SVN: r276106 --- gcc/ChangeLog | 5 +++++ gcc/config/rs6000/rs6000.md | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ab0cef7..420b3ac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Iain Sandoe + + * config/rs6000/rs6000.md: Move darwin.md include until + after the definition of the mode iterators. + 2019-09-23 Martin Sebor PR tree-optimization/91570 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index f0b0bb4..4dbf85b 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -361,8 +361,6 @@ (include "predicates.md") (include "constraints.md") -(include "darwin.md") - ;; Mode iterators @@ -731,6 +729,7 @@ (SF "TARGET_P8_VECTOR") (DI "TARGET_POWERPC64")]) +(include "darwin.md") ;; Start with fixed-point load and store insns. Here we put only the more ;; complex forms. Basic data transfer is done later. -- cgit v1.1 From dd9ed099056a247286a43a33cafa2cfd0d0a1524 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Tue, 24 Sep 2019 19:28:08 +0000 Subject: [Darwin, PPC, Mode Iterators 1/n] Use mode iterators in picbase patterns. This switches the picbase load and reload patterns to use the 'P' mode iterator instead of writing an SI and DI pattern for each. gcc/ChangeLog: 2019-09-24 Iain Sandoe * config/rs6000/rs6000.md (load_macho_picbase_): New, using the 'P' mode iterator, replacing the (removed) SI and DI variants. (reload_macho_picbase_): Likewise. From-SVN: r276107 --- gcc/ChangeLog | 6 +++++ gcc/config/rs6000/darwin.md | 55 +++++++-------------------------------------- 2 files changed, 14 insertions(+), 47 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 420b3ac..6450f18 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-24 Iain Sandoe + * config/rs6000/rs6000.md (load_macho_picbase_): New, using + the 'P' mode iterator, replacing the (removed) SI and DI variants. + (reload_macho_picbase_): Likewise. + +2019-09-24 Iain Sandoe + * config/rs6000/rs6000.md: Move darwin.md include until after the definition of the mode iterators. diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md index 471058d..4a28421 100644 --- a/gcc/config/rs6000/darwin.md +++ b/gcc/config/rs6000/darwin.md @@ -217,7 +217,7 @@ You should have received a copy of the GNU General Public License "") (define_expand "load_macho_picbase" - [(set (reg:SI LR_REGNO) + [(set (reg LR_REGNO) (unspec [(match_operand 0 "")] UNSPEC_LD_MPIC))] "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" @@ -230,9 +230,9 @@ You should have received a copy of the GNU General Public License DONE; }) -(define_insn "load_macho_picbase_si" - [(set (reg:SI LR_REGNO) - (unspec:SI [(match_operand:SI 0 "immediate_operand" "s") +(define_insn "load_macho_picbase_" + [(set (reg:P LR_REGNO) + (unspec:P [(match_operand:P 0 "immediate_operand" "s") (pc)] UNSPEC_LD_MPIC))] "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" { @@ -246,22 +246,6 @@ You should have received a copy of the GNU General Public License [(set_attr "type" "branch") (set_attr "cannot_copy" "yes")]) -(define_insn "load_macho_picbase_di" - [(set (reg:DI LR_REGNO) - (unspec:DI [(match_operand:DI 0 "immediate_operand" "s") - (pc)] UNSPEC_LD_MPIC))] - "(DEFAULT_ABI == ABI_DARWIN) && flag_pic && TARGET_64BIT" -{ -#if TARGET_MACHO - machopic_should_output_picbase_label (); /* Update for new func. */ -#else - gcc_unreachable (); -#endif - return "bcl 20,31,%0\n%0:"; -} - [(set_attr "type" "branch") - (set_attr "cannot_copy" "yes")]) - (define_expand "macho_correct_pic" [(set (match_operand 0 "") (plus (match_operand 1 "") @@ -301,7 +285,7 @@ You should have received a copy of the GNU General Public License [(set_attr "length" "8")]) (define_expand "reload_macho_picbase" - [(set (reg:SI LR_REGNO) + [(set (reg LR_REGNO) (unspec [(match_operand 0 "")] UNSPEC_RELD_MPIC))] "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" @@ -314,9 +298,9 @@ You should have received a copy of the GNU General Public License DONE; }) -(define_insn "reload_macho_picbase_si" - [(set (reg:SI LR_REGNO) - (unspec:SI [(match_operand:SI 0 "immediate_operand" "s") +(define_insn "reload_macho_picbase_" + [(set (reg:P LR_REGNO) + (unspec:P [(match_operand:P 0 "immediate_operand" "s") (pc)] UNSPEC_RELD_MPIC))] "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" { @@ -337,29 +321,6 @@ You should have received a copy of the GNU General Public License [(set_attr "type" "branch") (set_attr "cannot_copy" "yes")]) -(define_insn "reload_macho_picbase_di" - [(set (reg:DI LR_REGNO) - (unspec:DI [(match_operand:DI 0 "immediate_operand" "s") - (pc)] UNSPEC_RELD_MPIC))] - "(DEFAULT_ABI == ABI_DARWIN) && flag_pic && TARGET_64BIT" -{ -#if TARGET_MACHO - if (machopic_should_output_picbase_label ()) - { - static char tmp[64]; - const char *cnam = machopic_get_function_picbase (); - snprintf (tmp, 64, "bcl 20,31,%s\n%s:\n%%0:", cnam, cnam); - return tmp; - } - else -#else - gcc_unreachable (); -#endif - return "bcl 20,31,%0\n%0:"; -} - [(set_attr "type" "branch") - (set_attr "cannot_copy" "yes")]) - ;; We need to restore the PIC register, at the site of nonlocal label. (define_insn_and_split "nonlocal_goto_receiver" -- cgit v1.1 From a20673a560fa520d7ac8da146dcb4b64c574a011 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 25 Sep 2019 00:16:42 +0000 Subject: Daily bump. From-SVN: r276111 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 1012279..6319483 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190924 +20190925 -- cgit v1.1 From 1ed0d9f8ded4cfcff1c0409b183c5b64f69200be Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 24 Sep 2019 23:27:26 -0400 Subject: Fix location of dependent member CALL_EXPR. The break here was skipping over the code that sets EXPR_LOCATION on the call expressions, for no good reason. * parser.c (cp_parser_postfix_expression): Do set location of dependent member call. From-SVN: r276112 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/parser.c | 5 +---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f4c87c5..e5edd80 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-09-24 Jason Merrill + + * parser.c (cp_parser_postfix_expression): Do set location of + dependent member call. + 2019-09-24 Marek Polacek PR c++/91868 - improve -Wshadow location. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index da0ffac..44082f7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7375,11 +7375,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, maybe_generic_this_capture (instance, fn); postfix_expression = build_min_nt_call_vec (postfix_expression, args); - release_tree_vector (args); - break; } - - if (BASELINK_P (fn)) + else if (BASELINK_P (fn)) { postfix_expression = (build_new_method_call -- cgit v1.1 From a4cd9ac5f05bd0a6f73b1ec70fce841990ada959 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Wed, 25 Sep 2019 08:50:29 +0000 Subject: name-lookup.c (check_extern_c_conflict): Use DECL_SOURCE_LOCATION. /cp 2019-09-25 Paolo Carlini * name-lookup.c (check_extern_c_conflict): Use DECL_SOURCE_LOCATION. (check_local_shadow): Use it in three additional places. /testsuite 2019-09-25 Paolo Carlini * g++.dg/diagnostic/redeclaration-1.C: New. * g++.dg/lookup/extern-c-hidden.C: Test location(s) too. * g++.dg/lookup/extern-c-redecl.C: Likewise. * g++.dg/lookup/extern-c-redecl6.C: Likewise. * g++.old-deja/g++.other/using9.C: Likewise. From-SVN: r276119 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/name-lookup.c | 13 ++++++++----- gcc/testsuite/ChangeLog | 8 ++++++++ gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C | 20 ++++++++++++++++++++ gcc/testsuite/g++.dg/lookup/extern-c-hidden.C | 4 ++-- gcc/testsuite/g++.dg/lookup/extern-c-redecl.C | 2 +- gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C | 8 ++++---- gcc/testsuite/g++.old-deja/g++.other/using9.C | 2 +- 8 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e5edd80..ca317e7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-09-25 Paolo Carlini + + * name-lookup.c (check_extern_c_conflict): Use DECL_SOURCE_LOCATION. + (check_local_shadow): Use it in three additional places. + 2019-09-24 Jason Merrill * parser.c (cp_parser_postfix_expression): Do set location of diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 74f1072..4d01a54 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2549,12 +2549,12 @@ check_extern_c_conflict (tree decl) if (mismatch) { auto_diagnostic_group d; - pedwarn (input_location, 0, + pedwarn (DECL_SOURCE_LOCATION (decl), 0, "conflicting C language linkage declaration %q#D", decl); inform (DECL_SOURCE_LOCATION (old), "previous declaration %q#D", old); if (mismatch < 0) - inform (input_location, + inform (DECL_SOURCE_LOCATION (decl), "due to different exception specifications"); } else @@ -2674,7 +2674,8 @@ check_local_shadow (tree decl) /* ARM $8.3 */ if (b->kind == sk_function_parms) { - error ("declaration of %q#D shadows a parameter", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "declaration of %q#D shadows a parameter", decl); return; } } @@ -2700,7 +2701,8 @@ check_local_shadow (tree decl) && (old_scope->kind == sk_cond || old_scope->kind == sk_for)) { auto_diagnostic_group d; - error ("redeclaration of %q#D", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "redeclaration of %q#D", decl); inform (DECL_SOURCE_LOCATION (old), "%q#D previously declared here", old); return; @@ -2723,7 +2725,8 @@ check_local_shadow (tree decl) && in_function_try_handler)) { auto_diagnostic_group d; - if (permerror (input_location, "redeclaration of %q#D", decl)) + if (permerror (DECL_SOURCE_LOCATION (decl), + "redeclaration of %q#D", decl)) inform (DECL_SOURCE_LOCATION (old), "%q#D previously declared here", old); return; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f1f670b..44fc3e3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-09-25 Paolo Carlini + + * g++.dg/diagnostic/redeclaration-1.C: New. + * g++.dg/lookup/extern-c-hidden.C: Test location(s) too. + * g++.dg/lookup/extern-c-redecl.C: Likewise. + * g++.dg/lookup/extern-c-redecl6.C: Likewise. + * g++.old-deja/g++.other/using9.C: Likewise. + 2019-09-23 Martin Sebor PR tree-optimization/91570 diff --git a/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C b/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C new file mode 100644 index 0000000..a41a2b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/redeclaration-1.C @@ -0,0 +1,20 @@ +void +foo (int i) +{ + int i // { dg-error "7:declaration of .int i. shadows a parameter" } + (0); + + for (int j ;;) // { dg-message "12:.int j. previously declared here" } + int j // { dg-error "9:redeclaration of .int j." } + (0); +} + +void +bar (int i) // { dg-message "10:.int i. previously declared here" } + try + { } + catch (...) + { + int i // { dg-error "11:redeclaration of .int i." } + (0); + } diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C index 80593db..2b4a462 100644 --- a/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C +++ b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C @@ -4,8 +4,8 @@ extern "C" float fabsf (float); // { dg-message "previous declaration" } namespace Bob { - extern "C" float fabsf (float, float); // { dg-error "C language" } + extern "C" float fabsf (float, float); // { dg-error "20:conflicting C language" } extern "C" double fabs (double, double); // { dg-message "previous declaration" } } -extern "C" double fabs (double); // { dg-error "C language" } +extern "C" double fabs (double); // { dg-error "19:conflicting C language" } diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C index fd49868..4ffb822 100644 --- a/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C @@ -8,4 +8,4 @@ namespace A { // next line should trigger an error because // it conflicts with previous declaration of foo_func (), due to // different exception specifications. -extern "C" void foo_func (); // { dg-error "C language linkage|exception specifications" } +extern "C" void foo_func (); // { dg-error "17:conflicting C language linkage|exception specifications" } diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C index b4537d6..1d6c571 100644 --- a/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C @@ -16,10 +16,10 @@ extern "C" { namespace BAD { - long i; // { dg-error "C language linkage" } - double f; // { dg-error "C language linkage" } - int fn (); // { dg-error "C language linkage" } - int ai1[2]; // { dg-error "C language linkage" } + long i; // { dg-error "10:conflicting C language linkage" } + double f; // { dg-error "12:conflicting C language linkage" } + int fn (); // { dg-error "9:conflicting C language linkage" } + int ai1[2]; // { dg-error "9:conflicting C language linkage" } } } diff --git a/gcc/testsuite/g++.old-deja/g++.other/using9.C b/gcc/testsuite/g++.old-deja/g++.other/using9.C index c79f993..e1b5aa7 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/using9.C +++ b/gcc/testsuite/g++.old-deja/g++.other/using9.C @@ -16,6 +16,6 @@ using ::a; extern "C" void foo (); // { dg-message "previous declaration" } namespace { - extern "C" int foo (); // { dg-error "C.*linkage" } + extern "C" int foo (); // { dg-error "18:conflicting C.*linkage" } using ::foo; // { dg-error "" } already in use } -- cgit v1.1 From 48bea5dff4ced6dc87f08f615fcce5358606b0ba Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 25 Sep 2019 12:07:11 +0200 Subject: Move a target test-case to generic folder. 2019-09-25 Martin Liska * gcc.target/s390/pr91014.c: Move to ... * gcc.dg/pr91014.c: ... this. From-SVN: r276120 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/pr91014.c | 8 ++++++++ gcc/testsuite/gcc.target/s390/pr91014.c | 8 -------- 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr91014.c delete mode 100644 gcc/testsuite/gcc.target/s390/pr91014.c (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 44fc3e3..f948133 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-25 Martin Liska + + * gcc.target/s390/pr91014.c: Move to ... + * gcc.dg/pr91014.c: ... this. + 2019-09-25 Paolo Carlini * g++.dg/diagnostic/redeclaration-1.C: New. diff --git a/gcc/testsuite/gcc.dg/pr91014.c b/gcc/testsuite/gcc.dg/pr91014.c new file mode 100644 index 0000000..eb37b33 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr91014.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +/* { dg-require-effective-target alloca } */ + +void foo(void) +{ + __builtin_calloc (1, 1); /* { dg-warning "ignoring return value of '__builtin_calloc' declared with attribute 'warn_unused_result'" } */ +} diff --git a/gcc/testsuite/gcc.target/s390/pr91014.c b/gcc/testsuite/gcc.target/s390/pr91014.c deleted file mode 100644 index eb37b33..0000000 --- a/gcc/testsuite/gcc.target/s390/pr91014.c +++ /dev/null @@ -1,8 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O" } */ -/* { dg-require-effective-target alloca } */ - -void foo(void) -{ - __builtin_calloc (1, 1); /* { dg-warning "ignoring return value of '__builtin_calloc' declared with attribute 'warn_unused_result'" } */ -} -- cgit v1.1 From fadb01364d36a50836201bc9a6a03e525d267967 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 25 Sep 2019 13:09:25 +0000 Subject: re PR tree-optimization/91896 (ICE in vect_get_vec_def_for_stmt_copy, at tree-vect-stmts.c:1687) 2019-09-25 Richard Biener PR tree-optimization/91896 * tree-vect-loop.c (vectorizable_reduction): The single def-use cycle optimization cannot apply when there's more than one pattern stmt involved. * gcc.dg/torture/pr91896.c: New testcase. From-SVN: r276123 --- gcc/ChangeLog | 7 +++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/torture/pr91896.c | 18 ++++++++++++++++++ gcc/tree-vect-loop.c | 4 ++++ 4 files changed, 34 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/pr91896.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6450f18..f14a598 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-25 Richard Biener + + PR tree-optimization/91896 + * tree-vect-loop.c (vectorizable_reduction): The single + def-use cycle optimization cannot apply when there's more + than one pattern stmt involved. + 2019-09-24 Iain Sandoe * config/rs6000/rs6000.md (load_macho_picbase_): New, using diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f948133..bf03a5e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-25 Richard Biener + + PR tree-optimization/91896 + * gcc.dg/torture/pr91896.c: New testcase. + 2019-09-25 Martin Liska * gcc.target/s390/pr91014.c: Move to ... diff --git a/gcc/testsuite/gcc.dg/torture/pr91896.c b/gcc/testsuite/gcc.dg/torture/pr91896.c new file mode 100644 index 0000000..e728538 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr91896.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-ftree-vectorize" } */ + +unsigned int +zj (unsigned int et) +{ + signed char jr = 0; + + do { + et *= 3; + jr += 2; + } while (jr >= 0); + + if (et == (unsigned int) jr) + et = 0; + + return et; +} diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index bc705d8..ec00912 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -6101,6 +6101,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, if (ncopies > 1 && STMT_VINFO_RELEVANT (reduc_stmt_info) <= vect_used_only_live && (use_stmt_info = loop_vinfo->lookup_single_use (phi_result)) + && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) + || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) && vect_stmt_to_vectorize (use_stmt_info) == reduc_stmt_info) single_defuse_cycle = true; @@ -6868,6 +6870,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, if (ncopies > 1 && (STMT_VINFO_RELEVANT (stmt_info) <= vect_used_only_live) && (use_stmt_info = loop_vinfo->lookup_single_use (reduc_phi_result)) + && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) + || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) && vect_stmt_to_vectorize (use_stmt_info) == stmt_info) { single_defuse_cycle = true; -- cgit v1.1 From 9a3afc3564b36fb34826899a345a9c35b1c53e39 Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Wed, 25 Sep 2019 13:40:20 +0000 Subject: [AArch64] Use implementation namespace consistently in arm_neon.h We're somewhat inconsistent in arm_neon.h when it comes to using the implementation namespace for local identifiers. This means things like: #define hash_abcd 0 #define hash_e 1 #define wk 2 #include "arm_neon.h" uint32x4_t foo (uint32x4_t a, uint32_t b, uint32x4_t c) { return vsha1cq_u32 (a, b, c); } don't compile. This patch fixes these issues throughout the whole of arm_neon.h Bootstrapped and tested on aarch64-none-linux-gnu. The advsimd-intrinsics.exp tests pass just fine. From-SVN: r276125 --- gcc/ChangeLog | 650 +++++ gcc/config/aarch64/arm_neon.h | 5659 +++++++++++++++++++++-------------------- 2 files changed, 3489 insertions(+), 2820 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f14a598..fa43ab1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,653 @@ +2019-09-25 Kyrylo Tkachov + + * config/aarch64/arm_neon.h (vaba_s8): Use __ in identifiers + consistenly. + (vaba_s16): Likewise. + (vaba_s32): Likewise. + (vaba_u8): Likewise. + (vaba_u16): Likewise. + (vaba_u32): Likewise. + (vabal_high_s8): Likewise. + (vabal_high_s16): Likewise. + (vabal_high_s32): Likewise. + (vabal_high_u8): Likewise. + (vabal_high_u16): Likewise. + (vabal_high_u32): Likewise. + (vabal_s8): Likewise. + (vabal_s16): Likewise. + (vabal_s32): Likewise. + (vabal_u8): Likewise. + (vabal_u16): Likewise. + (vabal_u32): Likewise. + (vabaq_s8): Likewise. + (vabaq_s16): Likewise. + (vabaq_s32): Likewise. + (vabaq_u8): Likewise. + (vabaq_u16): Likewise. + (vabaq_u32): Likewise. + (vabd_s8): Likewise. + (vabd_s16): Likewise. + (vabd_s32): Likewise. + (vabd_u8): Likewise. + (vabd_u16): Likewise. + (vabd_u32): Likewise. + (vabdl_high_s8): Likewise. + (vabdl_high_s16): Likewise. + (vabdl_high_s32): Likewise. + (vabdl_high_u8): Likewise. + (vabdl_high_u16): Likewise. + (vabdl_high_u32): Likewise. + (vabdl_s8): Likewise. + (vabdl_s16): Likewise. + (vabdl_s32): Likewise. + (vabdl_u8): Likewise. + (vabdl_u16): Likewise. + (vabdl_u32): Likewise. + (vabdq_s8): Likewise. + (vabdq_s16): Likewise. + (vabdq_s32): Likewise. + (vabdq_u8): Likewise. + (vabdq_u16): Likewise. + (vabdq_u32): Likewise. + (vaddlv_s8): Likewise. + (vaddlv_s16): Likewise. + (vaddlv_u8): Likewise. + (vaddlv_u16): Likewise. + (vaddlvq_s8): Likewise. + (vaddlvq_s16): Likewise. + (vaddlvq_s32): Likewise. + (vaddlvq_u8): Likewise. + (vaddlvq_u16): Likewise. + (vaddlvq_u32): Likewise. + (vcvtx_f32_f64): Likewise. + (vcvtx_high_f32_f64): Likewise. + (vcvtxd_f32_f64): Likewise. + (vmla_n_f32): Likewise. + (vmla_n_s16): Likewise. + (vmla_n_s32): Likewise. + (vmla_n_u16): Likewise. + (vmla_n_u32): Likewise. + (vmla_s8): Likewise. + (vmla_s16): Likewise. + (vmla_s32): Likewise. + (vmla_u8): Likewise. + (vmla_u16): Likewise. + (vmla_u32): Likewise. + (vmlal_high_n_s16): Likewise. + (vmlal_high_n_s32): Likewise. + (vmlal_high_n_u16): Likewise. + (vmlal_high_n_u32): Likewise. + (vmlal_high_s8): Likewise. + (vmlal_high_s16): Likewise. + (vmlal_high_s32): Likewise. + (vmlal_high_u8): Likewise. + (vmlal_high_u16): Likewise. + (vmlal_high_u32): Likewise. + (vmlal_n_s16): Likewise. + (vmlal_n_s32): Likewise. + (vmlal_n_u16): Likewise. + (vmlal_n_u32): Likewise. + (vmlal_s8): Likewise. + (vmlal_s16): Likewise. + (vmlal_s32): Likewise. + (vmlal_u8): Likewise. + (vmlal_u16): Likewise. + (vmlal_u32): Likewise. + (vmlaq_n_f32): Likewise. + (vmlaq_n_s16): Likewise. + (vmlaq_n_s32): Likewise. + (vmlaq_n_u16): Likewise. + (vmlaq_n_u32): Likewise. + (vmlaq_s8): Likewise. + (vmlaq_s16): Likewise. + (vmlaq_s32): Likewise. + (vmlaq_u8): Likewise. + (vmlaq_u16): Likewise. + (vmlaq_u32): Likewise. + (vmls_n_f32): Likewise. + (vmls_n_s16): Likewise. + (vmls_n_s32): Likewise. + (vmls_n_u16): Likewise. + (vmls_n_u32): Likewise. + (vmls_s8): Likewise. + (vmls_s16): Likewise. + (vmls_s32): Likewise. + (vmls_u8): Likewise. + (vmls_u16): Likewise. + (vmls_u32): Likewise. + (vmlsl_high_n_s16): Likewise. + (vmlsl_high_n_s32): Likewise. + (vmlsl_high_n_u16): Likewise. + (vmlsl_high_n_u32): Likewise. + (vmlsl_high_s8): Likewise. + (vmlsl_high_s16): Likewise. + (vmlsl_high_s32): Likewise. + (vmlsl_high_u8): Likewise. + (vmlsl_high_u16): Likewise. + (vmlsl_high_u32): Likewise. + (vmlsl_n_s16): Likewise. + (vmlsl_n_s32): Likewise. + (vmlsl_n_u16): Likewise. + (vmlsl_n_u32): Likewise. + (vmlsl_s8): Likewise. + (vmlsl_s16): Likewise. + (vmlsl_s32): Likewise. + (vmlsl_u8): Likewise. + (vmlsl_u16): Likewise. + (vmlsl_u32): Likewise. + (vmlsq_n_f32): Likewise. + (vmlsq_n_s16): Likewise. + (vmlsq_n_s32): Likewise. + (vmlsq_n_u16): Likewise. + (vmlsq_n_u32): Likewise. + (vmlsq_s8): Likewise. + (vmlsq_s16): Likewise. + (vmlsq_s32): Likewise. + (vmlsq_u8): Likewise. + (vmlsq_u16): Likewise. + (vmlsq_u32): Likewise. + (vmovl_high_s8): Likewise. + (vmovl_high_s16): Likewise. + (vmovl_high_s32): Likewise. + (vmovl_high_u8): Likewise. + (vmovl_high_u16): Likewise. + (vmovl_high_u32): Likewise. + (vmovl_s8): Likewise. + (vmovl_s16): Likewise. + (vmovl_s32): Likewise. + (vmovl_u8): Likewise. + (vmovl_u16): Likewise. + (vmovl_u32): Likewise. + (vmovn_high_s16): Likewise. + (vmovn_high_s32): Likewise. + (vmovn_high_s64): Likewise. + (vmovn_high_u16): Likewise. + (vmovn_high_u32): Likewise. + (vmovn_high_u64): Likewise. + (vmovn_s16): Likewise. + (vmovn_s32): Likewise. + (vmovn_s64): Likewise. + (vmovn_u16): Likewise. + (vmovn_u32): Likewise. + (vmovn_u64): Likewise. + (vmull_high_n_s16): Likewise. + (vmull_high_n_s32): Likewise. + (vmull_high_n_u16): Likewise. + (vmull_high_n_u32): Likewise. + (vmull_high_p8): Likewise. + (vmull_high_s8): Likewise. + (vmull_high_s16): Likewise. + (vmull_high_s32): Likewise. + (vmull_high_u8): Likewise. + (vmull_high_u16): Likewise. + (vmull_high_u32): Likewise. + (vmull_n_s16): Likewise. + (vmull_n_s32): Likewise. + (vmull_n_u16): Likewise. + (vmull_n_u32): Likewise. + (vmull_p8): Likewise. + (vmull_s8): Likewise. + (vmull_s16): Likewise. + (vmull_s32): Likewise. + (vmull_u8): Likewise. + (vmull_u16): Likewise. + (vmull_u32): Likewise. + (vpadal_s8): Likewise. + (vpadal_s16): Likewise. + (vpadal_s32): Likewise. + (vpadal_u8): Likewise. + (vpadal_u16): Likewise. + (vpadal_u32): Likewise. + (vpadalq_s8): Likewise. + (vpadalq_s16): Likewise. + (vpadalq_s32): Likewise. + (vpadalq_u8): Likewise. + (vpadalq_u16): Likewise. + (vpadalq_u32): Likewise. + (vpaddl_s8): Likewise. + (vpaddl_s16): Likewise. + (vpaddl_s32): Likewise. + (vpaddl_u8): Likewise. + (vpaddl_u16): Likewise. + (vpaddl_u32): Likewise. + (vpaddlq_s8): Likewise. + (vpaddlq_s16): Likewise. + (vpaddlq_s32): Likewise. + (vpaddlq_u8): Likewise. + (vpaddlq_u16): Likewise. + (vpaddlq_u32): Likewise. + (vpaddq_s8): Likewise. + (vpaddq_s16): Likewise. + (vpaddq_s32): Likewise. + (vpaddq_s64): Likewise. + (vpaddq_u8): Likewise. + (vpaddq_u16): Likewise. + (vpaddq_u32): Likewise. + (vpaddq_u64): Likewise. + (vqdmulh_n_s16): Likewise. + (vqdmulh_n_s32): Likewise. + (vqdmulhq_n_s16): Likewise. + (vqdmulhq_n_s32): Likewise. + (vqmovn_high_s16): Likewise. + (vqmovn_high_s32): Likewise. + (vqmovn_high_s64): Likewise. + (vqmovn_high_u16): Likewise. + (vqmovn_high_u32): Likewise. + (vqmovn_high_u64): Likewise. + (vqmovun_high_s16): Likewise. + (vqmovun_high_s32): Likewise. + (vqmovun_high_s64): Likewise. + (vqrdmulh_n_s16): Likewise. + (vqrdmulh_n_s32): Likewise. + (vqrdmulhq_n_s16): Likewise. + (vqrdmulhq_n_s32): Likewise. + (vrsqrte_u32): Likewise. + (vrsqrteq_u32): Likewise. + (vtst_p8): Likewise. + (vtst_p16): Likewise. + (vtst_p64): Likewise. + (vtstq_p8): Likewise. + (vtstq_p16): Likewise. + (vtstq_p64): Likewise. + (vaddlv_s32): Likewise. + (vaddlv_u32): Likewise. + (vqtbl1_p8): Likewise. + (vqtbl1_s8): Likewise. + (vqtbl1_u8): Likewise. + (vqtbl1q_p8): Likewise. + (vqtbl1q_s8): Likewise. + (vqtbl1q_u8): Likewise. + (vqtbx1_s8): Likewise. + (vqtbx1_u8): Likewise. + (vqtbx1_p8): Likewise. + (vqtbx1q_s8): Likewise. + (vqtbx1q_u8): Likewise. + (vqtbx1q_p8): Likewise. + (vtbl1_s8): Likewise. + (vtbl1_u8): Likewise. + (vtbl1_p8): Likewise. + (vtbl2_s8): Likewise. + (vtbl2_u8): Likewise. + (vtbl2_p8): Likewise. + (vtbl3_s8): Likewise. + (vtbl3_u8): Likewise. + (vtbl3_p8): Likewise. + (vtbl4_s8): Likewise. + (vtbl4_u8): Likewise. + (vtbl4_p8): Likewise. + (vtbx2_s8): Likewise. + (vtbx2_u8): Likewise. + (vtbx2_p8): Likewise. + (vld1_f32): Likewise. + (vld1_f64): Likewise. + (vld1_p8): Likewise. + (vld1_p16): Likewise. + (vld1_p64): Likewise. + (vld1_s8): Likewise. + (vld1_s16): Likewise. + (vld1_s32): Likewise. + (vld1_s64): Likewise. + (vld1_u8): Likewise. + (vld1_u16): Likewise. + (vld1_u32): Likewise. + (vld1_u64): Likewise. + (vld1q_f32): Likewise. + (vld1q_f64): Likewise. + (vld1q_p8): Likewise. + (vld1q_p16): Likewise. + (vld1q_p64): Likewise. + (vld1q_s8): Likewise. + (vld1q_s16): Likewise. + (vld1q_s32): Likewise. + (vld1q_s64): Likewise. + (vld1q_u8): Likewise. + (vld1q_u16): Likewise. + (vld1q_u32): Likewise. + (vld1q_u64): Likewise. + (vpmax_s8): Likewise. + (vpmax_s16): Likewise. + (vpmax_s32): Likewise. + (vpmax_u8): Likewise. + (vpmax_u16): Likewise. + (vpmax_u32): Likewise. + (vpmaxq_s8): Likewise. + (vpmaxq_s16): Likewise. + (vpmaxq_s32): Likewise. + (vpmaxq_u8): Likewise. + (vpmaxq_u16): Likewise. + (vpmaxq_u32): Likewise. + (vpmax_f32): Likewise. + (vpmaxq_f32): Likewise. + (vpmaxq_f64): Likewise. + (vpmaxqd_f64): Likewise. + (vpmaxs_f32): Likewise. + (vpmaxnm_f32): Likewise. + (vpmaxnmq_f32): Likewise. + (vpmaxnmq_f64): Likewise. + (vpmaxnmqd_f64): Likewise. + (vpmaxnms_f32): Likewise. + (vpmin_s8): Likewise. + (vpmin_s16): Likewise. + (vpmin_s32): Likewise. + (vpmin_u8): Likewise. + (vpmin_u16): Likewise. + (vpmin_u32): Likewise. + (vpminq_s8): Likewise. + (vpminq_s16): Likewise. + (vpminq_s32): Likewise. + (vpminq_u8): Likewise. + (vpminq_u16): Likewise. + (vpminq_u32): Likewise. + (vpmin_f32): Likewise. + (vpminq_f32): Likewise. + (vpminq_f64): Likewise. + (vpminqd_f64): Likewise. + (vpmins_f32): Likewise. + (vpminnm_f32): Likewise. + (vpminnmq_f32): Likewise. + (vpminnmq_f64): Likewise. + (vpminnmqd_f64): Likewise. + (vpminnms_f32): Likewise. + (vmla_f32): Likewise. + (vmlaq_f32): Likewise. + (vmlaq_f64): Likewise. + (vmls_f32): Likewise. + (vmlsq_f32): Likewise. + (vmlsq_f64): Likewise. + (vqtbl2_s8): Likewise. + (vqtbl2_u8): Likewise. + (vqtbl2_p8): Likewise. + (vqtbl2q_s8): Likewise. + (vqtbl2q_u8): Likewise. + (vqtbl2q_p8): Likewise. + (vqtbl3_s8): Likewise. + (vqtbl3_u8): Likewise. + (vqtbl3_p8): Likewise. + (vqtbl3q_s8): Likewise. + (vqtbl3q_u8): Likewise. + (vqtbl3q_p8): Likewise. + (vqtbl4_s8): Likewise. + (vqtbl4_u8): Likewise. + (vqtbl4_p8): Likewise. + (vqtbl4q_s8): Likewise. + (vqtbl4q_u8): Likewise. + (vqtbl4q_p8): Likewise. + (vqtbx2_s8): Likewise. + (vqtbx2_u8): Likewise. + (vqtbx2_p8): Likewise. + (vqtbx2q_s8): Likewise. + (vqtbx2q_u8): Likewise. + (vqtbx2q_p8): Likewise. + (vqtbx3_s8): Likewise. + (vqtbx3_u8): Likewise. + (vqtbx3_p8): Likewise. + (vqtbx3q_s8): Likewise. + (vqtbx3q_u8): Likewise. + (vqtbx3q_p8): Likewise. + (vqtbx4_s8): Likewise. + (vqtbx4_u8): Likewise. + (vqtbx4_p8): Likewise. + (vqtbx4q_s8): Likewise. + (vqtbx4q_u8): Likewise. + (vqtbx4q_p8): Likewise. + (vrev16_p8): Likewise. + (vrev16_s8): Likewise. + (vrev16_u8): Likewise. + (vrev16q_p8): Likewise. + (vrev16q_s8): Likewise. + (vrev16q_u8): Likewise. + (vrev32_p8): Likewise. + (vrev32_p16): Likewise. + (vrev32_s8): Likewise. + (vrev32_s16): Likewise. + (vrev32_u8): Likewise. + (vrev32_u16): Likewise. + (vrev32q_p8): Likewise. + (vrev32q_p16): Likewise. + (vrev32q_s8): Likewise. + (vrev32q_s16): Likewise. + (vrev32q_u8): Likewise. + (vrev32q_u16): Likewise. + (vrev64_f32): Likewise. + (vrev64_p8): Likewise. + (vrev64_p16): Likewise. + (vrev64_s8): Likewise. + (vrev64_s16): Likewise. + (vrev64_s32): Likewise. + (vrev64_u8): Likewise. + (vrev64_u16): Likewise. + (vrev64_u32): Likewise. + (vrev64q_f32): Likewise. + (vrev64q_p8): Likewise. + (vrev64q_p16): Likewise. + (vrev64q_s8): Likewise. + (vrev64q_s16): Likewise. + (vrev64q_s32): Likewise. + (vrev64q_u8): Likewise. + (vrev64q_u16): Likewise. + (vrev64q_u32): Likewise. + (vsha1cq_u32): Likewise. + (vsha1mq_u32): Likewise. + (vsha1pq_u32): Likewise. + (vsha1h_u32): Likewise. + (vsha1su0q_u32): Likewise. + (vsha1su1q_u32): Likewise. + (vsha256hq_u32): Likewise. + (vsha256h2q_u32): Likewise. + (vsha256su0q_u32): Likewise. + (vsha256su1q_u32): Likewise. + (vmull_p64): Likewise. + (vmull_high_p64): Likewise. + (vsqrt_f32): Likewise. + (vsqrtq_f32): Likewise. + (vsqrt_f64): Likewise. + (vsqrtq_f64): Likewise. + (vst1_f32): Likewise. + (vst1_f64): Likewise. + (vst1_p8): Likewise. + (vst1_p16): Likewise. + (vst1_p64): Likewise. + (vst1_s8): Likewise. + (vst1_s16): Likewise. + (vst1_s32): Likewise. + (vst1_s64): Likewise. + (vst1_u8): Likewise. + (vst1_u16): Likewise. + (vst1_u32): Likewise. + (vst1_u64): Likewise. + (vst1q_f32): Likewise. + (vst1q_f64): Likewise. + (vst1q_p8): Likewise. + (vst1q_p16): Likewise. + (vst1q_p64): Likewise. + (vst1q_s8): Likewise. + (vst1q_s16): Likewise. + (vst1q_s32): Likewise. + (vst1q_s64): Likewise. + (vst1q_u8): Likewise. + (vst1q_u16): Likewise. + (vst1q_u32): Likewise. + (vst1q_u64): Likewise. + (vst1_s64_x2): Likewise. + (vst1_u64_x2): Likewise. + (vst1_f64_x2): Likewise. + (vst1_s8_x2): Likewise. + (vst1_p8_x2): Likewise. + (vst1_s16_x2): Likewise. + (vst1_p16_x2): Likewise. + (vst1_s32_x2): Likewise. + (vst1_u8_x2): Likewise. + (vst1_u16_x2): Likewise. + (vst1_u32_x2): Likewise. + (vst1_f16_x2): Likewise. + (vst1_f32_x2): Likewise. + (vst1_p64_x2): Likewise. + (vst1q_s8_x2): Likewise. + (vst1q_p8_x2): Likewise. + (vst1q_s16_x2): Likewise. + (vst1q_p16_x2): Likewise. + (vst1q_s32_x2): Likewise. + (vst1q_s64_x2): Likewise. + (vst1q_u8_x2): Likewise. + (vst1q_u16_x2): Likewise. + (vst1q_u32_x2): Likewise. + (vst1q_u64_x2): Likewise. + (vst1q_f16_x2): Likewise. + (vst1q_f32_x2): Likewise. + (vst1q_f64_x2): Likewise. + (vst1q_p64_x2): Likewise. + (vst1_s64_x3): Likewise. + (vst1_u64_x3): Likewise. + (vst1_f64_x3): Likewise. + (vst1_s8_x3): Likewise. + (vst1_p8_x3): Likewise. + (vst1_s16_x3): Likewise. + (vst1_p16_x3): Likewise. + (vst1_s32_x3): Likewise. + (vst1_u8_x3): Likewise. + (vst1_u16_x3): Likewise. + (vst1_u32_x3): Likewise. + (vst1_f16_x3): Likewise. + (vst1_f32_x3): Likewise. + (vst1_p64_x3): Likewise. + (vst1q_s8_x3): Likewise. + (vst1q_p8_x3): Likewise. + (vst1q_s16_x3): Likewise. + (vst1q_p16_x3): Likewise. + (vst1q_s32_x3): Likewise. + (vst1q_s64_x3): Likewise. + (vst1q_u8_x3): Likewise. + (vst1q_u16_x3): Likewise. + (vst1q_u32_x3): Likewise. + (vst1q_u64_x3): Likewise. + (vst1q_f16_x3): Likewise. + (vst1q_f32_x3): Likewise. + (vst1q_f64_x3): Likewise. + (vst1q_p64_x3): Likewise. + (vst2_s64): Likewise. + (vst2_u64): Likewise. + (vst2_f64): Likewise. + (vst2_s8): Likewise. + (vst2_p8): Likewise. + (vst2_s16): Likewise. + (vst2_p16): Likewise. + (vst2_s32): Likewise. + (vst2_u8): Likewise. + (vst2_u16): Likewise. + (vst2_u32): Likewise. + (vst2_f16): Likewise. + (vst2_f32): Likewise. + (vst2_p64): Likewise. + (vst2q_s8): Likewise. + (vst2q_p8): Likewise. + (vst2q_s16): Likewise. + (vst2q_p16): Likewise. + (vst2q_s32): Likewise. + (vst2q_s64): Likewise. + (vst2q_u8): Likewise. + (vst2q_u16): Likewise. + (vst2q_u32): Likewise. + (vst2q_u64): Likewise. + (vst2q_f16): Likewise. + (vst2q_f32): Likewise. + (vst2q_f64): Likewise. + (vst2q_p64): Likewise. + (vst3_s64): Likewise. + (vst3_u64): Likewise. + (vst3_f64): Likewise. + (vst3_s8): Likewise. + (vst3_p8): Likewise. + (vst3_s16): Likewise. + (vst3_p16): Likewise. + (vst3_s32): Likewise. + (vst3_u8): Likewise. + (vst3_u16): Likewise. + (vst3_u32): Likewise. + (vst3_f16): Likewise. + (vst3_f32): Likewise. + (vst3_p64): Likewise. + (vst3q_s8): Likewise. + (vst3q_p8): Likewise. + (vst3q_s16): Likewise. + (vst3q_p16): Likewise. + (vst3q_s32): Likewise. + (vst3q_s64): Likewise. + (vst3q_u8): Likewise. + (vst3q_u16): Likewise. + (vst3q_u32): Likewise. + (vst3q_u64): Likewise. + (vst3q_f16): Likewise. + (vst3q_f32): Likewise. + (vst3q_f64): Likewise. + (vst3q_p64): Likewise. + (vst4_s64): Likewise. + (vst4_u64): Likewise. + (vst4_f64): Likewise. + (vst4_s8): Likewise. + (vst4_p8): Likewise. + (vst4_s16): Likewise. + (vst4_p16): Likewise. + (vst4_s32): Likewise. + (vst4_u8): Likewise. + (vst4_u16): Likewise. + (vst4_u32): Likewise. + (vst4_f16): Likewise. + (vst4_f32): Likewise. + (vst4_p64): Likewise. + (vst4q_s8): Likewise. + (vst4q_p8): Likewise. + (vst4q_s16): Likewise. + (vst4q_p16): Likewise. + (vst4q_s32): Likewise. + (vst4q_s64): Likewise. + (vst4q_u8): Likewise. + (vst4q_u16): Likewise. + (vst4q_u32): Likewise. + (vst4q_u64): Likewise. + (vst4q_f16): Likewise. + (vst4q_f32): Likewise. + (vst4q_f64): Likewise. + (vst4q_p64): Likewise. + (vtbx4_s8): Likewise. + (vtbx4_u8): Likewise. + (vtbx4_p8): Likewise. + (vtrn_f32): Likewise. + (vtrn_p8): Likewise. + (vtrn_p16): Likewise. + (vtrn_s8): Likewise. + (vtrn_s16): Likewise. + (vtrn_s32): Likewise. + (vtrn_u8): Likewise. + (vtrn_u16): Likewise. + (vtrn_u32): Likewise. + (vtrnq_f32): Likewise. + (vtrnq_p8): Likewise. + (vtrnq_p16): Likewise. + (vtrnq_s8): Likewise. + (vtrnq_s16): Likewise. + (vtrnq_s32): Likewise. + (vtrnq_u8): Likewise. + (vtrnq_u16): Likewise. + (vtrnq_u32): Likewise. + (vrsqrte_f16): Likewise. + (vrsqrteq_f16): Likewise. + (vsqrt_f16): Likewise. + (vsqrtq_f16): Likewise. + (vabd_f16): Likewise. + (vabdq_f16): Likewise. + (vpadd_f16): Likewise. + (vpaddq_f16): Likewise. + (vpmax_f16): Likewise. + (vpmaxq_f16): Likewise. + (vpmaxnm_f16): Likewise. + (vpmaxnmq_f16): Likewise. + (vpmin_f16): Likewise. + (vpminq_f16): Likewise. + (vpminnm_f16): Likewise. + (vpminnmq_f16): Likewise. + (vrsqrts_f16): Likewise. + (vrsqrtsq_f16): Likewise. + 2019-09-25 Richard Biener PR tree-optimization/91896 diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index e1b2268..8b86160 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -6572,867 +6572,867 @@ vcombine_p64 (poly64x1_t __a, poly64x1_t __b) __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaba_s8 (int8x8_t a, int8x8_t b, int8x8_t c) +vaba_s8 (int8x8_t __a, int8x8_t __b, int8x8_t __c) { - int8x8_t result; + int8x8_t __result; __asm__ ("saba %0.8b,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaba_s16 (int16x4_t a, int16x4_t b, int16x4_t c) +vaba_s16 (int16x4_t __a, int16x4_t __b, int16x4_t __c) { - int16x4_t result; + int16x4_t __result; __asm__ ("saba %0.4h,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaba_s32 (int32x2_t a, int32x2_t b, int32x2_t c) +vaba_s32 (int32x2_t __a, int32x2_t __b, int32x2_t __c) { - int32x2_t result; + int32x2_t __result; __asm__ ("saba %0.2s,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaba_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) +vaba_u8 (uint8x8_t __a, uint8x8_t __b, uint8x8_t __c) { - uint8x8_t result; + uint8x8_t __result; __asm__ ("uaba %0.8b,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaba_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) +vaba_u16 (uint16x4_t __a, uint16x4_t __b, uint16x4_t __c) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("uaba %0.4h,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaba_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) +vaba_u32 (uint32x2_t __a, uint32x2_t __b, uint32x2_t __c) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("uaba %0.2s,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) +vabal_high_s8 (int16x8_t __a, int8x16_t __b, int8x16_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("sabal2 %0.8h,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) +vabal_high_s16 (int32x4_t __a, int16x8_t __b, int16x8_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("sabal2 %0.4s,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) +vabal_high_s32 (int64x2_t __a, int32x4_t __b, int32x4_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("sabal2 %0.2d,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) +vabal_high_u8 (uint16x8_t __a, uint8x16_t __b, uint8x16_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uabal2 %0.8h,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) +vabal_high_u16 (uint32x4_t __a, uint16x8_t __b, uint16x8_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uabal2 %0.4s,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) +vabal_high_u32 (uint64x2_t __a, uint32x4_t __b, uint32x4_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("uabal2 %0.2d,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_s8 (int16x8_t a, int8x8_t b, int8x8_t c) +vabal_s8 (int16x8_t __a, int8x8_t __b, int8x8_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("sabal %0.8h,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_s16 (int32x4_t a, int16x4_t b, int16x4_t c) +vabal_s16 (int32x4_t __a, int16x4_t __b, int16x4_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("sabal %0.4s,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_s32 (int64x2_t a, int32x2_t b, int32x2_t c) +vabal_s32 (int64x2_t __a, int32x2_t __b, int32x2_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("sabal %0.2d,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) +vabal_u8 (uint16x8_t __a, uint8x8_t __b, uint8x8_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uabal %0.8h,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) +vabal_u16 (uint32x4_t __a, uint16x4_t __b, uint16x4_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uabal %0.4s,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabal_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) +vabal_u32 (uint64x2_t __a, uint32x2_t __b, uint32x2_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("uabal %0.2d,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) +vabaq_s8 (int8x16_t __a, int8x16_t __b, int8x16_t __c) { - int8x16_t result; + int8x16_t __result; __asm__ ("saba %0.16b,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) +vabaq_s16 (int16x8_t __a, int16x8_t __b, int16x8_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("saba %0.8h,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) +vabaq_s32 (int32x4_t __a, int32x4_t __b, int32x4_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("saba %0.4s,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) +vabaq_u8 (uint8x16_t __a, uint8x16_t __b, uint8x16_t __c) { - uint8x16_t result; + uint8x16_t __result; __asm__ ("uaba %0.16b,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) +vabaq_u16 (uint16x8_t __a, uint16x8_t __b, uint16x8_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uaba %0.8h,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) +vabaq_u32 (uint32x4_t __a, uint32x4_t __b, uint32x4_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uaba %0.4s,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_s8 (int8x8_t a, int8x8_t b) +vabd_s8 (int8x8_t __a, int8x8_t __b) { - int8x8_t result; + int8x8_t __result; __asm__ ("sabd %0.8b, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_s16 (int16x4_t a, int16x4_t b) +vabd_s16 (int16x4_t __a, int16x4_t __b) { - int16x4_t result; + int16x4_t __result; __asm__ ("sabd %0.4h, %1.4h, %2.4h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_s32 (int32x2_t a, int32x2_t b) +vabd_s32 (int32x2_t __a, int32x2_t __b) { - int32x2_t result; + int32x2_t __result; __asm__ ("sabd %0.2s, %1.2s, %2.2s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_u8 (uint8x8_t a, uint8x8_t b) +vabd_u8 (uint8x8_t __a, uint8x8_t __b) { - uint8x8_t result; + uint8x8_t __result; __asm__ ("uabd %0.8b, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_u16 (uint16x4_t a, uint16x4_t b) +vabd_u16 (uint16x4_t __a, uint16x4_t __b) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("uabd %0.4h, %1.4h, %2.4h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_u32 (uint32x2_t a, uint32x2_t b) +vabd_u32 (uint32x2_t __a, uint32x2_t __b) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("uabd %0.2s, %1.2s, %2.2s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_high_s8 (int8x16_t a, int8x16_t b) +vabdl_high_s8 (int8x16_t __a, int8x16_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("sabdl2 %0.8h,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_high_s16 (int16x8_t a, int16x8_t b) +vabdl_high_s16 (int16x8_t __a, int16x8_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("sabdl2 %0.4s,%1.8h,%2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_high_s32 (int32x4_t a, int32x4_t b) +vabdl_high_s32 (int32x4_t __a, int32x4_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("sabdl2 %0.2d,%1.4s,%2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_high_u8 (uint8x16_t a, uint8x16_t b) +vabdl_high_u8 (uint8x16_t __a, uint8x16_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uabdl2 %0.8h,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_high_u16 (uint16x8_t a, uint16x8_t b) +vabdl_high_u16 (uint16x8_t __a, uint16x8_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uabdl2 %0.4s,%1.8h,%2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_high_u32 (uint32x4_t a, uint32x4_t b) +vabdl_high_u32 (uint32x4_t __a, uint32x4_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("uabdl2 %0.2d,%1.4s,%2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_s8 (int8x8_t a, int8x8_t b) +vabdl_s8 (int8x8_t __a, int8x8_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("sabdl %0.8h, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_s16 (int16x4_t a, int16x4_t b) +vabdl_s16 (int16x4_t __a, int16x4_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("sabdl %0.4s, %1.4h, %2.4h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_s32 (int32x2_t a, int32x2_t b) +vabdl_s32 (int32x2_t __a, int32x2_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("sabdl %0.2d, %1.2s, %2.2s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_u8 (uint8x8_t a, uint8x8_t b) +vabdl_u8 (uint8x8_t __a, uint8x8_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uabdl %0.8h, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_u16 (uint16x4_t a, uint16x4_t b) +vabdl_u16 (uint16x4_t __a, uint16x4_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uabdl %0.4s, %1.4h, %2.4h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdl_u32 (uint32x2_t a, uint32x2_t b) +vabdl_u32 (uint32x2_t __a, uint32x2_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("uabdl %0.2d, %1.2s, %2.2s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_s8 (int8x16_t a, int8x16_t b) +vabdq_s8 (int8x16_t __a, int8x16_t __b) { - int8x16_t result; + int8x16_t __result; __asm__ ("sabd %0.16b, %1.16b, %2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_s16 (int16x8_t a, int16x8_t b) +vabdq_s16 (int16x8_t __a, int16x8_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("sabd %0.8h, %1.8h, %2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_s32 (int32x4_t a, int32x4_t b) +vabdq_s32 (int32x4_t __a, int32x4_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("sabd %0.4s, %1.4s, %2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_u8 (uint8x16_t a, uint8x16_t b) +vabdq_u8 (uint8x16_t __a, uint8x16_t __b) { - uint8x16_t result; + uint8x16_t __result; __asm__ ("uabd %0.16b, %1.16b, %2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_u16 (uint16x8_t a, uint16x8_t b) +vabdq_u16 (uint16x8_t __a, uint16x8_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uabd %0.8h, %1.8h, %2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_u32 (uint32x4_t a, uint32x4_t b) +vabdq_u32 (uint32x4_t __a, uint32x4_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uabd %0.4s, %1.4s, %2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlv_s8 (int8x8_t a) +vaddlv_s8 (int8x8_t __a) { - int16_t result; + int16_t __result; __asm__ ("saddlv %h0,%1.8b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlv_s16 (int16x4_t a) +vaddlv_s16 (int16x4_t __a) { - int32_t result; + int32_t __result; __asm__ ("saddlv %s0,%1.4h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlv_u8 (uint8x8_t a) +vaddlv_u8 (uint8x8_t __a) { - uint16_t result; + uint16_t __result; __asm__ ("uaddlv %h0,%1.8b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlv_u16 (uint16x4_t a) +vaddlv_u16 (uint16x4_t __a) { - uint32_t result; + uint32_t __result; __asm__ ("uaddlv %s0,%1.4h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlvq_s8 (int8x16_t a) +vaddlvq_s8 (int8x16_t __a) { - int16_t result; + int16_t __result; __asm__ ("saddlv %h0,%1.16b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlvq_s16 (int16x8_t a) +vaddlvq_s16 (int16x8_t __a) { - int32_t result; + int32_t __result; __asm__ ("saddlv %s0,%1.8h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlvq_s32 (int32x4_t a) +vaddlvq_s32 (int32x4_t __a) { - int64_t result; + int64_t __result; __asm__ ("saddlv %d0,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlvq_u8 (uint8x16_t a) +vaddlvq_u8 (uint8x16_t __a) { - uint16_t result; + uint16_t __result; __asm__ ("uaddlv %h0,%1.16b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlvq_u16 (uint16x8_t a) +vaddlvq_u16 (uint16x8_t __a) { - uint32_t result; + uint32_t __result; __asm__ ("uaddlv %s0,%1.8h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlvq_u32 (uint32x4_t a) +vaddlvq_u32 (uint32x4_t __a) { - uint64_t result; + uint64_t __result; __asm__ ("uaddlv %d0,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vcvtx_f32_f64 (float64x2_t a) +vcvtx_f32_f64 (float64x2_t __a) { - float32x2_t result; + float32x2_t __result; __asm__ ("fcvtxn %0.2s,%1.2d" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vcvtx_high_f32_f64 (float32x2_t a, float64x2_t b) +vcvtx_high_f32_f64 (float32x2_t __a, float64x2_t __b) { - float32x4_t result; + float32x4_t __result; __asm__ ("fcvtxn2 %0.4s,%1.2d" - : "=w"(result) - : "w" (b), "0"(a) + : "=w"(__result) + : "w" (__b), "0"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vcvtxd_f32_f64 (float64_t a) +vcvtxd_f32_f64 (float64_t __a) { - float32_t result; + float32_t __result; __asm__ ("fcvtxn %s0,%d1" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_n_f32 (float32x2_t a, float32x2_t b, float32_t c) +vmla_n_f32 (float32x2_t __a, float32x2_t __b, float32_t __c) { - float32x2_t result; - float32x2_t t1; + float32x2_t __result; + float32x2_t __t1; __asm__ ("fmul %1.2s, %3.2s, %4.s[0]; fadd %0.2s, %0.2s, %1.2s" - : "=w"(result), "=w"(t1) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result), "=w"(__t1) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_n_s16 (int16x4_t a, int16x4_t b, int16_t c) +vmla_n_s16 (int16x4_t __a, int16x4_t __b, int16_t __c) { - int16x4_t result; + int16x4_t __result; __asm__ ("mla %0.4h,%2.4h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_n_s32 (int32x2_t a, int32x2_t b, int32_t c) +vmla_n_s32 (int32x2_t __a, int32x2_t __b, int32_t __c) { - int32x2_t result; + int32x2_t __result; __asm__ ("mla %0.2s,%2.2s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_n_u16 (uint16x4_t a, uint16x4_t b, uint16_t c) +vmla_n_u16 (uint16x4_t __a, uint16x4_t __b, uint16_t __c) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("mla %0.4h,%2.4h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_n_u32 (uint32x2_t a, uint32x2_t b, uint32_t c) +vmla_n_u32 (uint32x2_t __a, uint32x2_t __b, uint32_t __c) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("mla %0.2s,%2.2s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_s8 (int8x8_t a, int8x8_t b, int8x8_t c) +vmla_s8 (int8x8_t __a, int8x8_t __b, int8x8_t __c) { - int8x8_t result; + int8x8_t __result; __asm__ ("mla %0.8b, %2.8b, %3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_s16 (int16x4_t a, int16x4_t b, int16x4_t c) +vmla_s16 (int16x4_t __a, int16x4_t __b, int16x4_t __c) { - int16x4_t result; + int16x4_t __result; __asm__ ("mla %0.4h, %2.4h, %3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_s32 (int32x2_t a, int32x2_t b, int32x2_t c) +vmla_s32 (int32x2_t __a, int32x2_t __b, int32x2_t __c) { - int32x2_t result; + int32x2_t __result; __asm__ ("mla %0.2s, %2.2s, %3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) +vmla_u8 (uint8x8_t __a, uint8x8_t __b, uint8x8_t __c) { - uint8x8_t result; + uint8x8_t __result; __asm__ ("mla %0.8b, %2.8b, %3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) +vmla_u16 (uint16x4_t __a, uint16x4_t __b, uint16x4_t __c) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("mla %0.4h, %2.4h, %3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) +vmla_u32 (uint32x2_t __a, uint32x2_t __b, uint32x2_t __c) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("mla %0.2s, %2.2s, %3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } #define vmlal_high_lane_s16(a, b, c, d) \ @@ -7549,122 +7549,122 @@ vmla_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_n_s16 (int32x4_t a, int16x8_t b, int16_t c) +vmlal_high_n_s16 (int32x4_t __a, int16x8_t __b, int16_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlal2 %0.4s,%2.8h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_n_s32 (int64x2_t a, int32x4_t b, int32_t c) +vmlal_high_n_s32 (int64x2_t __a, int32x4_t __b, int32_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlal2 %0.2d,%2.4s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_n_u16 (uint32x4_t a, uint16x8_t b, uint16_t c) +vmlal_high_n_u16 (uint32x4_t __a, uint16x8_t __b, uint16_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlal2 %0.4s,%2.8h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_n_u32 (uint64x2_t a, uint32x4_t b, uint32_t c) +vmlal_high_n_u32 (uint64x2_t __a, uint32x4_t __b, uint32_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlal2 %0.2d,%2.4s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) +vmlal_high_s8 (int16x8_t __a, int8x16_t __b, int8x16_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("smlal2 %0.8h,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) +vmlal_high_s16 (int32x4_t __a, int16x8_t __b, int16x8_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlal2 %0.4s,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) +vmlal_high_s32 (int64x2_t __a, int32x4_t __b, int32x4_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlal2 %0.2d,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) +vmlal_high_u8 (uint16x8_t __a, uint8x16_t __b, uint8x16_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("umlal2 %0.8h,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) +vmlal_high_u16 (uint32x4_t __a, uint16x8_t __b, uint16x8_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlal2 %0.4s,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) +vmlal_high_u32 (uint64x2_t __a, uint32x4_t __b, uint32x4_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlal2 %0.2d,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } #define vmlal_lane_s16(a, b, c, d) \ @@ -7781,388 +7781,388 @@ vmlal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_n_s16 (int32x4_t a, int16x4_t b, int16_t c) +vmlal_n_s16 (int32x4_t __a, int16x4_t __b, int16_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlal %0.4s,%2.4h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_n_s32 (int64x2_t a, int32x2_t b, int32_t c) +vmlal_n_s32 (int64x2_t __a, int32x2_t __b, int32_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlal %0.2d,%2.2s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_n_u16 (uint32x4_t a, uint16x4_t b, uint16_t c) +vmlal_n_u16 (uint32x4_t __a, uint16x4_t __b, uint16_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlal %0.4s,%2.4h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_n_u32 (uint64x2_t a, uint32x2_t b, uint32_t c) +vmlal_n_u32 (uint64x2_t __a, uint32x2_t __b, uint32_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlal %0.2d,%2.2s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_s8 (int16x8_t a, int8x8_t b, int8x8_t c) +vmlal_s8 (int16x8_t __a, int8x8_t __b, int8x8_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("smlal %0.8h,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_s16 (int32x4_t a, int16x4_t b, int16x4_t c) +vmlal_s16 (int32x4_t __a, int16x4_t __b, int16x4_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlal %0.4s,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_s32 (int64x2_t a, int32x2_t b, int32x2_t c) +vmlal_s32 (int64x2_t __a, int32x2_t __b, int32x2_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlal %0.2d,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) +vmlal_u8 (uint16x8_t __a, uint8x8_t __b, uint8x8_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("umlal %0.8h,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) +vmlal_u16 (uint32x4_t __a, uint16x4_t __b, uint16x4_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlal %0.4s,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlal_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) +vmlal_u32 (uint64x2_t __a, uint32x2_t __b, uint32x2_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlal %0.2d,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_n_f32 (float32x4_t a, float32x4_t b, float32_t c) +vmlaq_n_f32 (float32x4_t __a, float32x4_t __b, float32_t __c) { - float32x4_t result; - float32x4_t t1; + float32x4_t __result; + float32x4_t __t1; __asm__ ("fmul %1.4s, %3.4s, %4.s[0]; fadd %0.4s, %0.4s, %1.4s" - : "=w"(result), "=w"(t1) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result), "=w"(__t1) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_n_s16 (int16x8_t a, int16x8_t b, int16_t c) +vmlaq_n_s16 (int16x8_t __a, int16x8_t __b, int16_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("mla %0.8h,%2.8h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_n_s32 (int32x4_t a, int32x4_t b, int32_t c) +vmlaq_n_s32 (int32x4_t __a, int32x4_t __b, int32_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("mla %0.4s,%2.4s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_n_u16 (uint16x8_t a, uint16x8_t b, uint16_t c) +vmlaq_n_u16 (uint16x8_t __a, uint16x8_t __b, uint16_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("mla %0.8h,%2.8h,%3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_n_u32 (uint32x4_t a, uint32x4_t b, uint32_t c) +vmlaq_n_u32 (uint32x4_t __a, uint32x4_t __b, uint32_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("mla %0.4s,%2.4s,%3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) +vmlaq_s8 (int8x16_t __a, int8x16_t __b, int8x16_t __c) { - int8x16_t result; + int8x16_t __result; __asm__ ("mla %0.16b, %2.16b, %3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) +vmlaq_s16 (int16x8_t __a, int16x8_t __b, int16x8_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("mla %0.8h, %2.8h, %3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) +vmlaq_s32 (int32x4_t __a, int32x4_t __b, int32x4_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("mla %0.4s, %2.4s, %3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) +vmlaq_u8 (uint8x16_t __a, uint8x16_t __b, uint8x16_t __c) { - uint8x16_t result; + uint8x16_t __result; __asm__ ("mla %0.16b, %2.16b, %3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) +vmlaq_u16 (uint16x8_t __a, uint16x8_t __b, uint16x8_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("mla %0.8h, %2.8h, %3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) +vmlaq_u32 (uint32x4_t __a, uint32x4_t __b, uint32x4_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("mla %0.4s, %2.4s, %3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_n_f32 (float32x2_t a, float32x2_t b, float32_t c) +vmls_n_f32 (float32x2_t __a, float32x2_t __b, float32_t __c) { - float32x2_t result; - float32x2_t t1; + float32x2_t __result; + float32x2_t __t1; __asm__ ("fmul %1.2s, %3.2s, %4.s[0]; fsub %0.2s, %0.2s, %1.2s" - : "=w"(result), "=w"(t1) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result), "=w"(__t1) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_n_s16 (int16x4_t a, int16x4_t b, int16_t c) +vmls_n_s16 (int16x4_t __a, int16x4_t __b, int16_t __c) { - int16x4_t result; + int16x4_t __result; __asm__ ("mls %0.4h, %2.4h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_n_s32 (int32x2_t a, int32x2_t b, int32_t c) +vmls_n_s32 (int32x2_t __a, int32x2_t __b, int32_t __c) { - int32x2_t result; + int32x2_t __result; __asm__ ("mls %0.2s, %2.2s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_n_u16 (uint16x4_t a, uint16x4_t b, uint16_t c) +vmls_n_u16 (uint16x4_t __a, uint16x4_t __b, uint16_t __c) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("mls %0.4h, %2.4h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_n_u32 (uint32x2_t a, uint32x2_t b, uint32_t c) +vmls_n_u32 (uint32x2_t __a, uint32x2_t __b, uint32_t __c) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("mls %0.2s, %2.2s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_s8 (int8x8_t a, int8x8_t b, int8x8_t c) +vmls_s8 (int8x8_t __a, int8x8_t __b, int8x8_t __c) { - int8x8_t result; + int8x8_t __result; __asm__ ("mls %0.8b,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_s16 (int16x4_t a, int16x4_t b, int16x4_t c) +vmls_s16 (int16x4_t __a, int16x4_t __b, int16x4_t __c) { - int16x4_t result; + int16x4_t __result; __asm__ ("mls %0.4h,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_s32 (int32x2_t a, int32x2_t b, int32x2_t c) +vmls_s32 (int32x2_t __a, int32x2_t __b, int32x2_t __c) { - int32x2_t result; + int32x2_t __result; __asm__ ("mls %0.2s,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) +vmls_u8 (uint8x8_t __a, uint8x8_t __b, uint8x8_t __c) { - uint8x8_t result; + uint8x8_t __result; __asm__ ("mls %0.8b,%2.8b,%3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) +vmls_u16 (uint16x4_t __a, uint16x4_t __b, uint16x4_t __c) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("mls %0.4h,%2.4h,%3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) +vmls_u32 (uint32x2_t __a, uint32x2_t __b, uint32x2_t __c) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("mls %0.2s,%2.2s,%3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } #define vmlsl_high_lane_s16(a, b, c, d) \ @@ -8279,122 +8279,122 @@ vmls_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_n_s16 (int32x4_t a, int16x8_t b, int16_t c) +vmlsl_high_n_s16 (int32x4_t __a, int16x8_t __b, int16_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlsl2 %0.4s, %2.8h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_n_s32 (int64x2_t a, int32x4_t b, int32_t c) +vmlsl_high_n_s32 (int64x2_t __a, int32x4_t __b, int32_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlsl2 %0.2d, %2.4s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_n_u16 (uint32x4_t a, uint16x8_t b, uint16_t c) +vmlsl_high_n_u16 (uint32x4_t __a, uint16x8_t __b, uint16_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlsl2 %0.4s, %2.8h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_n_u32 (uint64x2_t a, uint32x4_t b, uint32_t c) +vmlsl_high_n_u32 (uint64x2_t __a, uint32x4_t __b, uint32_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlsl2 %0.2d, %2.4s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) +vmlsl_high_s8 (int16x8_t __a, int8x16_t __b, int8x16_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("smlsl2 %0.8h,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) +vmlsl_high_s16 (int32x4_t __a, int16x8_t __b, int16x8_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlsl2 %0.4s,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) +vmlsl_high_s32 (int64x2_t __a, int32x4_t __b, int32x4_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlsl2 %0.2d,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) +vmlsl_high_u8 (uint16x8_t __a, uint8x16_t __b, uint8x16_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("umlsl2 %0.8h,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) +vmlsl_high_u16 (uint32x4_t __a, uint16x8_t __b, uint16x8_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlsl2 %0.4s,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) +vmlsl_high_u32 (uint64x2_t __a, uint32x4_t __b, uint32x4_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlsl2 %0.2d,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } #define vmlsl_lane_s16(a, b, c, d) \ @@ -8511,543 +8511,543 @@ vmlsl_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_n_s16 (int32x4_t a, int16x4_t b, int16_t c) +vmlsl_n_s16 (int32x4_t __a, int16x4_t __b, int16_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlsl %0.4s, %2.4h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_n_s32 (int64x2_t a, int32x2_t b, int32_t c) +vmlsl_n_s32 (int64x2_t __a, int32x2_t __b, int32_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlsl %0.2d, %2.2s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_n_u16 (uint32x4_t a, uint16x4_t b, uint16_t c) +vmlsl_n_u16 (uint32x4_t __a, uint16x4_t __b, uint16_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlsl %0.4s, %2.4h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_n_u32 (uint64x2_t a, uint32x2_t b, uint32_t c) +vmlsl_n_u32 (uint64x2_t __a, uint32x2_t __b, uint32_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlsl %0.2d, %2.2s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_s8 (int16x8_t a, int8x8_t b, int8x8_t c) +vmlsl_s8 (int16x8_t __a, int8x8_t __b, int8x8_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("smlsl %0.8h, %2.8b, %3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_s16 (int32x4_t a, int16x4_t b, int16x4_t c) +vmlsl_s16 (int32x4_t __a, int16x4_t __b, int16x4_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("smlsl %0.4s, %2.4h, %3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_s32 (int64x2_t a, int32x2_t b, int32x2_t c) +vmlsl_s32 (int64x2_t __a, int32x2_t __b, int32x2_t __c) { - int64x2_t result; + int64x2_t __result; __asm__ ("smlsl %0.2d, %2.2s, %3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) +vmlsl_u8 (uint16x8_t __a, uint8x8_t __b, uint8x8_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("umlsl %0.8h, %2.8b, %3.8b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) +vmlsl_u16 (uint32x4_t __a, uint16x4_t __b, uint16x4_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umlsl %0.4s, %2.4h, %3.4h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsl_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) +vmlsl_u32 (uint64x2_t __a, uint32x2_t __b, uint32x2_t __c) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umlsl %0.2d, %2.2s, %3.2s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_n_f32 (float32x4_t a, float32x4_t b, float32_t c) +vmlsq_n_f32 (float32x4_t __a, float32x4_t __b, float32_t __c) { - float32x4_t result; - float32x4_t t1; + float32x4_t __result; + float32x4_t __t1; __asm__ ("fmul %1.4s, %3.4s, %4.s[0]; fsub %0.4s, %0.4s, %1.4s" - : "=w"(result), "=w"(t1) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result), "=w"(__t1) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_n_s16 (int16x8_t a, int16x8_t b, int16_t c) +vmlsq_n_s16 (int16x8_t __a, int16x8_t __b, int16_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("mls %0.8h, %2.8h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_n_s32 (int32x4_t a, int32x4_t b, int32_t c) +vmlsq_n_s32 (int32x4_t __a, int32x4_t __b, int32_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("mls %0.4s, %2.4s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_n_u16 (uint16x8_t a, uint16x8_t b, uint16_t c) +vmlsq_n_u16 (uint16x8_t __a, uint16x8_t __b, uint16_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("mls %0.8h, %2.8h, %3.h[0]" - : "=w"(result) - : "0"(a), "w"(b), "x"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "x"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_n_u32 (uint32x4_t a, uint32x4_t b, uint32_t c) +vmlsq_n_u32 (uint32x4_t __a, uint32x4_t __b, uint32_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("mls %0.4s, %2.4s, %3.s[0]" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) +vmlsq_s8 (int8x16_t __a, int8x16_t __b, int8x16_t __c) { - int8x16_t result; + int8x16_t __result; __asm__ ("mls %0.16b,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) +vmlsq_s16 (int16x8_t __a, int16x8_t __b, int16x8_t __c) { - int16x8_t result; + int16x8_t __result; __asm__ ("mls %0.8h,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) +vmlsq_s32 (int32x4_t __a, int32x4_t __b, int32x4_t __c) { - int32x4_t result; + int32x4_t __result; __asm__ ("mls %0.4s,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) +vmlsq_u8 (uint8x16_t __a, uint8x16_t __b, uint8x16_t __c) { - uint8x16_t result; + uint8x16_t __result; __asm__ ("mls %0.16b,%2.16b,%3.16b" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) +vmlsq_u16 (uint16x8_t __a, uint16x8_t __b, uint16x8_t __c) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("mls %0.8h,%2.8h,%3.8h" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) +vmlsq_u32 (uint32x4_t __a, uint32x4_t __b, uint32x4_t __c) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("mls %0.4s,%2.4s,%3.4s" - : "=w"(result) - : "0"(a), "w"(b), "w"(c) + : "=w"(__result) + : "0"(__a), "w"(__b), "w"(__c) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_high_s8 (int8x16_t a) +vmovl_high_s8 (int8x16_t __a) { - int16x8_t result; + int16x8_t __result; __asm__ ("sshll2 %0.8h,%1.16b,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_high_s16 (int16x8_t a) +vmovl_high_s16 (int16x8_t __a) { - int32x4_t result; + int32x4_t __result; __asm__ ("sshll2 %0.4s,%1.8h,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_high_s32 (int32x4_t a) +vmovl_high_s32 (int32x4_t __a) { - int64x2_t result; + int64x2_t __result; __asm__ ("sshll2 %0.2d,%1.4s,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_high_u8 (uint8x16_t a) +vmovl_high_u8 (uint8x16_t __a) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("ushll2 %0.8h,%1.16b,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_high_u16 (uint16x8_t a) +vmovl_high_u16 (uint16x8_t __a) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("ushll2 %0.4s,%1.8h,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_high_u32 (uint32x4_t a) +vmovl_high_u32 (uint32x4_t __a) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("ushll2 %0.2d,%1.4s,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_s8 (int8x8_t a) +vmovl_s8 (int8x8_t __a) { - int16x8_t result; + int16x8_t __result; __asm__ ("sshll %0.8h,%1.8b,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_s16 (int16x4_t a) +vmovl_s16 (int16x4_t __a) { - int32x4_t result; + int32x4_t __result; __asm__ ("sshll %0.4s,%1.4h,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_s32 (int32x2_t a) +vmovl_s32 (int32x2_t __a) { - int64x2_t result; + int64x2_t __result; __asm__ ("sshll %0.2d,%1.2s,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_u8 (uint8x8_t a) +vmovl_u8 (uint8x8_t __a) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("ushll %0.8h,%1.8b,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_u16 (uint16x4_t a) +vmovl_u16 (uint16x4_t __a) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("ushll %0.4s,%1.4h,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovl_u32 (uint32x2_t a) +vmovl_u32 (uint32x2_t __a) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("ushll %0.2d,%1.2s,#0" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_high_s16 (int8x8_t a, int16x8_t b) +vmovn_high_s16 (int8x8_t __a, int16x8_t __b) { - int8x16_t result = vcombine_s8 (a, vcreate_s8 (__AARCH64_UINT64_C (0x0))); + int8x16_t __result = vcombine_s8 (__a, vcreate_s8 (__AARCH64_UINT64_C (0x0))); __asm__ ("xtn2 %0.16b,%1.8h" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_high_s32 (int16x4_t a, int32x4_t b) +vmovn_high_s32 (int16x4_t __a, int32x4_t __b) { - int16x8_t result = vcombine_s16 (a, vcreate_s16 (__AARCH64_UINT64_C (0x0))); + int16x8_t __result = vcombine_s16 (__a, vcreate_s16 (__AARCH64_UINT64_C (0x0))); __asm__ ("xtn2 %0.8h,%1.4s" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_high_s64 (int32x2_t a, int64x2_t b) +vmovn_high_s64 (int32x2_t __a, int64x2_t __b) { - int32x4_t result = vcombine_s32 (a, vcreate_s32 (__AARCH64_UINT64_C (0x0))); + int32x4_t __result = vcombine_s32 (__a, vcreate_s32 (__AARCH64_UINT64_C (0x0))); __asm__ ("xtn2 %0.4s,%1.2d" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_high_u16 (uint8x8_t a, uint16x8_t b) +vmovn_high_u16 (uint8x8_t __a, uint16x8_t __b) { - uint8x16_t result = vcombine_u8 (a, vcreate_u8 (__AARCH64_UINT64_C (0x0))); + uint8x16_t __result = vcombine_u8 (__a, vcreate_u8 (__AARCH64_UINT64_C (0x0))); __asm__ ("xtn2 %0.16b,%1.8h" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_high_u32 (uint16x4_t a, uint32x4_t b) +vmovn_high_u32 (uint16x4_t __a, uint32x4_t __b) { - uint16x8_t result = vcombine_u16 (a, vcreate_u16 (__AARCH64_UINT64_C (0x0))); + uint16x8_t __result = vcombine_u16 (__a, vcreate_u16 (__AARCH64_UINT64_C (0x0))); __asm__ ("xtn2 %0.8h,%1.4s" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_high_u64 (uint32x2_t a, uint64x2_t b) +vmovn_high_u64 (uint32x2_t __a, uint64x2_t __b) { - uint32x4_t result = vcombine_u32 (a, vcreate_u32 (__AARCH64_UINT64_C (0x0))); + uint32x4_t __result = vcombine_u32 (__a, vcreate_u32 (__AARCH64_UINT64_C (0x0))); __asm__ ("xtn2 %0.4s,%1.2d" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_s16 (int16x8_t a) +vmovn_s16 (int16x8_t __a) { - int8x8_t result; + int8x8_t __result; __asm__ ("xtn %0.8b,%1.8h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_s32 (int32x4_t a) +vmovn_s32 (int32x4_t __a) { - int16x4_t result; + int16x4_t __result; __asm__ ("xtn %0.4h,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_s64 (int64x2_t a) +vmovn_s64 (int64x2_t __a) { - int32x2_t result; + int32x2_t __result; __asm__ ("xtn %0.2s,%1.2d" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_u16 (uint16x8_t a) +vmovn_u16 (uint16x8_t __a) { - uint8x8_t result; + uint8x8_t __result; __asm__ ("xtn %0.8b,%1.8h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_u32 (uint32x4_t a) +vmovn_u32 (uint32x4_t __a) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("xtn %0.4h,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmovn_u64 (uint64x2_t a) +vmovn_u64 (uint64x2_t __a) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("xtn %0.2s,%1.2d" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } #define vmull_high_lane_s16(a, b, c) \ @@ -9156,134 +9156,134 @@ vmovn_u64 (uint64x2_t a) __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_n_s16 (int16x8_t a, int16_t b) +vmull_high_n_s16 (int16x8_t __a, int16_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("smull2 %0.4s,%1.8h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_n_s32 (int32x4_t a, int32_t b) +vmull_high_n_s32 (int32x4_t __a, int32_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("smull2 %0.2d,%1.4s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_n_u16 (uint16x8_t a, uint16_t b) +vmull_high_n_u16 (uint16x8_t __a, uint16_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umull2 %0.4s,%1.8h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_n_u32 (uint32x4_t a, uint32_t b) +vmull_high_n_u32 (uint32x4_t __a, uint32_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umull2 %0.2d,%1.4s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_p8 (poly8x16_t a, poly8x16_t b) +vmull_high_p8 (poly8x16_t __a, poly8x16_t __b) { - poly16x8_t result; + poly16x8_t __result; __asm__ ("pmull2 %0.8h,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_s8 (int8x16_t a, int8x16_t b) +vmull_high_s8 (int8x16_t __a, int8x16_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("smull2 %0.8h,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_s16 (int16x8_t a, int16x8_t b) +vmull_high_s16 (int16x8_t __a, int16x8_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("smull2 %0.4s,%1.8h,%2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_s32 (int32x4_t a, int32x4_t b) +vmull_high_s32 (int32x4_t __a, int32x4_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("smull2 %0.2d,%1.4s,%2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_u8 (uint8x16_t a, uint8x16_t b) +vmull_high_u8 (uint8x16_t __a, uint8x16_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("umull2 %0.8h,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_u16 (uint16x8_t a, uint16x8_t b) +vmull_high_u16 (uint16x8_t __a, uint16x8_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umull2 %0.4s,%1.8h,%2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_u32 (uint32x4_t a, uint32x4_t b) +vmull_high_u32 (uint32x4_t __a, uint32x4_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umull2 %0.2d,%1.4s,%2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } #define vmull_lane_s16(a, b, c) \ @@ -9392,722 +9392,722 @@ vmull_high_u32 (uint32x4_t a, uint32x4_t b) __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_n_s16 (int16x4_t a, int16_t b) +vmull_n_s16 (int16x4_t __a, int16_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("smull %0.4s,%1.4h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_n_s32 (int32x2_t a, int32_t b) +vmull_n_s32 (int32x2_t __a, int32_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("smull %0.2d,%1.2s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_n_u16 (uint16x4_t a, uint16_t b) +vmull_n_u16 (uint16x4_t __a, uint16_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umull %0.4s,%1.4h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_n_u32 (uint32x2_t a, uint32_t b) +vmull_n_u32 (uint32x2_t __a, uint32_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umull %0.2d,%1.2s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_p8 (poly8x8_t a, poly8x8_t b) +vmull_p8 (poly8x8_t __a, poly8x8_t __b) { - poly16x8_t result; + poly16x8_t __result; __asm__ ("pmull %0.8h, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_s8 (int8x8_t a, int8x8_t b) +vmull_s8 (int8x8_t __a, int8x8_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("smull %0.8h, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_s16 (int16x4_t a, int16x4_t b) +vmull_s16 (int16x4_t __a, int16x4_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("smull %0.4s, %1.4h, %2.4h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_s32 (int32x2_t a, int32x2_t b) +vmull_s32 (int32x2_t __a, int32x2_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("smull %0.2d, %1.2s, %2.2s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_u8 (uint8x8_t a, uint8x8_t b) +vmull_u8 (uint8x8_t __a, uint8x8_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("umull %0.8h, %1.8b, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_u16 (uint16x4_t a, uint16x4_t b) +vmull_u16 (uint16x4_t __a, uint16x4_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("umull %0.4s, %1.4h, %2.4h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_u32 (uint32x2_t a, uint32x2_t b) +vmull_u32 (uint32x2_t __a, uint32x2_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("umull %0.2d, %1.2s, %2.2s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadal_s8 (int16x4_t a, int8x8_t b) +vpadal_s8 (int16x4_t __a, int8x8_t __b) { - int16x4_t result; + int16x4_t __result; __asm__ ("sadalp %0.4h,%2.8b" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadal_s16 (int32x2_t a, int16x4_t b) +vpadal_s16 (int32x2_t __a, int16x4_t __b) { - int32x2_t result; + int32x2_t __result; __asm__ ("sadalp %0.2s,%2.4h" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadal_s32 (int64x1_t a, int32x2_t b) +vpadal_s32 (int64x1_t __a, int32x2_t __b) { - int64x1_t result; + int64x1_t __result; __asm__ ("sadalp %0.1d,%2.2s" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadal_u8 (uint16x4_t a, uint8x8_t b) +vpadal_u8 (uint16x4_t __a, uint8x8_t __b) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("uadalp %0.4h,%2.8b" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadal_u16 (uint32x2_t a, uint16x4_t b) +vpadal_u16 (uint32x2_t __a, uint16x4_t __b) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("uadalp %0.2s,%2.4h" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadal_u32 (uint64x1_t a, uint32x2_t b) +vpadal_u32 (uint64x1_t __a, uint32x2_t __b) { - uint64x1_t result; + uint64x1_t __result; __asm__ ("uadalp %0.1d,%2.2s" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadalq_s8 (int16x8_t a, int8x16_t b) +vpadalq_s8 (int16x8_t __a, int8x16_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("sadalp %0.8h,%2.16b" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadalq_s16 (int32x4_t a, int16x8_t b) +vpadalq_s16 (int32x4_t __a, int16x8_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("sadalp %0.4s,%2.8h" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadalq_s32 (int64x2_t a, int32x4_t b) +vpadalq_s32 (int64x2_t __a, int32x4_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("sadalp %0.2d,%2.4s" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadalq_u8 (uint16x8_t a, uint8x16_t b) +vpadalq_u8 (uint16x8_t __a, uint8x16_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uadalp %0.8h,%2.16b" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadalq_u16 (uint32x4_t a, uint16x8_t b) +vpadalq_u16 (uint32x4_t __a, uint16x8_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uadalp %0.4s,%2.8h" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadalq_u32 (uint64x2_t a, uint32x4_t b) +vpadalq_u32 (uint64x2_t __a, uint32x4_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("uadalp %0.2d,%2.4s" - : "=w"(result) - : "0"(a), "w"(b) + : "=w"(__result) + : "0"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddl_s8 (int8x8_t a) +vpaddl_s8 (int8x8_t __a) { - int16x4_t result; + int16x4_t __result; __asm__ ("saddlp %0.4h,%1.8b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddl_s16 (int16x4_t a) +vpaddl_s16 (int16x4_t __a) { - int32x2_t result; + int32x2_t __result; __asm__ ("saddlp %0.2s,%1.4h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddl_s32 (int32x2_t a) +vpaddl_s32 (int32x2_t __a) { - int64x1_t result; + int64x1_t __result; __asm__ ("saddlp %0.1d,%1.2s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddl_u8 (uint8x8_t a) +vpaddl_u8 (uint8x8_t __a) { - uint16x4_t result; + uint16x4_t __result; __asm__ ("uaddlp %0.4h,%1.8b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddl_u16 (uint16x4_t a) +vpaddl_u16 (uint16x4_t __a) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("uaddlp %0.2s,%1.4h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddl_u32 (uint32x2_t a) +vpaddl_u32 (uint32x2_t __a) { - uint64x1_t result; + uint64x1_t __result; __asm__ ("uaddlp %0.1d,%1.2s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddlq_s8 (int8x16_t a) +vpaddlq_s8 (int8x16_t __a) { - int16x8_t result; + int16x8_t __result; __asm__ ("saddlp %0.8h,%1.16b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddlq_s16 (int16x8_t a) +vpaddlq_s16 (int16x8_t __a) { - int32x4_t result; + int32x4_t __result; __asm__ ("saddlp %0.4s,%1.8h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddlq_s32 (int32x4_t a) +vpaddlq_s32 (int32x4_t __a) { - int64x2_t result; + int64x2_t __result; __asm__ ("saddlp %0.2d,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddlq_u8 (uint8x16_t a) +vpaddlq_u8 (uint8x16_t __a) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("uaddlp %0.8h,%1.16b" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddlq_u16 (uint16x8_t a) +vpaddlq_u16 (uint16x8_t __a) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("uaddlp %0.4s,%1.8h" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddlq_u32 (uint32x4_t a) +vpaddlq_u32 (uint32x4_t __a) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("uaddlp %0.2d,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_s8 (int8x16_t a, int8x16_t b) +vpaddq_s8 (int8x16_t __a, int8x16_t __b) { - int8x16_t result; + int8x16_t __result; __asm__ ("addp %0.16b,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_s16 (int16x8_t a, int16x8_t b) +vpaddq_s16 (int16x8_t __a, int16x8_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("addp %0.8h,%1.8h,%2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_s32 (int32x4_t a, int32x4_t b) +vpaddq_s32 (int32x4_t __a, int32x4_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("addp %0.4s,%1.4s,%2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_s64 (int64x2_t a, int64x2_t b) +vpaddq_s64 (int64x2_t __a, int64x2_t __b) { - int64x2_t result; + int64x2_t __result; __asm__ ("addp %0.2d,%1.2d,%2.2d" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_u8 (uint8x16_t a, uint8x16_t b) +vpaddq_u8 (uint8x16_t __a, uint8x16_t __b) { - uint8x16_t result; + uint8x16_t __result; __asm__ ("addp %0.16b,%1.16b,%2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_u16 (uint16x8_t a, uint16x8_t b) +vpaddq_u16 (uint16x8_t __a, uint16x8_t __b) { - uint16x8_t result; + uint16x8_t __result; __asm__ ("addp %0.8h,%1.8h,%2.8h" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_u32 (uint32x4_t a, uint32x4_t b) +vpaddq_u32 (uint32x4_t __a, uint32x4_t __b) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("addp %0.4s,%1.4s,%2.4s" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_u64 (uint64x2_t a, uint64x2_t b) +vpaddq_u64 (uint64x2_t __a, uint64x2_t __b) { - uint64x2_t result; + uint64x2_t __result; __asm__ ("addp %0.2d,%1.2d,%2.2d" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqdmulh_n_s16 (int16x4_t a, int16_t b) +vqdmulh_n_s16 (int16x4_t __a, int16_t __b) { - int16x4_t result; + int16x4_t __result; __asm__ ("sqdmulh %0.4h,%1.4h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqdmulh_n_s32 (int32x2_t a, int32_t b) +vqdmulh_n_s32 (int32x2_t __a, int32_t __b) { - int32x2_t result; + int32x2_t __result; __asm__ ("sqdmulh %0.2s,%1.2s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqdmulhq_n_s16 (int16x8_t a, int16_t b) +vqdmulhq_n_s16 (int16x8_t __a, int16_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("sqdmulh %0.8h,%1.8h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqdmulhq_n_s32 (int32x4_t a, int32_t b) +vqdmulhq_n_s32 (int32x4_t __a, int32_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("sqdmulh %0.4s,%1.4s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovn_high_s16 (int8x8_t a, int16x8_t b) +vqmovn_high_s16 (int8x8_t __a, int16x8_t __b) { - int8x16_t result = vcombine_s8 (a, vcreate_s8 (__AARCH64_UINT64_C (0x0))); + int8x16_t __result = vcombine_s8 (__a, vcreate_s8 (__AARCH64_UINT64_C (0x0))); __asm__ ("sqxtn2 %0.16b, %1.8h" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovn_high_s32 (int16x4_t a, int32x4_t b) +vqmovn_high_s32 (int16x4_t __a, int32x4_t __b) { - int16x8_t result = vcombine_s16 (a, vcreate_s16 (__AARCH64_UINT64_C (0x0))); + int16x8_t __result = vcombine_s16 (__a, vcreate_s16 (__AARCH64_UINT64_C (0x0))); __asm__ ("sqxtn2 %0.8h, %1.4s" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovn_high_s64 (int32x2_t a, int64x2_t b) +vqmovn_high_s64 (int32x2_t __a, int64x2_t __b) { - int32x4_t result = vcombine_s32 (a, vcreate_s32 (__AARCH64_UINT64_C (0x0))); + int32x4_t __result = vcombine_s32 (__a, vcreate_s32 (__AARCH64_UINT64_C (0x0))); __asm__ ("sqxtn2 %0.4s, %1.2d" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovn_high_u16 (uint8x8_t a, uint16x8_t b) +vqmovn_high_u16 (uint8x8_t __a, uint16x8_t __b) { - uint8x16_t result = vcombine_u8 (a, vcreate_u8 (__AARCH64_UINT64_C (0x0))); + uint8x16_t __result = vcombine_u8 (__a, vcreate_u8 (__AARCH64_UINT64_C (0x0))); __asm__ ("uqxtn2 %0.16b, %1.8h" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovn_high_u32 (uint16x4_t a, uint32x4_t b) +vqmovn_high_u32 (uint16x4_t __a, uint32x4_t __b) { - uint16x8_t result = vcombine_u16 (a, vcreate_u16 (__AARCH64_UINT64_C (0x0))); + uint16x8_t __result = vcombine_u16 (__a, vcreate_u16 (__AARCH64_UINT64_C (0x0))); __asm__ ("uqxtn2 %0.8h, %1.4s" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovn_high_u64 (uint32x2_t a, uint64x2_t b) +vqmovn_high_u64 (uint32x2_t __a, uint64x2_t __b) { - uint32x4_t result = vcombine_u32 (a, vcreate_u32 (__AARCH64_UINT64_C (0x0))); + uint32x4_t __result = vcombine_u32 (__a, vcreate_u32 (__AARCH64_UINT64_C (0x0))); __asm__ ("uqxtn2 %0.4s, %1.2d" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovun_high_s16 (uint8x8_t a, int16x8_t b) +vqmovun_high_s16 (uint8x8_t __a, int16x8_t __b) { - uint8x16_t result = vcombine_u8 (a, vcreate_u8 (__AARCH64_UINT64_C (0x0))); + uint8x16_t __result = vcombine_u8 (__a, vcreate_u8 (__AARCH64_UINT64_C (0x0))); __asm__ ("sqxtun2 %0.16b, %1.8h" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovun_high_s32 (uint16x4_t a, int32x4_t b) +vqmovun_high_s32 (uint16x4_t __a, int32x4_t __b) { - uint16x8_t result = vcombine_u16 (a, vcreate_u16 (__AARCH64_UINT64_C (0x0))); + uint16x8_t __result = vcombine_u16 (__a, vcreate_u16 (__AARCH64_UINT64_C (0x0))); __asm__ ("sqxtun2 %0.8h, %1.4s" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqmovun_high_s64 (uint32x2_t a, int64x2_t b) +vqmovun_high_s64 (uint32x2_t __a, int64x2_t __b) { - uint32x4_t result = vcombine_u32 (a, vcreate_u32 (__AARCH64_UINT64_C (0x0))); + uint32x4_t __result = vcombine_u32 (__a, vcreate_u32 (__AARCH64_UINT64_C (0x0))); __asm__ ("sqxtun2 %0.4s, %1.2d" - : "+w"(result) - : "w"(b) + : "+w"(__result) + : "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqrdmulh_n_s16 (int16x4_t a, int16_t b) +vqrdmulh_n_s16 (int16x4_t __a, int16_t __b) { - int16x4_t result; + int16x4_t __result; __asm__ ("sqrdmulh %0.4h,%1.4h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqrdmulh_n_s32 (int32x2_t a, int32_t b) +vqrdmulh_n_s32 (int32x2_t __a, int32_t __b) { - int32x2_t result; + int32x2_t __result; __asm__ ("sqrdmulh %0.2s,%1.2s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqrdmulhq_n_s16 (int16x8_t a, int16_t b) +vqrdmulhq_n_s16 (int16x8_t __a, int16_t __b) { - int16x8_t result; + int16x8_t __result; __asm__ ("sqrdmulh %0.8h,%1.8h,%2.h[0]" - : "=w"(result) - : "w"(a), "x"(b) + : "=w"(__result) + : "w"(__a), "x"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqrdmulhq_n_s32 (int32x4_t a, int32_t b) +vqrdmulhq_n_s32 (int32x4_t __a, int32_t __b) { - int32x4_t result; + int32x4_t __result; __asm__ ("sqrdmulh %0.4s,%1.4s,%2.s[0]" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } #define vqrshrn_high_n_s16(a, b, c) \ @@ -10544,26 +10544,26 @@ vqrdmulhq_n_s32 (int32x4_t a, int32_t b) __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrsqrte_u32 (uint32x2_t a) +vrsqrte_u32 (uint32x2_t __a) { - uint32x2_t result; + uint32x2_t __result; __asm__ ("ursqrte %0.2s,%1.2s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrsqrteq_u32 (uint32x4_t a) +vrsqrteq_u32 (uint32x4_t __a) { - uint32x4_t result; + uint32x4_t __result; __asm__ ("ursqrte %0.4s,%1.4s" - : "=w"(result) - : "w"(a) + : "=w"(__result) + : "w"(__a) : /* No clobbers */); - return result; + return __result; } #define vshrn_high_n_s16(a, b, c) \ @@ -10860,48 +10860,48 @@ vrsqrteq_u32 (uint32x4_t a) __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtst_p8 (poly8x8_t a, poly8x8_t b) +vtst_p8 (poly8x8_t __a, poly8x8_t __b) { - return (uint8x8_t) ((((uint8x8_t) a) & ((uint8x8_t) b)) + return (uint8x8_t) ((((uint8x8_t) __a) & ((uint8x8_t) __b)) != 0); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtst_p16 (poly16x4_t a, poly16x4_t b) +vtst_p16 (poly16x4_t __a, poly16x4_t __b) { - return (uint16x4_t) ((((uint16x4_t) a) & ((uint16x4_t) b)) + return (uint16x4_t) ((((uint16x4_t) __a) & ((uint16x4_t) __b)) != 0); } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtst_p64 (poly64x1_t a, poly64x1_t b) +vtst_p64 (poly64x1_t __a, poly64x1_t __b) { - return (uint64x1_t) ((a & b) != __AARCH64_INT64_C (0)); + return (uint64x1_t) ((__a & __b) != __AARCH64_INT64_C (0)); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtstq_p8 (poly8x16_t a, poly8x16_t b) +vtstq_p8 (poly8x16_t __a, poly8x16_t __b) { - return (uint8x16_t) ((((uint8x16_t) a) & ((uint8x16_t) b)) + return (uint8x16_t) ((((uint8x16_t) __a) & ((uint8x16_t) __b)) != 0); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtstq_p16 (poly16x8_t a, poly16x8_t b) +vtstq_p16 (poly16x8_t __a, poly16x8_t __b) { - return (uint16x8_t) ((((uint16x8_t) a) & ((uint16x8_t) b)) + return (uint16x8_t) ((((uint16x8_t) __a) & ((uint16x8_t) __b)) != 0); } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtstq_p64 (poly64x2_t a, poly64x2_t b) +vtstq_p64 (poly64x2_t __a, poly64x2_t __b) { - return (uint64x2_t) ((((uint64x2_t) a) & ((uint64x2_t) b)) + return (uint64x2_t) ((((uint64x2_t) __a) & ((uint64x2_t) __b)) != __AARCH64_INT64_C (0)); } @@ -11248,20 +11248,20 @@ __ST4_LANE_FUNC (uint64x2x4_t, uint64_t, v2di, di, u64) __extension__ extern __inline int64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlv_s32 (int32x2_t a) +vaddlv_s32 (int32x2_t __a) { - int64_t result; - __asm__ ("saddlp %0.1d, %1.2s" : "=w"(result) : "w"(a) : ); - return result; + int64_t __result; + __asm__ ("saddlp %0.1d, %1.2s" : "=w"(__result) : "w"(__a) : ); + return __result; } __extension__ extern __inline uint64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vaddlv_u32 (uint32x2_t a) +vaddlv_u32 (uint32x2_t __a) { - uint64_t result; - __asm__ ("uaddlp %0.1d, %1.2s" : "=w"(result) : "w"(a) : ); - return result; + uint64_t __result; + __asm__ ("uaddlp %0.1d, %1.2s" : "=w"(__result) : "w"(__a) : ); + return __result; } __extension__ extern __inline int16x4_t @@ -11324,367 +11324,367 @@ vqrdmulhq_laneq_s32 (int32x4_t __a, int32x4_t __b, const int __c) __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl1_p8 (poly8x16_t a, uint8x8_t b) +vqtbl1_p8 (poly8x16_t __a, uint8x8_t __b) { - poly8x8_t result; + poly8x8_t __result; __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl1_s8 (int8x16_t a, uint8x8_t b) +vqtbl1_s8 (int8x16_t __a, uint8x8_t __b) { - int8x8_t result; + int8x8_t __result; __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl1_u8 (uint8x16_t a, uint8x8_t b) +vqtbl1_u8 (uint8x16_t __a, uint8x8_t __b) { - uint8x8_t result; + uint8x8_t __result; __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl1q_p8 (poly8x16_t a, uint8x16_t b) +vqtbl1q_p8 (poly8x16_t __a, uint8x16_t __b) { - poly8x16_t result; + poly8x16_t __result; __asm__ ("tbl %0.16b, {%1.16b}, %2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl1q_s8 (int8x16_t a, uint8x16_t b) +vqtbl1q_s8 (int8x16_t __a, uint8x16_t __b) { - int8x16_t result; + int8x16_t __result; __asm__ ("tbl %0.16b, {%1.16b}, %2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl1q_u8 (uint8x16_t a, uint8x16_t b) +vqtbl1q_u8 (uint8x16_t __a, uint8x16_t __b) { - uint8x16_t result; + uint8x16_t __result; __asm__ ("tbl %0.16b, {%1.16b}, %2.16b" - : "=w"(result) - : "w"(a), "w"(b) + : "=w"(__result) + : "w"(__a), "w"(__b) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx1_s8 (int8x8_t r, int8x16_t tab, uint8x8_t idx) +vqtbx1_s8 (int8x8_t __r, int8x16_t __tab, uint8x8_t __idx) { - int8x8_t result = r; + int8x8_t __result = __r; __asm__ ("tbx %0.8b,{%1.16b},%2.8b" - : "+w"(result) - : "w"(tab), "w"(idx) + : "+w"(__result) + : "w"(__tab), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx1_u8 (uint8x8_t r, uint8x16_t tab, uint8x8_t idx) +vqtbx1_u8 (uint8x8_t __r, uint8x16_t __tab, uint8x8_t __idx) { - uint8x8_t result = r; + uint8x8_t __result = __r; __asm__ ("tbx %0.8b,{%1.16b},%2.8b" - : "+w"(result) - : "w"(tab), "w"(idx) + : "+w"(__result) + : "w"(__tab), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx1_p8 (poly8x8_t r, poly8x16_t tab, uint8x8_t idx) +vqtbx1_p8 (poly8x8_t __r, poly8x16_t __tab, uint8x8_t __idx) { - poly8x8_t result = r; + poly8x8_t __result = __r; __asm__ ("tbx %0.8b,{%1.16b},%2.8b" - : "+w"(result) - : "w"(tab), "w"(idx) + : "+w"(__result) + : "w"(__tab), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx1q_s8 (int8x16_t r, int8x16_t tab, uint8x16_t idx) +vqtbx1q_s8 (int8x16_t __r, int8x16_t __tab, uint8x16_t __idx) { - int8x16_t result = r; + int8x16_t __result = __r; __asm__ ("tbx %0.16b,{%1.16b},%2.16b" - : "+w"(result) - : "w"(tab), "w"(idx) + : "+w"(__result) + : "w"(__tab), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx1q_u8 (uint8x16_t r, uint8x16_t tab, uint8x16_t idx) +vqtbx1q_u8 (uint8x16_t __r, uint8x16_t __tab, uint8x16_t __idx) { - uint8x16_t result = r; + uint8x16_t __result = __r; __asm__ ("tbx %0.16b,{%1.16b},%2.16b" - : "+w"(result) - : "w"(tab), "w"(idx) + : "+w"(__result) + : "w"(__tab), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx1q_p8 (poly8x16_t r, poly8x16_t tab, uint8x16_t idx) +vqtbx1q_p8 (poly8x16_t __r, poly8x16_t __tab, uint8x16_t __idx) { - poly8x16_t result = r; + poly8x16_t __result = __r; __asm__ ("tbx %0.16b,{%1.16b},%2.16b" - : "+w"(result) - : "w"(tab), "w"(idx) + : "+w"(__result) + : "w"(__tab), "w"(__idx) : /* No clobbers */); - return result; + return __result; } /* V7 legacy table intrinsics. */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl1_s8 (int8x8_t tab, int8x8_t idx) +vtbl1_s8 (int8x8_t __tab, int8x8_t __idx) { - int8x8_t result; - int8x16_t temp = vcombine_s8 (tab, vcreate_s8 (__AARCH64_UINT64_C (0x0))); + int8x8_t __result; + int8x16_t __temp = vcombine_s8 (__tab, vcreate_s8 (__AARCH64_UINT64_C (0x0))); __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(temp), "w"(idx) + : "=w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl1_u8 (uint8x8_t tab, uint8x8_t idx) +vtbl1_u8 (uint8x8_t __tab, uint8x8_t __idx) { - uint8x8_t result; - uint8x16_t temp = vcombine_u8 (tab, vcreate_u8 (__AARCH64_UINT64_C (0x0))); + uint8x8_t __result; + uint8x16_t __temp = vcombine_u8 (__tab, vcreate_u8 (__AARCH64_UINT64_C (0x0))); __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(temp), "w"(idx) + : "=w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl1_p8 (poly8x8_t tab, uint8x8_t idx) +vtbl1_p8 (poly8x8_t __tab, uint8x8_t __idx) { - poly8x8_t result; - poly8x16_t temp = vcombine_p8 (tab, vcreate_p8 (__AARCH64_UINT64_C (0x0))); + poly8x8_t __result; + poly8x16_t __temp = vcombine_p8 (__tab, vcreate_p8 (__AARCH64_UINT64_C (0x0))); __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(temp), "w"(idx) + : "=w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl2_s8 (int8x8x2_t tab, int8x8_t idx) +vtbl2_s8 (int8x8x2_t __tab, int8x8_t __idx) { - int8x8_t result; - int8x16_t temp = vcombine_s8 (tab.val[0], tab.val[1]); + int8x8_t __result; + int8x16_t __temp = vcombine_s8 (__tab.val[0], __tab.val[1]); __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(temp), "w"(idx) + : "=w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl2_u8 (uint8x8x2_t tab, uint8x8_t idx) +vtbl2_u8 (uint8x8x2_t __tab, uint8x8_t __idx) { - uint8x8_t result; - uint8x16_t temp = vcombine_u8 (tab.val[0], tab.val[1]); + uint8x8_t __result; + uint8x16_t __temp = vcombine_u8 (__tab.val[0], __tab.val[1]); __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(temp), "w"(idx) + : "=w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl2_p8 (poly8x8x2_t tab, uint8x8_t idx) +vtbl2_p8 (poly8x8x2_t __tab, uint8x8_t __idx) { - poly8x8_t result; - poly8x16_t temp = vcombine_p8 (tab.val[0], tab.val[1]); + poly8x8_t __result; + poly8x16_t __temp = vcombine_p8 (__tab.val[0], __tab.val[1]); __asm__ ("tbl %0.8b, {%1.16b}, %2.8b" - : "=w"(result) - : "w"(temp), "w"(idx) + : "=w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl3_s8 (int8x8x3_t tab, int8x8_t idx) +vtbl3_s8 (int8x8x3_t __tab, int8x8_t __idx) { - int8x8_t result; - int8x16x2_t temp; + int8x8_t __result; + int8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_s8 (tab.val[0], tab.val[1]); - temp.val[1] = vcombine_s8 (tab.val[2], vcreate_s8 (__AARCH64_UINT64_C (0x0))); + __temp.val[0] = vcombine_s8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_s8 (__tab.val[2], vcreate_s8 (__AARCH64_UINT64_C (0x0))); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = __builtin_aarch64_tbl3v8qi (__o, idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = __builtin_aarch64_tbl3v8qi (__o, __idx); + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl3_u8 (uint8x8x3_t tab, uint8x8_t idx) +vtbl3_u8 (uint8x8x3_t __tab, uint8x8_t __idx) { - uint8x8_t result; - uint8x16x2_t temp; + uint8x8_t __result; + uint8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_u8 (tab.val[0], tab.val[1]); - temp.val[1] = vcombine_u8 (tab.val[2], vcreate_u8 (__AARCH64_UINT64_C (0x0))); + __temp.val[0] = vcombine_u8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_u8 (__tab.val[2], vcreate_u8 (__AARCH64_UINT64_C (0x0))); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = (uint8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = (uint8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl3_p8 (poly8x8x3_t tab, uint8x8_t idx) +vtbl3_p8 (poly8x8x3_t __tab, uint8x8_t __idx) { - poly8x8_t result; - poly8x16x2_t temp; + poly8x8_t __result; + poly8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_p8 (tab.val[0], tab.val[1]); - temp.val[1] = vcombine_p8 (tab.val[2], vcreate_p8 (__AARCH64_UINT64_C (0x0))); + __temp.val[0] = vcombine_p8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_p8 (__tab.val[2], vcreate_p8 (__AARCH64_UINT64_C (0x0))); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = (poly8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = (poly8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl4_s8 (int8x8x4_t tab, int8x8_t idx) +vtbl4_s8 (int8x8x4_t __tab, int8x8_t __idx) { - int8x8_t result; - int8x16x2_t temp; + int8x8_t __result; + int8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_s8 (tab.val[0], tab.val[1]); - temp.val[1] = vcombine_s8 (tab.val[2], tab.val[3]); + __temp.val[0] = vcombine_s8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_s8 (__tab.val[2], __tab.val[3]); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = __builtin_aarch64_tbl3v8qi (__o, idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = __builtin_aarch64_tbl3v8qi (__o, __idx); + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl4_u8 (uint8x8x4_t tab, uint8x8_t idx) +vtbl4_u8 (uint8x8x4_t __tab, uint8x8_t __idx) { - uint8x8_t result; - uint8x16x2_t temp; + uint8x8_t __result; + uint8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_u8 (tab.val[0], tab.val[1]); - temp.val[1] = vcombine_u8 (tab.val[2], tab.val[3]); + __temp.val[0] = vcombine_u8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_u8 (__tab.val[2], __tab.val[3]); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = (uint8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = (uint8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbl4_p8 (poly8x8x4_t tab, uint8x8_t idx) +vtbl4_p8 (poly8x8x4_t __tab, uint8x8_t __idx) { - poly8x8_t result; - poly8x16x2_t temp; + poly8x8_t __result; + poly8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_p8 (tab.val[0], tab.val[1]); - temp.val[1] = vcombine_p8 (tab.val[2], tab.val[3]); + __temp.val[0] = vcombine_p8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_p8 (__tab.val[2], __tab.val[3]); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = (poly8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = (poly8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); + return __result; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbx2_s8 (int8x8_t r, int8x8x2_t tab, int8x8_t idx) +vtbx2_s8 (int8x8_t __r, int8x8x2_t __tab, int8x8_t __idx) { - int8x8_t result = r; - int8x16_t temp = vcombine_s8 (tab.val[0], tab.val[1]); + int8x8_t __result = __r; + int8x16_t __temp = vcombine_s8 (__tab.val[0], __tab.val[1]); __asm__ ("tbx %0.8b, {%1.16b}, %2.8b" - : "+w"(result) - : "w"(temp), "w"(idx) + : "+w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbx2_u8 (uint8x8_t r, uint8x8x2_t tab, uint8x8_t idx) +vtbx2_u8 (uint8x8_t __r, uint8x8x2_t __tab, uint8x8_t __idx) { - uint8x8_t result = r; - uint8x16_t temp = vcombine_u8 (tab.val[0], tab.val[1]); + uint8x8_t __result = __r; + uint8x16_t __temp = vcombine_u8 (__tab.val[0], __tab.val[1]); __asm__ ("tbx %0.8b, {%1.16b}, %2.8b" - : "+w"(result) - : "w"(temp), "w"(idx) + : "+w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtbx2_p8 (poly8x8_t r, poly8x8x2_t tab, uint8x8_t idx) +vtbx2_p8 (poly8x8_t __r, poly8x8x2_t __tab, uint8x8_t __idx) { - poly8x8_t result = r; - poly8x16_t temp = vcombine_p8 (tab.val[0], tab.val[1]); + poly8x8_t __result = __r; + poly8x16_t __temp = vcombine_p8 (__tab.val[0], __tab.val[1]); __asm__ ("tbx %0.8b, {%1.16b}, %2.8b" - : "+w"(result) - : "w"(temp), "w"(idx) + : "+w"(__result) + : "w"(__temp), "w"(__idx) : /* No clobbers */); - return result; + return __result; } /* End of temporary inline asm. */ @@ -17063,98 +17063,98 @@ vld1_f16 (const float16_t *__a) __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_f32 (const float32_t *a) +vld1_f32 (const float32_t *__a) { - return __builtin_aarch64_ld1v2sf ((const __builtin_aarch64_simd_sf *) a); + return __builtin_aarch64_ld1v2sf ((const __builtin_aarch64_simd_sf *) __a); } __extension__ extern __inline float64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_f64 (const float64_t *a) +vld1_f64 (const float64_t *__a) { - return (float64x1_t) {*a}; + return (float64x1_t) {*__a}; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_p8 (const poly8_t *a) +vld1_p8 (const poly8_t *__a) { return (poly8x8_t) - __builtin_aarch64_ld1v8qi ((const __builtin_aarch64_simd_qi *) a); + __builtin_aarch64_ld1v8qi ((const __builtin_aarch64_simd_qi *) __a); } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_p16 (const poly16_t *a) +vld1_p16 (const poly16_t *__a) { return (poly16x4_t) - __builtin_aarch64_ld1v4hi ((const __builtin_aarch64_simd_hi *) a); + __builtin_aarch64_ld1v4hi ((const __builtin_aarch64_simd_hi *) __a); } __extension__ extern __inline poly64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_p64 (const poly64_t *a) +vld1_p64 (const poly64_t *__a) { - return (poly64x1_t) {*a}; + return (poly64x1_t) {*__a}; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_s8 (const int8_t *a) +vld1_s8 (const int8_t *__a) { - return __builtin_aarch64_ld1v8qi ((const __builtin_aarch64_simd_qi *) a); + return __builtin_aarch64_ld1v8qi ((const __builtin_aarch64_simd_qi *) __a); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_s16 (const int16_t *a) +vld1_s16 (const int16_t *__a) { - return __builtin_aarch64_ld1v4hi ((const __builtin_aarch64_simd_hi *) a); + return __builtin_aarch64_ld1v4hi ((const __builtin_aarch64_simd_hi *) __a); } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_s32 (const int32_t *a) +vld1_s32 (const int32_t *__a) { - return __builtin_aarch64_ld1v2si ((const __builtin_aarch64_simd_si *) a); + return __builtin_aarch64_ld1v2si ((const __builtin_aarch64_simd_si *) __a); } __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_s64 (const int64_t *a) +vld1_s64 (const int64_t *__a) { - return (int64x1_t) {*a}; + return (int64x1_t) {*__a}; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_u8 (const uint8_t *a) +vld1_u8 (const uint8_t *__a) { return (uint8x8_t) - __builtin_aarch64_ld1v8qi ((const __builtin_aarch64_simd_qi *) a); + __builtin_aarch64_ld1v8qi ((const __builtin_aarch64_simd_qi *) __a); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_u16 (const uint16_t *a) +vld1_u16 (const uint16_t *__a) { return (uint16x4_t) - __builtin_aarch64_ld1v4hi ((const __builtin_aarch64_simd_hi *) a); + __builtin_aarch64_ld1v4hi ((const __builtin_aarch64_simd_hi *) __a); } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_u32 (const uint32_t *a) +vld1_u32 (const uint32_t *__a) { return (uint32x2_t) - __builtin_aarch64_ld1v2si ((const __builtin_aarch64_simd_si *) a); + __builtin_aarch64_ld1v2si ((const __builtin_aarch64_simd_si *) __a); } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1_u64 (const uint64_t *a) +vld1_u64 (const uint64_t *__a) { - return (uint64x1_t) {*a}; + return (uint64x1_t) {*__a}; } /* vld1x3 */ @@ -17536,76 +17536,76 @@ vld1q_f16 (const float16_t *__a) __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_f32 (const float32_t *a) +vld1q_f32 (const float32_t *__a) { - return __builtin_aarch64_ld1v4sf ((const __builtin_aarch64_simd_sf *) a); + return __builtin_aarch64_ld1v4sf ((const __builtin_aarch64_simd_sf *) __a); } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_f64 (const float64_t *a) +vld1q_f64 (const float64_t *__a) { - return __builtin_aarch64_ld1v2df ((const __builtin_aarch64_simd_df *) a); + return __builtin_aarch64_ld1v2df ((const __builtin_aarch64_simd_df *) __a); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_p8 (const poly8_t *a) +vld1q_p8 (const poly8_t *__a) { return (poly8x16_t) - __builtin_aarch64_ld1v16qi ((const __builtin_aarch64_simd_qi *) a); + __builtin_aarch64_ld1v16qi ((const __builtin_aarch64_simd_qi *) __a); } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_p16 (const poly16_t *a) +vld1q_p16 (const poly16_t *__a) { return (poly16x8_t) - __builtin_aarch64_ld1v8hi ((const __builtin_aarch64_simd_hi *) a); + __builtin_aarch64_ld1v8hi ((const __builtin_aarch64_simd_hi *) __a); } __extension__ extern __inline poly64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_p64 (const poly64_t *a) +vld1q_p64 (const poly64_t *__a) { return (poly64x2_t) - __builtin_aarch64_ld1v2di ((const __builtin_aarch64_simd_di *) a); + __builtin_aarch64_ld1v2di ((const __builtin_aarch64_simd_di *) __a); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_s8 (const int8_t *a) +vld1q_s8 (const int8_t *__a) { - return __builtin_aarch64_ld1v16qi ((const __builtin_aarch64_simd_qi *) a); + return __builtin_aarch64_ld1v16qi ((const __builtin_aarch64_simd_qi *) __a); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_s16 (const int16_t *a) +vld1q_s16 (const int16_t *__a) { - return __builtin_aarch64_ld1v8hi ((const __builtin_aarch64_simd_hi *) a); + return __builtin_aarch64_ld1v8hi ((const __builtin_aarch64_simd_hi *) __a); } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_s32 (const int32_t *a) +vld1q_s32 (const int32_t *__a) { - return __builtin_aarch64_ld1v4si ((const __builtin_aarch64_simd_si *) a); + return __builtin_aarch64_ld1v4si ((const __builtin_aarch64_simd_si *) __a); } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_s64 (const int64_t *a) +vld1q_s64 (const int64_t *__a) { - return __builtin_aarch64_ld1v2di ((const __builtin_aarch64_simd_di *) a); + return __builtin_aarch64_ld1v2di ((const __builtin_aarch64_simd_di *) __a); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_u8 (const uint8_t *a) +vld1q_u8 (const uint8_t *__a) { return (uint8x16_t) - __builtin_aarch64_ld1v16qi ((const __builtin_aarch64_simd_qi *) a); + __builtin_aarch64_ld1v16qi ((const __builtin_aarch64_simd_qi *) __a); } __extension__ extern __inline uint8x8x2_t @@ -17946,26 +17946,26 @@ vld1q_p64_x2 (const poly64_t *__a) __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_u16 (const uint16_t *a) +vld1q_u16 (const uint16_t *__a) { return (uint16x8_t) - __builtin_aarch64_ld1v8hi ((const __builtin_aarch64_simd_hi *) a); + __builtin_aarch64_ld1v8hi ((const __builtin_aarch64_simd_hi *) __a); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_u32 (const uint32_t *a) +vld1q_u32 (const uint32_t *__a) { return (uint32x4_t) - __builtin_aarch64_ld1v4si ((const __builtin_aarch64_simd_si *) a); + __builtin_aarch64_ld1v4si ((const __builtin_aarch64_simd_si *) __a); } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vld1q_u64 (const uint64_t *a) +vld1q_u64 (const uint64_t *__a) { return (uint64x2_t) - __builtin_aarch64_ld1v2di ((const __builtin_aarch64_simd_di *) a); + __builtin_aarch64_ld1v2di ((const __builtin_aarch64_simd_di *) __a); } /* vld1(q)_x4. */ @@ -21397,328 +21397,328 @@ vmulxd_laneq_f64 (float64_t __a, float64x2_t __v, const int __lane) __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_s8 (int8x8_t a, int8x8_t b) +vpmax_s8 (int8x8_t __a, int8x8_t __b) { - return __builtin_aarch64_smaxpv8qi (a, b); + return __builtin_aarch64_smaxpv8qi (__a, __b); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_s16 (int16x4_t a, int16x4_t b) +vpmax_s16 (int16x4_t __a, int16x4_t __b) { - return __builtin_aarch64_smaxpv4hi (a, b); + return __builtin_aarch64_smaxpv4hi (__a, __b); } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_s32 (int32x2_t a, int32x2_t b) +vpmax_s32 (int32x2_t __a, int32x2_t __b) { - return __builtin_aarch64_smaxpv2si (a, b); + return __builtin_aarch64_smaxpv2si (__a, __b); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_u8 (uint8x8_t a, uint8x8_t b) +vpmax_u8 (uint8x8_t __a, uint8x8_t __b) { - return (uint8x8_t) __builtin_aarch64_umaxpv8qi ((int8x8_t) a, - (int8x8_t) b); + return (uint8x8_t) __builtin_aarch64_umaxpv8qi ((int8x8_t) __a, + (int8x8_t) __b); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_u16 (uint16x4_t a, uint16x4_t b) +vpmax_u16 (uint16x4_t __a, uint16x4_t __b) { - return (uint16x4_t) __builtin_aarch64_umaxpv4hi ((int16x4_t) a, - (int16x4_t) b); + return (uint16x4_t) __builtin_aarch64_umaxpv4hi ((int16x4_t) __a, + (int16x4_t) __b); } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_u32 (uint32x2_t a, uint32x2_t b) +vpmax_u32 (uint32x2_t __a, uint32x2_t __b) { - return (uint32x2_t) __builtin_aarch64_umaxpv2si ((int32x2_t) a, - (int32x2_t) b); + return (uint32x2_t) __builtin_aarch64_umaxpv2si ((int32x2_t) __a, + (int32x2_t) __b); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_s8 (int8x16_t a, int8x16_t b) +vpmaxq_s8 (int8x16_t __a, int8x16_t __b) { - return __builtin_aarch64_smaxpv16qi (a, b); + return __builtin_aarch64_smaxpv16qi (__a, __b); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_s16 (int16x8_t a, int16x8_t b) +vpmaxq_s16 (int16x8_t __a, int16x8_t __b) { - return __builtin_aarch64_smaxpv8hi (a, b); + return __builtin_aarch64_smaxpv8hi (__a, __b); } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_s32 (int32x4_t a, int32x4_t b) +vpmaxq_s32 (int32x4_t __a, int32x4_t __b) { - return __builtin_aarch64_smaxpv4si (a, b); + return __builtin_aarch64_smaxpv4si (__a, __b); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_u8 (uint8x16_t a, uint8x16_t b) +vpmaxq_u8 (uint8x16_t __a, uint8x16_t __b) { - return (uint8x16_t) __builtin_aarch64_umaxpv16qi ((int8x16_t) a, - (int8x16_t) b); + return (uint8x16_t) __builtin_aarch64_umaxpv16qi ((int8x16_t) __a, + (int8x16_t) __b); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_u16 (uint16x8_t a, uint16x8_t b) +vpmaxq_u16 (uint16x8_t __a, uint16x8_t __b) { - return (uint16x8_t) __builtin_aarch64_umaxpv8hi ((int16x8_t) a, - (int16x8_t) b); + return (uint16x8_t) __builtin_aarch64_umaxpv8hi ((int16x8_t) __a, + (int16x8_t) __b); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_u32 (uint32x4_t a, uint32x4_t b) +vpmaxq_u32 (uint32x4_t __a, uint32x4_t __b) { - return (uint32x4_t) __builtin_aarch64_umaxpv4si ((int32x4_t) a, - (int32x4_t) b); + return (uint32x4_t) __builtin_aarch64_umaxpv4si ((int32x4_t) __a, + (int32x4_t) __b); } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_f32 (float32x2_t a, float32x2_t b) +vpmax_f32 (float32x2_t __a, float32x2_t __b) { - return __builtin_aarch64_smax_nanpv2sf (a, b); + return __builtin_aarch64_smax_nanpv2sf (__a, __b); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_f32 (float32x4_t a, float32x4_t b) +vpmaxq_f32 (float32x4_t __a, float32x4_t __b) { - return __builtin_aarch64_smax_nanpv4sf (a, b); + return __builtin_aarch64_smax_nanpv4sf (__a, __b); } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_f64 (float64x2_t a, float64x2_t b) +vpmaxq_f64 (float64x2_t __a, float64x2_t __b) { - return __builtin_aarch64_smax_nanpv2df (a, b); + return __builtin_aarch64_smax_nanpv2df (__a, __b); } __extension__ extern __inline float64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxqd_f64 (float64x2_t a) +vpmaxqd_f64 (float64x2_t __a) { - return __builtin_aarch64_reduc_smax_nan_scal_v2df (a); + return __builtin_aarch64_reduc_smax_nan_scal_v2df (__a); } __extension__ extern __inline float32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxs_f32 (float32x2_t a) +vpmaxs_f32 (float32x2_t __a) { - return __builtin_aarch64_reduc_smax_nan_scal_v2sf (a); + return __builtin_aarch64_reduc_smax_nan_scal_v2sf (__a); } /* vpmaxnm */ __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnm_f32 (float32x2_t a, float32x2_t b) +vpmaxnm_f32 (float32x2_t __a, float32x2_t __b) { - return __builtin_aarch64_smaxpv2sf (a, b); + return __builtin_aarch64_smaxpv2sf (__a, __b); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnmq_f32 (float32x4_t a, float32x4_t b) +vpmaxnmq_f32 (float32x4_t __a, float32x4_t __b) { - return __builtin_aarch64_smaxpv4sf (a, b); + return __builtin_aarch64_smaxpv4sf (__a, __b); } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnmq_f64 (float64x2_t a, float64x2_t b) +vpmaxnmq_f64 (float64x2_t __a, float64x2_t __b) { - return __builtin_aarch64_smaxpv2df (a, b); + return __builtin_aarch64_smaxpv2df (__a, __b); } __extension__ extern __inline float64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnmqd_f64 (float64x2_t a) +vpmaxnmqd_f64 (float64x2_t __a) { - return __builtin_aarch64_reduc_smax_scal_v2df (a); + return __builtin_aarch64_reduc_smax_scal_v2df (__a); } __extension__ extern __inline float32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnms_f32 (float32x2_t a) +vpmaxnms_f32 (float32x2_t __a) { - return __builtin_aarch64_reduc_smax_scal_v2sf (a); + return __builtin_aarch64_reduc_smax_scal_v2sf (__a); } /* vpmin */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_s8 (int8x8_t a, int8x8_t b) +vpmin_s8 (int8x8_t __a, int8x8_t __b) { - return __builtin_aarch64_sminpv8qi (a, b); + return __builtin_aarch64_sminpv8qi (__a, __b); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_s16 (int16x4_t a, int16x4_t b) +vpmin_s16 (int16x4_t __a, int16x4_t __b) { - return __builtin_aarch64_sminpv4hi (a, b); + return __builtin_aarch64_sminpv4hi (__a, __b); } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_s32 (int32x2_t a, int32x2_t b) +vpmin_s32 (int32x2_t __a, int32x2_t __b) { - return __builtin_aarch64_sminpv2si (a, b); + return __builtin_aarch64_sminpv2si (__a, __b); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_u8 (uint8x8_t a, uint8x8_t b) +vpmin_u8 (uint8x8_t __a, uint8x8_t __b) { - return (uint8x8_t) __builtin_aarch64_uminpv8qi ((int8x8_t) a, - (int8x8_t) b); + return (uint8x8_t) __builtin_aarch64_uminpv8qi ((int8x8_t) __a, + (int8x8_t) __b); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_u16 (uint16x4_t a, uint16x4_t b) +vpmin_u16 (uint16x4_t __a, uint16x4_t __b) { - return (uint16x4_t) __builtin_aarch64_uminpv4hi ((int16x4_t) a, - (int16x4_t) b); + return (uint16x4_t) __builtin_aarch64_uminpv4hi ((int16x4_t) __a, + (int16x4_t) __b); } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_u32 (uint32x2_t a, uint32x2_t b) +vpmin_u32 (uint32x2_t __a, uint32x2_t __b) { - return (uint32x2_t) __builtin_aarch64_uminpv2si ((int32x2_t) a, - (int32x2_t) b); + return (uint32x2_t) __builtin_aarch64_uminpv2si ((int32x2_t) __a, + (int32x2_t) __b); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_s8 (int8x16_t a, int8x16_t b) +vpminq_s8 (int8x16_t __a, int8x16_t __b) { - return __builtin_aarch64_sminpv16qi (a, b); + return __builtin_aarch64_sminpv16qi (__a, __b); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_s16 (int16x8_t a, int16x8_t b) +vpminq_s16 (int16x8_t __a, int16x8_t __b) { - return __builtin_aarch64_sminpv8hi (a, b); + return __builtin_aarch64_sminpv8hi (__a, __b); } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_s32 (int32x4_t a, int32x4_t b) +vpminq_s32 (int32x4_t __a, int32x4_t __b) { - return __builtin_aarch64_sminpv4si (a, b); + return __builtin_aarch64_sminpv4si (__a, __b); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_u8 (uint8x16_t a, uint8x16_t b) +vpminq_u8 (uint8x16_t __a, uint8x16_t __b) { - return (uint8x16_t) __builtin_aarch64_uminpv16qi ((int8x16_t) a, - (int8x16_t) b); + return (uint8x16_t) __builtin_aarch64_uminpv16qi ((int8x16_t) __a, + (int8x16_t) __b); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_u16 (uint16x8_t a, uint16x8_t b) +vpminq_u16 (uint16x8_t __a, uint16x8_t __b) { - return (uint16x8_t) __builtin_aarch64_uminpv8hi ((int16x8_t) a, - (int16x8_t) b); + return (uint16x8_t) __builtin_aarch64_uminpv8hi ((int16x8_t) __a, + (int16x8_t) __b); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_u32 (uint32x4_t a, uint32x4_t b) +vpminq_u32 (uint32x4_t __a, uint32x4_t __b) { - return (uint32x4_t) __builtin_aarch64_uminpv4si ((int32x4_t) a, - (int32x4_t) b); + return (uint32x4_t) __builtin_aarch64_uminpv4si ((int32x4_t) __a, + (int32x4_t) __b); } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_f32 (float32x2_t a, float32x2_t b) +vpmin_f32 (float32x2_t __a, float32x2_t __b) { - return __builtin_aarch64_smin_nanpv2sf (a, b); + return __builtin_aarch64_smin_nanpv2sf (__a, __b); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_f32 (float32x4_t a, float32x4_t b) +vpminq_f32 (float32x4_t __a, float32x4_t __b) { - return __builtin_aarch64_smin_nanpv4sf (a, b); + return __builtin_aarch64_smin_nanpv4sf (__a, __b); } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_f64 (float64x2_t a, float64x2_t b) +vpminq_f64 (float64x2_t __a, float64x2_t __b) { - return __builtin_aarch64_smin_nanpv2df (a, b); + return __builtin_aarch64_smin_nanpv2df (__a, __b); } __extension__ extern __inline float64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminqd_f64 (float64x2_t a) +vpminqd_f64 (float64x2_t __a) { - return __builtin_aarch64_reduc_smin_nan_scal_v2df (a); + return __builtin_aarch64_reduc_smin_nan_scal_v2df (__a); } __extension__ extern __inline float32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmins_f32 (float32x2_t a) +vpmins_f32 (float32x2_t __a) { - return __builtin_aarch64_reduc_smin_nan_scal_v2sf (a); + return __builtin_aarch64_reduc_smin_nan_scal_v2sf (__a); } /* vpminnm */ __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnm_f32 (float32x2_t a, float32x2_t b) +vpminnm_f32 (float32x2_t __a, float32x2_t __b) { - return __builtin_aarch64_sminpv2sf (a, b); + return __builtin_aarch64_sminpv2sf (__a, __b); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnmq_f32 (float32x4_t a, float32x4_t b) +vpminnmq_f32 (float32x4_t __a, float32x4_t __b) { - return __builtin_aarch64_sminpv4sf (a, b); + return __builtin_aarch64_sminpv4sf (__a, __b); } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnmq_f64 (float64x2_t a, float64x2_t b) +vpminnmq_f64 (float64x2_t __a, float64x2_t __b) { - return __builtin_aarch64_sminpv2df (a, b); + return __builtin_aarch64_sminpv2df (__a, __b); } __extension__ extern __inline float64_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnmqd_f64 (float64x2_t a) +vpminnmqd_f64 (float64x2_t __a) { - return __builtin_aarch64_reduc_smin_scal_v2df (a); + return __builtin_aarch64_reduc_smin_scal_v2df (__a); } __extension__ extern __inline float32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnms_f32 (float32x2_t a) +vpminnms_f32 (float32x2_t __a) { - return __builtin_aarch64_reduc_smin_scal_v2sf (a); + return __builtin_aarch64_reduc_smin_scal_v2sf (__a); } /* vmaxnm */ @@ -22171,9 +22171,9 @@ vminnmvq_f64 (float64x2_t __a) __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmla_f32 (float32x2_t a, float32x2_t b, float32x2_t c) +vmla_f32 (float32x2_t __a, float32x2_t __b, float32x2_t __c) { - return a + b * c; + return __a + __b * __c; } __extension__ extern __inline float64x1_t @@ -22185,16 +22185,16 @@ vmla_f64 (float64x1_t __a, float64x1_t __b, float64x1_t __c) __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) +vmlaq_f32 (float32x4_t __a, float32x4_t __b, float32x4_t __c) { - return a + b * c; + return __a + __b * __c; } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) +vmlaq_f64 (float64x2_t __a, float64x2_t __b, float64x2_t __c) { - return a + b * c; + return __a + __b * __c; } /* vmla_lane */ @@ -22369,9 +22369,9 @@ vmlaq_laneq_u32 (uint32x4_t __a, uint32x4_t __b, __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmls_f32 (float32x2_t a, float32x2_t b, float32x2_t c) +vmls_f32 (float32x2_t __a, float32x2_t __b, float32x2_t __c) { - return a - b * c; + return __a - __b * __c; } __extension__ extern __inline float64x1_t @@ -22383,16 +22383,16 @@ vmls_f64 (float64x1_t __a, float64x1_t __b, float64x1_t __c) __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) +vmlsq_f32 (float32x4_t __a, float32x4_t __b, float32x4_t __c) { - return a - b * c; + return __a - __b * __c; } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmlsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) +vmlsq_f64 (float64x2_t __a, float64x2_t __b, float64x2_t __c) { - return a - b * c; + return __a - __b * __c; } /* vmls_lane */ @@ -25156,419 +25156,419 @@ vqsubd_u64 (uint64_t __a, uint64_t __b) __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl2_s8 (int8x16x2_t tab, uint8x8_t idx) +vqtbl2_s8 (int8x16x2_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, tab.val[1], 1); - return __builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, __tab.val[1], 1); + return __builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl2_u8 (uint8x16x2_t tab, uint8x8_t idx) +vqtbl2_u8 (uint8x16x2_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (uint8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (uint8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl2_p8 (poly8x16x2_t tab, uint8x8_t idx) +vqtbl2_p8 (poly8x16x2_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (poly8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (poly8x8_t)__builtin_aarch64_tbl3v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl2q_s8 (int8x16x2_t tab, uint8x16_t idx) +vqtbl2q_s8 (int8x16x2_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return __builtin_aarch64_tbl3v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return __builtin_aarch64_tbl3v16qi (__o, (int8x16_t)__idx); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl2q_u8 (uint8x16x2_t tab, uint8x16_t idx) +vqtbl2q_u8 (uint8x16x2_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (uint8x16_t)__builtin_aarch64_tbl3v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (uint8x16_t)__builtin_aarch64_tbl3v16qi (__o, (int8x16_t)__idx); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl2q_p8 (poly8x16x2_t tab, uint8x16_t idx) +vqtbl2q_p8 (poly8x16x2_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (poly8x16_t)__builtin_aarch64_tbl3v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (poly8x16_t)__builtin_aarch64_tbl3v16qi (__o, (int8x16_t)__idx); } /* vqtbl3 */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl3_s8 (int8x16x3_t tab, uint8x8_t idx) +vqtbl3_s8 (int8x16x3_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return __builtin_aarch64_qtbl3v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return __builtin_aarch64_qtbl3v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl3_u8 (uint8x16x3_t tab, uint8x8_t idx) +vqtbl3_u8 (uint8x16x3_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (uint8x8_t)__builtin_aarch64_qtbl3v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (uint8x8_t)__builtin_aarch64_qtbl3v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl3_p8 (poly8x16x3_t tab, uint8x8_t idx) +vqtbl3_p8 (poly8x16x3_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (poly8x8_t)__builtin_aarch64_qtbl3v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (poly8x8_t)__builtin_aarch64_qtbl3v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl3q_s8 (int8x16x3_t tab, uint8x16_t idx) +vqtbl3q_s8 (int8x16x3_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return __builtin_aarch64_qtbl3v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return __builtin_aarch64_qtbl3v16qi (__o, (int8x16_t)__idx); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl3q_u8 (uint8x16x3_t tab, uint8x16_t idx) +vqtbl3q_u8 (uint8x16x3_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (uint8x16_t)__builtin_aarch64_qtbl3v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (uint8x16_t)__builtin_aarch64_qtbl3v16qi (__o, (int8x16_t)__idx); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl3q_p8 (poly8x16x3_t tab, uint8x16_t idx) +vqtbl3q_p8 (poly8x16x3_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (poly8x16_t)__builtin_aarch64_qtbl3v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (poly8x16_t)__builtin_aarch64_qtbl3v16qi (__o, (int8x16_t)__idx); } /* vqtbl4 */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl4_s8 (int8x16x4_t tab, uint8x8_t idx) +vqtbl4_s8 (int8x16x4_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return __builtin_aarch64_qtbl4v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return __builtin_aarch64_qtbl4v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl4_u8 (uint8x16x4_t tab, uint8x8_t idx) +vqtbl4_u8 (uint8x16x4_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (uint8x8_t)__builtin_aarch64_qtbl4v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (uint8x8_t)__builtin_aarch64_qtbl4v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl4_p8 (poly8x16x4_t tab, uint8x8_t idx) +vqtbl4_p8 (poly8x16x4_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (poly8x8_t)__builtin_aarch64_qtbl4v8qi (__o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (poly8x8_t)__builtin_aarch64_qtbl4v8qi (__o, (int8x8_t)__idx); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl4q_s8 (int8x16x4_t tab, uint8x16_t idx) +vqtbl4q_s8 (int8x16x4_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return __builtin_aarch64_qtbl4v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return __builtin_aarch64_qtbl4v16qi (__o, (int8x16_t)__idx); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl4q_u8 (uint8x16x4_t tab, uint8x16_t idx) +vqtbl4q_u8 (uint8x16x4_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (uint8x16_t)__builtin_aarch64_qtbl4v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (uint8x16_t)__builtin_aarch64_qtbl4v16qi (__o, (int8x16_t)__idx); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbl4q_p8 (poly8x16x4_t tab, uint8x16_t idx) +vqtbl4q_p8 (poly8x16x4_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (poly8x16_t)__builtin_aarch64_qtbl4v16qi (__o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (poly8x16_t)__builtin_aarch64_qtbl4v16qi (__o, (int8x16_t)__idx); } /* vqtbx2 */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx2_s8 (int8x8_t r, int8x16x2_t tab, uint8x8_t idx) +vqtbx2_s8 (int8x8_t __r, int8x16x2_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, tab.val[1], 1); - return __builtin_aarch64_tbx4v8qi (r, __o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, __tab.val[1], 1); + return __builtin_aarch64_tbx4v8qi (__r, __o, (int8x8_t)__idx); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx2_u8 (uint8x8_t r, uint8x16x2_t tab, uint8x8_t idx) +vqtbx2_u8 (uint8x8_t __r, uint8x16x2_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (uint8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)r, __o, - (int8x8_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (uint8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)__r, __o, + (int8x8_t)__idx); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx2_p8 (poly8x8_t r, poly8x16x2_t tab, uint8x8_t idx) +vqtbx2_p8 (poly8x8_t __r, poly8x16x2_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (poly8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)r, __o, - (int8x8_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (poly8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)__r, __o, + (int8x8_t)__idx); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx2q_s8 (int8x16_t r, int8x16x2_t tab, uint8x16_t idx) +vqtbx2q_s8 (int8x16_t __r, int8x16x2_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, tab.val[1], 1); - return __builtin_aarch64_tbx4v16qi (r, __o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, __tab.val[1], 1); + return __builtin_aarch64_tbx4v16qi (__r, __o, (int8x16_t)__idx); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx2q_u8 (uint8x16_t r, uint8x16x2_t tab, uint8x16_t idx) +vqtbx2q_u8 (uint8x16_t __r, uint8x16x2_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (uint8x16_t)__builtin_aarch64_tbx4v16qi ((int8x16_t)r, __o, - (int8x16_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (uint8x16_t)__builtin_aarch64_tbx4v16qi ((int8x16_t)__r, __o, + (int8x16_t)__idx); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx2q_p8 (poly8x16_t r, poly8x16x2_t tab, uint8x16_t idx) +vqtbx2q_p8 (poly8x16_t __r, poly8x16x2_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)tab.val[1], 1); - return (poly8x16_t)__builtin_aarch64_tbx4v16qi ((int8x16_t)r, __o, - (int8x16_t)idx); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t)__tab.val[1], 1); + return (poly8x16_t)__builtin_aarch64_tbx4v16qi ((int8x16_t)__r, __o, + (int8x16_t)__idx); } /* vqtbx3 */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx3_s8 (int8x8_t r, int8x16x3_t tab, uint8x8_t idx) +vqtbx3_s8 (int8x8_t __r, int8x16x3_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, tab.val[2], 2); - return __builtin_aarch64_qtbx3v8qi (r, __o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, __tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, __tab.val[2], 2); + return __builtin_aarch64_qtbx3v8qi (__r, __o, (int8x8_t)__idx); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx3_u8 (uint8x8_t r, uint8x16x3_t tab, uint8x8_t idx) +vqtbx3_u8 (uint8x8_t __r, uint8x16x3_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (uint8x8_t)__builtin_aarch64_qtbx3v8qi ((int8x8_t)r, __o, - (int8x8_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (uint8x8_t)__builtin_aarch64_qtbx3v8qi ((int8x8_t)__r, __o, + (int8x8_t)__idx); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx3_p8 (poly8x8_t r, poly8x16x3_t tab, uint8x8_t idx) +vqtbx3_p8 (poly8x8_t __r, poly8x16x3_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (poly8x8_t)__builtin_aarch64_qtbx3v8qi ((int8x8_t)r, __o, - (int8x8_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (poly8x8_t)__builtin_aarch64_qtbx3v8qi ((int8x8_t)__r, __o, + (int8x8_t)__idx); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx3q_s8 (int8x16_t r, int8x16x3_t tab, uint8x16_t idx) +vqtbx3q_s8 (int8x16_t __r, int8x16x3_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, tab.val[2], 2); - return __builtin_aarch64_qtbx3v16qi (r, __o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, __tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, __tab.val[2], 2); + return __builtin_aarch64_qtbx3v16qi (__r, __o, (int8x16_t)__idx); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx3q_u8 (uint8x16_t r, uint8x16x3_t tab, uint8x16_t idx) +vqtbx3q_u8 (uint8x16_t __r, uint8x16x3_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (uint8x16_t)__builtin_aarch64_qtbx3v16qi ((int8x16_t)r, __o, - (int8x16_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (uint8x16_t)__builtin_aarch64_qtbx3v16qi ((int8x16_t)__r, __o, + (int8x16_t)__idx); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx3q_p8 (poly8x16_t r, poly8x16x3_t tab, uint8x16_t idx) +vqtbx3q_p8 (poly8x16_t __r, poly8x16x3_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)tab.val[2], 2); - return (poly8x16_t)__builtin_aarch64_qtbx3v16qi ((int8x16_t)r, __o, - (int8x16_t)idx); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t)__tab.val[2], 2); + return (poly8x16_t)__builtin_aarch64_qtbx3v16qi ((int8x16_t)__r, __o, + (int8x16_t)__idx); } /* vqtbx4 */ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx4_s8 (int8x8_t r, int8x16x4_t tab, uint8x8_t idx) +vqtbx4_s8 (int8x8_t __r, int8x16x4_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[3], 3); - return __builtin_aarch64_qtbx4v8qi (r, __o, (int8x8_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[3], 3); + return __builtin_aarch64_qtbx4v8qi (__r, __o, (int8x8_t)__idx); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx4_u8 (uint8x8_t r, uint8x16x4_t tab, uint8x8_t idx) +vqtbx4_u8 (uint8x8_t __r, uint8x16x4_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (uint8x8_t)__builtin_aarch64_qtbx4v8qi ((int8x8_t)r, __o, - (int8x8_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (uint8x8_t)__builtin_aarch64_qtbx4v8qi ((int8x8_t)__r, __o, + (int8x8_t)__idx); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx4_p8 (poly8x8_t r, poly8x16x4_t tab, uint8x8_t idx) +vqtbx4_p8 (poly8x8_t __r, poly8x16x4_t __tab, uint8x8_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (poly8x8_t)__builtin_aarch64_qtbx4v8qi ((int8x8_t)r, __o, - (int8x8_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (poly8x8_t)__builtin_aarch64_qtbx4v8qi ((int8x8_t)__r, __o, + (int8x8_t)__idx); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx4q_s8 (int8x16_t r, int8x16x4_t tab, uint8x16_t idx) +vqtbx4q_s8 (int8x16_t __r, int8x16x4_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, tab.val[3], 3); - return __builtin_aarch64_qtbx4v16qi (r, __o, (int8x16_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, __tab.val[3], 3); + return __builtin_aarch64_qtbx4v16qi (__r, __o, (int8x16_t)__idx); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx4q_u8 (uint8x16_t r, uint8x16x4_t tab, uint8x16_t idx) +vqtbx4q_u8 (uint8x16_t __r, uint8x16x4_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (uint8x16_t)__builtin_aarch64_qtbx4v16qi ((int8x16_t)r, __o, - (int8x16_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (uint8x16_t)__builtin_aarch64_qtbx4v16qi ((int8x16_t)__r, __o, + (int8x16_t)__idx); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vqtbx4q_p8 (poly8x16_t r, poly8x16x4_t tab, uint8x16_t idx) +vqtbx4q_p8 (poly8x16_t __r, poly8x16x4_t __tab, uint8x16_t __idx) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)tab.val[3], 3); - return (poly8x16_t)__builtin_aarch64_qtbx4v16qi ((int8x16_t)r, __o, - (int8x16_t)idx); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t)__tab.val[3], 3); + return (poly8x16_t)__builtin_aarch64_qtbx4v16qi ((int8x16_t)__r, __o, + (int8x16_t)__idx); } /* vrbit */ @@ -25739,134 +25739,134 @@ vrecpxd_f64 (float64_t __a) __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev16_p8 (poly8x8_t a) +vrev16_p8 (poly8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); + return __builtin_shuffle (__a, (uint8x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev16_s8 (int8x8_t a) +vrev16_s8 (int8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); + return __builtin_shuffle (__a, (uint8x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev16_u8 (uint8x8_t a) +vrev16_u8 (uint8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); + return __builtin_shuffle (__a, (uint8x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev16q_p8 (poly8x16_t a) +vrev16q_p8 (poly8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 }); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev16q_s8 (int8x16_t a) +vrev16q_s8 (int8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 }); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev16q_u8 (uint8x16_t a) +vrev16q_u8 (uint8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 }); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32_p8 (poly8x8_t a) +vrev32_p8 (poly8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); + return __builtin_shuffle (__a, (uint8x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32_p16 (poly16x4_t a) +vrev32_p16 (poly16x4_t __a) { - return __builtin_shuffle (a, (uint16x4_t) { 1, 0, 3, 2 }); + return __builtin_shuffle (__a, (uint16x4_t) { 1, 0, 3, 2 }); } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32_s8 (int8x8_t a) +vrev32_s8 (int8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); + return __builtin_shuffle (__a, (uint8x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32_s16 (int16x4_t a) +vrev32_s16 (int16x4_t __a) { - return __builtin_shuffle (a, (uint16x4_t) { 1, 0, 3, 2 }); + return __builtin_shuffle (__a, (uint16x4_t) { 1, 0, 3, 2 }); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32_u8 (uint8x8_t a) +vrev32_u8 (uint8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); + return __builtin_shuffle (__a, (uint8x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32_u16 (uint16x4_t a) +vrev32_u16 (uint16x4_t __a) { - return __builtin_shuffle (a, (uint16x4_t) { 1, 0, 3, 2 }); + return __builtin_shuffle (__a, (uint16x4_t) { 1, 0, 3, 2 }); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32q_p8 (poly8x16_t a) +vrev32q_p8 (poly8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 }); } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32q_p16 (poly16x8_t a) +vrev32q_p16 (poly16x8_t __a) { - return __builtin_shuffle (a, (uint16x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); + return __builtin_shuffle (__a, (uint16x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32q_s8 (int8x16_t a) +vrev32q_s8 (int8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 }); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32q_s16 (int16x8_t a) +vrev32q_s16 (int16x8_t __a) { - return __builtin_shuffle (a, (uint16x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); + return __builtin_shuffle (__a, (uint16x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32q_u8 (uint8x16_t a) +vrev32q_u8 (uint8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 }); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev32q_u16 (uint16x8_t a) +vrev32q_u16 (uint16x8_t __a) { - return __builtin_shuffle (a, (uint16x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); + return __builtin_shuffle (__a, (uint16x8_t) { 1, 0, 3, 2, 5, 4, 7, 6 }); } __extension__ extern __inline float16x4_t @@ -25878,65 +25878,65 @@ vrev64_f16 (float16x4_t __a) __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_f32 (float32x2_t a) +vrev64_f32 (float32x2_t __a) { - return __builtin_shuffle (a, (uint32x2_t) { 1, 0 }); + return __builtin_shuffle (__a, (uint32x2_t) { 1, 0 }); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_p8 (poly8x8_t a) +vrev64_p8 (poly8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 7, 6, 5, 4, 3, 2, 1, 0 }); + return __builtin_shuffle (__a, (uint8x8_t) { 7, 6, 5, 4, 3, 2, 1, 0 }); } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_p16 (poly16x4_t a) +vrev64_p16 (poly16x4_t __a) { - return __builtin_shuffle (a, (uint16x4_t) { 3, 2, 1, 0 }); + return __builtin_shuffle (__a, (uint16x4_t) { 3, 2, 1, 0 }); } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_s8 (int8x8_t a) +vrev64_s8 (int8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 7, 6, 5, 4, 3, 2, 1, 0 }); + return __builtin_shuffle (__a, (uint8x8_t) { 7, 6, 5, 4, 3, 2, 1, 0 }); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_s16 (int16x4_t a) +vrev64_s16 (int16x4_t __a) { - return __builtin_shuffle (a, (uint16x4_t) { 3, 2, 1, 0 }); + return __builtin_shuffle (__a, (uint16x4_t) { 3, 2, 1, 0 }); } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_s32 (int32x2_t a) +vrev64_s32 (int32x2_t __a) { - return __builtin_shuffle (a, (uint32x2_t) { 1, 0 }); + return __builtin_shuffle (__a, (uint32x2_t) { 1, 0 }); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_u8 (uint8x8_t a) +vrev64_u8 (uint8x8_t __a) { - return __builtin_shuffle (a, (uint8x8_t) { 7, 6, 5, 4, 3, 2, 1, 0 }); + return __builtin_shuffle (__a, (uint8x8_t) { 7, 6, 5, 4, 3, 2, 1, 0 }); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_u16 (uint16x4_t a) +vrev64_u16 (uint16x4_t __a) { - return __builtin_shuffle (a, (uint16x4_t) { 3, 2, 1, 0 }); + return __builtin_shuffle (__a, (uint16x4_t) { 3, 2, 1, 0 }); } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64_u32 (uint32x2_t a) +vrev64_u32 (uint32x2_t __a) { - return __builtin_shuffle (a, (uint32x2_t) { 1, 0 }); + return __builtin_shuffle (__a, (uint32x2_t) { 1, 0 }); } __extension__ extern __inline float16x8_t @@ -25948,68 +25948,68 @@ vrev64q_f16 (float16x8_t __a) __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_f32 (float32x4_t a) +vrev64q_f32 (float32x4_t __a) { - return __builtin_shuffle (a, (uint32x4_t) { 1, 0, 3, 2 }); + return __builtin_shuffle (__a, (uint32x4_t) { 1, 0, 3, 2 }); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_p8 (poly8x16_t a) +vrev64q_p8 (poly8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 }); } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_p16 (poly16x8_t a) +vrev64q_p16 (poly16x8_t __a) { - return __builtin_shuffle (a, (uint16x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); + return __builtin_shuffle (__a, (uint16x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_s8 (int8x16_t a) +vrev64q_s8 (int8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 }); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_s16 (int16x8_t a) +vrev64q_s16 (int16x8_t __a) { - return __builtin_shuffle (a, (uint16x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); + return __builtin_shuffle (__a, (uint16x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_s32 (int32x4_t a) +vrev64q_s32 (int32x4_t __a) { - return __builtin_shuffle (a, (uint32x4_t) { 1, 0, 3, 2 }); + return __builtin_shuffle (__a, (uint32x4_t) { 1, 0, 3, 2 }); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_u8 (uint8x16_t a) +vrev64q_u8 (uint8x16_t __a) { - return __builtin_shuffle (a, + return __builtin_shuffle (__a, (uint8x16_t) { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 }); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_u16 (uint16x8_t a) +vrev64q_u16 (uint16x8_t __a) { - return __builtin_shuffle (a, (uint16x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); + return __builtin_shuffle (__a, (uint16x8_t) { 3, 2, 1, 0, 7, 6, 5, 4 }); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrev64q_u32 (uint32x4_t a) +vrev64q_u32 (uint32x4_t __a) { - return __builtin_shuffle (a, (uint32x4_t) { 1, 0, 3, 2 }); + return __builtin_shuffle (__a, (uint32x4_t) { 1, 0, 3, 2 }); } /* vrnd */ @@ -26702,87 +26702,90 @@ vrsrad_n_u64 (uint64_t __a, uint64_t __b, const int __c) __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha1cq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) +vsha1cq_u32 (uint32x4_t __hash_abcd, uint32_t __hash_e, uint32x4_t __wk) { - return __builtin_aarch64_crypto_sha1cv4si_uuuu (hash_abcd, hash_e, wk); + return __builtin_aarch64_crypto_sha1cv4si_uuuu (__hash_abcd, __hash_e, __wk); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha1mq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) +vsha1mq_u32 (uint32x4_t __hash_abcd, uint32_t __hash_e, uint32x4_t __wk) { - return __builtin_aarch64_crypto_sha1mv4si_uuuu (hash_abcd, hash_e, wk); + return __builtin_aarch64_crypto_sha1mv4si_uuuu (__hash_abcd, __hash_e, __wk); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha1pq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) +vsha1pq_u32 (uint32x4_t __hash_abcd, uint32_t __hash_e, uint32x4_t __wk) { - return __builtin_aarch64_crypto_sha1pv4si_uuuu (hash_abcd, hash_e, wk); + return __builtin_aarch64_crypto_sha1pv4si_uuuu (__hash_abcd, __hash_e, __wk); } __extension__ extern __inline uint32_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha1h_u32 (uint32_t hash_e) +vsha1h_u32 (uint32_t __hash_e) { - return __builtin_aarch64_crypto_sha1hsi_uu (hash_e); + return __builtin_aarch64_crypto_sha1hsi_uu (__hash_e); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha1su0q_u32 (uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11) +vsha1su0q_u32 (uint32x4_t __w0_3, uint32x4_t __w4_7, uint32x4_t __w8_11) { - return __builtin_aarch64_crypto_sha1su0v4si_uuuu (w0_3, w4_7, w8_11); + return __builtin_aarch64_crypto_sha1su0v4si_uuuu (__w0_3, __w4_7, __w8_11); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha1su1q_u32 (uint32x4_t tw0_3, uint32x4_t w12_15) +vsha1su1q_u32 (uint32x4_t __tw0_3, uint32x4_t __w12_15) { - return __builtin_aarch64_crypto_sha1su1v4si_uuu (tw0_3, w12_15); + return __builtin_aarch64_crypto_sha1su1v4si_uuu (__tw0_3, __w12_15); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha256hq_u32 (uint32x4_t hash_abcd, uint32x4_t hash_efgh, uint32x4_t wk) +vsha256hq_u32 (uint32x4_t __hash_abcd, uint32x4_t __hash_efgh, uint32x4_t __wk) { - return __builtin_aarch64_crypto_sha256hv4si_uuuu (hash_abcd, hash_efgh, wk); + return __builtin_aarch64_crypto_sha256hv4si_uuuu (__hash_abcd, __hash_efgh, + __wk); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha256h2q_u32 (uint32x4_t hash_efgh, uint32x4_t hash_abcd, uint32x4_t wk) +vsha256h2q_u32 (uint32x4_t __hash_efgh, uint32x4_t __hash_abcd, uint32x4_t __wk) { - return __builtin_aarch64_crypto_sha256h2v4si_uuuu (hash_efgh, hash_abcd, wk); + return __builtin_aarch64_crypto_sha256h2v4si_uuuu (__hash_efgh, __hash_abcd, + __wk); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha256su0q_u32 (uint32x4_t w0_3, uint32x4_t w4_7) +vsha256su0q_u32 (uint32x4_t __w0_3, uint32x4_t __w4_7) { - return __builtin_aarch64_crypto_sha256su0v4si_uuu (w0_3, w4_7); + return __builtin_aarch64_crypto_sha256su0v4si_uuu (__w0_3, __w4_7); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsha256su1q_u32 (uint32x4_t tw0_3, uint32x4_t w8_11, uint32x4_t w12_15) +vsha256su1q_u32 (uint32x4_t __tw0_3, uint32x4_t __w8_11, uint32x4_t __w12_15) { - return __builtin_aarch64_crypto_sha256su1v4si_uuuu (tw0_3, w8_11, w12_15); + return __builtin_aarch64_crypto_sha256su1v4si_uuuu (__tw0_3, __w8_11, + __w12_15); } __extension__ extern __inline poly128_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_p64 (poly64_t a, poly64_t b) +vmull_p64 (poly64_t __a, poly64_t __b) { return - __builtin_aarch64_crypto_pmulldi_ppp (a, b); + __builtin_aarch64_crypto_pmulldi_ppp (__a, __b); } __extension__ extern __inline poly128_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vmull_high_p64 (poly64x2_t a, poly64x2_t b) +vmull_high_p64 (poly64x2_t __a, poly64x2_t __b) { - return __builtin_aarch64_crypto_pmullv2di_ppp (a, b); + return __builtin_aarch64_crypto_pmullv2di_ppp (__a, __b); } #pragma GCC pop_options @@ -27484,30 +27487,30 @@ vsqaddd_u64 (uint64_t __a, int64_t __b) /* vsqrt */ __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsqrt_f32 (float32x2_t a) +vsqrt_f32 (float32x2_t __a) { - return __builtin_aarch64_sqrtv2sf (a); + return __builtin_aarch64_sqrtv2sf (__a); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsqrtq_f32 (float32x4_t a) +vsqrtq_f32 (float32x4_t __a) { - return __builtin_aarch64_sqrtv4sf (a); + return __builtin_aarch64_sqrtv4sf (__a); } __extension__ extern __inline float64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsqrt_f64 (float64x1_t a) +vsqrt_f64 (float64x1_t __a) { - return (float64x1_t) { __builtin_aarch64_sqrtdf (a[0]) }; + return (float64x1_t) { __builtin_aarch64_sqrtdf (__a[0]) }; } __extension__ extern __inline float64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsqrtq_f64 (float64x2_t a) +vsqrtq_f64 (float64x2_t __a) { - return __builtin_aarch64_sqrtv2df (a); + return __builtin_aarch64_sqrtv2df (__a); } /* vsra */ @@ -27777,98 +27780,98 @@ vst1_f16 (float16_t *__a, float16x4_t __b) __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f32 (float32_t *a, float32x2_t b) +vst1_f32 (float32_t *__a, float32x2_t __b) { - __builtin_aarch64_st1v2sf ((__builtin_aarch64_simd_sf *) a, b); + __builtin_aarch64_st1v2sf ((__builtin_aarch64_simd_sf *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f64 (float64_t *a, float64x1_t b) +vst1_f64 (float64_t *__a, float64x1_t __b) { - *a = b[0]; + *__a = __b[0]; } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p8 (poly8_t *a, poly8x8_t b) +vst1_p8 (poly8_t *__a, poly8x8_t __b) { - __builtin_aarch64_st1v8qi ((__builtin_aarch64_simd_qi *) a, - (int8x8_t) b); + __builtin_aarch64_st1v8qi ((__builtin_aarch64_simd_qi *) __a, + (int8x8_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p16 (poly16_t *a, poly16x4_t b) +vst1_p16 (poly16_t *__a, poly16x4_t __b) { - __builtin_aarch64_st1v4hi ((__builtin_aarch64_simd_hi *) a, - (int16x4_t) b); + __builtin_aarch64_st1v4hi ((__builtin_aarch64_simd_hi *) __a, + (int16x4_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p64 (poly64_t *a, poly64x1_t b) +vst1_p64 (poly64_t *__a, poly64x1_t __b) { - *a = b[0]; + *__a = __b[0]; } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s8 (int8_t *a, int8x8_t b) +vst1_s8 (int8_t *__a, int8x8_t __b) { - __builtin_aarch64_st1v8qi ((__builtin_aarch64_simd_qi *) a, b); + __builtin_aarch64_st1v8qi ((__builtin_aarch64_simd_qi *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s16 (int16_t *a, int16x4_t b) +vst1_s16 (int16_t *__a, int16x4_t __b) { - __builtin_aarch64_st1v4hi ((__builtin_aarch64_simd_hi *) a, b); + __builtin_aarch64_st1v4hi ((__builtin_aarch64_simd_hi *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s32 (int32_t *a, int32x2_t b) +vst1_s32 (int32_t *__a, int32x2_t __b) { - __builtin_aarch64_st1v2si ((__builtin_aarch64_simd_si *) a, b); + __builtin_aarch64_st1v2si ((__builtin_aarch64_simd_si *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s64 (int64_t *a, int64x1_t b) +vst1_s64 (int64_t *__a, int64x1_t __b) { - *a = b[0]; + *__a = __b[0]; } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u8 (uint8_t *a, uint8x8_t b) +vst1_u8 (uint8_t *__a, uint8x8_t __b) { - __builtin_aarch64_st1v8qi ((__builtin_aarch64_simd_qi *) a, - (int8x8_t) b); + __builtin_aarch64_st1v8qi ((__builtin_aarch64_simd_qi *) __a, + (int8x8_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u16 (uint16_t *a, uint16x4_t b) +vst1_u16 (uint16_t *__a, uint16x4_t __b) { - __builtin_aarch64_st1v4hi ((__builtin_aarch64_simd_hi *) a, - (int16x4_t) b); + __builtin_aarch64_st1v4hi ((__builtin_aarch64_simd_hi *) __a, + (int16x4_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u32 (uint32_t *a, uint32x2_t b) +vst1_u32 (uint32_t *__a, uint32x2_t __b) { - __builtin_aarch64_st1v2si ((__builtin_aarch64_simd_si *) a, - (int32x2_t) b); + __builtin_aarch64_st1v2si ((__builtin_aarch64_simd_si *) __a, + (int32x2_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u64 (uint64_t *a, uint64x1_t b) +vst1_u64 (uint64_t *__a, uint64x1_t __b) { - *a = b[0]; + *__a = __b[0]; } /* vst1q */ @@ -27882,100 +27885,100 @@ vst1q_f16 (float16_t *__a, float16x8_t __b) __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f32 (float32_t *a, float32x4_t b) +vst1q_f32 (float32_t *__a, float32x4_t __b) { - __builtin_aarch64_st1v4sf ((__builtin_aarch64_simd_sf *) a, b); + __builtin_aarch64_st1v4sf ((__builtin_aarch64_simd_sf *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f64 (float64_t *a, float64x2_t b) +vst1q_f64 (float64_t *__a, float64x2_t __b) { - __builtin_aarch64_st1v2df ((__builtin_aarch64_simd_df *) a, b); + __builtin_aarch64_st1v2df ((__builtin_aarch64_simd_df *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p8 (poly8_t *a, poly8x16_t b) +vst1q_p8 (poly8_t *__a, poly8x16_t __b) { - __builtin_aarch64_st1v16qi ((__builtin_aarch64_simd_qi *) a, - (int8x16_t) b); + __builtin_aarch64_st1v16qi ((__builtin_aarch64_simd_qi *) __a, + (int8x16_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p16 (poly16_t *a, poly16x8_t b) +vst1q_p16 (poly16_t *__a, poly16x8_t __b) { - __builtin_aarch64_st1v8hi ((__builtin_aarch64_simd_hi *) a, - (int16x8_t) b); + __builtin_aarch64_st1v8hi ((__builtin_aarch64_simd_hi *) __a, + (int16x8_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p64 (poly64_t *a, poly64x2_t b) +vst1q_p64 (poly64_t *__a, poly64x2_t __b) { - __builtin_aarch64_st1v2di_sp ((__builtin_aarch64_simd_di *) a, - (poly64x2_t) b); + __builtin_aarch64_st1v2di_sp ((__builtin_aarch64_simd_di *) __a, + (poly64x2_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s8 (int8_t *a, int8x16_t b) +vst1q_s8 (int8_t *__a, int8x16_t __b) { - __builtin_aarch64_st1v16qi ((__builtin_aarch64_simd_qi *) a, b); + __builtin_aarch64_st1v16qi ((__builtin_aarch64_simd_qi *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s16 (int16_t *a, int16x8_t b) +vst1q_s16 (int16_t *__a, int16x8_t __b) { - __builtin_aarch64_st1v8hi ((__builtin_aarch64_simd_hi *) a, b); + __builtin_aarch64_st1v8hi ((__builtin_aarch64_simd_hi *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s32 (int32_t *a, int32x4_t b) +vst1q_s32 (int32_t *__a, int32x4_t __b) { - __builtin_aarch64_st1v4si ((__builtin_aarch64_simd_si *) a, b); + __builtin_aarch64_st1v4si ((__builtin_aarch64_simd_si *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s64 (int64_t *a, int64x2_t b) +vst1q_s64 (int64_t *__a, int64x2_t __b) { - __builtin_aarch64_st1v2di ((__builtin_aarch64_simd_di *) a, b); + __builtin_aarch64_st1v2di ((__builtin_aarch64_simd_di *) __a, __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u8 (uint8_t *a, uint8x16_t b) +vst1q_u8 (uint8_t *__a, uint8x16_t __b) { - __builtin_aarch64_st1v16qi ((__builtin_aarch64_simd_qi *) a, - (int8x16_t) b); + __builtin_aarch64_st1v16qi ((__builtin_aarch64_simd_qi *) __a, + (int8x16_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u16 (uint16_t *a, uint16x8_t b) +vst1q_u16 (uint16_t *__a, uint16x8_t __b) { - __builtin_aarch64_st1v8hi ((__builtin_aarch64_simd_hi *) a, - (int16x8_t) b); + __builtin_aarch64_st1v8hi ((__builtin_aarch64_simd_hi *) __a, + (int16x8_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u32 (uint32_t *a, uint32x4_t b) +vst1q_u32 (uint32_t *__a, uint32x4_t __b) { - __builtin_aarch64_st1v4si ((__builtin_aarch64_simd_si *) a, - (int32x4_t) b); + __builtin_aarch64_st1v4si ((__builtin_aarch64_simd_si *) __a, + (int32x4_t) __b); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u64 (uint64_t *a, uint64x2_t b) +vst1q_u64 (uint64_t *__a, uint64x2_t __b) { - __builtin_aarch64_st1v2di ((__builtin_aarch64_simd_di *) a, - (int64x2_t) b); + __builtin_aarch64_st1v2di ((__builtin_aarch64_simd_di *) __a, + (int64x2_t) __b); } /* vst1_lane */ @@ -28182,327 +28185,343 @@ vst1q_lane_u64 (uint64_t *__a, uint64x2_t __b, const int __lane) __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s64_x2 (int64_t * __a, int64x1x2_t val) +vst1_s64_x2 (int64_t * __a, int64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - int64x2x2_t temp; - temp.val[0] = vcombine_s64 (val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s64 (val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[1], 1); + int64x2x2_t __temp; + __temp.val[0] + = vcombine_s64 (__val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[1] + = vcombine_s64 (__val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); __builtin_aarch64_st1x2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u64_x2 (uint64_t * __a, uint64x1x2_t val) +vst1_u64_x2 (uint64_t * __a, uint64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - uint64x2x2_t temp; - temp.val[0] = vcombine_u64 (val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u64 (val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[1], 1); + uint64x2x2_t __temp; + __temp.val[0] + = vcombine_u64 (__val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[1] + = vcombine_u64 (__val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); __builtin_aarch64_st1x2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f64_x2 (float64_t * __a, float64x1x2_t val) +vst1_f64_x2 (float64_t * __a, float64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - float64x2x2_t temp; - temp.val[0] = vcombine_f64 (val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f64 (val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) temp.val[1], 1); + float64x2x2_t __temp; + __temp.val[0] + = vcombine_f64 (__val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[1] + = vcombine_f64 (__val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[1], 1); __builtin_aarch64_st1x2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s8_x2 (int8_t * __a, int8x8x2_t val) +vst1_s8_x2 (int8_t * __a, int8x8x2_t __val) { __builtin_aarch64_simd_oi __o; - int8x16x2_t temp; - temp.val[0] = vcombine_s8 (val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s8 (val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[1], 1); + int8x16x2_t __temp; + __temp.val[0] + = vcombine_s8 (__val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[1] + = vcombine_s8 (__val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); __builtin_aarch64_st1x2v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p8_x2 (poly8_t * __a, poly8x8x2_t val) +vst1_p8_x2 (poly8_t * __a, poly8x8x2_t __val) { __builtin_aarch64_simd_oi __o; - poly8x16x2_t temp; - temp.val[0] = vcombine_p8 (val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p8 (val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[1], 1); + poly8x16x2_t __temp; + __temp.val[0] + = vcombine_p8 (__val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[1] + = vcombine_p8 (__val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); __builtin_aarch64_st1x2v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s16_x2 (int16_t * __a, int16x4x2_t val) +vst1_s16_x2 (int16_t * __a, int16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - int16x8x2_t temp; - temp.val[0] = vcombine_s16 (val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s16 (val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[1], 1); + int16x8x2_t __temp; + __temp.val[0] + = vcombine_s16 (__val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[1] + = vcombine_s16 (__val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); __builtin_aarch64_st1x2v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p16_x2 (poly16_t * __a, poly16x4x2_t val) +vst1_p16_x2 (poly16_t * __a, poly16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - poly16x8x2_t temp; - temp.val[0] = vcombine_p16 (val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p16 (val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[1], 1); + poly16x8x2_t __temp; + __temp.val[0] + = vcombine_p16 (__val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[1] + = vcombine_p16 (__val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); __builtin_aarch64_st1x2v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s32_x2 (int32_t * __a, int32x2x2_t val) +vst1_s32_x2 (int32_t * __a, int32x2x2_t __val) { __builtin_aarch64_simd_oi __o; - int32x4x2_t temp; - temp.val[0] = vcombine_s32 (val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s32 (val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[1], 1); + int32x4x2_t __temp; + __temp.val[0] + = vcombine_s32 (__val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[1] + = vcombine_s32 (__val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); __builtin_aarch64_st1x2v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u8_x2 (uint8_t * __a, uint8x8x2_t val) +vst1_u8_x2 (uint8_t * __a, uint8x8x2_t __val) { __builtin_aarch64_simd_oi __o; - uint8x16x2_t temp; - temp.val[0] = vcombine_u8 (val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u8 (val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[1], 1); + uint8x16x2_t __temp; + __temp.val[0] = vcombine_u8 (__val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u8 (__val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); __builtin_aarch64_st1x2v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u16_x2 (uint16_t * __a, uint16x4x2_t val) +vst1_u16_x2 (uint16_t * __a, uint16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - uint16x8x2_t temp; - temp.val[0] = vcombine_u16 (val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u16 (val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[1], 1); + uint16x8x2_t __temp; + __temp.val[0] = vcombine_u16 (__val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u16 (__val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); __builtin_aarch64_st1x2v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u32_x2 (uint32_t * __a, uint32x2x2_t val) +vst1_u32_x2 (uint32_t * __a, uint32x2x2_t __val) { __builtin_aarch64_simd_oi __o; - uint32x4x2_t temp; - temp.val[0] = vcombine_u32 (val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u32 (val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[1], 1); + uint32x4x2_t __temp; + __temp.val[0] = vcombine_u32 (__val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u32 (__val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); __builtin_aarch64_st1x2v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f16_x2 (float16_t * __a, float16x4x2_t val) +vst1_f16_x2 (float16_t * __a, float16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - float16x8x2_t temp; - temp.val[0] = vcombine_f16 (val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f16 (val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hf (__o, temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hf (__o, temp.val[1], 1); + float16x8x2_t __temp; + __temp.val[0] = vcombine_f16 (__val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f16 (__val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __temp.val[1], 1); __builtin_aarch64_st1x2v4hf (__a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f32_x2 (float32_t * __a, float32x2x2_t val) +vst1_f32_x2 (float32_t * __a, float32x2x2_t __val) { __builtin_aarch64_simd_oi __o; - float32x4x2_t temp; - temp.val[0] = vcombine_f32 (val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f32 (val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) temp.val[1], 1); + float32x4x2_t __temp; + __temp.val[0] = vcombine_f32 (__val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f32 (__val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[1], 1); __builtin_aarch64_st1x2v2sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p64_x2 (poly64_t * __a, poly64x1x2_t val) +vst1_p64_x2 (poly64_t * __a, poly64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - poly64x2x2_t temp; - temp.val[0] = vcombine_p64 (val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p64 (val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); + poly64x2x2_t __temp; + __temp.val[0] = vcombine_p64 (__val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p64 (__val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) temp.val[0], 0); + (poly64x2_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) temp.val[1], 1); + (poly64x2_t) __temp.val[1], 1); __builtin_aarch64_st1x2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s8_x2 (int8_t * __a, int8x16x2_t val) +vst1q_s8_x2 (int8_t * __a, int8x16x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[1], 1); __builtin_aarch64_st1x2v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p8_x2 (poly8_t * __a, poly8x16x2_t val) +vst1q_p8_x2 (poly8_t * __a, poly8x16x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[1], 1); __builtin_aarch64_st1x2v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s16_x2 (int16_t * __a, int16x8x2_t val) +vst1q_s16_x2 (int16_t * __a, int16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[1], 1); __builtin_aarch64_st1x2v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p16_x2 (poly16_t * __a, poly16x8x2_t val) +vst1q_p16_x2 (poly16_t * __a, poly16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[1], 1); __builtin_aarch64_st1x2v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s32_x2 (int32_t * __a, int32x4x2_t val) +vst1q_s32_x2 (int32_t * __a, int32x4x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[1], 1); __builtin_aarch64_st1x2v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s64_x2 (int64_t * __a, int64x2x2_t val) +vst1q_s64_x2 (int64_t * __a, int64x2x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[1], 1); __builtin_aarch64_st1x2v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u8_x2 (uint8_t * __a, uint8x16x2_t val) +vst1q_u8_x2 (uint8_t * __a, uint8x16x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[1], 1); __builtin_aarch64_st1x2v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u16_x2 (uint16_t * __a, uint16x8x2_t val) +vst1q_u16_x2 (uint16_t * __a, uint16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[1], 1); __builtin_aarch64_st1x2v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u32_x2 (uint32_t * __a, uint32x4x2_t val) +vst1q_u32_x2 (uint32_t * __a, uint32x4x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[1], 1); __builtin_aarch64_st1x2v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u64_x2 (uint64_t * __a, uint64x2x2_t val) +vst1q_u64_x2 (uint64_t * __a, uint64x2x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[1], 1); __builtin_aarch64_st1x2v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f16_x2 (float16_t * __a, float16x8x2_t val) +vst1q_f16_x2 (float16_t * __a, float16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hf (__o, val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hf (__o, val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __val.val[1], 1); __builtin_aarch64_st1x2v8hf (__a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f32_x2 (float32_t * __a, float32x4x2_t val) +vst1q_f32_x2 (float32_t * __a, float32x4x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __val.val[1], 1); __builtin_aarch64_st1x2v4sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f64_x2 (float64_t * __a, float64x2x2_t val) +vst1q_f64_x2 (float64_t * __a, float64x2x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __val.val[1], 1); __builtin_aarch64_st1x2v2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p64_x2 (poly64_t * __a, poly64x2x2_t val) +vst1q_p64_x2 (poly64_t * __a, poly64x2x2_t __val) { __builtin_aarch64_simd_oi __o; __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) val.val[0], 0); + (poly64x2_t) __val.val[0], 0); __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) val.val[1], 1); + (poly64x2_t) __val.val[1], 1); __builtin_aarch64_st1x2v2di ((__builtin_aarch64_simd_di *) __a, __o); } @@ -28510,371 +28529,371 @@ vst1q_p64_x2 (poly64_t * __a, poly64x2x2_t val) __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s64_x3 (int64_t * __a, int64x1x3_t val) +vst1_s64_x3 (int64_t * __a, int64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - int64x2x3_t temp; - temp.val[0] = vcombine_s64 (val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s64 (val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s64 (val.val[2], vcreate_s64 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[2], 2); + int64x2x3_t __temp; + __temp.val[0] = vcombine_s64 (__val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s64 (__val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s64 (__val.val[2], vcreate_s64 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); __builtin_aarch64_st1x3di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u64_x3 (uint64_t * __a, uint64x1x3_t val) +vst1_u64_x3 (uint64_t * __a, uint64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - uint64x2x3_t temp; - temp.val[0] = vcombine_u64 (val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u64 (val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u64 (val.val[2], vcreate_u64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[2], 2); + uint64x2x3_t __temp; + __temp.val[0] = vcombine_u64 (__val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u64 (__val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u64 (__val.val[2], vcreate_u64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); __builtin_aarch64_st1x3di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f64_x3 (float64_t * __a, float64x1x3_t val) +vst1_f64_x3 (float64_t * __a, float64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - float64x2x3_t temp; - temp.val[0] = vcombine_f64 (val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f64 (val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f64 (val.val[2], vcreate_f64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) temp.val[2], 2); + float64x2x3_t __temp; + __temp.val[0] = vcombine_f64 (__val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f64 (__val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f64 (__val.val[2], vcreate_f64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[2], 2); __builtin_aarch64_st1x3df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s8_x3 (int8_t * __a, int8x8x3_t val) +vst1_s8_x3 (int8_t * __a, int8x8x3_t __val) { __builtin_aarch64_simd_ci __o; - int8x16x3_t temp; - temp.val[0] = vcombine_s8 (val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s8 (val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s8 (val.val[2], vcreate_s8 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[2], 2); + int8x16x3_t __temp; + __temp.val[0] = vcombine_s8 (__val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s8 (__val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s8 (__val.val[2], vcreate_s8 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); __builtin_aarch64_st1x3v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p8_x3 (poly8_t * __a, poly8x8x3_t val) +vst1_p8_x3 (poly8_t * __a, poly8x8x3_t __val) { __builtin_aarch64_simd_ci __o; - poly8x16x3_t temp; - temp.val[0] = vcombine_p8 (val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p8 (val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p8 (val.val[2], vcreate_p8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[2], 2); + poly8x16x3_t __temp; + __temp.val[0] = vcombine_p8 (__val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p8 (__val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p8 (__val.val[2], vcreate_p8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); __builtin_aarch64_st1x3v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s16_x3 (int16_t * __a, int16x4x3_t val) +vst1_s16_x3 (int16_t * __a, int16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - int16x8x3_t temp; - temp.val[0] = vcombine_s16 (val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s16 (val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s16 (val.val[2], vcreate_s16 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[2], 2); + int16x8x3_t __temp; + __temp.val[0] = vcombine_s16 (__val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s16 (__val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s16 (__val.val[2], vcreate_s16 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); __builtin_aarch64_st1x3v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p16_x3 (poly16_t * __a, poly16x4x3_t val) +vst1_p16_x3 (poly16_t * __a, poly16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - poly16x8x3_t temp; - temp.val[0] = vcombine_p16 (val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p16 (val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p16 (val.val[2], vcreate_p16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[2], 2); + poly16x8x3_t __temp; + __temp.val[0] = vcombine_p16 (__val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p16 (__val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p16 (__val.val[2], vcreate_p16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); __builtin_aarch64_st1x3v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_s32_x3 (int32_t * __a, int32x2x3_t val) +vst1_s32_x3 (int32_t * __a, int32x2x3_t __val) { __builtin_aarch64_simd_ci __o; - int32x4x3_t temp; - temp.val[0] = vcombine_s32 (val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s32 (val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s32 (val.val[2], vcreate_s32 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[2], 2); + int32x4x3_t __temp; + __temp.val[0] = vcombine_s32 (__val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s32 (__val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s32 (__val.val[2], vcreate_s32 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); __builtin_aarch64_st1x3v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u8_x3 (uint8_t * __a, uint8x8x3_t val) +vst1_u8_x3 (uint8_t * __a, uint8x8x3_t __val) { __builtin_aarch64_simd_ci __o; - uint8x16x3_t temp; - temp.val[0] = vcombine_u8 (val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u8 (val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u8 (val.val[2], vcreate_u8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[2], 2); + uint8x16x3_t __temp; + __temp.val[0] = vcombine_u8 (__val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u8 (__val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u8 (__val.val[2], vcreate_u8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); __builtin_aarch64_st1x3v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u16_x3 (uint16_t * __a, uint16x4x3_t val) +vst1_u16_x3 (uint16_t * __a, uint16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - uint16x8x3_t temp; - temp.val[0] = vcombine_u16 (val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u16 (val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u16 (val.val[2], vcreate_u16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[2], 2); + uint16x8x3_t __temp; + __temp.val[0] = vcombine_u16 (__val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u16 (__val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u16 (__val.val[2], vcreate_u16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); __builtin_aarch64_st1x3v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_u32_x3 (uint32_t * __a, uint32x2x3_t val) +vst1_u32_x3 (uint32_t * __a, uint32x2x3_t __val) { __builtin_aarch64_simd_ci __o; - uint32x4x3_t temp; - temp.val[0] = vcombine_u32 (val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u32 (val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u32 (val.val[2], vcreate_u32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[2], 2); + uint32x4x3_t __temp; + __temp.val[0] = vcombine_u32 (__val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u32 (__val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u32 (__val.val[2], vcreate_u32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); __builtin_aarch64_st1x3v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f16_x3 (float16_t * __a, float16x4x3_t val) +vst1_f16_x3 (float16_t * __a, float16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - float16x8x3_t temp; - temp.val[0] = vcombine_f16 (val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f16 (val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f16 (val.val[2], vcreate_f16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) temp.val[2], 2); + float16x8x3_t __temp; + __temp.val[0] = vcombine_f16 (__val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f16 (__val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f16 (__val.val[2], vcreate_f16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[2], 2); __builtin_aarch64_st1x3v4hf ((__builtin_aarch64_simd_hf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_f32_x3 (float32_t * __a, float32x2x3_t val) +vst1_f32_x3 (float32_t * __a, float32x2x3_t __val) { __builtin_aarch64_simd_ci __o; - float32x4x3_t temp; - temp.val[0] = vcombine_f32 (val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f32 (val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f32 (val.val[2], vcreate_f32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) temp.val[2], 2); + float32x4x3_t __temp; + __temp.val[0] = vcombine_f32 (__val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f32 (__val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f32 (__val.val[2], vcreate_f32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[2], 2); __builtin_aarch64_st1x3v2sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1_p64_x3 (poly64_t * __a, poly64x1x3_t val) +vst1_p64_x3 (poly64_t * __a, poly64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - poly64x2x3_t temp; - temp.val[0] = vcombine_p64 (val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p64 (val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p64 (val.val[2], vcreate_p64 (__AARCH64_UINT64_C (0))); + poly64x2x3_t __temp; + __temp.val[0] = vcombine_p64 (__val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p64 (__val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p64 (__val.val[2], vcreate_p64 (__AARCH64_UINT64_C (0))); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) temp.val[0], 0); + (poly64x2_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) temp.val[1], 1); + (poly64x2_t) __temp.val[1], 1); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) temp.val[2], 2); + (poly64x2_t) __temp.val[2], 2); __builtin_aarch64_st1x3di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s8_x3 (int8_t * __a, int8x16x3_t val) +vst1q_s8_x3 (int8_t * __a, int8x16x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[2], 2); __builtin_aarch64_st1x3v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p8_x3 (poly8_t * __a, poly8x16x3_t val) +vst1q_p8_x3 (poly8_t * __a, poly8x16x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[2], 2); __builtin_aarch64_st1x3v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s16_x3 (int16_t * __a, int16x8x3_t val) +vst1q_s16_x3 (int16_t * __a, int16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[2], 2); __builtin_aarch64_st1x3v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p16_x3 (poly16_t * __a, poly16x8x3_t val) +vst1q_p16_x3 (poly16_t * __a, poly16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[2], 2); __builtin_aarch64_st1x3v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s32_x3 (int32_t * __a, int32x4x3_t val) +vst1q_s32_x3 (int32_t * __a, int32x4x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[2], 2); __builtin_aarch64_st1x3v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_s64_x3 (int64_t * __a, int64x2x3_t val) +vst1q_s64_x3 (int64_t * __a, int64x2x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[2], 2); __builtin_aarch64_st1x3v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u8_x3 (uint8_t * __a, uint8x16x3_t val) +vst1q_u8_x3 (uint8_t * __a, uint8x16x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[2], 2); __builtin_aarch64_st1x3v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u16_x3 (uint16_t * __a, uint16x8x3_t val) +vst1q_u16_x3 (uint16_t * __a, uint16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[2], 2); __builtin_aarch64_st1x3v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u32_x3 (uint32_t * __a, uint32x4x3_t val) +vst1q_u32_x3 (uint32_t * __a, uint32x4x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[2], 2); __builtin_aarch64_st1x3v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_u64_x3 (uint64_t * __a, uint64x2x3_t val) +vst1q_u64_x3 (uint64_t * __a, uint64x2x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[2], 2); __builtin_aarch64_st1x3v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f16_x3 (float16_t * __a, float16x8x3_t val) +vst1q_f16_x3 (float16_t * __a, float16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __val.val[2], 2); __builtin_aarch64_st1x3v8hf ((__builtin_aarch64_simd_hf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f32_x3 (float32_t * __a, float32x4x3_t val) +vst1q_f32_x3 (float32_t * __a, float32x4x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __val.val[2], 2); __builtin_aarch64_st1x3v4sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_f64_x3 (float64_t * __a, float64x2x3_t val) +vst1q_f64_x3 (float64_t * __a, float64x2x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __val.val[2], 2); __builtin_aarch64_st1x3v2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst1q_p64_x3 (poly64_t * __a, poly64x2x3_t val) +vst1q_p64_x3 (poly64_t * __a, poly64x2x3_t __val) { __builtin_aarch64_simd_ci __o; __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) val.val[0], 0); + (poly64x2_t) __val.val[0], 0); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) val.val[1], 1); + (poly64x2_t) __val.val[1], 1); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) val.val[2], 2); + (poly64x2_t) __val.val[2], 2); __builtin_aarch64_st1x3v2di ((__builtin_aarch64_simd_di *) __a, __o); } @@ -29108,1111 +29127,1111 @@ vst1q_f64_x4 (float64_t * __a, float64x2x4_t val) __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_s64 (int64_t * __a, int64x1x2_t val) +vst2_s64 (int64_t * __a, int64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - int64x2x2_t temp; - temp.val[0] = vcombine_s64 (val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s64 (val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[1], 1); + int64x2x2_t __temp; + __temp.val[0] = vcombine_s64 (__val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s64 (__val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); __builtin_aarch64_st2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_u64 (uint64_t * __a, uint64x1x2_t val) +vst2_u64 (uint64_t * __a, uint64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - uint64x2x2_t temp; - temp.val[0] = vcombine_u64 (val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u64 (val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) temp.val[1], 1); + uint64x2x2_t __temp; + __temp.val[0] = vcombine_u64 (__val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u64 (__val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); __builtin_aarch64_st2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_f64 (float64_t * __a, float64x1x2_t val) +vst2_f64 (float64_t * __a, float64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - float64x2x2_t temp; - temp.val[0] = vcombine_f64 (val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f64 (val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) temp.val[1], 1); + float64x2x2_t __temp; + __temp.val[0] = vcombine_f64 (__val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f64 (__val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[1], 1); __builtin_aarch64_st2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_s8 (int8_t * __a, int8x8x2_t val) +vst2_s8 (int8_t * __a, int8x8x2_t __val) { __builtin_aarch64_simd_oi __o; - int8x16x2_t temp; - temp.val[0] = vcombine_s8 (val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s8 (val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[1], 1); + int8x16x2_t __temp; + __temp.val[0] = vcombine_s8 (__val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s8 (__val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); __builtin_aarch64_st2v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_p8 (poly8_t * __a, poly8x8x2_t val) +vst2_p8 (poly8_t * __a, poly8x8x2_t __val) { __builtin_aarch64_simd_oi __o; - poly8x16x2_t temp; - temp.val[0] = vcombine_p8 (val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p8 (val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[1], 1); + poly8x16x2_t __temp; + __temp.val[0] = vcombine_p8 (__val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p8 (__val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); __builtin_aarch64_st2v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_s16 (int16_t * __a, int16x4x2_t val) +vst2_s16 (int16_t * __a, int16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - int16x8x2_t temp; - temp.val[0] = vcombine_s16 (val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s16 (val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[1], 1); + int16x8x2_t __temp; + __temp.val[0] = vcombine_s16 (__val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s16 (__val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); __builtin_aarch64_st2v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_p16 (poly16_t * __a, poly16x4x2_t val) +vst2_p16 (poly16_t * __a, poly16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - poly16x8x2_t temp; - temp.val[0] = vcombine_p16 (val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p16 (val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[1], 1); + poly16x8x2_t __temp; + __temp.val[0] = vcombine_p16 (__val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p16 (__val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); __builtin_aarch64_st2v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_s32 (int32_t * __a, int32x2x2_t val) +vst2_s32 (int32_t * __a, int32x2x2_t __val) { __builtin_aarch64_simd_oi __o; - int32x4x2_t temp; - temp.val[0] = vcombine_s32 (val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s32 (val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[1], 1); + int32x4x2_t __temp; + __temp.val[0] = vcombine_s32 (__val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s32 (__val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); __builtin_aarch64_st2v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_u8 (uint8_t * __a, uint8x8x2_t val) +vst2_u8 (uint8_t * __a, uint8x8x2_t __val) { __builtin_aarch64_simd_oi __o; - uint8x16x2_t temp; - temp.val[0] = vcombine_u8 (val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u8 (val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) temp.val[1], 1); + uint8x16x2_t __temp; + __temp.val[0] = vcombine_u8 (__val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u8 (__val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); __builtin_aarch64_st2v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_u16 (uint16_t * __a, uint16x4x2_t val) +vst2_u16 (uint16_t * __a, uint16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - uint16x8x2_t temp; - temp.val[0] = vcombine_u16 (val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u16 (val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) temp.val[1], 1); + uint16x8x2_t __temp; + __temp.val[0] = vcombine_u16 (__val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u16 (__val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); __builtin_aarch64_st2v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_u32 (uint32_t * __a, uint32x2x2_t val) +vst2_u32 (uint32_t * __a, uint32x2x2_t __val) { __builtin_aarch64_simd_oi __o; - uint32x4x2_t temp; - temp.val[0] = vcombine_u32 (val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u32 (val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) temp.val[1], 1); + uint32x4x2_t __temp; + __temp.val[0] = vcombine_u32 (__val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u32 (__val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); __builtin_aarch64_st2v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_f16 (float16_t * __a, float16x4x2_t val) +vst2_f16 (float16_t * __a, float16x4x2_t __val) { __builtin_aarch64_simd_oi __o; - float16x8x2_t temp; - temp.val[0] = vcombine_f16 (val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f16 (val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv8hf (__o, temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hf (__o, temp.val[1], 1); + float16x8x2_t __temp; + __temp.val[0] = vcombine_f16 (__val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f16 (__val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __temp.val[1], 1); __builtin_aarch64_st2v4hf (__a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_f32 (float32_t * __a, float32x2x2_t val) +vst2_f32 (float32_t * __a, float32x2x2_t __val) { __builtin_aarch64_simd_oi __o; - float32x4x2_t temp; - temp.val[0] = vcombine_f32 (val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f32 (val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) temp.val[1], 1); + float32x4x2_t __temp; + __temp.val[0] = vcombine_f32 (__val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f32 (__val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[1], 1); __builtin_aarch64_st2v2sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2_p64 (poly64_t * __a, poly64x1x2_t val) +vst2_p64 (poly64_t * __a, poly64x1x2_t __val) { __builtin_aarch64_simd_oi __o; - poly64x2x2_t temp; - temp.val[0] = vcombine_p64 (val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p64 (val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); + poly64x2x2_t __temp; + __temp.val[0] = vcombine_p64 (__val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p64 (__val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) temp.val[0], 0); + (poly64x2_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) temp.val[1], 1); + (poly64x2_t) __temp.val[1], 1); __builtin_aarch64_st2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_s8 (int8_t * __a, int8x16x2_t val) +vst2q_s8 (int8_t * __a, int8x16x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[1], 1); __builtin_aarch64_st2v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_p8 (poly8_t * __a, poly8x16x2_t val) +vst2q_p8 (poly8_t * __a, poly8x16x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[1], 1); __builtin_aarch64_st2v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_s16 (int16_t * __a, int16x8x2_t val) +vst2q_s16 (int16_t * __a, int16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[1], 1); __builtin_aarch64_st2v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_p16 (poly16_t * __a, poly16x8x2_t val) +vst2q_p16 (poly16_t * __a, poly16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[1], 1); __builtin_aarch64_st2v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_s32 (int32_t * __a, int32x4x2_t val) +vst2q_s32 (int32_t * __a, int32x4x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[1], 1); __builtin_aarch64_st2v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_s64 (int64_t * __a, int64x2x2_t val) +vst2q_s64 (int64_t * __a, int64x2x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[1], 1); __builtin_aarch64_st2v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_u8 (uint8_t * __a, uint8x16x2_t val) +vst2q_u8 (uint8_t * __a, uint8x16x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __val.val[1], 1); __builtin_aarch64_st2v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_u16 (uint16_t * __a, uint16x8x2_t val) +vst2q_u16 (uint16_t * __a, uint16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __val.val[1], 1); __builtin_aarch64_st2v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_u32 (uint32_t * __a, uint32x4x2_t val) +vst2q_u32 (uint32_t * __a, uint32x4x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __val.val[1], 1); __builtin_aarch64_st2v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_u64 (uint64_t * __a, uint64x2x2_t val) +vst2q_u64 (uint64_t * __a, uint64x2x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __val.val[1], 1); __builtin_aarch64_st2v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_f16 (float16_t * __a, float16x8x2_t val) +vst2q_f16 (float16_t * __a, float16x8x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv8hf (__o, val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv8hf (__o, val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hf (__o, __val.val[1], 1); __builtin_aarch64_st2v8hf (__a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_f32 (float32_t * __a, float32x4x2_t val) +vst2q_f32 (float32_t * __a, float32x4x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __val.val[1], 1); __builtin_aarch64_st2v4sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_f64 (float64_t * __a, float64x2x2_t val) +vst2q_f64 (float64_t * __a, float64x2x2_t __val) { __builtin_aarch64_simd_oi __o; - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) val.val[1], 1); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __val.val[1], 1); __builtin_aarch64_st2v2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst2q_p64 (poly64_t * __a, poly64x2x2_t val) +vst2q_p64 (poly64_t * __a, poly64x2x2_t __val) { __builtin_aarch64_simd_oi __o; __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) val.val[0], 0); + (poly64x2_t) __val.val[0], 0); __o = __builtin_aarch64_set_qregoiv2di_ssps (__o, - (poly64x2_t) val.val[1], 1); + (poly64x2_t) __val.val[1], 1); __builtin_aarch64_st2v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_s64 (int64_t * __a, int64x1x3_t val) +vst3_s64 (int64_t * __a, int64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - int64x2x3_t temp; - temp.val[0] = vcombine_s64 (val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s64 (val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s64 (val.val[2], vcreate_s64 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[2], 2); + int64x2x3_t __temp; + __temp.val[0] = vcombine_s64 (__val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s64 (__val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s64 (__val.val[2], vcreate_s64 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); __builtin_aarch64_st3di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_u64 (uint64_t * __a, uint64x1x3_t val) +vst3_u64 (uint64_t * __a, uint64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - uint64x2x3_t temp; - temp.val[0] = vcombine_u64 (val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u64 (val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u64 (val.val[2], vcreate_u64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) temp.val[2], 2); + uint64x2x3_t __temp; + __temp.val[0] = vcombine_u64 (__val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u64 (__val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u64 (__val.val[2], vcreate_u64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); __builtin_aarch64_st3di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_f64 (float64_t * __a, float64x1x3_t val) +vst3_f64 (float64_t * __a, float64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - float64x2x3_t temp; - temp.val[0] = vcombine_f64 (val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f64 (val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f64 (val.val[2], vcreate_f64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) temp.val[2], 2); + float64x2x3_t __temp; + __temp.val[0] = vcombine_f64 (__val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f64 (__val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f64 (__val.val[2], vcreate_f64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[2], 2); __builtin_aarch64_st3df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_s8 (int8_t * __a, int8x8x3_t val) +vst3_s8 (int8_t * __a, int8x8x3_t __val) { __builtin_aarch64_simd_ci __o; - int8x16x3_t temp; - temp.val[0] = vcombine_s8 (val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s8 (val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s8 (val.val[2], vcreate_s8 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[2], 2); + int8x16x3_t __temp; + __temp.val[0] = vcombine_s8 (__val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s8 (__val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s8 (__val.val[2], vcreate_s8 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); __builtin_aarch64_st3v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_p8 (poly8_t * __a, poly8x8x3_t val) +vst3_p8 (poly8_t * __a, poly8x8x3_t __val) { __builtin_aarch64_simd_ci __o; - poly8x16x3_t temp; - temp.val[0] = vcombine_p8 (val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p8 (val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p8 (val.val[2], vcreate_p8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[2], 2); + poly8x16x3_t __temp; + __temp.val[0] = vcombine_p8 (__val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p8 (__val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p8 (__val.val[2], vcreate_p8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); __builtin_aarch64_st3v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_s16 (int16_t * __a, int16x4x3_t val) +vst3_s16 (int16_t * __a, int16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - int16x8x3_t temp; - temp.val[0] = vcombine_s16 (val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s16 (val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s16 (val.val[2], vcreate_s16 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[2], 2); + int16x8x3_t __temp; + __temp.val[0] = vcombine_s16 (__val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s16 (__val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s16 (__val.val[2], vcreate_s16 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); __builtin_aarch64_st3v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_p16 (poly16_t * __a, poly16x4x3_t val) +vst3_p16 (poly16_t * __a, poly16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - poly16x8x3_t temp; - temp.val[0] = vcombine_p16 (val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p16 (val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p16 (val.val[2], vcreate_p16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[2], 2); + poly16x8x3_t __temp; + __temp.val[0] = vcombine_p16 (__val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p16 (__val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p16 (__val.val[2], vcreate_p16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); __builtin_aarch64_st3v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_s32 (int32_t * __a, int32x2x3_t val) +vst3_s32 (int32_t * __a, int32x2x3_t __val) { __builtin_aarch64_simd_ci __o; - int32x4x3_t temp; - temp.val[0] = vcombine_s32 (val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s32 (val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s32 (val.val[2], vcreate_s32 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[2], 2); + int32x4x3_t __temp; + __temp.val[0] = vcombine_s32 (__val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s32 (__val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s32 (__val.val[2], vcreate_s32 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); __builtin_aarch64_st3v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_u8 (uint8_t * __a, uint8x8x3_t val) +vst3_u8 (uint8_t * __a, uint8x8x3_t __val) { __builtin_aarch64_simd_ci __o; - uint8x16x3_t temp; - temp.val[0] = vcombine_u8 (val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u8 (val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u8 (val.val[2], vcreate_u8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) temp.val[2], 2); + uint8x16x3_t __temp; + __temp.val[0] = vcombine_u8 (__val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u8 (__val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u8 (__val.val[2], vcreate_u8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); __builtin_aarch64_st3v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_u16 (uint16_t * __a, uint16x4x3_t val) +vst3_u16 (uint16_t * __a, uint16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - uint16x8x3_t temp; - temp.val[0] = vcombine_u16 (val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u16 (val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u16 (val.val[2], vcreate_u16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) temp.val[2], 2); + uint16x8x3_t __temp; + __temp.val[0] = vcombine_u16 (__val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u16 (__val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u16 (__val.val[2], vcreate_u16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); __builtin_aarch64_st3v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_u32 (uint32_t * __a, uint32x2x3_t val) +vst3_u32 (uint32_t * __a, uint32x2x3_t __val) { __builtin_aarch64_simd_ci __o; - uint32x4x3_t temp; - temp.val[0] = vcombine_u32 (val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u32 (val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u32 (val.val[2], vcreate_u32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) temp.val[2], 2); + uint32x4x3_t __temp; + __temp.val[0] = vcombine_u32 (__val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u32 (__val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u32 (__val.val[2], vcreate_u32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); __builtin_aarch64_st3v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_f16 (float16_t * __a, float16x4x3_t val) +vst3_f16 (float16_t * __a, float16x4x3_t __val) { __builtin_aarch64_simd_ci __o; - float16x8x3_t temp; - temp.val[0] = vcombine_f16 (val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f16 (val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f16 (val.val[2], vcreate_f16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) temp.val[2], 2); + float16x8x3_t __temp; + __temp.val[0] = vcombine_f16 (__val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f16 (__val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f16 (__val.val[2], vcreate_f16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[2], 2); __builtin_aarch64_st3v4hf ((__builtin_aarch64_simd_hf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_f32 (float32_t * __a, float32x2x3_t val) +vst3_f32 (float32_t * __a, float32x2x3_t __val) { __builtin_aarch64_simd_ci __o; - float32x4x3_t temp; - temp.val[0] = vcombine_f32 (val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f32 (val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f32 (val.val[2], vcreate_f32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) temp.val[2], 2); + float32x4x3_t __temp; + __temp.val[0] = vcombine_f32 (__val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f32 (__val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f32 (__val.val[2], vcreate_f32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[2], 2); __builtin_aarch64_st3v2sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3_p64 (poly64_t * __a, poly64x1x3_t val) +vst3_p64 (poly64_t * __a, poly64x1x3_t __val) { __builtin_aarch64_simd_ci __o; - poly64x2x3_t temp; - temp.val[0] = vcombine_p64 (val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p64 (val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p64 (val.val[2], vcreate_p64 (__AARCH64_UINT64_C (0))); + poly64x2x3_t __temp; + __temp.val[0] = vcombine_p64 (__val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p64 (__val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p64 (__val.val[2], vcreate_p64 (__AARCH64_UINT64_C (0))); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) temp.val[0], 0); + (poly64x2_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) temp.val[1], 1); + (poly64x2_t) __temp.val[1], 1); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) temp.val[2], 2); + (poly64x2_t) __temp.val[2], 2); __builtin_aarch64_st3di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_s8 (int8_t * __a, int8x16x3_t val) +vst3q_s8 (int8_t * __a, int8x16x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[2], 2); __builtin_aarch64_st3v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_p8 (poly8_t * __a, poly8x16x3_t val) +vst3q_p8 (poly8_t * __a, poly8x16x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[2], 2); __builtin_aarch64_st3v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_s16 (int16_t * __a, int16x8x3_t val) +vst3q_s16 (int16_t * __a, int16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[2], 2); __builtin_aarch64_st3v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_p16 (poly16_t * __a, poly16x8x3_t val) +vst3q_p16 (poly16_t * __a, poly16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[2], 2); __builtin_aarch64_st3v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_s32 (int32_t * __a, int32x4x3_t val) +vst3q_s32 (int32_t * __a, int32x4x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[2], 2); __builtin_aarch64_st3v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_s64 (int64_t * __a, int64x2x3_t val) +vst3q_s64 (int64_t * __a, int64x2x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[2], 2); __builtin_aarch64_st3v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_u8 (uint8_t * __a, uint8x16x3_t val) +vst3q_u8 (uint8_t * __a, uint8x16x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __val.val[2], 2); __builtin_aarch64_st3v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_u16 (uint16_t * __a, uint16x8x3_t val) +vst3q_u16 (uint16_t * __a, uint16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __val.val[2], 2); __builtin_aarch64_st3v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_u32 (uint32_t * __a, uint32x4x3_t val) +vst3q_u32 (uint32_t * __a, uint32x4x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __val.val[2], 2); __builtin_aarch64_st3v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_u64 (uint64_t * __a, uint64x2x3_t val) +vst3q_u64 (uint64_t * __a, uint64x2x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __val.val[2], 2); __builtin_aarch64_st3v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_f16 (float16_t * __a, float16x8x3_t val) +vst3q_f16 (float16_t * __a, float16x8x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __val.val[2], 2); __builtin_aarch64_st3v8hf ((__builtin_aarch64_simd_hf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_f32 (float32_t * __a, float32x4x3_t val) +vst3q_f32 (float32_t * __a, float32x4x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __val.val[2], 2); __builtin_aarch64_st3v4sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_f64 (float64_t * __a, float64x2x3_t val) +vst3q_f64 (float64_t * __a, float64x2x3_t __val) { __builtin_aarch64_simd_ci __o; - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) val.val[2], 2); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __val.val[2], 2); __builtin_aarch64_st3v2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst3q_p64 (poly64_t * __a, poly64x2x3_t val) +vst3q_p64 (poly64_t * __a, poly64x2x3_t __val) { __builtin_aarch64_simd_ci __o; __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) val.val[0], 0); + (poly64x2_t) __val.val[0], 0); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) val.val[1], 1); + (poly64x2_t) __val.val[1], 1); __o = __builtin_aarch64_set_qregciv2di_ssps (__o, - (poly64x2_t) val.val[2], 2); + (poly64x2_t) __val.val[2], 2); __builtin_aarch64_st3v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_s64 (int64_t * __a, int64x1x4_t val) +vst4_s64 (int64_t * __a, int64x1x4_t __val) { __builtin_aarch64_simd_xi __o; - int64x2x4_t temp; - temp.val[0] = vcombine_s64 (val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s64 (val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s64 (val.val[2], vcreate_s64 (__AARCH64_INT64_C (0))); - temp.val[3] = vcombine_s64 (val.val[3], vcreate_s64 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[3], 3); + int64x2x4_t __temp; + __temp.val[0] = vcombine_s64 (__val.val[0], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s64 (__val.val[1], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s64 (__val.val[2], vcreate_s64 (__AARCH64_INT64_C (0))); + __temp.val[3] = vcombine_s64 (__val.val[3], vcreate_s64 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); __builtin_aarch64_st4di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_u64 (uint64_t * __a, uint64x1x4_t val) +vst4_u64 (uint64_t * __a, uint64x1x4_t __val) { __builtin_aarch64_simd_xi __o; - uint64x2x4_t temp; - temp.val[0] = vcombine_u64 (val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u64 (val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u64 (val.val[2], vcreate_u64 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_u64 (val.val[3], vcreate_u64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) temp.val[3], 3); + uint64x2x4_t __temp; + __temp.val[0] = vcombine_u64 (__val.val[0], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u64 (__val.val[1], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u64 (__val.val[2], vcreate_u64 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_u64 (__val.val[3], vcreate_u64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); __builtin_aarch64_st4di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_f64 (float64_t * __a, float64x1x4_t val) +vst4_f64 (float64_t * __a, float64x1x4_t __val) { __builtin_aarch64_simd_xi __o; - float64x2x4_t temp; - temp.val[0] = vcombine_f64 (val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f64 (val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f64 (val.val[2], vcreate_f64 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_f64 (val.val[3], vcreate_f64 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) temp.val[3], 3); + float64x2x4_t __temp; + __temp.val[0] = vcombine_f64 (__val.val[0], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f64 (__val.val[1], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f64 (__val.val[2], vcreate_f64 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_f64 (__val.val[3], vcreate_f64 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[3], 3); __builtin_aarch64_st4df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_s8 (int8_t * __a, int8x8x4_t val) +vst4_s8 (int8_t * __a, int8x8x4_t __val) { __builtin_aarch64_simd_xi __o; - int8x16x4_t temp; - temp.val[0] = vcombine_s8 (val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s8 (val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s8 (val.val[2], vcreate_s8 (__AARCH64_INT64_C (0))); - temp.val[3] = vcombine_s8 (val.val[3], vcreate_s8 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[3], 3); + int8x16x4_t __temp; + __temp.val[0] = vcombine_s8 (__val.val[0], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s8 (__val.val[1], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s8 (__val.val[2], vcreate_s8 (__AARCH64_INT64_C (0))); + __temp.val[3] = vcombine_s8 (__val.val[3], vcreate_s8 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); __builtin_aarch64_st4v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_p8 (poly8_t * __a, poly8x8x4_t val) +vst4_p8 (poly8_t * __a, poly8x8x4_t __val) { __builtin_aarch64_simd_xi __o; - poly8x16x4_t temp; - temp.val[0] = vcombine_p8 (val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p8 (val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p8 (val.val[2], vcreate_p8 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_p8 (val.val[3], vcreate_p8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[3], 3); + poly8x16x4_t __temp; + __temp.val[0] = vcombine_p8 (__val.val[0], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p8 (__val.val[1], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p8 (__val.val[2], vcreate_p8 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_p8 (__val.val[3], vcreate_p8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); __builtin_aarch64_st4v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_s16 (int16_t * __a, int16x4x4_t val) +vst4_s16 (int16_t * __a, int16x4x4_t __val) { __builtin_aarch64_simd_xi __o; - int16x8x4_t temp; - temp.val[0] = vcombine_s16 (val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s16 (val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s16 (val.val[2], vcreate_s16 (__AARCH64_INT64_C (0))); - temp.val[3] = vcombine_s16 (val.val[3], vcreate_s16 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[3], 3); + int16x8x4_t __temp; + __temp.val[0] = vcombine_s16 (__val.val[0], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s16 (__val.val[1], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s16 (__val.val[2], vcreate_s16 (__AARCH64_INT64_C (0))); + __temp.val[3] = vcombine_s16 (__val.val[3], vcreate_s16 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); __builtin_aarch64_st4v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_p16 (poly16_t * __a, poly16x4x4_t val) +vst4_p16 (poly16_t * __a, poly16x4x4_t __val) { __builtin_aarch64_simd_xi __o; - poly16x8x4_t temp; - temp.val[0] = vcombine_p16 (val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p16 (val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p16 (val.val[2], vcreate_p16 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_p16 (val.val[3], vcreate_p16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[3], 3); + poly16x8x4_t __temp; + __temp.val[0] = vcombine_p16 (__val.val[0], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p16 (__val.val[1], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p16 (__val.val[2], vcreate_p16 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_p16 (__val.val[3], vcreate_p16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); __builtin_aarch64_st4v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_s32 (int32_t * __a, int32x2x4_t val) +vst4_s32 (int32_t * __a, int32x2x4_t __val) { __builtin_aarch64_simd_xi __o; - int32x4x4_t temp; - temp.val[0] = vcombine_s32 (val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[1] = vcombine_s32 (val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[2] = vcombine_s32 (val.val[2], vcreate_s32 (__AARCH64_INT64_C (0))); - temp.val[3] = vcombine_s32 (val.val[3], vcreate_s32 (__AARCH64_INT64_C (0))); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[3], 3); + int32x4x4_t __temp; + __temp.val[0] = vcombine_s32 (__val.val[0], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[1] = vcombine_s32 (__val.val[1], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[2] = vcombine_s32 (__val.val[2], vcreate_s32 (__AARCH64_INT64_C (0))); + __temp.val[3] = vcombine_s32 (__val.val[3], vcreate_s32 (__AARCH64_INT64_C (0))); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[3], 3); __builtin_aarch64_st4v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_u8 (uint8_t * __a, uint8x8x4_t val) +vst4_u8 (uint8_t * __a, uint8x8x4_t __val) { __builtin_aarch64_simd_xi __o; - uint8x16x4_t temp; - temp.val[0] = vcombine_u8 (val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u8 (val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u8 (val.val[2], vcreate_u8 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_u8 (val.val[3], vcreate_u8 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) temp.val[3], 3); + uint8x16x4_t __temp; + __temp.val[0] = vcombine_u8 (__val.val[0], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u8 (__val.val[1], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u8 (__val.val[2], vcreate_u8 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_u8 (__val.val[3], vcreate_u8 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); __builtin_aarch64_st4v8qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_u16 (uint16_t * __a, uint16x4x4_t val) +vst4_u16 (uint16_t * __a, uint16x4x4_t __val) { __builtin_aarch64_simd_xi __o; - uint16x8x4_t temp; - temp.val[0] = vcombine_u16 (val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u16 (val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u16 (val.val[2], vcreate_u16 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_u16 (val.val[3], vcreate_u16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) temp.val[3], 3); + uint16x8x4_t __temp; + __temp.val[0] = vcombine_u16 (__val.val[0], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u16 (__val.val[1], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u16 (__val.val[2], vcreate_u16 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_u16 (__val.val[3], vcreate_u16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); __builtin_aarch64_st4v4hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_u32 (uint32_t * __a, uint32x2x4_t val) +vst4_u32 (uint32_t * __a, uint32x2x4_t __val) { __builtin_aarch64_simd_xi __o; - uint32x4x4_t temp; - temp.val[0] = vcombine_u32 (val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_u32 (val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_u32 (val.val[2], vcreate_u32 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_u32 (val.val[3], vcreate_u32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) temp.val[3], 3); + uint32x4x4_t __temp; + __temp.val[0] = vcombine_u32 (__val.val[0], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_u32 (__val.val[1], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_u32 (__val.val[2], vcreate_u32 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_u32 (__val.val[3], vcreate_u32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[3], 3); __builtin_aarch64_st4v2si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_f16 (float16_t * __a, float16x4x4_t val) +vst4_f16 (float16_t * __a, float16x4x4_t __val) { __builtin_aarch64_simd_xi __o; - float16x8x4_t temp; - temp.val[0] = vcombine_f16 (val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f16 (val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f16 (val.val[2], vcreate_f16 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_f16 (val.val[3], vcreate_f16 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) temp.val[3], 3); + float16x8x4_t __temp; + __temp.val[0] = vcombine_f16 (__val.val[0], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f16 (__val.val[1], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f16 (__val.val[2], vcreate_f16 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_f16 (__val.val[3], vcreate_f16 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[3], 3); __builtin_aarch64_st4v4hf ((__builtin_aarch64_simd_hf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_f32 (float32_t * __a, float32x2x4_t val) +vst4_f32 (float32_t * __a, float32x2x4_t __val) { __builtin_aarch64_simd_xi __o; - float32x4x4_t temp; - temp.val[0] = vcombine_f32 (val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_f32 (val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_f32 (val.val[2], vcreate_f32 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_f32 (val.val[3], vcreate_f32 (__AARCH64_UINT64_C (0))); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) temp.val[0], 0); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) temp.val[1], 1); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) temp.val[2], 2); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) temp.val[3], 3); + float32x4x4_t __temp; + __temp.val[0] = vcombine_f32 (__val.val[0], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_f32 (__val.val[1], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_f32 (__val.val[2], vcreate_f32 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_f32 (__val.val[3], vcreate_f32 (__AARCH64_UINT64_C (0))); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[3], 3); __builtin_aarch64_st4v2sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4_p64 (poly64_t * __a, poly64x1x4_t val) +vst4_p64 (poly64_t * __a, poly64x1x4_t __val) { __builtin_aarch64_simd_xi __o; - poly64x2x4_t temp; - temp.val[0] = vcombine_p64 (val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[1] = vcombine_p64 (val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[2] = vcombine_p64 (val.val[2], vcreate_p64 (__AARCH64_UINT64_C (0))); - temp.val[3] = vcombine_p64 (val.val[3], vcreate_p64 (__AARCH64_UINT64_C (0))); + poly64x2x4_t __temp; + __temp.val[0] = vcombine_p64 (__val.val[0], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[1] = vcombine_p64 (__val.val[1], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[2] = vcombine_p64 (__val.val[2], vcreate_p64 (__AARCH64_UINT64_C (0))); + __temp.val[3] = vcombine_p64 (__val.val[3], vcreate_p64 (__AARCH64_UINT64_C (0))); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) temp.val[0], 0); + (poly64x2_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) temp.val[1], 1); + (poly64x2_t) __temp.val[1], 1); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) temp.val[2], 2); + (poly64x2_t) __temp.val[2], 2); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) temp.val[3], 3); + (poly64x2_t) __temp.val[3], 3); __builtin_aarch64_st4di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_s8 (int8_t * __a, int8x16x4_t val) +vst4q_s8 (int8_t * __a, int8x16x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[3], 3); __builtin_aarch64_st4v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_p8 (poly8_t * __a, poly8x16x4_t val) +vst4q_p8 (poly8_t * __a, poly8x16x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[3], 3); __builtin_aarch64_st4v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_s16 (int16_t * __a, int16x8x4_t val) +vst4q_s16 (int16_t * __a, int16x8x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[3], 3); __builtin_aarch64_st4v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_p16 (poly16_t * __a, poly16x8x4_t val) +vst4q_p16 (poly16_t * __a, poly16x8x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[3], 3); __builtin_aarch64_st4v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_s32 (int32_t * __a, int32x4x4_t val) +vst4q_s32 (int32_t * __a, int32x4x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[3], 3); __builtin_aarch64_st4v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_s64 (int64_t * __a, int64x2x4_t val) +vst4q_s64 (int64_t * __a, int64x2x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[3], 3); __builtin_aarch64_st4v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_u8 (uint8_t * __a, uint8x16x4_t val) +vst4q_u8 (uint8_t * __a, uint8x16x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __val.val[3], 3); __builtin_aarch64_st4v16qi ((__builtin_aarch64_simd_qi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_u16 (uint16_t * __a, uint16x8x4_t val) +vst4q_u16 (uint16_t * __a, uint16x8x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __val.val[3], 3); __builtin_aarch64_st4v8hi ((__builtin_aarch64_simd_hi *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_u32 (uint32_t * __a, uint32x4x4_t val) +vst4q_u32 (uint32_t * __a, uint32x4x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __val.val[3], 3); __builtin_aarch64_st4v4si ((__builtin_aarch64_simd_si *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_u64 (uint64_t * __a, uint64x2x4_t val) +vst4q_u64 (uint64_t * __a, uint64x2x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __val.val[3], 3); __builtin_aarch64_st4v2di ((__builtin_aarch64_simd_di *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_f16 (float16_t * __a, float16x8x4_t val) +vst4q_f16 (float16_t * __a, float16x8x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __val.val[3], 3); __builtin_aarch64_st4v8hf ((__builtin_aarch64_simd_hf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_f32 (float32_t * __a, float32x4x4_t val) +vst4q_f32 (float32_t * __a, float32x4x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __val.val[3], 3); __builtin_aarch64_st4v4sf ((__builtin_aarch64_simd_sf *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_f64 (float64_t * __a, float64x2x4_t val) +vst4q_f64 (float64_t * __a, float64x2x4_t __val) { __builtin_aarch64_simd_xi __o; - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) val.val[0], 0); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) val.val[1], 1); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) val.val[2], 2); - __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) val.val[3], 3); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __val.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __val.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __val.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __val.val[3], 3); __builtin_aarch64_st4v2df ((__builtin_aarch64_simd_df *) __a, __o); } __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vst4q_p64 (poly64_t * __a, poly64x2x4_t val) +vst4q_p64 (poly64_t * __a, poly64x2x4_t __val) { __builtin_aarch64_simd_xi __o; __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) val.val[0], 0); + (poly64x2_t) __val.val[0], 0); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) val.val[1], 1); + (poly64x2_t) __val.val[1], 1); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) val.val[2], 2); + (poly64x2_t) __val.val[2], 2); __o = __builtin_aarch64_set_qregxiv2di_ssps (__o, - (poly64x2_t) val.val[3], 3); + (poly64x2_t) __val.val[3], 3); __builtin_aarch64_st4v2di ((__builtin_aarch64_simd_di *) __a, __o); } @@ -30304,53 +30323,53 @@ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vtbx4_s8 (int8x8_t __r, int8x8x4_t __tab, int8x8_t __idx) { - int8x8_t result; - int8x16x2_t temp; + int8x8_t __result; + int8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_s8 (__tab.val[0], __tab.val[1]); - temp.val[1] = vcombine_s8 (__tab.val[2], __tab.val[3]); + __temp.val[0] = vcombine_s8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_s8 (__tab.val[2], __tab.val[3]); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = __builtin_aarch64_tbx4v8qi (__r, __o, __idx); - return result; + (int8x16_t) __temp.val[1], 1); + __result = __builtin_aarch64_tbx4v8qi (__r, __o, __idx); + return __result; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vtbx4_u8 (uint8x8_t __r, uint8x8x4_t __tab, uint8x8_t __idx) { - uint8x8_t result; - uint8x16x2_t temp; + uint8x8_t __result; + uint8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_u8 (__tab.val[0], __tab.val[1]); - temp.val[1] = vcombine_u8 (__tab.val[2], __tab.val[3]); + __temp.val[0] = vcombine_u8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_u8 (__tab.val[2], __tab.val[3]); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = (uint8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)__r, __o, + (int8x16_t) __temp.val[1], 1); + __result = (uint8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)__r, __o, (int8x8_t)__idx); - return result; + return __result; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vtbx4_p8 (poly8x8_t __r, poly8x8x4_t __tab, uint8x8_t __idx) { - poly8x8_t result; - poly8x16x2_t temp; + poly8x8_t __result; + poly8x16x2_t __temp; __builtin_aarch64_simd_oi __o; - temp.val[0] = vcombine_p8 (__tab.val[0], __tab.val[1]); - temp.val[1] = vcombine_p8 (__tab.val[2], __tab.val[3]); + __temp.val[0] = vcombine_p8 (__tab.val[0], __tab.val[1]); + __temp.val[1] = vcombine_p8 (__tab.val[2], __tab.val[3]); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[0], 0); + (int8x16_t) __temp.val[0], 0); __o = __builtin_aarch64_set_qregoiv16qi (__o, - (int8x16_t) temp.val[1], 1); - result = (poly8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)__r, __o, + (int8x16_t) __temp.val[1], 1); + __result = (poly8x8_t)__builtin_aarch64_tbx4v8qi ((int8x8_t)__r, __o, (int8x8_t)__idx); - return result; + return __result; } /* vtrn */ @@ -30882,65 +30901,65 @@ vtrn_f16 (float16x4_t __a, float16x4_t __b) __extension__ extern __inline float32x2x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_f32 (float32x2_t a, float32x2_t b) +vtrn_f32 (float32x2_t __a, float32x2_t __b) { - return (float32x2x2_t) {vtrn1_f32 (a, b), vtrn2_f32 (a, b)}; + return (float32x2x2_t) {vtrn1_f32 (__a, __b), vtrn2_f32 (__a, __b)}; } __extension__ extern __inline poly8x8x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_p8 (poly8x8_t a, poly8x8_t b) +vtrn_p8 (poly8x8_t __a, poly8x8_t __b) { - return (poly8x8x2_t) {vtrn1_p8 (a, b), vtrn2_p8 (a, b)}; + return (poly8x8x2_t) {vtrn1_p8 (__a, __b), vtrn2_p8 (__a, __b)}; } __extension__ extern __inline poly16x4x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_p16 (poly16x4_t a, poly16x4_t b) +vtrn_p16 (poly16x4_t __a, poly16x4_t __b) { - return (poly16x4x2_t) {vtrn1_p16 (a, b), vtrn2_p16 (a, b)}; + return (poly16x4x2_t) {vtrn1_p16 (__a, __b), vtrn2_p16 (__a, __b)}; } __extension__ extern __inline int8x8x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_s8 (int8x8_t a, int8x8_t b) +vtrn_s8 (int8x8_t __a, int8x8_t __b) { - return (int8x8x2_t) {vtrn1_s8 (a, b), vtrn2_s8 (a, b)}; + return (int8x8x2_t) {vtrn1_s8 (__a, __b), vtrn2_s8 (__a, __b)}; } __extension__ extern __inline int16x4x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_s16 (int16x4_t a, int16x4_t b) +vtrn_s16 (int16x4_t __a, int16x4_t __b) { - return (int16x4x2_t) {vtrn1_s16 (a, b), vtrn2_s16 (a, b)}; + return (int16x4x2_t) {vtrn1_s16 (__a, __b), vtrn2_s16 (__a, __b)}; } __extension__ extern __inline int32x2x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_s32 (int32x2_t a, int32x2_t b) +vtrn_s32 (int32x2_t __a, int32x2_t __b) { - return (int32x2x2_t) {vtrn1_s32 (a, b), vtrn2_s32 (a, b)}; + return (int32x2x2_t) {vtrn1_s32 (__a, __b), vtrn2_s32 (__a, __b)}; } __extension__ extern __inline uint8x8x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_u8 (uint8x8_t a, uint8x8_t b) +vtrn_u8 (uint8x8_t __a, uint8x8_t __b) { - return (uint8x8x2_t) {vtrn1_u8 (a, b), vtrn2_u8 (a, b)}; + return (uint8x8x2_t) {vtrn1_u8 (__a, __b), vtrn2_u8 (__a, __b)}; } __extension__ extern __inline uint16x4x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_u16 (uint16x4_t a, uint16x4_t b) +vtrn_u16 (uint16x4_t __a, uint16x4_t __b) { - return (uint16x4x2_t) {vtrn1_u16 (a, b), vtrn2_u16 (a, b)}; + return (uint16x4x2_t) {vtrn1_u16 (__a, __b), vtrn2_u16 (__a, __b)}; } __extension__ extern __inline uint32x2x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrn_u32 (uint32x2_t a, uint32x2_t b) +vtrn_u32 (uint32x2_t __a, uint32x2_t __b) { - return (uint32x2x2_t) {vtrn1_u32 (a, b), vtrn2_u32 (a, b)}; + return (uint32x2x2_t) {vtrn1_u32 (__a, __b), vtrn2_u32 (__a, __b)}; } __extension__ extern __inline float16x8x2_t @@ -30952,65 +30971,65 @@ vtrnq_f16 (float16x8_t __a, float16x8_t __b) __extension__ extern __inline float32x4x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_f32 (float32x4_t a, float32x4_t b) +vtrnq_f32 (float32x4_t __a, float32x4_t __b) { - return (float32x4x2_t) {vtrn1q_f32 (a, b), vtrn2q_f32 (a, b)}; + return (float32x4x2_t) {vtrn1q_f32 (__a, __b), vtrn2q_f32 (__a, __b)}; } __extension__ extern __inline poly8x16x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_p8 (poly8x16_t a, poly8x16_t b) +vtrnq_p8 (poly8x16_t __a, poly8x16_t __b) { - return (poly8x16x2_t) {vtrn1q_p8 (a, b), vtrn2q_p8 (a, b)}; + return (poly8x16x2_t) {vtrn1q_p8 (__a, __b), vtrn2q_p8 (__a, __b)}; } __extension__ extern __inline poly16x8x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_p16 (poly16x8_t a, poly16x8_t b) +vtrnq_p16 (poly16x8_t __a, poly16x8_t __b) { - return (poly16x8x2_t) {vtrn1q_p16 (a, b), vtrn2q_p16 (a, b)}; + return (poly16x8x2_t) {vtrn1q_p16 (__a, __b), vtrn2q_p16 (__a, __b)}; } __extension__ extern __inline int8x16x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_s8 (int8x16_t a, int8x16_t b) +vtrnq_s8 (int8x16_t __a, int8x16_t __b) { - return (int8x16x2_t) {vtrn1q_s8 (a, b), vtrn2q_s8 (a, b)}; + return (int8x16x2_t) {vtrn1q_s8 (__a, __b), vtrn2q_s8 (__a, __b)}; } __extension__ extern __inline int16x8x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_s16 (int16x8_t a, int16x8_t b) +vtrnq_s16 (int16x8_t __a, int16x8_t __b) { - return (int16x8x2_t) {vtrn1q_s16 (a, b), vtrn2q_s16 (a, b)}; + return (int16x8x2_t) {vtrn1q_s16 (__a, __b), vtrn2q_s16 (__a, __b)}; } __extension__ extern __inline int32x4x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_s32 (int32x4_t a, int32x4_t b) +vtrnq_s32 (int32x4_t __a, int32x4_t __b) { - return (int32x4x2_t) {vtrn1q_s32 (a, b), vtrn2q_s32 (a, b)}; + return (int32x4x2_t) {vtrn1q_s32 (__a, __b), vtrn2q_s32 (__a, __b)}; } __extension__ extern __inline uint8x16x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_u8 (uint8x16_t a, uint8x16_t b) +vtrnq_u8 (uint8x16_t __a, uint8x16_t __b) { - return (uint8x16x2_t) {vtrn1q_u8 (a, b), vtrn2q_u8 (a, b)}; + return (uint8x16x2_t) {vtrn1q_u8 (__a, __b), vtrn2q_u8 (__a, __b)}; } __extension__ extern __inline uint16x8x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_u16 (uint16x8_t a, uint16x8_t b) +vtrnq_u16 (uint16x8_t __a, uint16x8_t __b) { - return (uint16x8x2_t) {vtrn1q_u16 (a, b), vtrn2q_u16 (a, b)}; + return (uint16x8x2_t) {vtrn1q_u16 (__a, __b), vtrn2q_u16 (__a, __b)}; } __extension__ extern __inline uint32x4x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vtrnq_u32 (uint32x4_t a, uint32x4_t b) +vtrnq_u32 (uint32x4_t __a, uint32x4_t __b) { - return (uint32x4x2_t) {vtrn1q_u32 (a, b), vtrn2q_u32 (a, b)}; + return (uint32x4x2_t) {vtrn1q_u32 (__a, __b), vtrn2q_u32 (__a, __b)}; } /* vtst */ @@ -32708,30 +32727,30 @@ vrndxq_f16 (float16x8_t __a) __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrsqrte_f16 (float16x4_t a) +vrsqrte_f16 (float16x4_t __a) { - return __builtin_aarch64_rsqrtev4hf (a); + return __builtin_aarch64_rsqrtev4hf (__a); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrsqrteq_f16 (float16x8_t a) +vrsqrteq_f16 (float16x8_t __a) { - return __builtin_aarch64_rsqrtev8hf (a); + return __builtin_aarch64_rsqrtev8hf (__a); } __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsqrt_f16 (float16x4_t a) +vsqrt_f16 (float16x4_t __a) { - return __builtin_aarch64_sqrtv4hf (a); + return __builtin_aarch64_sqrtv4hf (__a); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vsqrtq_f16 (float16x8_t a) +vsqrtq_f16 (float16x8_t __a) { - return __builtin_aarch64_sqrtv8hf (a); + return __builtin_aarch64_sqrtv8hf (__a); } /* ARMv8.2-A FP16 two operands vector intrinsics. */ @@ -32752,16 +32771,16 @@ vaddq_f16 (float16x8_t __a, float16x8_t __b) __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabd_f16 (float16x4_t a, float16x4_t b) +vabd_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_fabdv4hf (a, b); + return __builtin_aarch64_fabdv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vabdq_f16 (float16x8_t a, float16x8_t b) +vabdq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_fabdv8hf (a, b); + return __builtin_aarch64_fabdv8hf (__a, __b); } __extension__ extern __inline uint16x4_t @@ -33046,72 +33065,72 @@ vmulxq_f16 (float16x8_t __a, float16x8_t __b) __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpadd_f16 (float16x4_t a, float16x4_t b) +vpadd_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_faddpv4hf (a, b); + return __builtin_aarch64_faddpv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpaddq_f16 (float16x8_t a, float16x8_t b) +vpaddq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_faddpv8hf (a, b); + return __builtin_aarch64_faddpv8hf (__a, __b); } __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmax_f16 (float16x4_t a, float16x4_t b) +vpmax_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_smax_nanpv4hf (a, b); + return __builtin_aarch64_smax_nanpv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxq_f16 (float16x8_t a, float16x8_t b) +vpmaxq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_smax_nanpv8hf (a, b); + return __builtin_aarch64_smax_nanpv8hf (__a, __b); } __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnm_f16 (float16x4_t a, float16x4_t b) +vpmaxnm_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_smaxpv4hf (a, b); + return __builtin_aarch64_smaxpv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmaxnmq_f16 (float16x8_t a, float16x8_t b) +vpmaxnmq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_smaxpv8hf (a, b); + return __builtin_aarch64_smaxpv8hf (__a, __b); } __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpmin_f16 (float16x4_t a, float16x4_t b) +vpmin_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_smin_nanpv4hf (a, b); + return __builtin_aarch64_smin_nanpv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminq_f16 (float16x8_t a, float16x8_t b) +vpminq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_smin_nanpv8hf (a, b); + return __builtin_aarch64_smin_nanpv8hf (__a, __b); } __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnm_f16 (float16x4_t a, float16x4_t b) +vpminnm_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_sminpv4hf (a, b); + return __builtin_aarch64_sminpv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vpminnmq_f16 (float16x8_t a, float16x8_t b) +vpminnmq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_sminpv8hf (a, b); + return __builtin_aarch64_sminpv8hf (__a, __b); } __extension__ extern __inline float16x4_t @@ -33130,16 +33149,16 @@ vrecpsq_f16 (float16x8_t __a, float16x8_t __b) __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrsqrts_f16 (float16x4_t a, float16x4_t b) +vrsqrts_f16 (float16x4_t __a, float16x4_t __b) { - return __builtin_aarch64_rsqrtsv4hf (a, b); + return __builtin_aarch64_rsqrtsv4hf (__a, __b); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -vrsqrtsq_f16 (float16x8_t a, float16x8_t b) +vrsqrtsq_f16 (float16x8_t __a, float16x8_t __b) { - return __builtin_aarch64_rsqrtsv8hf (a, b); + return __builtin_aarch64_rsqrtsv8hf (__a, __b); } __extension__ extern __inline float16x4_t -- cgit v1.1 From b134cab0cfb4283b3b5581d81ae777d684af82a9 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 25 Sep 2019 13:53:04 +0000 Subject: PR c++/91877 - ICE with converting member of packed struct. * call.c (convert_like_real): Use similar_type_p in an assert. * g++.dg/conversion/packed1.C: New test. From-SVN: r276127 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/call.c | 3 +-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/conversion/packed1.C | 12 ++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/conversion/packed1.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ca317e7..1d30cef 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-09-25 Marek Polacek + + PR c++/91877 - ICE with converting member of packed struct. + * call.c (convert_like_real): Use similar_type_p in an assert. + 2019-09-25 Paolo Carlini * name-lookup.c (check_extern_c_conflict): Use DECL_SOURCE_LOCATION. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 77f10a9..45b984e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7382,8 +7382,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, tree type = TREE_TYPE (ref_type); cp_lvalue_kind lvalue = lvalue_kind (expr); - gcc_assert (same_type_ignoring_top_level_qualifiers_p - (type, next_conversion (convs)->type)); + gcc_assert (similar_type_p (type, next_conversion (convs)->type)); if (!CP_TYPE_CONST_NON_VOLATILE_P (type) && !TYPE_REF_IS_RVALUE (ref_type)) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bf03a5e..8830baa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-25 Marek Polacek + + PR c++/91877 - ICE with converting member of packed struct. + * g++.dg/conversion/packed1.C: New test. + 2019-09-25 Richard Biener PR tree-optimization/91896 diff --git a/gcc/testsuite/g++.dg/conversion/packed1.C b/gcc/testsuite/g++.dg/conversion/packed1.C new file mode 100644 index 0000000..c4be930 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/packed1.C @@ -0,0 +1,12 @@ +// PR c++/91877 - ICE with converting member of packed struct. +// { dg-do compile { target c++11 } } +// { dg-options "-fpack-struct" } + +template class b { +public: + b(const a &); +}; +struct { + int *c; +} d; +void e() { b(d.c); } -- cgit v1.1 From b867051636ee21523b993484a0fa2fe915c25b21 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Wed, 25 Sep 2019 16:24:33 +0200 Subject: Remove newly unused function and variable in tree-sra Hi, Martin and his clang warnings discovered that I forgot to remove a static inline function and a variable when ripping out the old IPA-SRA from tree-sra.c and both are now unused. Thus I am doing that now with the patch below which I will commit as obvious (after including it in a round of a bootstrap and testing on an x86_64-linux). Thanks, Martin 2019-09-25 Martin Jambor * tree-sra.c (no_accesses_p): Remove. (no_accesses_representant): Likewise. From-SVN: r276128 --- gcc/ChangeLog | 5 +++++ gcc/tree-sra.c | 11 ----------- 2 files changed, 5 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fa43ab1..6786524 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-25 Martin Jambor + + * tree-sra.c (no_accesses_p): Remove. + (no_accesses_representant): Likewise. + 2019-09-25 Kyrylo Tkachov * config/aarch64/arm_neon.h (vaba_s8): Use __ in identifiers diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 4858932..ba6d540 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -327,17 +327,6 @@ static struct obstack name_obstack; propagated to their assignment counterparts. */ static struct access *work_queue_head; -/* Representative of no accesses at all. */ -static struct access no_accesses_representant; - -/* Predicate to test the special value. */ - -static inline bool -no_accesses_p (struct access *access) -{ - return access == &no_accesses_representant; -} - /* Dump contents of ACCESS to file F in a human friendly way. If GRP is true, representative fields are dumped, otherwise those which only describe the individual access are. */ -- cgit v1.1 From 736a6efc4fd2159f0f6092d1767697ef16b51b3a Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 25 Sep 2019 19:32:44 +0000 Subject: Colorize %L and %C text to match diagnostic_show_locus (PR fortran/91426) gcc/fortran/ChangeLog: PR fortran/91426 * error.c (curr_diagnostic): New static variable. (gfc_report_diagnostic): New static function. (gfc_warning): Replace call to diagnostic_report_diagnostic with call to gfc_report_diagnostic. (gfc_format_decoder): Colorize the text of %L and %C to match the colorization used by diagnostic_show_locus. (gfc_warning_now_at): Replace call to diagnostic_report_diagnostic with call to gfc_report_diagnostic. (gfc_warning_now): Likewise. (gfc_warning_internal): Likewise. (gfc_error_now): Likewise. (gfc_fatal_error): Likewise. (gfc_error_opt): Likewise. (gfc_internal_error): Likewise. From-SVN: r276132 --- gcc/fortran/ChangeLog | 18 ++++++++++++++++++ gcc/fortran/error.c | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index cd1ca75..d4946bd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,21 @@ +2019-09-25 David Malcolm + + PR fortran/91426 + * error.c (curr_diagnostic): New static variable. + (gfc_report_diagnostic): New static function. + (gfc_warning): Replace call to diagnostic_report_diagnostic with + call to gfc_report_diagnostic. + (gfc_format_decoder): Colorize the text of %L and %C to match the + colorization used by diagnostic_show_locus. + (gfc_warning_now_at): Replace call to diagnostic_report_diagnostic with + call to gfc_report_diagnostic. + (gfc_warning_now): Likewise. + (gfc_warning_internal): Likewise. + (gfc_error_now): Likewise. + (gfc_fatal_error): Likewise. + (gfc_error_opt): Likewise. + (gfc_internal_error): Likewise. + 2019-09-23 Paul Thomas PR fortran/91729 diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c index 68a2791..a0ce7a6 100644 --- a/gcc/fortran/error.c +++ b/gcc/fortran/error.c @@ -760,6 +760,23 @@ gfc_clear_pp_buffer (output_buffer *this_buffer) global_dc->last_location = UNKNOWN_LOCATION; } +/* The currently-printing diagnostic, for use by gfc_format_decoder, + for colorizing %C and %L. */ + +static diagnostic_info *curr_diagnostic; + +/* A helper function to call diagnostic_report_diagnostic, while setting + curr_diagnostic for the duration of the call. */ + +static bool +gfc_report_diagnostic (diagnostic_info *diagnostic) +{ + gcc_assert (diagnostic != NULL); + curr_diagnostic = diagnostic; + bool ret = diagnostic_report_diagnostic (global_dc, diagnostic); + curr_diagnostic = NULL; + return ret; +} /* This is just a helper function to avoid duplicating the logic of gfc_warning. */ @@ -789,7 +806,7 @@ gfc_warning (int opt, const char *gmsgid, va_list ap) diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING); diagnostic.option_index = opt; - bool ret = diagnostic_report_diagnostic (global_dc, &diagnostic); + bool ret = gfc_report_diagnostic (&diagnostic); if (buffered_p) { @@ -954,7 +971,18 @@ gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec, loc->lb->location, offset); text->set_location (loc_num, src_loc, SHOW_RANGE_WITH_CARET); + /* Colorize the markers to match the color choices of + diagnostic_show_locus (the initial location has a color given + by the "kind" of the diagnostic, the secondary location has + color "range1"). */ + gcc_assert (curr_diagnostic != NULL); + const char *color + = (loc_num + ? "range1" + : diagnostic_get_color_for_kind (curr_diagnostic->kind)); + pp_string (pp, colorize_start (pp_show_color (pp), color)); pp_string (pp, result[loc_num]); + pp_string (pp, colorize_stop (pp_show_color (pp))); return true; } default: @@ -1153,7 +1181,7 @@ gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...) va_start (argp, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING); diagnostic.option_index = opt; - ret = diagnostic_report_diagnostic (global_dc, &diagnostic); + ret = gfc_report_diagnostic (&diagnostic); va_end (argp); return ret; } @@ -1172,7 +1200,7 @@ gfc_warning_now (int opt, const char *gmsgid, ...) diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING); diagnostic.option_index = opt; - ret = diagnostic_report_diagnostic (global_dc, &diagnostic); + ret = gfc_report_diagnostic (&diagnostic); va_end (argp); return ret; } @@ -1191,7 +1219,7 @@ gfc_warning_internal (int opt, const char *gmsgid, ...) diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING); diagnostic.option_index = opt; - ret = diagnostic_report_diagnostic (global_dc, &diagnostic); + ret = gfc_report_diagnostic (&diagnostic); va_end (argp); return ret; } @@ -1209,7 +1237,7 @@ gfc_error_now (const char *gmsgid, ...) va_start (argp, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR); - diagnostic_report_diagnostic (global_dc, &diagnostic); + gfc_report_diagnostic (&diagnostic); va_end (argp); } @@ -1225,7 +1253,7 @@ gfc_fatal_error (const char *gmsgid, ...) va_start (argp, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL); - diagnostic_report_diagnostic (global_dc, &diagnostic); + gfc_report_diagnostic (&diagnostic); va_end (argp); gcc_unreachable (); @@ -1310,7 +1338,7 @@ gfc_error_opt (int opt, const char *gmsgid, va_list ap) } diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR); - diagnostic_report_diagnostic (global_dc, &diagnostic); + gfc_report_diagnostic (&diagnostic); if (buffered_p) { @@ -1360,7 +1388,7 @@ gfc_internal_error (const char *gmsgid, ...) va_start (argp, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE); - diagnostic_report_diagnostic (global_dc, &diagnostic); + gfc_report_diagnostic (&diagnostic); va_end (argp); gcc_unreachable (); -- cgit v1.1 From ec14f8abf00880d8fd7051d828bd2cbfd385b92b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 26 Sep 2019 00:16:23 +0000 Subject: Daily bump. From-SVN: r276139 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 6319483..1c14e6d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190925 +20190926 -- cgit v1.1 From 835d50c66aa5bde2f354a6e63a2afa7d2f76a05a Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 26 Sep 2019 07:38:21 +0000 Subject: [AArch64] Fix cost of (plus ... (const_int -C)) The PLUS handling in aarch64_rtx_costs only checked for nonnegative constants, meaning that simple immediate subtractions like: (set (reg R1) (plus (reg R2) (const_int -8))) had a cost of two instructions. 2019-09-26 Richard Sandiford gcc/ * config/aarch64/aarch64.c (aarch64_rtx_costs): Use aarch64_plus_immediate rather than aarch64_uimm12_shift to test for valid PLUS immediates. From-SVN: r276140 --- gcc/ChangeLog | 6 ++++++ gcc/config/aarch64/aarch64.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6786524..8382571 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-26 Richard Sandiford + + * config/aarch64/aarch64.c (aarch64_rtx_costs): Use + aarch64_plus_immediate rather than aarch64_uimm12_shift + to test for valid PLUS immediates. + 2019-09-25 Martin Jambor * tree-sra.c (no_accesses_p): Remove. diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 56a4a47d..71d44de 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -10753,7 +10753,7 @@ cost_plus: } if (GET_MODE_CLASS (mode) == MODE_INT - && ((CONST_INT_P (op1) && aarch64_uimm12_shift (INTVAL (op1))) + && (aarch64_plus_immediate (op1, mode) || aarch64_sve_addvl_addpl_immediate (op1, mode))) { *cost += rtx_cost (op0, mode, PLUS, 0, speed); -- cgit v1.1 From 704bc4bb36a0b091c42955608c47aee4d43faf8d Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 26 Sep 2019 09:40:09 +0200 Subject: Add TODO_update_ssa for SLP BB vectorization (PR tree-optimization/91885). 2019-09-26 Martin Liska PR tree-optimization/91885 * tree-vectorizer.c (try_vectorize_loop_1): Add TODO_update_ssa_only_virtuals similarly to what slp pass does. 2019-09-26 Martin Liska PR tree-optimization/91885 * gcc.dg/pr91885.c: New test. From-SVN: r276141 --- gcc/ChangeLog | 7 +++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/pr91885.c | 47 ++++++++++++++++++++++++++++++++++++++++++ gcc/tree-vectorizer.c | 2 +- 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/pr91885.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8382571..f876c5b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-26 Martin Liska + + PR tree-optimization/91885 + * tree-vectorizer.c (try_vectorize_loop_1): + Add TODO_update_ssa_only_virtuals similarly to what slp + pass does. + 2019-09-26 Richard Sandiford * config/aarch64/aarch64.c (aarch64_rtx_costs): Use diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8830baa..1f99dbd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-26 Martin Liska + + PR tree-optimization/91885 + * gcc.dg/pr91885.c: New test. + 2019-09-25 Marek Polacek PR c++/91877 - ICE with converting member of packed struct. diff --git a/gcc/testsuite/gcc.dg/pr91885.c b/gcc/testsuite/gcc.dg/pr91885.c new file mode 100644 index 0000000..934e8d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr91885.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fprofile-generate" } */ +/* { dg-require-profiling "-fprofile-generate" } */ + +typedef signed long int __int64_t; +typedef unsigned long int __uint64_t; +typedef __int64_t int64_t; +typedef __uint64_t uint64_t; +inline void +BLI_endian_switch_int64 (int64_t *val) +{ + uint64_t tval = *val; + *val = ((tval >> 56)) | ((tval << 40) & 0x00ff000000000000ll) + | ((tval << 24) & 0x0000ff0000000000ll) + | ((tval << 8) & 0x000000ff00000000ll) + | ((tval >> 8) & 0x00000000ff000000ll) + | ((tval >> 24) & 0x0000000000ff0000ll) + | ((tval >> 40) & 0x000000000000ff00ll) | ((tval << 56)); +} +typedef struct anim_index_entry +{ + unsigned long long seek_pos_dts; + unsigned long long pts; +} anim_index_entry; +extern struct anim_index_entry * +MEM_callocN (int); +struct anim_index +{ + int num_entries; + struct anim_index_entry *entries; +}; +struct anim_index * +IMB_indexer_open (const char *name) +{ + char header[13]; + struct anim_index *idx; + int i; + idx->entries = MEM_callocN (8); + if (((1 == 0) != (header[8] == 'V'))) + { + for (i = 0; i < idx->num_entries; i++) + { + BLI_endian_switch_int64 ((int64_t *) &idx->entries[i].seek_pos_dts); + BLI_endian_switch_int64 ((int64_t *) &idx->entries[i].pts); + } + } +} diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index c3004f6..8fb70b7 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -943,7 +943,7 @@ try_vectorize_loop_1 (hash_table *&simduid_to_vf_htab, fold_loop_internal_call (loop_vectorized_call, boolean_true_node); loop_vectorized_call = NULL; - ret |= TODO_cleanup_cfg; + ret |= TODO_cleanup_cfg | TODO_update_ssa_only_virtuals; } } /* If outer loop vectorization fails for LOOP_VECTORIZED guarded -- cgit v1.1 From 581b519f037a8787b9121d6fcdc33a9d518d97c0 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Thu, 26 Sep 2019 12:32:45 +0200 Subject: [PATCH] Fix continue condition in IPA-SRA's process_scan_results 2019-09-26 Martin Jambor * ipa-sra.c (process_scan_results): Fix continue condition. From-SVN: r276143 --- gcc/ChangeLog | 4 ++++ gcc/ipa-sra.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f876c5b..1d73129 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2019-09-26 Martin Jambor + + * ipa-sra.c (process_scan_results): Fix continue condition. + 2019-09-26 Martin Liska PR tree-optimization/91885 diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c index 0ccebbd..b35fff6 100644 --- a/gcc/ipa-sra.c +++ b/gcc/ipa-sra.c @@ -2239,7 +2239,7 @@ process_scan_results (cgraph_node *node, struct function *fun, desc_index++, parm = DECL_CHAIN (parm)) { gensum_param_desc *desc = &(*param_descriptions)[desc_index]; - if (!desc->locally_unused && !desc->split_candidate) + if (!desc->split_candidate) continue; if (flag_checking) -- cgit v1.1 From e2b1923b8d1f81ac83b40095577e0c318d3716b3 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Thu, 26 Sep 2019 12:39:48 +0200 Subject: [PATCH] Fix quoting in a call to internal_error 2019-09-26 Martin Jambor * ipa-sra.c (verify_splitting_accesses): Fix quoting in a call to internal_error. From-SVN: r276144 --- gcc/ChangeLog | 5 +++++ gcc/ipa-sra.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1d73129..6bbcfe5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-09-26 Martin Jambor + * ipa-sra.c (verify_splitting_accesses): Fix quoting in a call to + internal_error. + +2019-09-26 Martin Jambor + * ipa-sra.c (process_scan_results): Fix continue condition. 2019-09-26 Martin Liska diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c index b35fff6..50dee69 100644 --- a/gcc/ipa-sra.c +++ b/gcc/ipa-sra.c @@ -2452,7 +2452,7 @@ verify_splitting_accesses (cgraph_node *node, bool certain_must_exist) bool certain_access_present = !certain_must_exist; if (overlapping_certain_accesses_p (desc, &certain_access_present)) - internal_error ("Function %s, parameter %u, has IPA_SRA accesses " + internal_error ("Function %qs, parameter %u, has IPA-SRA accesses " "which overlap", node->dump_name (), pidx); if (!certain_access_present) internal_error ("Function %s, parameter %u, is used but does not " -- cgit v1.1 From 1275a541a59e4d74101bd34eb907ba6d5844f810 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 26 Sep 2019 10:43:09 +0000 Subject: [arm] Update FP16 tests My recent assemble_real patch (r275873) meant that we now output negative FP16 constants in the same way as we'd output an integer subreg of them. This patch updates gcc.target/arm/fp16-* accordingly. 2019-09-26 Richard Sandiford gcc/testsuite/ * gcc.target/arm/fp16-compile-alt-3.c: Expect (__fp16) -2.0 to be written as a negative short rather than a positive one. * gcc.target/arm/fp16-compile-ieee-3.c: Likewise. From-SVN: r276145 --- gcc/testsuite/ChangeLog | 6 ++++++ gcc/testsuite/gcc.target/arm/fp16-compile-alt-3.c | 2 +- gcc/testsuite/gcc.target/arm/fp16-compile-ieee-3.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1f99dbd..0274587 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-09-26 Richard Sandiford + + * gcc.target/arm/fp16-compile-alt-3.c: Expect (__fp16) -2.0 + to be written as a negative short rather than a positive one. + * gcc.target/arm/fp16-compile-ieee-3.c: Likewise. + 2019-09-26 Martin Liska PR tree-optimization/91885 diff --git a/gcc/testsuite/gcc.target/arm/fp16-compile-alt-3.c b/gcc/testsuite/gcc.target/arm/fp16-compile-alt-3.c index e786a51..7221766 100644 --- a/gcc/testsuite/gcc.target/arm/fp16-compile-alt-3.c +++ b/gcc/testsuite/gcc.target/arm/fp16-compile-alt-3.c @@ -7,4 +7,4 @@ __fp16 xx = -2.0; /* { dg-final { scan-assembler "\t.size\txx, 2" } } */ -/* { dg-final { scan-assembler "\t.short\t49152" } } */ +/* { dg-final { scan-assembler "\t.short\t-16384" } } */ diff --git a/gcc/testsuite/gcc.target/arm/fp16-compile-ieee-3.c b/gcc/testsuite/gcc.target/arm/fp16-compile-ieee-3.c index 90edd01..1f1e074 100644 --- a/gcc/testsuite/gcc.target/arm/fp16-compile-ieee-3.c +++ b/gcc/testsuite/gcc.target/arm/fp16-compile-ieee-3.c @@ -6,4 +6,4 @@ __fp16 xx = -2.0; /* { dg-final { scan-assembler "\t.size\txx, 2" } } */ -/* { dg-final { scan-assembler "\t.short\t49152" } } */ +/* { dg-final { scan-assembler "\t.short\t-16384" } } */ -- cgit v1.1 From 53cd0ac643ed1fcb507ceb01dc531da1868f88d7 Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Thu, 26 Sep 2019 10:46:14 +0000 Subject: [arm] Implement non-GE-setting SIMD32 intrinsics This patch is part of a series to implement the SIMD32 ACLE intrinsics [1]. The interesting parts implementation-wise involve adding support for setting and reading the Q bit for saturation and the GE-bits for the packed SIMD instructions. That will come in a later patch. For now, this patch implements the other intrinsics that don't need anything special ; just a mapping from arm_acle.h function to builtin to RTL expander+unspec. I've compressed as many as I could with iterators so that we end up needing only 3 new define_insns. Bootstrapped and tested on arm-none-linux-gnueabihf. [1] https://developer.arm.com/docs/101028/latest/data-processing-intrinsics * config/arm/arm.md (arm_): New define_insn. (arm_xtb16): Likewise. (arm_usada8): Likewise. * config/arm/arm_acle.h (__qadd8, __qsub8, __shadd8, __shsub8, __uhadd8, __uhsub8, __uqadd8, __uqsub8, __qadd16, __qasx, __qsax, __qsub16, __shadd16, __shasx, __shsax, __shsub16, __uhadd16, __uhasx, __uhsax, __uhsub16, __uqadd16, __uqasx, __uqsax, __uqsub16, __sxtab16, __sxtb16, __uxtab16, __uxtb16): Define. * config/arm/arm_acle_builtins.def: Define builtins for the above. * config/arm/unspecs.md: Define unspecs for the above. * config/arm/iterators.md (SIMD32_NOGE_BINOP): New int_iterator. (USXTB16): Likewise. (simd32_op): New int_attribute. (sup): Handle UNSPEC_SXTB16, UNSPEC_UXTB16. * doc/sourcebuild.exp (arm_simd32_ok): Document. * lib/target-supports.exp (check_effective_target_arm_simd32_ok_nocache): New procedure. (check_effective_target_arm_simd32_ok): Likewise. (add_options_for_arm_simd32): Likewise. * gcc.target/arm/acle/simd32.c: New test. From-SVN: r276146 --- gcc/ChangeLog | 18 +++ gcc/config/arm/arm.md | 30 ++++ gcc/config/arm/arm_acle.h | 232 +++++++++++++++++++++++++++ gcc/config/arm/arm_acle_builtins.def | 33 ++++ gcc/config/arm/iterators.md | 30 ++++ gcc/config/arm/unspecs.md | 34 ++++ gcc/doc/sourcebuild.texi | 7 + gcc/testsuite/ChangeLog | 8 + gcc/testsuite/gcc.target/arm/acle/simd32.c | 246 +++++++++++++++++++++++++++++ gcc/testsuite/lib/target-supports.exp | 39 +++++ 10 files changed, 677 insertions(+) create mode 100644 gcc/testsuite/gcc.target/arm/acle/simd32.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6bbcfe5..fad363b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2019-09-26 Kyrylo Tkachov + + * config/arm/arm.md (arm_): New define_insn. + (arm_xtb16): Likewise. + (arm_usada8): Likewise. + * config/arm/arm_acle.h (__qadd8, __qsub8, __shadd8, __shsub8, + __uhadd8, __uhsub8, __uqadd8, __uqsub8, __qadd16, __qasx, __qsax, + __qsub16, __shadd16, __shasx, __shsax, __shsub16, __uhadd16, __uhasx, + __uhsax, __uhsub16, __uqadd16, __uqasx, __uqsax, __uqsub16, __sxtab16, + __sxtb16, __uxtab16, __uxtb16): Define. + * config/arm/arm_acle_builtins.def: Define builtins for the above. + * config/arm/unspecs.md: Define unspecs for the above. + * config/arm/iterators.md (SIMD32_NOGE_BINOP): New int_iterator. + (USXTB16): Likewise. + (simd32_op): New int_attribute. + (sup): Handle UNSPEC_SXTB16, UNSPEC_UXTB16. + * doc/sourcebuild.exp (arm_simd32_ok): Document. + 2019-09-26 Martin Jambor * ipa-sra.c (verify_splitting_accesses): Fix quoting in a call to diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index d607f88..99e4acd 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -5058,6 +5058,36 @@ (set_attr "predicable" "yes")] ) +(define_insn "arm_xtb16" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI + [(match_operand:SI 1 "s_register_operand" "r")] USXTB16))] + "TARGET_INT_SIMD" + "xtb16%?\\t%0, %1" + [(set_attr "predicable" "yes") + (set_attr "type" "alu_dsp_reg")]) + +(define_insn "arm_" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r")] SIMD32_NOGE_BINOP))] + "TARGET_INT_SIMD" + "%?\\t%0, %1, %2" + [(set_attr "predicable" "yes") + (set_attr "type" "alu_dsp_reg")]) + +(define_insn "arm_usada8" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (unspec:SI + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "s_register_operand" "r")] UNSPEC_USADA8))] + "TARGET_INT_SIMD" + "usada8%?\\t%0, %1, %2, %3" + [(set_attr "predicable" "yes") + (set_attr "type" "alu_dsp_reg")]) + (define_expand "extendsfdf2" [(set (match_operand:DF 0 "s_register_operand") (float_extend:DF (match_operand:SF 1 "s_register_operand")))] diff --git a/gcc/config/arm/arm_acle.h b/gcc/config/arm/arm_acle.h index 6857ab1..9c6f12d 100644 --- a/gcc/config/arm/arm_acle.h +++ b/gcc/config/arm/arm_acle.h @@ -173,6 +173,238 @@ __arm_mrrc2 (const unsigned int __coproc, const unsigned int __opc1, #endif /* __ARM_ARCH >= 5. */ #endif /* (!__thumb__ || __thumb2__) && __ARM_ARCH >= 4. */ +#ifdef __ARM_FEATURE_SIMD32 +typedef int32_t int16x2_t; +typedef uint32_t uint16x2_t; +typedef int32_t int8x4_t; +typedef uint32_t uint8x4_t; + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__sxtab16 (int16x2_t __a, int8x4_t __b) +{ + return __builtin_arm_sxtab16 (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__sxtb16 (int8x4_t __a) +{ + return __builtin_arm_sxtb16 (__a); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uxtab16 (uint16x2_t __a, uint8x4_t __b) +{ + return __builtin_arm_uxtab16 (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uxtb16 (uint8x4_t __a) +{ + return __builtin_arm_uxtb16 (__a); +} + +__extension__ extern __inline int8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__qadd8 (int8x4_t __a, int8x4_t __b) +{ + return __builtin_arm_qadd8 (__a, __b); +} + +__extension__ extern __inline int8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__qsub8 (int8x4_t __a, int8x4_t __b) +{ + return __builtin_arm_qsub8 (__a, __b); +} + +__extension__ extern __inline int8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__shadd8 (int8x4_t __a, int8x4_t __b) +{ + return __builtin_arm_shadd8 (__a, __b); +} + +__extension__ extern __inline int8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__shsub8 (int8x4_t __a, int8x4_t __b) +{ + return __builtin_arm_shsub8 (__a, __b); +} + +__extension__ extern __inline uint8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uhadd8 (uint8x4_t __a, uint8x4_t __b) +{ + return __builtin_arm_uhadd8 (__a, __b); +} + +__extension__ extern __inline uint8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uhsub8 (uint8x4_t __a, uint8x4_t __b) +{ + return __builtin_arm_uhsub8 (__a, __b); +} + +__extension__ extern __inline uint8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uqadd8 (uint8x4_t __a, uint8x4_t __b) +{ + return __builtin_arm_uqadd8 (__a, __b); +} + +__extension__ extern __inline uint8x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uqsub8 (uint8x4_t __a, uint8x4_t __b) +{ + return __builtin_arm_uqsub8 (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__qadd16 (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_qadd16 (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__qasx (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_qasx (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__qsax (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_qsax (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__qsub16 (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_qsub16 (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__shadd16 (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_shadd16 (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__shasx (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_shasx (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__shsax (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_shsax (__a, __b); +} + +__extension__ extern __inline int16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__shsub16 (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_shsub16 (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uhadd16 (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uhadd16 (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uhasx (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uhasx (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uhsax (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uhsax (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uhsub16 (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uhsub16 (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uqadd16 (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uqadd16 (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uqasx (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uqasx (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uqsax (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uqsax (__a, __b); +} + +__extension__ extern __inline uint16x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__uqsub16 (uint16x2_t __a, uint16x2_t __b) +{ + return __builtin_arm_uqsub16 (__a, __b); +} + +__extension__ extern __inline int32_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__smusd (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_smusd (__a, __b); +} + +__extension__ extern __inline int32_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__smusdx (int16x2_t __a, int16x2_t __b) +{ + return __builtin_arm_smusdx (__a, __b); +} + +__extension__ extern __inline uint32_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__usad8 (uint8x4_t __a, uint8x4_t __b) +{ + return __builtin_arm_usad8 (__a, __b); +} + +__extension__ extern __inline uint32_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__usada8 (uint8x4_t __a, uint8x4_t __b, uint32_t __c) +{ + return __builtin_arm_usada8 (__a, __b, __c); +} + +#endif + #pragma GCC push_options #ifdef __ARM_FEATURE_CRC32 #ifdef __ARM_FP diff --git a/gcc/config/arm/arm_acle_builtins.def b/gcc/config/arm/arm_acle_builtins.def index b2438d6..c675fc4 100644 --- a/gcc/config/arm/arm_acle_builtins.def +++ b/gcc/config/arm/arm_acle_builtins.def @@ -42,3 +42,36 @@ VAR1 (MCRR, mcrr, void) VAR1 (MCRR, mcrr2, void) VAR1 (MRRC, mrrc, di) VAR1 (MRRC, mrrc2, di) + +VAR1 (BINOP, sxtab16, si) +VAR1 (UBINOP, uxtab16, si) +VAR1 (UNOP, sxtb16, si) +VAR1 (BSWAP, uxtb16, si) +VAR1 (BINOP, qadd8, si) +VAR1 (BINOP, qsub8, si) +VAR1 (BINOP, shadd8, si) +VAR1 (BINOP, shsub8, si) +VAR1 (UBINOP, uhadd8, si) +VAR1 (UBINOP, uhsub8, si) +VAR1 (UBINOP, uqadd8, si) +VAR1 (UBINOP, uqsub8, si) +VAR1 (BINOP, qadd16, si) +VAR1 (BINOP, qasx, si) +VAR1 (BINOP, qsax, si) +VAR1 (BINOP, qsub16, si) +VAR1 (BINOP, shadd16, si) +VAR1 (BINOP, shasx, si) +VAR1 (BINOP, shsax, si) +VAR1 (BINOP, shsub16, si) +VAR1 (UBINOP, uhadd16, si) +VAR1 (UBINOP, uhasx, si) +VAR1 (UBINOP, uhsax, si) +VAR1 (UBINOP, uhsub16, si) +VAR1 (UBINOP, uqadd16, si) +VAR1 (UBINOP, uqasx, si) +VAR1 (UBINOP, uqsax, si) +VAR1 (UBINOP, uqsub16, si) +VAR1 (BINOP, smusd, si) +VAR1 (BINOP, smusdx, si) +VAR1 (UBINOP, usad8, si) +VAR1 (UBINOP, usada8, si) diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 2d8ef3f..538f5bf 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -430,6 +430,19 @@ (define_int_iterator CRYPTO_SELECTING [UNSPEC_SHA1C UNSPEC_SHA1M UNSPEC_SHA1P]) +(define_int_iterator USXTB16 [UNSPEC_SXTB16 UNSPEC_UXTB16]) +(define_int_iterator SIMD32_NOGE_BINOP + [UNSPEC_QADD8 UNSPEC_QSUB8 UNSPEC_SHADD8 + UNSPEC_SHSUB8 UNSPEC_UHADD8 UNSPEC_UHSUB8 + UNSPEC_UQADD8 UNSPEC_UQSUB8 + UNSPEC_QADD16 UNSPEC_QASX UNSPEC_QSAX + UNSPEC_QSUB16 UNSPEC_SHADD16 UNSPEC_SHASX + UNSPEC_SHSAX UNSPEC_SHSUB16 UNSPEC_UHADD16 + UNSPEC_UHASX UNSPEC_UHSAX UNSPEC_UHSUB16 + UNSPEC_UQADD16 UNSPEC_UQASX UNSPEC_UQSAX + UNSPEC_UQSUB16 UNSPEC_SMUSD UNSPEC_SMUSDX + UNSPEC_SXTAB16 UNSPEC_UXTAB16 UNSPEC_USAD8]) + (define_int_iterator VQRDMLH_AS [UNSPEC_VQRDMLAH UNSPEC_VQRDMLSH]) (define_int_iterator VFM_LANE_AS [UNSPEC_VFMA_LANE UNSPEC_VFMS_LANE]) @@ -835,6 +848,7 @@ ;; Mapping between vector UNSPEC operations and the signed ('s'), ;; unsigned ('u'), poly ('p') or float ('f') nature of their data type. (define_int_attr sup [ + (UNSPEC_SXTB16 "s") (UNSPEC_UXTB16 "u") (UNSPEC_VADDL_S "s") (UNSPEC_VADDL_U "u") (UNSPEC_VADDW_S "s") (UNSPEC_VADDW_U "u") (UNSPEC_VRHADD_S "s") (UNSPEC_VRHADD_U "u") @@ -1023,6 +1037,22 @@ (UNSPEC_VCMLA180 "180") (UNSPEC_VCMLA270 "270")]) +(define_int_attr simd32_op [(UNSPEC_QADD8 "qadd8") (UNSPEC_QSUB8 "qsub8") + (UNSPEC_SHADD8 "shadd8") (UNSPEC_SHSUB8 "shsub8") + (UNSPEC_UHADD8 "uhadd8") (UNSPEC_UHSUB8 "uhsub8") + (UNSPEC_UQADD8 "uqadd8") (UNSPEC_UQSUB8 "uqsub8") + (UNSPEC_QADD16 "qadd16") (UNSPEC_QASX "qasx") + (UNSPEC_QSAX "qsax") (UNSPEC_QSUB16 "qsub16") + (UNSPEC_SHADD16 "shadd16") (UNSPEC_SHASX "shasx") + (UNSPEC_SHSAX "shsax") (UNSPEC_SHSUB16 "shsub16") + (UNSPEC_UHADD16 "uhadd16") (UNSPEC_UHASX "uhasx") + (UNSPEC_UHSAX "uhsax") (UNSPEC_UHSUB16 "uhsub16") + (UNSPEC_UQADD16 "uqadd16") (UNSPEC_UQASX "uqasx") + (UNSPEC_UQSAX "uqsax") (UNSPEC_UQSUB16 "uqsub16") + (UNSPEC_SMUSD "smusd") (UNSPEC_SMUSDX "smusdx") + (UNSPEC_SXTAB16 "sxtab16") (UNSPEC_UXTAB16 "uxtab16") + (UNSPEC_USAD8 "usad8")]) + ;; Both kinds of return insn. (define_code_iterator RETURNS [return simple_return]) (define_code_attr return_str [(return "") (simple_return "simple_")]) diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md index a9f99d0..08a6cd7 100644 --- a/gcc/config/arm/unspecs.md +++ b/gcc/config/arm/unspecs.md @@ -90,8 +90,42 @@ UNSPEC_SP_TEST ; Represent the testing of stack protector's canary ; against the guard. UNSPEC_PIC_RESTORE ; Use to restore fdpic register + + UNSPEC_SXTAB16 ; Represent the SXTAB16 operation. + UNSPEC_UXTAB16 ; Represent the UXTAB16 operation. + UNSPEC_SXTB16 ; Represent the SXTB16 operation. + UNSPEC_UXTB16 ; Represent the UXTB16 operation. + UNSPEC_QADD8 ; Represent the QADD8 operation. + UNSPEC_QSUB8 ; Represent the QSUB8 operation. + UNSPEC_SHADD8 ; Represent the SHADD8 operation. + UNSPEC_SHSUB8 ; Represent the SHSUB8 operation. + UNSPEC_UHADD8 ; Represent the UHADD8 operation. + UNSPEC_UHSUB8 ; Represent the UHSUB8 operation. + UNSPEC_UQADD8 ; Represent the UQADD8 operation. + UNSPEC_UQSUB8 ; Represent the UQSUB8 operation. + UNSPEC_QADD16 ; Represent the QADD16 operation. + UNSPEC_QASX ; Represent the QASX operation. + UNSPEC_QSAX ; Represent the QSAX operation. + UNSPEC_QSUB16 ; Represent the QSUB16 operation. + UNSPEC_SHADD16 ; Represent the SHADD16 operation. + UNSPEC_SHASX ; Represent the SHASX operation. + UNSPEC_SHSAX ; Represent the SSAX operation. + UNSPEC_SHSUB16 ; Represent the SHSUB16 operation. + UNSPEC_UHADD16 ; Represent the UHADD16 operation. + UNSPEC_UHASX ; Represent the UHASX operation. + UNSPEC_UHSAX ; Represent the USAX operation. + UNSPEC_UHSUB16 ; Represent the UHSUB16 operation. + UNSPEC_UQADD16 ; Represent the UQADD16 operation. + UNSPEC_UQASX ; Represent the UQASX operation. + UNSPEC_UQSAX ; Represent the UQSAX operation. + UNSPEC_UQSUB16 ; Represent the UQSUB16 operation. + UNSPEC_SMUSD ; Represent the SMUSD operation. + UNSPEC_SMUSDX ; Represent the SMUSDX operation. + UNSPEC_USAD8 ; Represent the USAD8 operation. + UNSPEC_USADA8 ; Represent the USADA8 operation. ]) + (define_c_enum "unspec" [ UNSPEC_WADDC ; Used by the intrinsic form of the iWMMXt WADDC instruction. UNSPEC_WABS ; Used by the intrinsic form of the iWMMXt WABS instruction. diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 4ace224..9b98f01 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -1900,6 +1900,13 @@ in @ref{arm_coproc2_ok} in addition the following: @code{MCRR} and @code{MRRC}. @item arm_coproc4_ok ARM target supports all the coprocessor instructions also listed as supported in @ref{arm_coproc3_ok} in addition the following: @code{MCRR2} and @code{MRRC2}. + +@item arm_simd32_ok +@anchor{arm_simd32_ok} +ARM Target supports options suitable for accessing the SIMD32 intrinsics from +@code{arm_acle.h}. +Some multilibs may be incompatible with these options. + @end table @subsubsection AArch64-specific attributes diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0274587..d3a0af6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-09-26 Kyrylo Tkachov + + * lib/target-supports.exp + (check_effective_target_arm_simd32_ok_nocache): New procedure. + (check_effective_target_arm_simd32_ok): Likewise. + (add_options_for_arm_simd32): Likewise. + * gcc.target/arm/acle/simd32.c: New test. + 2019-09-26 Richard Sandiford * gcc.target/arm/fp16-compile-alt-3.c: Expect (__fp16) -2.0 diff --git a/gcc/testsuite/gcc.target/arm/acle/simd32.c b/gcc/testsuite/gcc.target/arm/acle/simd32.c new file mode 100644 index 0000000..f5c116d --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/acle/simd32.c @@ -0,0 +1,246 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_simd32_ok } */ +/* { dg-add-options arm_simd32 } */ + +#include + +int16x2_t +test_sxtab16 (int16x2_t a, int8x4_t b) +{ + return __sxtab16 (a, b); +} + +/* { dg-final { scan-assembler-times "sxtab16\t...?, ...?, ...?" 1 } } */ + + +int16x2_t +test_sxtb16 (int8x4_t a) +{ + return __sxtb16 (a); +} + +/* { dg-final { scan-assembler-times "sxtab16\t...?, ...?" 1 } } */ + +int8x4_t +test_qadd8 (int8x4_t a, int8x4_t b) +{ + return __qadd8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tqadd8\t...?, ...?, ...?" 1 } } */ + +int8x4_t +test_qsub8 (int8x4_t a, int8x4_t b) +{ + return __qsub8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tqsub8\t...?, ...?, ...?" 1 } } */ + +int8x4_t +test_shadd8 (int8x4_t a, int8x4_t b) +{ + return __shadd8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tshadd8\t...?, ...?, ...?" 1 } } */ + +int8x4_t +test_shsub8 (int8x4_t a, int8x4_t b) +{ + return __shsub8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tshsub8\t...?, ...?, ...?" 1 } } */ + +uint8x4_t +test_uhadd8 (uint8x4_t a, uint8x4_t b) +{ + return __uhadd8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuhadd8\t...?, ...?, ...?" 1 } } */ + +uint8x4_t +test_uhsub8 (uint8x4_t a, uint8x4_t b) +{ + return __uhsub8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuhsub8\t...?, ...?, ...?" 1 } } */ + +uint8x4_t +test_uqadd8 (uint8x4_t a, uint8x4_t b) +{ + return __uqadd8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuqadd8\t...?, ...?, ...?" 1 } } */ + +uint8x4_t +test_uqsub8 (uint8x4_t a, uint8x4_t b) +{ + return __uqsub8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuqsub8\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_qadd16 (int16x2_t a, int16x2_t b) +{ + return __qadd16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tqadd16\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_qasx (int16x2_t a, int16x2_t b) +{ + return __qasx (a, b); +} + +/* { dg-final { scan-assembler-times "\tqasx\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_qsax (int16x2_t a, int16x2_t b) +{ + return __qsax (a, b); +} + +/* { dg-final { scan-assembler-times "\tqsax\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_qsub16 (int16x2_t a, int16x2_t b) +{ + return __qsub16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tqsub16\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_shadd16 (int16x2_t a, int16x2_t b) +{ + return __shadd16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tshadd16\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_shasx (int16x2_t a, int16x2_t b) +{ + return __shasx (a, b); +} + +/* { dg-final { scan-assembler-times "\tshasx\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_shsax (int16x2_t a, int16x2_t b) +{ + return __shsax (a, b); +} + +/* { dg-final { scan-assembler-times "\tshsax\t...?, ...?, ...?" 1 } } */ + +int16x2_t +test_shsub16 (int16x2_t a, int16x2_t b) +{ + return __shsub16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tshsub16\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uhadd16 (uint16x2_t a, uint16x2_t b) +{ + return __uhadd16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuhadd16\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uhasx (uint16x2_t a, uint16x2_t b) +{ + return __uhasx (a, b); +} + +/* { dg-final { scan-assembler-times "\tuhasx\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uhsax (uint16x2_t a, uint16x2_t b) +{ + return __uhsax (a, b); +} + +/* { dg-final { scan-assembler-times "\tuhsax\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uhsub16 (uint16x2_t a, uint16x2_t b) +{ + return __uhsub16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuhsub16\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uqadd16 (uint16x2_t a, uint16x2_t b) +{ + return __uqadd16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuqadd16\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uqasx (uint16x2_t a, uint16x2_t b) +{ + return __uqasx (a, b); +} + +/* { dg-final { scan-assembler-times "\tuqasx\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uqsax (uint16x2_t a, uint16x2_t b) +{ + return __uqsax (a, b); +} + +/* { dg-final { scan-assembler-times "\tuqsax\t...?, ...?, ...?" 1 } } */ + +uint16x2_t +test_uqsub16 (uint16x2_t a, uint16x2_t b) +{ + return __uqsub16 (a, b); +} + +/* { dg-final { scan-assembler-times "\tuqsub16\t...?, ...?, ...?" 1 } } */ + +int32_t +test_smusd (int16x2_t a, int16x2_t b) +{ + return __smusd (a, b); +} + +/* { dg-final { scan-assembler-times "\tsmusd\t...?, ...?, ...?" 1 } } */ + +int32_t +test_smusdx (int16x2_t a, int16x2_t b) +{ + return __smusdx (a, b); +} + +/* { dg-final { scan-assembler-times "\tsmusdx\t...?, ...?, ...?" 1 } } */ + +uint32_t +test_usad8 (uint8x4_t a, uint8x4_t b) +{ + return __usad8 (a, b); +} + +/* { dg-final { scan-assembler-times "\tusad8\t...?, ...?, ...?" 1 } } */ + +uint32_t +test_usada8 (uint8x4_t a, uint8x4_t b, uint32_t c) +{ + return __usada8 (a, b, c); +} + +/* { dg-final { scan-assembler-times "\tusada8\t...?, ...?, ...?, ...?" 1 } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 6a1aaca..0268acd 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -3806,6 +3806,45 @@ proc check_effective_target_arm_neon_ok { } { check_effective_target_arm_neon_ok_nocache] } + +# Return 1 if this is an ARM target supporting the SIMD32 intrinsics +# from arm_acle.h. Some multilibs may be incompatible with these options. +# Also set et_arm_simd32_flags to the best options to add. +# arm_acle.h includes stdint.h which can cause trouble with incompatible +# -mfloat-abi= options. + +proc check_effective_target_arm_simd32_ok_nocache { } { + global et_arm_simd32_flags + set et_arm_simd32_flags "" + foreach flags {"" "-march=armv6" "-march=armv6 -mfloat-abi=softfp" "-march=armv6 -mfloat-abi=hard"} { + if { [check_no_compiler_messages_nocache arm_simd32_ok object { + #include + int dummy; + #ifndef __ARM_FEATURE_SIMD32 + #error not SIMD32 + #endif + } "$flags"] } { + set et_arm_simd32_flags $flags + return 1 + } + } + + return 0 +} + +proc check_effective_target_arm_simd32_ok { } { + return [check_cached_effective_target arm_simd32_ok \ + check_effective_target_arm_simd32_ok_nocache] +} + +proc add_options_for_arm_simd32 { flags } { + if { ! [check_effective_target_arm_simd32_ok] } { + return "$flags" + } + global et_arm_simd32_flags + return "$flags $et_arm_simd32_flags" +} + # Return 1 if this is an ARM target supporting -mfpu=neon without any # -mfloat-abi= option. Useful in tests where add_options is not # supported (such as lto tests). -- cgit v1.1 From 2b5b5e24149160e38ff3cd98c6a911f0eba4acc5 Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Thu, 26 Sep 2019 10:48:02 +0000 Subject: [arm] Implement DImode SIMD32 intrinsics This patch implements some more SIMD32, but these ones have a DImode result+addend. Apart from that there's nothing too exciting about them. Bootstrapped and tested on arm-none-linux-gnueabihf. * config/arm/arm.md (arm_): New define_insn. * config/arm/arm_acle.h (__smlald, __smlaldx, __smlsld, __smlsldx): Define. * config/arm/arm_acle.h: Define builtins for the above. * config/arm/iterators.md (SIMD32_DIMODE): New int_iterator. (simd32_op): Handle the above. * config/arm/unspecs.md: Define unspecs for the above. * gcc.target/arm/acle/simd32.c: Update test. From-SVN: r276147 --- gcc/ChangeLog | 10 ++++++++++ gcc/config/arm/arm.md | 11 ++++++++++ gcc/config/arm/arm_acle.h | 29 +++++++++++++++++++++++++++ gcc/config/arm/arm_acle_builtins.def | 4 ++++ gcc/config/arm/iterators.md | 7 ++++++- gcc/config/arm/unspecs.md | 4 ++++ gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gcc.target/arm/acle/simd32.c | 32 ++++++++++++++++++++++++++++++ 8 files changed, 100 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fad363b..ac39c2f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,16 @@ 2019-09-26 Kyrylo Tkachov * config/arm/arm.md (arm_): New define_insn. + * config/arm/arm_acle.h (__smlald, __smlaldx, __smlsld, __smlsldx): + Define. + * config/arm/arm_acle.h: Define builtins for the above. + * config/arm/iterators.md (SIMD32_DIMODE): New int_iterator. + (simd32_op): Handle the above. + * config/arm/unspecs.md: Define unspecs for the above. + +2019-09-26 Kyrylo Tkachov + + * config/arm/arm.md (arm_): New define_insn. (arm_xtb16): Likewise. (arm_usada8): Likewise. * config/arm/arm_acle.h (__qadd8, __qsub8, __shadd8, __shsub8, diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 99e4acd..d3ee59a 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -5088,6 +5088,17 @@ [(set_attr "predicable" "yes") (set_attr "type" "alu_dsp_reg")]) +(define_insn "arm_" + [(set (match_operand:DI 0 "s_register_operand" "=r") + (unspec:DI + [(match_operand:SI 1 "s_register_operand" "r") + (match_operand:SI 2 "s_register_operand" "r") + (match_operand:DI 3 "s_register_operand" "0")] SIMD32_DIMODE))] + "TARGET_INT_SIMD" + "%?\\t%Q0, %R0, %1, %2" + [(set_attr "predicable" "yes") + (set_attr "type" "smlald")]) + (define_expand "extendsfdf2" [(set (match_operand:DF 0 "s_register_operand") (float_extend:DF (match_operand:SF 1 "s_register_operand")))] diff --git a/gcc/config/arm/arm_acle.h b/gcc/config/arm/arm_acle.h index 9c6f12d..248a355 100644 --- a/gcc/config/arm/arm_acle.h +++ b/gcc/config/arm/arm_acle.h @@ -403,8 +403,37 @@ __usada8 (uint8x4_t __a, uint8x4_t __b, uint32_t __c) return __builtin_arm_usada8 (__a, __b, __c); } +__extension__ extern __inline int64_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__smlald (int16x2_t __a, int16x2_t __b, int64_t __c) +{ + return __builtin_arm_smlald (__a, __b, __c); +} + +__extension__ extern __inline int64_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__smlaldx (int16x2_t __a, int16x2_t __b, int64_t __c) +{ + return __builtin_arm_smlaldx (__a, __b, __c); +} + +__extension__ extern __inline int64_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__smlsld (int16x2_t __a, int16x2_t __b, int64_t __c) +{ + return __builtin_arm_smlsld (__a, __b, __c); +} + +__extension__ extern __inline int64_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +__smlsldx (int16x2_t __a, int16x2_t __b, int64_t __c) +{ + return __builtin_arm_smlsldx (__a, __b, __c); +} + #endif + #pragma GCC push_options #ifdef __ARM_FEATURE_CRC32 #ifdef __ARM_FP diff --git a/gcc/config/arm/arm_acle_builtins.def b/gcc/config/arm/arm_acle_builtins.def index c675fc4..0021c00 100644 --- a/gcc/config/arm/arm_acle_builtins.def +++ b/gcc/config/arm/arm_acle_builtins.def @@ -75,3 +75,7 @@ VAR1 (BINOP, smusd, si) VAR1 (BINOP, smusdx, si) VAR1 (UBINOP, usad8, si) VAR1 (UBINOP, usada8, si) +VAR1 (TERNOP, smlald, di) +VAR1 (TERNOP, smlaldx, di) +VAR1 (TERNOP, smlsld, di) +VAR1 (TERNOP, smlsldx, di) diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 538f5bf..8c9f712 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -443,6 +443,9 @@ UNSPEC_UQSUB16 UNSPEC_SMUSD UNSPEC_SMUSDX UNSPEC_SXTAB16 UNSPEC_UXTAB16 UNSPEC_USAD8]) +(define_int_iterator SIMD32_DIMODE [UNSPEC_SMLALD UNSPEC_SMLALDX + UNSPEC_SMLSLD UNSPEC_SMLSLDX]) + (define_int_iterator VQRDMLH_AS [UNSPEC_VQRDMLAH UNSPEC_VQRDMLSH]) (define_int_iterator VFM_LANE_AS [UNSPEC_VFMA_LANE UNSPEC_VFMS_LANE]) @@ -1051,7 +1054,9 @@ (UNSPEC_UQSAX "uqsax") (UNSPEC_UQSUB16 "uqsub16") (UNSPEC_SMUSD "smusd") (UNSPEC_SMUSDX "smusdx") (UNSPEC_SXTAB16 "sxtab16") (UNSPEC_UXTAB16 "uxtab16") - (UNSPEC_USAD8 "usad8")]) + (UNSPEC_USAD8 "usad8") (UNSPEC_SMLALD "smlald") + (UNSPEC_SMLALDX "smlaldx") (UNSPEC_SMLSLD "smlsld") + (UNSPEC_SMLSLDX "smlsldx")]) ;; Both kinds of return insn. (define_code_iterator RETURNS [return simple_return]) diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md index 08a6cd7..78f88d5 100644 --- a/gcc/config/arm/unspecs.md +++ b/gcc/config/arm/unspecs.md @@ -123,6 +123,10 @@ UNSPEC_SMUSDX ; Represent the SMUSDX operation. UNSPEC_USAD8 ; Represent the USAD8 operation. UNSPEC_USADA8 ; Represent the USADA8 operation. + UNSPEC_SMLALD ; Represent the SMLALD operation. + UNSPEC_SMLALDX ; Represent the SMLALDX operation. + UNSPEC_SMLSLD ; Represent the SMLSLD operation. + UNSPEC_SMLSLDX ; Represent the SMLSLDX operation. ]) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d3a0af6..2323593 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2019-09-26 Kyrylo Tkachov + * gcc.target/arm/acle/simd32.c: Update test. + +2019-09-26 Kyrylo Tkachov + * lib/target-supports.exp (check_effective_target_arm_simd32_ok_nocache): New procedure. (check_effective_target_arm_simd32_ok): Likewise. diff --git a/gcc/testsuite/gcc.target/arm/acle/simd32.c b/gcc/testsuite/gcc.target/arm/acle/simd32.c index f5c116d..e43ea96 100644 --- a/gcc/testsuite/gcc.target/arm/acle/simd32.c +++ b/gcc/testsuite/gcc.target/arm/acle/simd32.c @@ -244,3 +244,35 @@ test_usada8 (uint8x4_t a, uint8x4_t b, uint32_t c) } /* { dg-final { scan-assembler-times "\tusada8\t...?, ...?, ...?, ...?" 1 } } */ + +int64_t +test_smlald (int16x2_t a, int16x2_t b, int64_t c) +{ + return __smlald (a, b, c); +} + +/* { dg-final { scan-assembler-times "\tsmlald\t...?, ...?, ...?, ...?" 1 } } */ + +int64_t +test_smlaldx (int16x2_t a, int16x2_t b, int64_t c) +{ + return __smlaldx (a, b, c); +} + +/* { dg-final { scan-assembler-times "\tsmlaldx\t...?, ...?, ...?, ...?" 1 } } */ + +int64_t +test_smlsld (int16x2_t a, int16x2_t b, int64_t c) +{ + return __smlsld (a, b, c); +} + +/* { dg-final { scan-assembler-times "\tsmlsld\t...?, ...?, ...?, ...?" 1 } } */ + +int64_t +test_smlsldx (int16x2_t a, int16x2_t b, int64_t c) +{ + return __smlsldx (a, b, c); +} + +/* { dg-final { scan-assembler-times "\tsmlsldx\t...?, ...?, ...?, ...?" 1 } } */ -- cgit v1.1 From 6fdbe41963a7aecad80f27e9805c7e18cbd4ab48 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Thu, 26 Sep 2019 10:52:42 +0000 Subject: driver: Also prune joined switches with negation When -march=native is passed to host_detect_local_cpu to the backend, it overrides all command lines after it. That means $ gcc -march=native -march=armv8-a is treated as $ gcc -march=armv8-a -march=native Prune joined switches with Negative and RejectNegative to allow -march=armv8-a to override previous -march=native on command-line. This is the same fix as was applied for i386 in SVN revision 269164 but for aarch64 and arm. 2019-09-26 Matt Turner PR driver/69471 * config/aarch64/aarch64.opt (march=): Add Negative(march=). (mtune=): Add Negative(mtune=). (mcpu=): Add Negative(mcpu=). * config/arm/arm.opt: Likewise. From-SVN: r276148 --- gcc/ChangeLog | 8 ++++++++ gcc/config/aarch64/aarch64.opt | 6 +++--- gcc/config/arm/arm.opt | 6 +++--- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ac39c2f..98fa0ff 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-26 Matt Turner + + PR driver/69471 + * config/aarch64/aarch64.opt (march=): Add Negative(march=). + (mtune=): Add Negative(mtune=). + (mcpu=): Add Negative(mcpu=). + * config/arm/arm.opt: Likewise. + 2019-09-26 Kyrylo Tkachov * config/arm/arm.md (arm_): New define_insn. diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 865b6a6..fc43428 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -119,15 +119,15 @@ EnumValue Enum(aarch64_tls_size) String(48) Value(48) march= -Target RejectNegative ToLower Joined Var(aarch64_arch_string) +Target RejectNegative Negative(march=) ToLower Joined Var(aarch64_arch_string) Use features of architecture ARCH. mcpu= -Target RejectNegative ToLower Joined Var(aarch64_cpu_string) +Target RejectNegative Negative(mcpu=) ToLower Joined Var(aarch64_cpu_string) Use features of and optimize for CPU. mtune= -Target RejectNegative ToLower Joined Var(aarch64_tune_string) +Target RejectNegative Negative(mtune=) ToLower Joined Var(aarch64_tune_string) Optimize for CPU. mabi= diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt index 452f0cf..76c10ab 100644 --- a/gcc/config/arm/arm.opt +++ b/gcc/config/arm/arm.opt @@ -82,7 +82,7 @@ mapcs-stack-check Target Report Mask(APCS_STACK) Undocumented march= -Target RejectNegative ToLower Joined Var(arm_arch_string) +Target RejectNegative Negative(march=) ToLower Joined Var(arm_arch_string) Specify the name of the target architecture. ; Other arm_arch values are loaded from arm-tables.opt @@ -107,7 +107,7 @@ Target Report Mask(CALLER_INTERWORKING) Thumb: Assume function pointers may go to non-Thumb aware code. mcpu= -Target RejectNegative ToLower Joined Var(arm_cpu_string) +Target RejectNegative Negative(mcpu=) ToLower Joined Var(arm_cpu_string) Specify the name of the target CPU. mfloat-abi= @@ -232,7 +232,7 @@ Target Report Mask(TPCS_LEAF_FRAME) Thumb: Generate (leaf) stack frames even if not needed. mtune= -Target RejectNegative ToLower Joined Var(arm_tune_string) +Target RejectNegative Negative(mtune=) ToLower Joined Var(arm_tune_string) Tune code for the given processor. mprint-tune-info -- cgit v1.1 From 9593e8e5e391e77bb065d4689b7511bed6a640a3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 26 Sep 2019 13:52:45 +0000 Subject: tree-vect-loop.c (vect_analyze_loop_operations): Also call vectorizable_reduction for vect_double_reduction_def. 2019-09-26 Richard Biener * tree-vect-loop.c (vect_analyze_loop_operations): Also call vectorizable_reduction for vect_double_reduction_def. (vect_transform_loop): Likewise. (vect_create_epilog_for_reduction): Move double-reduction PHI creation and preheader argument setting of PHIs ... (vectorizable_reduction): ... here. Also process vect_double_reduction_def PHIs, creating the vectorized PHI nodes, remembering the scalar adjustment computed for the epilogue in STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT. Remember the original reduction code in STMT_VINFO_REDUC_CODE. * tree-vectorizer.c (vec_info::new_stmt_vec_info): Initialize STMT_VINFO_REDUC_CODE. * tree-vectorizer.h (_stmt_vec_info::reduc_epilogue_adjustment): New. (_stmt_vec_info::reduc_code): Likewise. (STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT): Likewise. (STMT_VINFO_REDUC_CODE): Likewise. From-SVN: r276150 --- gcc/ChangeLog | 19 +++ gcc/tree-vect-loop.c | 319 +++++++++++++++++++++++++++----------------------- gcc/tree-vectorizer.c | 1 + gcc/tree-vectorizer.h | 8 ++ 4 files changed, 198 insertions(+), 149 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 98fa0ff..19892af 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2019-09-26 Richard Biener + + * tree-vect-loop.c (vect_analyze_loop_operations): Also call + vectorizable_reduction for vect_double_reduction_def. + (vect_transform_loop): Likewise. + (vect_create_epilog_for_reduction): Move double-reduction + PHI creation and preheader argument setting of PHIs ... + (vectorizable_reduction): ... here. Also process + vect_double_reduction_def PHIs, creating the vectorized + PHI nodes, remembering the scalar adjustment computed for + the epilogue in STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT. + Remember the original reduction code in STMT_VINFO_REDUC_CODE. + * tree-vectorizer.c (vec_info::new_stmt_vec_info): + Initialize STMT_VINFO_REDUC_CODE. + * tree-vectorizer.h (_stmt_vec_info::reduc_epilogue_adjustment): New. + (_stmt_vec_info::reduc_code): Likewise. + (STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT): Likewise. + (STMT_VINFO_REDUC_CODE): Likewise. + 2019-09-26 Matt Turner PR driver/69471 diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index ec00912..1a561f9 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -1548,6 +1548,8 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) ok = vectorizable_induction (stmt_info, NULL, NULL, NULL, &cost_vec); else if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def + || (STMT_VINFO_DEF_TYPE (stmt_info) + == vect_double_reduction_def) || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle) && ! PURE_SLP_STMT (stmt_info)) ok = vectorizable_reduction (stmt_info, NULL, NULL, NULL, NULL, @@ -4299,20 +4301,17 @@ vect_create_epilog_for_reduction (vec vect_defs, gimple *exit_phi; tree bitsize; tree adjustment_def = NULL; - tree vec_initial_def = NULL; tree expr, def, initial_def = NULL; tree orig_name, scalar_result; imm_use_iterator imm_iter, phi_imm_iter; use_operand_p use_p, phi_use_p; gimple *use_stmt; - stmt_vec_info reduction_phi_info = NULL; bool nested_in_vect_loop = false; auto_vec new_phis; auto_vec inner_phis; int j, i; auto_vec scalar_results; unsigned int group_size = 1, k, ratio; - auto_vec vec_initial_defs; auto_vec phis; bool slp_reduc = false; bool direct_slp_reduc; @@ -4336,10 +4335,10 @@ vect_create_epilog_for_reduction (vec vect_defs, mode = TYPE_MODE (vectype); /* 1. Create the reduction def-use cycle: - Set the arguments of REDUCTION_PHIS, i.e., transform + Set the backedge argument of REDUCTION_PHIS, i.e., transform loop: - vec_def = phi # REDUCTION_PHI + vec_def = phi # REDUCTION_PHI VECT_DEF = vector_stmt # vectorized form of STMT ... @@ -4350,18 +4349,10 @@ vect_create_epilog_for_reduction (vec vect_defs, VECT_DEF = vector_stmt # vectorized form of STMT ... - (in case of SLP, do it for all the phis). */ + (in case of SLP, do it for all the phis). */ - /* Get the loop-entry arguments. */ if (slp_node) - { - unsigned vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); - vec_initial_defs.reserve (vec_num); - get_initial_defs_for_reduction (slp_node_instance->reduc_phis, - &vec_initial_defs, vec_num, - REDUC_GROUP_FIRST_ELEMENT (stmt_info), - neutral_op); - } + ; else { /* Get at the scalar def before the loop, that defines the initial value @@ -4373,64 +4364,29 @@ vect_create_epilog_for_reduction (vec vect_defs, for REDUC_MIN and initial_def larger than the base. */ if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION) - { - induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info); - if (TREE_CODE (initial_def) == INTEGER_CST - && (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) - == INTEGER_INDUC_COND_REDUCTION) - && !integer_zerop (induc_val) - && ((code == MAX_EXPR - && tree_int_cst_lt (initial_def, induc_val)) - || (code == MIN_EXPR - && tree_int_cst_lt (induc_val, initial_def)))) - induc_val = initial_def; - vec_initial_def = build_vector_from_val (vectype, induc_val); - } + induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info); else if (double_reduc) - /* In case of double reduction we only create a vector variable - to be put in the reduction phi node. The actual statement - creation is done later in this function. */ - vec_initial_def = vect_create_destination_var (initial_def, vectype); + ; else if (nested_in_vect_loop) - { - /* Do not use an adjustment def as that case is not supported - correctly if ncopies is not one. */ - vec_initial_def = vect_get_vec_def_for_operand (initial_def, - stmt_info); - } + ; else - vec_initial_def - = get_initial_def_for_reduction (stmt_info, code, initial_def, - &adjustment_def); - vec_initial_defs.create (1); - vec_initial_defs.quick_push (vec_initial_def); + adjustment_def = STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (stmt_info); } - /* Set phi nodes arguments. */ + /* Set phi nodes latch arguments. */ FOR_EACH_VEC_ELT (reduction_phis, i, phi_info) { - tree vec_init_def = vec_initial_defs[i]; tree def = vect_defs[i]; for (j = 0; j < ncopies; j++) { + /* Set the loop-latch arg for the reduction-phi. */ if (j != 0) { phi_info = STMT_VINFO_RELATED_STMT (phi_info); - if (nested_in_vect_loop) - vec_init_def - = vect_get_vec_def_for_stmt_copy (loop_vinfo, vec_init_def); + def = vect_get_vec_def_for_stmt_copy (loop_vinfo, def); } - /* Set the loop-entry arg of the reduction-phi. */ - gphi *phi = as_a (phi_info->stmt); - add_phi_arg (phi, vec_init_def, loop_preheader_edge (loop), - UNKNOWN_LOCATION); - - /* Set the loop-latch arg for the reduction-phi. */ - if (j > 0) - def = vect_get_vec_def_for_stmt_copy (loop_vinfo, def); - add_phi_arg (phi, def, loop_latch_edge (loop), UNKNOWN_LOCATION); if (dump_enabled_p ()) @@ -4934,7 +4890,7 @@ vect_create_epilog_for_reduction (vec vect_defs, if ((STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION) - && !operand_equal_p (initial_def, induc_val, 0)) + && induc_val) { /* Earlier we set the initial value to be a vector if induc_val values. Check the result and if it is induc_val then replace @@ -5297,7 +5253,7 @@ vect_create_epilog_for_reduction (vec vect_defs, if ((STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION) - && !operand_equal_p (initial_def, induc_val, 0)) + && induc_val) { /* Earlier we set the initial value to be a vector if induc_val values. Check the result and if it is induc_val then replace @@ -5420,7 +5376,6 @@ vect_create_epilog_for_reduction (vec vect_defs, if (k % ratio == 0) { epilog_stmt_info = loop_vinfo->lookup_stmt (new_phis[k / ratio]); - reduction_phi_info = reduction_phis[k / ratio]; if (double_reduc) inner_phi = inner_phis[k / ratio]; } @@ -5435,6 +5390,8 @@ vect_create_epilog_for_reduction (vec vect_defs, scalar_dest = gimple_assign_lhs (scalar_stmt_info->stmt); } + if (outer_loop) + { phis.create (3); /* Find the loop-closed-use at the loop exit of the original scalar result. (The reduction result is expected to have two immediate uses - @@ -5449,8 +5406,6 @@ vect_create_epilog_for_reduction (vec vect_defs, FOR_EACH_VEC_ELT (phis, i, exit_phi) { - if (outer_loop) - { stmt_vec_info exit_phi_vinfo = loop_vinfo->lookup_stmt (exit_phi); gphi *vect_phi; @@ -5482,7 +5437,6 @@ vect_create_epilog_for_reduction (vec vect_defs, FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, orig_name) { stmt_vec_info use_stmt_vinfo; - tree vect_phi_init, preheader_arg, vect_phi_res; basic_block bb = gimple_bb (use_stmt); /* Check that USE_STMT is really double reduction phi @@ -5497,53 +5451,23 @@ vect_create_epilog_for_reduction (vec vect_defs, != vect_double_reduction_def) continue; - /* Create vector phi node for double reduction: - vs1 = phi - vs1 was created previously in this function by a call to - vect_get_vec_def_for_operand and is stored in - vec_initial_def; - vs2 is defined by INNER_PHI, the vectorized EXIT_PHI; - vs0 is created here. */ - - /* Create vector phi node. */ - vect_phi = create_phi_node (vec_initial_def, bb); - loop_vec_info_for_loop (outer_loop)->add_stmt (vect_phi); - - /* Create vs0 - initial def of the double reduction phi. */ - preheader_arg = PHI_ARG_DEF_FROM_EDGE (use_stmt, - loop_preheader_edge (outer_loop)); - vect_phi_init = get_initial_def_for_reduction - (stmt_info, code, preheader_arg, NULL); - - /* Update phi node arguments with vs0 and vs2. */ - add_phi_arg (vect_phi, vect_phi_init, - loop_preheader_edge (outer_loop), - UNKNOWN_LOCATION); + /* Set the outer loop vector phi args. The PHI node + itself was created in vectorizable_reduction. */ + vect_phi = as_a + (STMT_VINFO_VEC_STMT (use_stmt_vinfo)->stmt); + + /* Update phi node argument with vs2. */ add_phi_arg (vect_phi, PHI_RESULT (inner_phi->stmt), loop_latch_edge (outer_loop), UNKNOWN_LOCATION); if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "created double reduction phi node: %G", vect_phi); - - vect_phi_res = PHI_RESULT (vect_phi); - - /* Replace the use, i.e., set the correct vs1 in the regular - reduction phi node. FORNOW, NCOPIES is always 1, so the - loop is redundant. */ - stmt_vec_info use_info = reduction_phi_info; - for (j = 0; j < ncopies; j++) - { - edge pr_edge = loop_preheader_edge (loop); - SET_PHI_ARG_DEF (as_a (use_info->stmt), - pr_edge->dest_idx, vect_phi_res); - use_info = STMT_VINFO_RELATED_STMT (use_info); - } } - } } - phis.release (); + } + if (nested_in_vect_loop) { if (double_reduc) @@ -6027,6 +5951,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, /* Make sure it was already recognized as a reduction computation. */ if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_reduction_def + && STMT_VINFO_DEF_TYPE (stmt_info) != vect_double_reduction_def && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle) return false; @@ -6067,25 +5992,24 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, /* Leave the scalar phi in place. */ return true; - gassign *reduc_stmt = as_a (reduc_stmt_info->stmt); - code = gimple_assign_rhs_code (reduc_stmt); - for (unsigned k = 1; k < gimple_num_ops (reduc_stmt); ++k) - { - tree op = gimple_op (reduc_stmt, k); - if (op == phi_result) - continue; - if (k == 1 && code == COND_EXPR) - continue; - bool is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt); - gcc_assert (is_simple_use); - if (dt == vect_constant_def || dt == vect_external_def) - continue; - if (!vectype_in - || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in))) - < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (op))))) - vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op)); - break; - } + if (gassign *reduc_stmt = dyn_cast (reduc_stmt_info->stmt)) + for (unsigned k = 1; k < gimple_num_ops (reduc_stmt); ++k) + { + tree op = gimple_op (reduc_stmt, k); + if (op == phi_result) + continue; + if (k == 1 && gimple_assign_rhs_code (reduc_stmt) == COND_EXPR) + continue; + bool is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt); + gcc_assert (is_simple_use); + if (dt == vect_constant_def || dt == vect_external_def) + continue; + if (!vectype_in + || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in))) + < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (op))))) + vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op)); + break; + } /* For a nested cycle we might end up with an operation like phi_result * phi_result. */ if (!vectype_in) @@ -6093,10 +6017,21 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, gcc_assert (vectype_in); if (slp_node) - ncopies = 1; + { + /* The size vect_schedule_slp_instance computes is off for us. */ + vec_num = vect_get_num_vectors + (LOOP_VINFO_VECT_FACTOR (loop_vinfo) + * SLP_TREE_SCALAR_STMTS (slp_node).length (), vectype_in); + ncopies = 1; + } else - ncopies = vect_get_num_copies (loop_vinfo, vectype_in); + { + vec_num = 1; + ncopies = vect_get_num_copies (loop_vinfo, vectype_in); + } + /* Check whether we can use a single PHI node and accumulate + vectors to one before the backedge. */ stmt_vec_info use_stmt_info; if (ncopies > 1 && STMT_VINFO_RELEVANT (reduc_stmt_info) <= vect_used_only_live @@ -6104,45 +6039,129 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) && vect_stmt_to_vectorize (use_stmt_info) == reduc_stmt_info) - single_defuse_cycle = true; + { + single_defuse_cycle = true; + ncopies = 1; + } /* Create the destination vector */ - scalar_dest = gimple_assign_lhs (reduc_stmt); - vec_dest = vect_create_destination_var (scalar_dest, vectype_out); + vec_dest = vect_create_destination_var (phi_result, vectype_out); + /* Get the loop-entry arguments. */ + tree vec_initial_def; + auto_vec vec_initial_defs; if (slp_node) - /* The size vect_schedule_slp_instance computes is off for us. */ - vec_num = vect_get_num_vectors - (LOOP_VINFO_VECT_FACTOR (loop_vinfo) - * SLP_TREE_SCALAR_STMTS (slp_node).length (), - vectype_in); + { + vec_initial_defs.reserve (vec_num); + gcc_assert (slp_node == slp_node_instance->reduc_phis); + stmt_vec_info first = REDUC_GROUP_FIRST_ELEMENT (reduc_stmt_info); + tree neutral_op + = neutral_op_for_slp_reduction (slp_node, + STMT_VINFO_REDUC_CODE + (first ? first : reduc_stmt_info), + first != NULL); + get_initial_defs_for_reduction (slp_node_instance->reduc_phis, + &vec_initial_defs, vec_num, + first != NULL, neutral_op); + } else - vec_num = 1; + { + /* Get at the scalar def before the loop, that defines the initial + value of the reduction variable. */ + tree initial_def = PHI_ARG_DEF_FROM_EDGE (phi, + loop_preheader_edge (loop)); + /* Optimize: if initial_def is for REDUC_MAX smaller than the base + and we can't use zero for induc_val, use initial_def. Similarly + for REDUC_MIN and initial_def larger than the base. */ + if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + { + tree induc_val + = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info); + if (TREE_CODE (initial_def) == INTEGER_CST + && (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + && !integer_zerop (induc_val) + && (((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info) + == MAX_EXPR) + && tree_int_cst_lt (initial_def, induc_val)) + || ((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info) + == MIN_EXPR) + && tree_int_cst_lt (induc_val, initial_def)))) + { + induc_val = initial_def; + /* Communicate we used the initial_def to epilouge + generation. */ + STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info) + = NULL_TREE; + } + vec_initial_def = build_vector_from_val (vectype_out, induc_val); + } + else if (nested_cycle) + { + /* Do not use an adjustment def as that case is not supported + correctly if ncopies is not one. */ + vec_initial_def = vect_get_vec_def_for_operand (initial_def, + reduc_stmt_info); + } + else + { + tree adjustment_def = NULL_TREE; + tree *adjustment_defp = &adjustment_def; + enum tree_code code = STMT_VINFO_REDUC_CODE (reduc_stmt_info); + /* ??? For the outer loop PHI we have to do a bit of searching + to find the stmt with the code. reduc_stmt_info here is the + loop-closed PHI of the inner reduction which means we can look + at its single-arg def. */ + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def) + { + tree def = gimple_phi_arg_def + (as_a (reduc_stmt_info->stmt), 0); + code = STMT_VINFO_REDUC_CODE + (vect_stmt_to_vectorize (loop_vinfo->lookup_def (def))); + adjustment_defp = NULL; + } + vec_initial_def + = get_initial_def_for_reduction (reduc_stmt_info, code, + initial_def, adjustment_defp); + STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (reduc_stmt_info) + = adjustment_def; + } + vec_initial_defs.create (1); + vec_initial_defs.quick_push (vec_initial_def); + } /* Generate the reduction PHIs upfront. */ prev_phi_info = NULL; - for (j = 0; j < ncopies; j++) + for (i = 0; i < vec_num; i++) { - if (j == 0 || !single_defuse_cycle) + tree vec_init_def = vec_initial_defs[i]; + for (j = 0; j < ncopies; j++) { - for (i = 0; i < vec_num; i++) + /* Create the reduction-phi that defines the reduction + operand. */ + gphi *new_phi = create_phi_node (vec_dest, loop->header); + stmt_vec_info new_phi_info = loop_vinfo->add_stmt (new_phi); + + /* Set the loop-entry arg of the reduction-phi. */ + if (j != 0 && nested_cycle) + vec_init_def = vect_get_vec_def_for_stmt_copy (loop_vinfo, + vec_init_def); + add_phi_arg (new_phi, vec_init_def, loop_preheader_edge (loop), + UNKNOWN_LOCATION); + + /* The loop-latch arg is set in epilogue processing. */ + + if (slp_node) + SLP_TREE_VEC_STMTS (slp_node).quick_push (new_phi_info); + else { - /* Create the reduction-phi that defines the reduction - operand. */ - gimple *new_phi = create_phi_node (vec_dest, loop->header); - stmt_vec_info new_phi_info = loop_vinfo->add_stmt (new_phi); - - if (slp_node) - SLP_TREE_VEC_STMTS (slp_node).quick_push (new_phi_info); + if (j == 0) + STMT_VINFO_VEC_STMT (stmt_info) + = *vec_stmt = new_phi_info; else - { - if (j == 0) - STMT_VINFO_VEC_STMT (stmt_info) - = *vec_stmt = new_phi_info; - else - STMT_VINFO_RELATED_STMT (prev_phi_info) = new_phi_info; - prev_phi_info = new_phi_info; - } + STMT_VINFO_RELATED_STMT (prev_phi_info) = new_phi_info; + prev_phi_info = new_phi_info; } } } @@ -6633,6 +6652,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, gcc_assert (orig_code == MAX_EXPR || orig_code == MIN_EXPR); } } + STMT_VINFO_REDUC_CODE (stmt_info) = orig_code; reduc_fn = IFN_LAST; @@ -8378,6 +8398,7 @@ vect_transform_loop (loop_vec_info loop_vinfo) if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle) && ! PURE_SLP_STMT (stmt_info)) { diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 8fb70b7..50d508d 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -639,6 +639,7 @@ vec_info::new_stmt_vec_info (gimple *stmt) STMT_VINFO_VECTORIZABLE (res) = true; STMT_VINFO_VEC_REDUCTION_TYPE (res) = TREE_CODE_REDUCTION; STMT_VINFO_VEC_COND_REDUC_CODE (res) = ERROR_MARK; + STMT_VINFO_REDUC_CODE (res) = ERROR_MARK; STMT_VINFO_REDUC_IDX (res) = -1; STMT_VINFO_SLP_VECT_ONLY (res) = false; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 370ce13..f140405 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -941,10 +941,16 @@ public: /* For INTEGER_INDUC_COND_REDUCTION, the initial value to be used. */ tree induc_cond_initial_val; + /* If not NULL the value to be added to compute final reduction value. */ + tree reduc_epilogue_adjustment; + /* On a reduction PHI the reduction type as detected by vect_force_simple_reduction. */ enum vect_reduction_type reduc_type; + /* The original reduction code, to be used in the epilogue. */ + enum tree_code reduc_code; + /* On a stmt participating in the reduction the index of the operand on the reduction SSA cycle. */ int reduc_idx; @@ -1039,6 +1045,7 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) #define STMT_VINFO_VEC_REDUCTION_TYPE(S) (S)->v_reduc_type #define STMT_VINFO_VEC_COND_REDUC_CODE(S) (S)->cond_reduc_code #define STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL(S) (S)->induc_cond_initial_val +#define STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT(S) (S)->reduc_epilogue_adjustment #define STMT_VINFO_REDUC_IDX(S) (S)->reduc_idx #define STMT_VINFO_DR_WRT_VEC_LOOP(S) (S)->dr_wrt_vec_loop @@ -1070,6 +1077,7 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) #define STMT_VINFO_MIN_NEG_DIST(S) (S)->min_neg_dist #define STMT_VINFO_NUM_SLP_USES(S) (S)->num_slp_uses #define STMT_VINFO_REDUC_TYPE(S) (S)->reduc_type +#define STMT_VINFO_REDUC_CODE(S) (S)->reduc_code #define STMT_VINFO_REDUC_DEF(S) (S)->reduc_def #define STMT_VINFO_SLP_VECT_ONLY(S) (S)->slp_vect_only_p -- cgit v1.1 From 25a0f9cfaeca20baeaaa0c76911821949aadcb40 Mon Sep 17 00:00:00 2001 From: Arnaud Charlet Date: Thu, 26 Sep 2019 14:10:46 +0000 Subject: * osint.adb (OS_Time_To_GNAT_Time): Remove dependency on To_C/To_Ada From-SVN: r276151 --- gcc/ada/ChangeLog | 4 ++++ gcc/ada/osint.adb | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 08244e8..a5f3843 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,7 @@ +2019-09-26 Arnaud Charlet + + * osint.adb (OS_Time_To_GNAT_Time): Remove dependency on To_C/To_Ada + 2019-09-23 Rainer Orth * libgnarl/s-osinte__solaris.ads (sysconf): Declare. diff --git a/gcc/ada/osint.adb b/gcc/ada/osint.adb index 973f463..ac89187 100644 --- a/gcc/ada/osint.adb +++ b/gcc/ada/osint.adb @@ -2183,7 +2183,19 @@ package body Osint is function OS_Time_To_GNAT_Time (T : OS_Time) return Time_Stamp_Type is GNAT_Time : Time_Stamp_Type; - TI : Long_Integer := To_C (T); + type Underlying_OS_Time is + range -(2 ** (Standard'Address_Size - Integer'(1))) .. + +(2 ** (Standard'Address_Size - Integer'(1)) - 1); + -- Underlying_OS_Time is a redeclaration of OS_Time to allow integer + -- manipulation. Remove this in favor of To_Ada/To_C once newer + -- GNAT releases are available with these functions. + + function To_Int is + new Unchecked_Conversion (OS_Time, Underlying_OS_Time); + function From_Int is + new Unchecked_Conversion (Underlying_OS_Time, OS_Time); + + TI : Underlying_OS_Time := To_Int (T); Y : Year_Type; Mo : Month_Type; D : Day_Type; @@ -2205,7 +2217,7 @@ package body Osint is TI := TI + 1; end if; - GM_Split (To_Ada (TI), Y, Mo, D, H, Mn, S); + GM_Split (From_Int (TI), Y, Mo, D, H, Mn, S); Make_Time_Stamp (Year => Nat (Y), -- cgit v1.1 From 26cdf7bd5e9cb47f2a8761d8d5d2babf0bf5bb15 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 26 Sep 2019 16:17:22 +0000 Subject: PR tree-optimization/91914 - Invalid strlen folding for offset into struct gcc/testsuite/CHangeLog: * gcc.dg/strlenopt-79.c: New test. From-SVN: r276156 --- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.dg/strlenopt-79.c | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/strlenopt-79.c (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2323593..8d75c29 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-26 Martin Sebor + + PR tree-optimization/91914 + * gcc.dg/strlenopt-79.c: New test. + 2019-09-26 Kyrylo Tkachov * gcc.target/arm/acle/simd32.c: Update test. diff --git a/gcc/testsuite/gcc.dg/strlenopt-79.c b/gcc/testsuite/gcc.dg/strlenopt-79.c new file mode 100644 index 0000000..362cbfb --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-79.c @@ -0,0 +1,46 @@ +/* PR tree-optimization/91914 - Invalid strlen folding for offset into struct + { dg-do run } + { dg-options "-O2 -Wall" } */ + +#define assert(expr) \ + ((expr) \ + ? (void)0 \ + : (__builtin_printf ("%s:%i: assertion failed: %s\n", \ + __FILE__, __LINE__, #expr), \ + __builtin_abort ())) + +extern __SIZE_TYPE__ strlen (const char*); + +struct stringpool_t +{ + char s1[sizeof ("1")]; + char s2[sizeof ("12")]; + char s3[sizeof ("123")]; + char s4[sizeof ("1234")]; + char s5[sizeof ("12345")]; +}; + +static const struct stringpool_t stringpool_contents = + { + "1", "12", "123", "1234", "12345" + }; + +#define stringpool ((const char *) &stringpool_contents) + +volatile int i0 = 0, i2 = 2, i5 = 5, i9 = 9, i14 = 14; + +int main (void) +{ + /* These shouldn't trigger warnings. */ + assert (strlen (stringpool) == 1); + assert (strlen (stringpool + 2) == 2); + assert (strlen (stringpool + 5) == 3); + assert (strlen (stringpool + 9) == 4); + assert (strlen (stringpool + 14) == 5); + + assert (strlen (stringpool + i0) == 1); + assert (strlen (stringpool + i2) == 2); + assert (strlen (stringpool + i5) == 3); + assert (strlen (stringpool + i9) == 4); + assert (strlen (stringpool + i14) == 5); +} -- cgit v1.1 From 1b4dbccc1f828fa00e6acc8b88d24301c65552df Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 26 Sep 2019 16:52:50 +0000 Subject: tree-vect-loop.c (vect_analyze_loop_operations): Analyze loop-closed PHIs that are vect_internal_def. 2019-09-26 Richard Biener * tree-vect-loop.c (vect_analyze_loop_operations): Analyze loop-closed PHIs that are vect_internal_def. (vect_create_epilog_for_reduction): Exit early for nested cycles. Simplify. (vectorizable_lc_phi): New. * tree-vect-stmts.c (vect_analyze_stmt): Call vectorize_lc_phi. (vect_transform_stmt): Likewise. * tree-vectorizer.h (stmt_vec_info_type): Add lc_phi_info_type. (vectorizable_lc_phi): Declare. From-SVN: r276157 --- gcc/ChangeLog | 12 +++++++ gcc/tree-vect-loop.c | 98 +++++++++++++++++++++++++++++++++++++++++++-------- gcc/tree-vect-stmts.c | 8 ++++- gcc/tree-vectorizer.h | 2 ++ 4 files changed, 104 insertions(+), 16 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 19892af..66d7d86 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,17 @@ 2019-09-26 Richard Biener + * tree-vect-loop.c (vect_analyze_loop_operations): Analyze + loop-closed PHIs that are vect_internal_def. + (vect_create_epilog_for_reduction): Exit early for nested cycles. + Simplify. + (vectorizable_lc_phi): New. + * tree-vect-stmts.c (vect_analyze_stmt): Call vectorize_lc_phi. + (vect_transform_stmt): Likewise. + * tree-vectorizer.h (stmt_vec_info_type): Add lc_phi_info_type. + (vectorizable_lc_phi): Declare. + +2019-09-26 Richard Biener + * tree-vect-loop.c (vect_analyze_loop_operations): Also call vectorizable_reduction for vect_double_reduction_def. (vect_transform_loop): Likewise. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 1a561f9..237d28b 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -1519,12 +1519,16 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) phi_op = PHI_ARG_DEF (phi, 0); stmt_vec_info op_def_info = loop_vinfo->lookup_def (phi_op); if (!op_def_info) - return opt_result::failure_at (phi, "unsupported phi"); + return opt_result::failure_at (phi, "unsupported phi\n"); if (STMT_VINFO_RELEVANT (op_def_info) != vect_used_in_outer && (STMT_VINFO_RELEVANT (op_def_info) != vect_used_in_outer_by_reduction)) - return opt_result::failure_at (phi, "unsupported phi"); + return opt_result::failure_at (phi, "unsupported phi\n"); + + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def + && !vectorizable_lc_phi (stmt_info, NULL, NULL)) + return opt_result::failure_at (phi, "unsupported phi\n"); } continue; @@ -4396,6 +4400,10 @@ vect_create_epilog_for_reduction (vec vect_defs, } } + /* For vectorizing nested cycles the above is all we need to do. */ + if (nested_in_vect_loop && !double_reduc) + return; + /* For cond reductions we want to create a new vector (INDEX_COND_EXPR) which is updated with the current index of the loop for every match of the original loop's cond_expr (VEC_STMT). This results in a vector @@ -4588,16 +4596,6 @@ vect_create_epilog_for_reduction (vec vect_defs, new_scalar_dest = vect_create_destination_var (scalar_dest, NULL); bitsize = TYPE_SIZE (scalar_type); - /* In case this is a reduction in an inner-loop while vectorizing an outer - loop - we don't need to extract a single scalar result at the end of the - inner-loop (unless it is double reduction, i.e., the use of reduction is - outside the outer-loop). The final vector of partial results will be used - in the vectorized outer-loop, or reduced to a scalar result at the end of - the outer-loop. */ - if (nested_in_vect_loop && !double_reduc) - ; - else - { /* SLP reduction without reduction chain, e.g., # a1 = phi # b1 = phi @@ -5313,7 +5311,6 @@ vect_create_epilog_for_reduction (vec vect_defs, new_phis[0] = epilog_stmt; } - } if (double_reduc) loop = loop->inner; @@ -5473,7 +5470,7 @@ vect_create_epilog_for_reduction (vec vect_defs, if (double_reduc) loop = outer_loop; else - continue; + gcc_unreachable (); } phis.create (3); @@ -7167,6 +7164,76 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, return true; } +/* Vectorizes LC PHIs of nested cycles (sofar). */ + +bool +vectorizable_lc_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt, + slp_tree slp_node) +{ + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + if (!loop_vinfo + || !is_a (stmt_info->stmt) + || gimple_phi_num_args (stmt_info->stmt) != 1) + return false; + + /* To handle the nested_cycle_def for double-reductions we have to + refactor epilogue generation more. */ + if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def + /* && STMT_VINFO_DEF_TYPE (stmt_info) != vect_double_reduction_def */) + return false; + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_TYPE (stmt_info) = lc_phi_info_type; + return true; + } + + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + tree scalar_dest = gimple_phi_result (stmt_info->stmt); + basic_block bb = gimple_bb (stmt_info->stmt); + edge e = single_pred_edge (bb); + tree vec_dest = vect_create_destination_var (scalar_dest, vectype); + vec vec_oprnds = vNULL; + vect_get_vec_defs (gimple_phi_arg_def (stmt_info->stmt, 0), NULL_TREE, + stmt_info, &vec_oprnds, NULL, slp_node); + if (slp_node) + { + unsigned vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); + gcc_assert (vec_oprnds.length () == vec_num); + for (unsigned i = 0; i < vec_num; i++) + { + /* Create the vectorized LC PHI node. */ + gphi *new_phi = create_phi_node (vec_dest, bb); + add_phi_arg (new_phi, vec_oprnds[i], e, UNKNOWN_LOCATION); + stmt_vec_info new_phi_info = loop_vinfo->add_stmt (new_phi); + SLP_TREE_VEC_STMTS (slp_node).quick_push (new_phi_info); + } + } + else + { + unsigned ncopies = vect_get_num_copies (loop_vinfo, vectype); + stmt_vec_info prev_phi_info = NULL; + for (unsigned i = 0; i < ncopies; i++) + { + if (i != 0) + vect_get_vec_defs_for_stmt_copy (loop_vinfo, &vec_oprnds, NULL); + /* Create the vectorized LC PHI node. */ + gphi *new_phi = create_phi_node (vec_dest, bb); + add_phi_arg (new_phi, vec_oprnds[0], e, UNKNOWN_LOCATION); + stmt_vec_info new_phi_info = loop_vinfo->add_stmt (new_phi); + if (i == 0) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_phi_info; + else + STMT_VINFO_RELATED_STMT (prev_phi_info) = new_phi_info; + prev_phi_info = new_phi_info; + } + } + vec_oprnds.release (); + + return true; +} + + /* Function vect_min_worthwhile_factor. For a loop where we could vectorize the operation indicated by CODE, @@ -8399,7 +8466,8 @@ vect_transform_loop (loop_vec_info loop_vinfo) if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle) + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def) && ! PURE_SLP_STMT (stmt_info)) { if (dump_enabled_p ()) diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index b1e97f8..5734068 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -10671,7 +10671,8 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize, || vectorizable_condition (stmt_info, NULL, NULL, false, -1, node, cost_vec) || vectorizable_comparison (stmt_info, NULL, NULL, node, - cost_vec)); + cost_vec) + || vectorizable_lc_phi (stmt_info, NULL, node)); else { if (bb_vinfo) @@ -10820,6 +10821,11 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, gcc_assert (done); break; + case lc_phi_info_type: + done = vectorizable_lc_phi (stmt_info, &vec_stmt, slp_node); + gcc_assert (done); + break; + default: if (!STMT_VINFO_LIVE_P (stmt_info)) { diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index f140405..1ab4af7 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -694,6 +694,7 @@ enum stmt_vec_info_type { type_promotion_vec_info_type, type_demotion_vec_info_type, type_conversion_vec_info_type, + lc_phi_info_type, loop_exit_ctrl_vec_info_type }; @@ -1653,6 +1654,7 @@ extern bool vectorizable_reduction (stmt_vec_info, gimple_stmt_iterator *, extern bool vectorizable_induction (stmt_vec_info, gimple_stmt_iterator *, stmt_vec_info *, slp_tree, stmt_vector_for_cost *); +extern bool vectorizable_lc_phi (stmt_vec_info, stmt_vec_info *, slp_tree); extern bool vect_worthwhile_without_simd_p (vec_info *, tree_code); extern int vect_get_known_peeling_cost (loop_vec_info, int, int *, stmt_vector_for_cost *, -- cgit v1.1 From 0bfc204142439b8167bf3447d7d12b65d1da82f8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 26 Sep 2019 16:54:51 +0000 Subject: re PR tree-optimization/91896 (ICE in vect_get_vec_def_for_stmt_copy, at tree-vect-stmts.c:1687) 2019-09-25 Richard Biener PR tree-optimization/91896 * tree-vect-loop.c (vectorizable_reduction): The single def-use cycle optimization cannot apply when there's more than one pattern stmt involved. * gcc.dg/torture/pr91896.c: New testcase. From-SVN: r276158 --- gcc/ChangeLog | 7 +++++++ gcc/expr.c | 13 +++++++------ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/i386/pr91897.c | 12 ++++++++++++ 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr91897.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 66d7d86..1358d4b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-25 Richard Biener + + PR tree-optimization/91896 + * tree-vect-loop.c (vectorizable_reduction): The single + def-use cycle optimization cannot apply when there's more + than one pattern stmt involved. + 2019-09-26 Richard Biener * tree-vect-loop.c (vect_analyze_loop_operations): Analyze diff --git a/gcc/expr.c b/gcc/expr.c index 2f2b53f..7a70706 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -7230,12 +7230,13 @@ get_inner_reference (tree exp, poly_int64_pod *pbitsize, *punsignedp = (! INTEGRAL_TYPE_P (TREE_TYPE (exp)) || TYPE_UNSIGNED (TREE_TYPE (exp))); - /* For vector types, with the correct size of access, use the mode of - inner type. */ - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE - && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))) - && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp)))) - mode = TYPE_MODE (TREE_TYPE (exp)); + /* For vector element types with the correct size of access or for + vector typed accesses use the mode of the access type. */ + if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE + && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))) + && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp)))) + || VECTOR_TYPE_P (TREE_TYPE (exp))) + mode = TYPE_MODE (TREE_TYPE (exp)); } else { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8d75c29..19ad393 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-26 Richard Biener + + PR middle-end/91897 + * gcc.target/i386/pr91897.c: New testcase. + 2019-09-26 Martin Sebor PR tree-optimization/91914 diff --git a/gcc/testsuite/gcc.target/i386/pr91897.c b/gcc/testsuite/gcc.target/i386/pr91897.c new file mode 100644 index 0000000..0615ad2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr91897.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx" } */ + +typedef double Double16 __attribute__((vector_size(8*16))); + +void mult(Double16 *res, const Double16 *v1, const Double16 *v2) +{ + *res = *v1 * *v2; +} + +/* We want 4 ymm loads and 4 ymm stores. */ +/* { dg-final { scan-assembler-times "movapd" 8 } } */ -- cgit v1.1 From 4fc1d2629ab373945a30031c1b49bdfa4e9f5f12 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 26 Sep 2019 18:50:55 +0000 Subject: [Darwin, PPC, Mode Iterators 2/n] Eliminate picbase expanders. We can use the mode iterators directly with an @pattern to avoid the need for an expander that was only there to pass the mode through. gcc/ChangeLog: 2019-09-26 Iain Sandoe * config/rs6000/darwin.md: Replace the expanders for load_macho_picbase and reload_macho_picbase with use of '@' in their respective define_insns. (nonlocal_goto_receiver): Pass Pmode to gen_reload_macho_picbase. * config/rs6000/rs6000-logue.c (rs6000_emit_prologue): Pass Pmode to gen_load_macho_picbase. * config/rs6000/rs6000.md: Likewise. From-SVN: r276159 --- gcc/ChangeLog | 10 ++++++++++ gcc/config/rs6000/darwin.md | 34 +++------------------------------- gcc/config/rs6000/rs6000-logue.c | 2 +- gcc/config/rs6000/rs6000.md | 2 +- 4 files changed, 15 insertions(+), 33 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1358d4b..9bbae7a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-09-26 Iain Sandoe + + * config/rs6000/darwin.md: Replace the expanders for + load_macho_picbase and reload_macho_picbase with use of '@' + and in their respective define_insns. + (nonlocal_goto_receiver): Pass Pmode to gen_reload_macho_picbase. + * config/rs6000/rs6000-logue.c (rs6000_emit_prologue): Pass + Pmode to gen_load_macho_picbase. + * config/rs6000/rs6000.md: Likewise. + 2019-09-25 Richard Biener PR tree-optimization/91896 diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md index 4a28421..a5c5a3a 100644 --- a/gcc/config/rs6000/darwin.md +++ b/gcc/config/rs6000/darwin.md @@ -216,21 +216,7 @@ You should have received a copy of the GNU General Public License (match_dup 2))] "") -(define_expand "load_macho_picbase" - [(set (reg LR_REGNO) - (unspec [(match_operand 0 "")] - UNSPEC_LD_MPIC))] - "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" -{ - if (TARGET_32BIT) - emit_insn (gen_load_macho_picbase_si (operands[0])); - else - emit_insn (gen_load_macho_picbase_di (operands[0])); - - DONE; -}) - -(define_insn "load_macho_picbase_" +(define_insn "@load_macho_picbase_" [(set (reg:P LR_REGNO) (unspec:P [(match_operand:P 0 "immediate_operand" "s") (pc)] UNSPEC_LD_MPIC))] @@ -284,21 +270,7 @@ You should have received a copy of the GNU General Public License "addis %0,%1,ha16(%2-%3)\n\taddi %0,%0,lo16(%2-%3)" [(set_attr "length" "8")]) -(define_expand "reload_macho_picbase" - [(set (reg LR_REGNO) - (unspec [(match_operand 0 "")] - UNSPEC_RELD_MPIC))] - "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" -{ - if (TARGET_32BIT) - emit_insn (gen_reload_macho_picbase_si (operands[0])); - else - emit_insn (gen_reload_macho_picbase_di (operands[0])); - - DONE; -}) - -(define_insn "reload_macho_picbase_" +(define_insn "@reload_macho_picbase_" [(set (reg:P LR_REGNO) (unspec:P [(match_operand:P 0 "immediate_operand" "s") (pc)] UNSPEC_RELD_MPIC))] @@ -342,7 +314,7 @@ You should have received a copy of the GNU General Public License ASM_GENERATE_INTERNAL_LABEL(tmplab, "Lnlgr", ++n); tmplrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (tmplab)); - emit_insn (gen_reload_macho_picbase (tmplrtx)); + emit_insn (gen_reload_macho_picbase (Pmode, tmplrtx)); emit_move_insn (picreg, gen_rtx_REG (Pmode, LR_REGNO)); emit_insn (gen_macho_correct_pic (picreg, picreg, picrtx, tmplrtx)); } diff --git a/gcc/config/rs6000/rs6000-logue.c b/gcc/config/rs6000/rs6000-logue.c index 633a253..e98893a 100644 --- a/gcc/config/rs6000/rs6000-logue.c +++ b/gcc/config/rs6000/rs6000-logue.c @@ -3809,7 +3809,7 @@ rs6000_emit_prologue (void) if (!info->lr_save_p) emit_move_insn (gen_rtx_REG (Pmode, 0), lr); - emit_insn (gen_load_macho_picbase (src)); + emit_insn (gen_load_macho_picbase (Pmode, src)); emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM), diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 4dbf85b..c5443ba 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -10053,7 +10053,7 @@ CODE_LABEL_NUMBER (operands[0])); tmplabrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (tmplab)); - emit_insn (gen_load_macho_picbase (tmplabrtx)); + emit_insn (gen_load_macho_picbase (Pmode, tmplabrtx)); emit_move_insn (picreg, gen_rtx_REG (Pmode, LR_REGNO)); emit_insn (gen_macho_correct_pic (picreg, picreg, picrtx, tmplabrtx)); } -- cgit v1.1 From be193fa7c9842f30f3aa804696ad83a4117d826e Mon Sep 17 00:00:00 2001 From: Will Schmidt Date: Thu, 26 Sep 2019 19:19:10 +0000 Subject: rs6000-builtin.def: (LVSL... [gcc] 2019-09-26 Will Schmidt * config/rs6000/rs6000-builtin.def: (LVSL, LVSR, LVEBX, LVEHX, LVEWX, LVXL, LVXL_V2DF, LVXL_V2DI, LVXL_V4SF, LVXL_V4SI, LVXL_V8HI, LVXL_V16QI, LVX, LVX_V1TI, LVX_V2DF, LVX_V2DI, LVX_V4SF, LVX_V4SI, LVX_V8HI, LVX_V16QI, LVLX, LVLXL, LVRX, LVRXL, LXSDX, LXVD2X_V1TI, LXVD2X_V2DF, LXVD2X_V2DI, LXVDSX, LXVW4X_V4SF, LXVW4X_V4SI, LXVW4X_V8HI, LXVW4X_V16QI, LD_ELEMREV_V1TI, LD_ELEMREV_V2DF, LD_ELEMREV_V2DI, LD_ELEMREV_V4SF, LD_ELEMREV_V4SI, LD_ELEMREV_V8HI, LD_ELEMREV_V16QI): Use the PURE attribute. [testsuite] 2019-09-26 Will Schmidt * gcc.target/powerpc/pure-builtin-redundant-load.c: New. From-SVN: r276162 --- gcc/ChangeLog | 11 +++++ gcc/config/rs6000/rs6000-builtin.def | 80 ++++++++++++++++++------------------ gcc/testsuite/ChangeLog | 4 ++ 3 files changed, 55 insertions(+), 40 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9bbae7a..c4cd4ac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-09-26 Will Schmidt + + * config/rs6000/rs6000-builtin.def: (LVSL, LVSR, LVEBX, LVEHX, + LVEWX, LVXL, LVXL_V2DF, LVXL_V2DI, LVXL_V4SF, LVXL_V4SI, LVXL_V8HI, + LVXL_V16QI, LVX, LVX_V1TI, LVX_V2DF, LVX_V2DI, LVX_V4SF, LVX_V4SI, + LVX_V8HI, LVX_V16QI, LVLX, LVLXL, LVRX, LVRXL, LXSDX, LXVD2X_V1TI, + LXVD2X_V2DF, LXVD2X_V2DI, LXVDSX, LXVW4X_V4SF, LXVW4X_V4SI, + LXVW4X_V8HI, LXVW4X_V16QI, LD_ELEMREV_V1TI, LD_ELEMREV_V2DF, + LD_ELEMREV_V2DI, LD_ELEMREV_V4SF, LD_ELEMREV_V4SI, LD_ELEMREV_V8HI, + LD_ELEMREV_V16QI): Use the PURE attribute. + 2019-09-26 Iain Sandoe * config/rs6000/darwin.md: Replace the expanders for diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def index 0a2bdb7..4d4f3b3 100644 --- a/gcc/config/rs6000/rs6000-builtin.def +++ b/gcc/config/rs6000/rs6000-builtin.def @@ -1177,26 +1177,26 @@ BU_ALTIVEC_X (MTVSCR, "mtvscr", MISC) BU_ALTIVEC_X (MFVSCR, "mfvscr", MISC) BU_ALTIVEC_X (DSSALL, "dssall", MISC) BU_ALTIVEC_X (DSS, "dss", MISC) -BU_ALTIVEC_X (LVSL, "lvsl", MEM) -BU_ALTIVEC_X (LVSR, "lvsr", MEM) -BU_ALTIVEC_X (LVEBX, "lvebx", MEM) -BU_ALTIVEC_X (LVEHX, "lvehx", MEM) -BU_ALTIVEC_X (LVEWX, "lvewx", MEM) -BU_ALTIVEC_X (LVXL, "lvxl", MEM) -BU_ALTIVEC_X (LVXL_V2DF, "lvxl_v2df", MEM) -BU_ALTIVEC_X (LVXL_V2DI, "lvxl_v2di", MEM) -BU_ALTIVEC_X (LVXL_V4SF, "lvxl_v4sf", MEM) -BU_ALTIVEC_X (LVXL_V4SI, "lvxl_v4si", MEM) -BU_ALTIVEC_X (LVXL_V8HI, "lvxl_v8hi", MEM) -BU_ALTIVEC_X (LVXL_V16QI, "lvxl_v16qi", MEM) -BU_ALTIVEC_X (LVX, "lvx", MEM) -BU_ALTIVEC_X (LVX_V1TI, "lvx_v1ti", MEM) -BU_ALTIVEC_X (LVX_V2DF, "lvx_v2df", MEM) -BU_ALTIVEC_X (LVX_V2DI, "lvx_v2di", MEM) -BU_ALTIVEC_X (LVX_V4SF, "lvx_v4sf", MEM) -BU_ALTIVEC_X (LVX_V4SI, "lvx_v4si", MEM) -BU_ALTIVEC_X (LVX_V8HI, "lvx_v8hi", MEM) -BU_ALTIVEC_X (LVX_V16QI, "lvx_v16qi", MEM) +BU_ALTIVEC_X (LVSL, "lvsl", PURE) +BU_ALTIVEC_X (LVSR, "lvsr", PURE) +BU_ALTIVEC_X (LVEBX, "lvebx", PURE) +BU_ALTIVEC_X (LVEHX, "lvehx", PURE) +BU_ALTIVEC_X (LVEWX, "lvewx", PURE) +BU_ALTIVEC_X (LVXL, "lvxl", PURE) +BU_ALTIVEC_X (LVXL_V2DF, "lvxl_v2df", PURE) +BU_ALTIVEC_X (LVXL_V2DI, "lvxl_v2di", PURE) +BU_ALTIVEC_X (LVXL_V4SF, "lvxl_v4sf", PURE) +BU_ALTIVEC_X (LVXL_V4SI, "lvxl_v4si", PURE) +BU_ALTIVEC_X (LVXL_V8HI, "lvxl_v8hi", PURE) +BU_ALTIVEC_X (LVXL_V16QI, "lvxl_v16qi", PURE) +BU_ALTIVEC_X (LVX, "lvx", PURE) +BU_ALTIVEC_X (LVX_V1TI, "lvx_v1ti", PURE) +BU_ALTIVEC_X (LVX_V2DF, "lvx_v2df", PURE) +BU_ALTIVEC_X (LVX_V2DI, "lvx_v2di", PURE) +BU_ALTIVEC_X (LVX_V4SF, "lvx_v4sf", PURE) +BU_ALTIVEC_X (LVX_V4SI, "lvx_v4si", PURE) +BU_ALTIVEC_X (LVX_V8HI, "lvx_v8hi", PURE) +BU_ALTIVEC_X (LVX_V16QI, "lvx_v16qi", PURE) BU_ALTIVEC_X (STVX, "stvx", MEM) BU_ALTIVEC_X (STVX_V2DF, "stvx_v2df", MEM) BU_ALTIVEC_X (STVX_V2DI, "stvx_v2di", MEM) @@ -1204,10 +1204,10 @@ BU_ALTIVEC_X (STVX_V4SF, "stvx_v4sf", MEM) BU_ALTIVEC_X (STVX_V4SI, "stvx_v4si", MEM) BU_ALTIVEC_X (STVX_V8HI, "stvx_v8hi", MEM) BU_ALTIVEC_X (STVX_V16QI, "stvx_v16qi", MEM) -BU_ALTIVEC_C (LVLX, "lvlx", MEM) -BU_ALTIVEC_C (LVLXL, "lvlxl", MEM) -BU_ALTIVEC_C (LVRX, "lvrx", MEM) -BU_ALTIVEC_C (LVRXL, "lvrxl", MEM) +BU_ALTIVEC_C (LVLX, "lvlx", PURE) +BU_ALTIVEC_C (LVLXL, "lvlxl", PURE) +BU_ALTIVEC_C (LVRX, "lvrx", PURE) +BU_ALTIVEC_C (LVRXL, "lvrxl", PURE) BU_ALTIVEC_X (STVEBX, "stvebx", MEM) BU_ALTIVEC_X (STVEHX, "stvehx", MEM) BU_ALTIVEC_X (STVEWX, "stvewx", MEM) @@ -1718,15 +1718,15 @@ BU_VSX_P (XVCMPGEDP_P, "xvcmpgedp_p", CONST, vector_ge_v2df_p) BU_VSX_P (XVCMPGTDP_P, "xvcmpgtdp_p", CONST, vector_gt_v2df_p) /* VSX builtins that are handled as special cases. */ -BU_VSX_X (LXSDX, "lxsdx", MEM) -BU_VSX_X (LXVD2X_V1TI, "lxvd2x_v1ti", MEM) -BU_VSX_X (LXVD2X_V2DF, "lxvd2x_v2df", MEM) -BU_VSX_X (LXVD2X_V2DI, "lxvd2x_v2di", MEM) -BU_VSX_X (LXVDSX, "lxvdsx", MEM) -BU_VSX_X (LXVW4X_V4SF, "lxvw4x_v4sf", MEM) -BU_VSX_X (LXVW4X_V4SI, "lxvw4x_v4si", MEM) -BU_VSX_X (LXVW4X_V8HI, "lxvw4x_v8hi", MEM) -BU_VSX_X (LXVW4X_V16QI, "lxvw4x_v16qi", MEM) +BU_VSX_X (LXSDX, "lxsdx", PURE) +BU_VSX_X (LXVD2X_V1TI, "lxvd2x_v1ti", PURE) +BU_VSX_X (LXVD2X_V2DF, "lxvd2x_v2df", PURE) +BU_VSX_X (LXVD2X_V2DI, "lxvd2x_v2di", PURE) +BU_VSX_X (LXVDSX, "lxvdsx", PURE) +BU_VSX_X (LXVW4X_V4SF, "lxvw4x_v4sf", PURE) +BU_VSX_X (LXVW4X_V4SI, "lxvw4x_v4si", PURE) +BU_VSX_X (LXVW4X_V8HI, "lxvw4x_v8hi", PURE) +BU_VSX_X (LXVW4X_V16QI, "lxvw4x_v16qi", PURE) BU_VSX_X (STXSDX, "stxsdx", MEM) BU_VSX_X (STXVD2X_V1TI, "stxvd2x_v1ti", MEM) BU_VSX_X (STXVD2X_V2DF, "stxvd2x_v2df", MEM) @@ -1735,13 +1735,13 @@ BU_VSX_X (STXVW4X_V4SF, "stxvw4x_v4sf", MEM) BU_VSX_X (STXVW4X_V4SI, "stxvw4x_v4si", MEM) BU_VSX_X (STXVW4X_V8HI, "stxvw4x_v8hi", MEM) BU_VSX_X (STXVW4X_V16QI, "stxvw4x_v16qi", MEM) -BU_VSX_X (LD_ELEMREV_V1TI, "ld_elemrev_v1ti", MEM) -BU_VSX_X (LD_ELEMREV_V2DF, "ld_elemrev_v2df", MEM) -BU_VSX_X (LD_ELEMREV_V2DI, "ld_elemrev_v2di", MEM) -BU_VSX_X (LD_ELEMREV_V4SF, "ld_elemrev_v4sf", MEM) -BU_VSX_X (LD_ELEMREV_V4SI, "ld_elemrev_v4si", MEM) -BU_VSX_X (LD_ELEMREV_V8HI, "ld_elemrev_v8hi", MEM) -BU_VSX_X (LD_ELEMREV_V16QI, "ld_elemrev_v16qi", MEM) +BU_VSX_X (LD_ELEMREV_V1TI, "ld_elemrev_v1ti", PURE) +BU_VSX_X (LD_ELEMREV_V2DF, "ld_elemrev_v2df", PURE) +BU_VSX_X (LD_ELEMREV_V2DI, "ld_elemrev_v2di", PURE) +BU_VSX_X (LD_ELEMREV_V4SF, "ld_elemrev_v4sf", PURE) +BU_VSX_X (LD_ELEMREV_V4SI, "ld_elemrev_v4si", PURE) +BU_VSX_X (LD_ELEMREV_V8HI, "ld_elemrev_v8hi", PURE) +BU_VSX_X (LD_ELEMREV_V16QI, "ld_elemrev_v16qi", PURE) BU_VSX_X (ST_ELEMREV_V1TI, "st_elemrev_v1ti", MEM) BU_VSX_X (ST_ELEMREV_V2DF, "st_elemrev_v2df", MEM) BU_VSX_X (ST_ELEMREV_V2DI, "st_elemrev_v2di", MEM) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 19ad393..2d78fdd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-26 Will Schmidt + + * gcc.target/powerpc/pure-builtin-redundant-load.c: New. + 2019-09-26 Richard Biener PR middle-end/91897 -- cgit v1.1 From 9ab2f9aed07c3c02ee633801d30b86a216b4cc3b Mon Sep 17 00:00:00 2001 From: Will Schmidt Date: Thu, 26 Sep 2019 19:19:47 +0000 Subject: rs6000-builtin.def: (LVSL... [gcc] 2019-09-26 Will Schmidt * config/rs6000/rs6000-builtin.def: (LVSL, LVSR, LVEBX, LVEHX, LVEWX, LVXL, LVXL_V2DF, LVXL_V2DI, LVXL_V4SF, LVXL_V4SI, LVXL_V8HI, LVXL_V16QI, LVX, LVX_V1TI, LVX_V2DF, LVX_V2DI, LVX_V4SF, LVX_V4SI, LVX_V8HI, LVX_V16QI, LVLX, LVLXL, LVRX, LVRXL, LXSDX, LXVD2X_V1TI, LXVD2X_V2DF, LXVD2X_V2DI, LXVDSX, LXVW4X_V4SF, LXVW4X_V4SI, LXVW4X_V8HI, LXVW4X_V16QI, LD_ELEMREV_V1TI, LD_ELEMREV_V2DF, LD_ELEMREV_V2DI, LD_ELEMREV_V4SF, LD_ELEMREV_V4SI, LD_ELEMREV_V8HI, LD_ELEMREV_V16QI): Use the PURE attribute. [testsuite] 2019-09-26 Will Schmidt * gcc.target/powerpc/pure-builtin-redundant-load.c: New. From-SVN: r276163 --- .../powerpc/pure-builtin-redundant-load.c | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 gcc/testsuite/gcc.target/powerpc/pure-builtin-redundant-load.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/powerpc/pure-builtin-redundant-load.c b/gcc/testsuite/gcc.target/powerpc/pure-builtin-redundant-load.c new file mode 100644 index 0000000..16ab6ab --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pure-builtin-redundant-load.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-O2 -fdump-tree-fre-all -mvsx" } */ + +/* Verify we remove a redundant load that occurs both before and after +we call a vector load builtin. +This testcase is introduced as we updated a number of our vector load +built-ins with the attribute of PURE instead of MEM, to indicate that +those builtins only read from memory, versus reading from and writing +to the same. +This means we can identify the redundant load instructions in an earlier +pass, and optimize them away. */ + +#include + +vector signed short load_data; + +vector signed short foo() +{ + vector signed short r11,r12,r13; + r11 = load_data; + r12 = vec_xl (0, &load_data[0]); + r13 = load_data; + return (r11 + r12 + r13); +} + +vector signed short biz() +{ + vector signed short r21,r22,r23; + r21 = load_data; + r22 = vec_lvehx (0, &load_data[0]); + r23 = load_data; + return (r21 + r22 + r23); +} + +vector signed short bar() +{ + vector signed short r31,r32,r33; + r31 = load_data; + r32 = vec_lvx (0, &load_data[0]); + r33 = load_data; + return (r31 + r32 + r33); +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt r13_. = load_data;" 1 "fre1" } } */ +/* { dg-final { scan-tree-dump-times "Removing dead stmt r23_. = load_data;" 1 "fre1" } } */ +/* { dg-final { scan-tree-dump-times "Removing dead stmt r33_. = load_data;" 1 "fre1" } } */ -- cgit v1.1 From c78d3425209f3c4ad529906bb43e7947f13311db Mon Sep 17 00:00:00 2001 From: Alessandro Fanfarillo Date: Thu, 26 Sep 2019 13:59:00 -0600 Subject: CO_BROADCAST for derived types with allocatable components From-SVN: r276164 --- gcc/fortran/ChangeLog | 14 +++ gcc/fortran/trans-array.c | 202 +++++++++++++++++++++++++++++++++++++----- gcc/fortran/trans-array.h | 2 + gcc/fortran/trans-intrinsic.c | 92 +++++++++++-------- gcc/fortran/trans.h | 8 ++ 5 files changed, 260 insertions(+), 58 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d4946bd..1c1997f 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,17 @@ +2019-09-26 Alessandro Fanfarillo + + * trans-array.c (structure_alloc_comps): + Add new enum item for BCAST_ALLOC_COMP. + New argument for structure_alloc_comp, and new case to handle + recursive components in derived types. + * trans-array.c (gfc_bcast_alloc_comp): New function + used to handleco_broadcast for allocatable components + of derived types. + * trans-array.h: Add gfc_bcast_alloc_comp + * trans-intrinsics.c (conv_co_collective): Add check for + derived type variable and invocation of co_bcast_alloc_comp. + * trans.h: New data structure gfc_co_subroutines_args. + 2019-09-25 David Malcolm PR fortran/91426 diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 8881fd9..07c4d7e 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -8580,13 +8580,15 @@ gfc_caf_is_dealloc_only (int caf_mode) enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP, COPY_ONLY_ALLOC_COMP, REASSIGN_CAF_COMP, - ALLOCATE_PDT_COMP, DEALLOCATE_PDT_COMP, CHECK_PDT_DUMMY}; + ALLOCATE_PDT_COMP, DEALLOCATE_PDT_COMP, CHECK_PDT_DUMMY, + BCAST_ALLOC_COMP}; static gfc_actual_arglist *pdt_param_list; static tree structure_alloc_comps (gfc_symbol * der_type, tree decl, - tree dest, int rank, int purpose, int caf_mode) + tree dest, int rank, int purpose, int caf_mode, + gfc_co_subroutines_args *args) { gfc_component *c; gfc_loopinfo loop; @@ -8672,14 +8674,14 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, && !caf_enabled (caf_mode)) { tmp = build_fold_indirect_ref_loc (input_location, - gfc_conv_array_data (dest)); + gfc_conv_array_data (dest)); dref = gfc_build_array_ref (tmp, index, NULL); tmp = structure_alloc_comps (der_type, vref, dref, rank, - COPY_ALLOC_COMP, 0); + COPY_ALLOC_COMP, 0, args); } else tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose, - caf_mode); + caf_mode, args); gfc_add_expr_to_block (&loopbody, tmp); @@ -8713,13 +8715,13 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, if (purpose == DEALLOCATE_ALLOC_COMP && der_type->attr.pdt_type) { tmp = structure_alloc_comps (der_type, decl, NULL_TREE, rank, - DEALLOCATE_PDT_COMP, 0); + DEALLOCATE_PDT_COMP, 0, args); gfc_add_expr_to_block (&fnblock, tmp); } else if (purpose == ALLOCATE_PDT_COMP && der_type->attr.alloc_comp) { tmp = structure_alloc_comps (der_type, decl, NULL_TREE, rank, - NULLIFY_ALLOC_COMP, 0); + NULLIFY_ALLOC_COMP, 0, args); gfc_add_expr_to_block (&fnblock, tmp); } @@ -8741,6 +8743,125 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, switch (purpose) { + + case BCAST_ALLOC_COMP: + + tree ubound; + tree cdesc; + stmtblock_t derived_type_block; + + gfc_init_block (&tmpblock); + + comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, + decl, cdecl, NULL_TREE); + + /* Shortcut to get the attributes of the component. */ + if (c->ts.type == BT_CLASS) + { + attr = &CLASS_DATA (c)->attr; + if (attr->class_pointer) + continue; + } + else + { + attr = &c->attr; + if (attr->pointer) + continue; + } + + add_when_allocated = NULL_TREE; + if (cmp_has_alloc_comps + && !c->attr.pointer && !c->attr.proc_pointer) + { + if (c->ts.type == BT_CLASS) + { + rank = CLASS_DATA (c)->as ? CLASS_DATA (c)->as->rank : 0; + add_when_allocated + = structure_alloc_comps (CLASS_DATA (c)->ts.u.derived, + comp, NULL_TREE, rank, purpose, + caf_mode, args); + } + else + { + rank = c->as ? c->as->rank : 0; + add_when_allocated = structure_alloc_comps (c->ts.u.derived, + comp, NULL_TREE, + rank, purpose, + caf_mode, args); + } + } + + gfc_init_block (&derived_type_block); + if (add_when_allocated) + gfc_add_expr_to_block (&derived_type_block, add_when_allocated); + tmp = gfc_finish_block (&derived_type_block); + gfc_add_expr_to_block (&tmpblock, tmp); + + /* Convert the component into a rank 1 descriptor type. */ + if (attr->dimension) + { + tmp = gfc_get_element_type (TREE_TYPE (comp)); + ubound = gfc_full_array_size (&tmpblock, comp, + c->ts.type == BT_CLASS + ? CLASS_DATA (c)->as->rank + : c->as->rank); + } + else + { + tmp = TREE_TYPE (comp); + ubound = build_int_cst (gfc_array_index_type, 1); + } + + cdesc = gfc_get_array_type_bounds (tmp, 1, 0, &gfc_index_one_node, + &ubound, 1, + GFC_ARRAY_ALLOCATABLE, false); + + cdesc = gfc_create_var (cdesc, "cdesc"); + DECL_ARTIFICIAL (cdesc) = 1; + + gfc_add_modify (&tmpblock, gfc_conv_descriptor_dtype (cdesc), + gfc_get_dtype_rank_type (1, tmp)); + gfc_conv_descriptor_lbound_set (&tmpblock, cdesc, + gfc_index_zero_node, + gfc_index_one_node); + gfc_conv_descriptor_stride_set (&tmpblock, cdesc, + gfc_index_zero_node, + gfc_index_one_node); + gfc_conv_descriptor_ubound_set (&tmpblock, cdesc, + gfc_index_zero_node, ubound); + + if (attr->dimension) + comp = gfc_conv_descriptor_data_get (comp); + else + { + gfc_se se; + + gfc_init_se (&se, NULL); + + comp = gfc_conv_scalar_to_descriptor (&se, comp, + c->ts.type == BT_CLASS + ? CLASS_DATA (c)->attr + : c->attr); + comp = gfc_build_addr_expr (NULL_TREE, comp); + gfc_add_block_to_block (&tmpblock, &se.pre); + } + + gfc_conv_descriptor_data_set (&tmpblock, cdesc, comp); + + tree fndecl; + + fndecl = build_call_expr_loc (input_location, + gfor_fndecl_co_broadcast, 5, + gfc_build_addr_expr (pvoid_type_node,cdesc), + args->image_index, + null_pointer_node, null_pointer_node, + null_pointer_node); + + gfc_add_expr_to_block (&tmpblock, fndecl); + gfc_add_block_to_block (&fnblock, &tmpblock); + + break; + case DEALLOCATE_ALLOC_COMP: gfc_init_block (&tmpblock); @@ -8791,7 +8912,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, add_when_allocated = structure_alloc_comps (CLASS_DATA (c)->ts.u.derived, comp, NULL_TREE, rank, purpose, - caf_mode); + caf_mode, args); } else { @@ -8799,7 +8920,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, add_when_allocated = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE, rank, purpose, - caf_mode); + caf_mode, args); } } @@ -9075,7 +9196,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, decl, cdecl, NULL_TREE); rank = c->as ? c->as->rank : 0; tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE, - rank, purpose, caf_mode); + rank, purpose, caf_mode, args); gfc_add_expr_to_block (&fnblock, tmp); } break; @@ -9110,7 +9231,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, { tmp = structure_alloc_comps (c->ts.u.derived, comp, dcmp, rank, purpose, caf_mode - | GFC_STRUCTURE_CAF_MODE_IN_COARRAY); + | GFC_STRUCTURE_CAF_MODE_IN_COARRAY, + args); gfc_add_expr_to_block (&fnblock, tmp); } } @@ -9230,7 +9352,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, add_when_allocated = structure_alloc_comps (c->ts.u.derived, comp, dcmp, rank, purpose, - caf_mode); + caf_mode, args); } else add_when_allocated = NULL_TREE; @@ -9594,7 +9716,7 @@ gfc_nullify_alloc_comp (gfc_symbol * der_type, tree decl, int rank, { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, NULLIFY_ALLOC_COMP, - GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY | caf_mode); + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY | caf_mode, NULL); } @@ -9607,9 +9729,47 @@ gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank, { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, DEALLOCATE_ALLOC_COMP, - GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY | caf_mode); + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY | caf_mode, NULL); } +tree +gfc_bcast_alloc_comp (gfc_symbol *derived, gfc_expr *expr, int rank, + tree image_index, tree stat, tree errmsg, + tree errmsg_len) +{ + tree tmp, array; + gfc_se argse; + stmtblock_t block, post_block; + gfc_co_subroutines_args args; + + args.image_index = image_index; + args.stat = stat; + args.errmsg = errmsg; + args.errmsg = errmsg_len; + + if (rank == 0) + { + gfc_start_block (&block); + gfc_init_block (&post_block); + gfc_init_se (&argse, NULL); + gfc_conv_expr (&argse, expr); + gfc_add_block_to_block (&block, &argse.pre); + gfc_add_block_to_block (&post_block, &argse.post); + array = argse.expr; + } + else + { + gfc_init_se (&argse, NULL); + argse.want_pointer = 1; + gfc_conv_expr_descriptor (&argse, expr); + array = argse.expr; + } + + tmp = structure_alloc_comps (derived, array, NULL_TREE, rank, + BCAST_ALLOC_COMP, + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY, &args); + return tmp; +} /* Recursively traverse an object of derived type, generating code to deallocate allocatable components. But do not deallocate coarrays. @@ -9620,7 +9780,7 @@ tree gfc_deallocate_alloc_comp_no_caf (gfc_symbol * der_type, tree decl, int rank) { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, - DEALLOCATE_ALLOC_COMP, 0); + DEALLOCATE_ALLOC_COMP, 0, NULL); } @@ -9628,7 +9788,7 @@ tree gfc_reassign_alloc_comp_caf (gfc_symbol *der_type, tree decl, tree dest) { return structure_alloc_comps (der_type, decl, dest, 0, REASSIGN_CAF_COMP, - GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY); + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY, NULL); } @@ -9640,7 +9800,7 @@ gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank, int caf_mode) { return structure_alloc_comps (der_type, decl, dest, rank, COPY_ALLOC_COMP, - caf_mode); + caf_mode, NULL); } @@ -9651,7 +9811,7 @@ tree gfc_copy_only_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) { return structure_alloc_comps (der_type, decl, dest, rank, - COPY_ONLY_ALLOC_COMP, 0); + COPY_ONLY_ALLOC_COMP, 0, NULL); } @@ -9666,7 +9826,7 @@ gfc_allocate_pdt_comp (gfc_symbol * der_type, tree decl, int rank, gfc_actual_arglist *old_param_list = pdt_param_list; pdt_param_list = param_list; res = structure_alloc_comps (der_type, decl, NULL_TREE, rank, - ALLOCATE_PDT_COMP, 0); + ALLOCATE_PDT_COMP, 0, NULL); pdt_param_list = old_param_list; return res; } @@ -9678,7 +9838,7 @@ tree gfc_deallocate_pdt_comp (gfc_symbol * der_type, tree decl, int rank) { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, - DEALLOCATE_PDT_COMP, 0); + DEALLOCATE_PDT_COMP, 0, NULL); } @@ -9693,7 +9853,7 @@ gfc_check_pdt_dummy (gfc_symbol * der_type, tree decl, int rank, gfc_actual_arglist *old_param_list = pdt_param_list; pdt_param_list = param_list; res = structure_alloc_comps (der_type, decl, NULL_TREE, rank, - CHECK_PDT_DUMMY, 0); + CHECK_PDT_DUMMY, 0, NULL); pdt_param_list = old_param_list; return res; } diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h index 8c2d518..5a7eee7 100644 --- a/gcc/fortran/trans-array.h +++ b/gcc/fortran/trans-array.h @@ -52,6 +52,8 @@ bool gfc_caf_is_dealloc_only (int); tree gfc_nullify_alloc_comp (gfc_symbol *, tree, int, int cm = 0); tree gfc_deallocate_alloc_comp (gfc_symbol *, tree, int, int cm = 0); +tree gfc_bcast_alloc_comp (gfc_symbol *, gfc_expr *, int, tree, + tree, tree, tree); tree gfc_deallocate_alloc_comp_no_caf (gfc_symbol *, tree, int); tree gfc_reassign_alloc_comp_caf (gfc_symbol *, tree, tree); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 26ea624..c2e0533 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -10786,13 +10786,12 @@ gfc_walk_intrinsic_function (gfc_ss * ss, gfc_expr * expr, } } - static tree conv_co_collective (gfc_code *code) { gfc_se argse; stmtblock_t block, post_block; - tree fndecl, array, strlen, image_index, stat, errmsg, errmsg_len; + tree fndecl, array = NULL_TREE, strlen, image_index, stat, errmsg, errmsg_len; gfc_expr *image_idx_expr, *stat_expr, *errmsg_expr, *opr_expr; gfc_start_block (&block); @@ -10857,6 +10856,7 @@ conv_co_collective (gfc_code *code) gfc_conv_expr_descriptor (&argse, code->ext.actual->expr); array = argse.expr; } + gfc_add_block_to_block (&block, &argse.pre); gfc_add_block_to_block (&post_block, &argse.post); @@ -10915,46 +10915,64 @@ conv_co_collective (gfc_code *code) gcc_unreachable (); } - if (code->resolved_isym->id == GFC_ISYM_CO_SUM - || code->resolved_isym->id == GFC_ISYM_CO_BROADCAST) - fndecl = build_call_expr_loc (input_location, fndecl, 5, array, - image_index, stat, errmsg, errmsg_len); - else if (code->resolved_isym->id != GFC_ISYM_CO_REDUCE) - fndecl = build_call_expr_loc (input_location, fndecl, 6, array, image_index, - stat, errmsg, strlen, errmsg_len); + gfc_symbol *derived = code->ext.actual->expr->ts.type == BT_DERIVED + ? code->ext.actual->expr->ts.u.derived : NULL; + + if (derived && derived->attr.alloc_comp + && code->resolved_isym->id == GFC_ISYM_CO_BROADCAST) + /* The derived type has the attribute 'alloc_comp'. */ + { + tree tmp = gfc_bcast_alloc_comp (derived, code->ext.actual->expr, + code->ext.actual->expr->rank, + image_index, stat, errmsg, errmsg_len); + gfc_add_expr_to_block (&block, tmp); + } else { - tree opr, opr_flags; - - // FIXME: Handle TS29113's bind(C) strings with descriptor. - int opr_flag_int; - if (gfc_is_proc_ptr_comp (opr_expr)) - { - gfc_symbol *sym = gfc_get_proc_ptr_comp (opr_expr)->ts.interface; - opr_flag_int = sym->attr.dimension - || (sym->ts.type == BT_CHARACTER - && !sym->attr.is_bind_c) - ? GFC_CAF_BYREF : 0; - opr_flag_int |= opr_expr->ts.type == BT_CHARACTER - && !sym->attr.is_bind_c - ? GFC_CAF_HIDDENLEN : 0; - opr_flag_int |= sym->formal->sym->attr.value ? GFC_CAF_ARG_VALUE : 0; - } + if (code->resolved_isym->id == GFC_ISYM_CO_SUM + || code->resolved_isym->id == GFC_ISYM_CO_BROADCAST) + fndecl = build_call_expr_loc (input_location, fndecl, 5, array, + image_index, stat, errmsg, errmsg_len); + else if (code->resolved_isym->id != GFC_ISYM_CO_REDUCE) + fndecl = build_call_expr_loc (input_location, fndecl, 6, array, + image_index, stat, errmsg, + strlen, errmsg_len); else { - opr_flag_int = gfc_return_by_reference (opr_expr->symtree->n.sym) - ? GFC_CAF_BYREF : 0; - opr_flag_int |= opr_expr->ts.type == BT_CHARACTER - && !opr_expr->symtree->n.sym->attr.is_bind_c - ? GFC_CAF_HIDDENLEN : 0; - opr_flag_int |= opr_expr->symtree->n.sym->formal->sym->attr.value - ? GFC_CAF_ARG_VALUE : 0; + tree opr, opr_flags; + + // FIXME: Handle TS29113's bind(C) strings with descriptor. + int opr_flag_int; + if (gfc_is_proc_ptr_comp (opr_expr)) + { + gfc_symbol *sym = gfc_get_proc_ptr_comp (opr_expr)->ts.interface; + opr_flag_int = sym->attr.dimension + || (sym->ts.type == BT_CHARACTER + && !sym->attr.is_bind_c) + ? GFC_CAF_BYREF : 0; + opr_flag_int |= opr_expr->ts.type == BT_CHARACTER + && !sym->attr.is_bind_c + ? GFC_CAF_HIDDENLEN : 0; + opr_flag_int |= sym->formal->sym->attr.value + ? GFC_CAF_ARG_VALUE : 0; + } + else + { + opr_flag_int = gfc_return_by_reference (opr_expr->symtree->n.sym) + ? GFC_CAF_BYREF : 0; + opr_flag_int |= opr_expr->ts.type == BT_CHARACTER + && !opr_expr->symtree->n.sym->attr.is_bind_c + ? GFC_CAF_HIDDENLEN : 0; + opr_flag_int |= opr_expr->symtree->n.sym->formal->sym->attr.value + ? GFC_CAF_ARG_VALUE : 0; + } + opr_flags = build_int_cst (integer_type_node, opr_flag_int); + gfc_conv_expr (&argse, opr_expr); + opr = argse.expr; + fndecl = build_call_expr_loc (input_location, fndecl, 8, array, opr, + opr_flags, image_index, stat, errmsg, + strlen, errmsg_len); } - opr_flags = build_int_cst (integer_type_node, opr_flag_int); - gfc_conv_expr (&argse, opr_expr); - opr = argse.expr; - fndecl = build_call_expr_loc (input_location, fndecl, 8, array, opr, opr_flags, - image_index, stat, errmsg, strlen, errmsg_len); } gfc_add_expr_to_block (&block, fndecl); diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 8082b41..84793dc 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -107,6 +107,14 @@ typedef struct gfc_se } gfc_se; +typedef struct gfc_co_subroutines_args +{ + tree image_index; + tree stat; + tree errmsg; + tree errmsg_len; +} +gfc_co_subroutines_args; /* Denotes different types of coarray. Please keep in sync with libgfortran/caf/libcaf.h. */ -- cgit v1.1 From 25b45c7c6cea24f85d2f87c11c0e3c99ef20b655 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 26 Sep 2019 22:03:12 +0200 Subject: function.c (gimplify_parameters): Use build_clobber function. * function.c (gimplify_parameters): Use build_clobber function. * tree-ssa.c (execute_update_addresses_taken): Likewise. * tree-inline.c (expand_call_inline): Likewise. * tree-sra.c (clobber_subtree): Likewise. * tree-ssa-ccp.c (insert_clobber_before_stack_restore): Likewise. * omp-low.c (lower_rec_simd_input_clauses, lower_rec_input_clauses, lower_omp_single, lower_depend_clauses, lower_omp_taskreg, lower_omp_target): Likewise. * omp-expand.c (expand_omp_for_generic): Likewise. * omp-offload.c (ompdevlow_adjust_simt_enter): Likewise. From-SVN: r276165 --- gcc/ChangeLog | 13 +++++++++++++ gcc/function.c | 3 +-- gcc/omp-expand.c | 6 ++---- gcc/omp-low.c | 22 +++++++--------------- gcc/omp-offload.c | 3 +-- gcc/tree-inline.c | 9 +++------ gcc/tree-sra.c | 3 +-- gcc/tree-ssa-ccp.c | 4 +--- gcc/tree-ssa.c | 4 +--- 9 files changed, 30 insertions(+), 37 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c4cd4ac..416bf63 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-09-26 Jakub Jelinek + + * function.c (gimplify_parameters): Use build_clobber function. + * tree-ssa.c (execute_update_addresses_taken): Likewise. + * tree-inline.c (expand_call_inline): Likewise. + * tree-sra.c (clobber_subtree): Likewise. + * tree-ssa-ccp.c (insert_clobber_before_stack_restore): Likewise. + * omp-low.c (lower_rec_simd_input_clauses, lower_rec_input_clauses, + lower_omp_single, lower_depend_clauses, lower_omp_taskreg, + lower_omp_target): Likewise. + * omp-expand.c (expand_omp_for_generic): Likewise. + * omp-offload.c (ompdevlow_adjust_simt_enter): Likewise. + 2019-09-26 Will Schmidt * config/rs6000/rs6000-builtin.def: (LVSL, LVSR, LVEBX, LVEHX, diff --git a/gcc/function.c b/gcc/function.c index e60b6fa..9c158ce 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3892,9 +3892,8 @@ gimplify_parameters (gimple_seq *cleanup) if (!is_gimple_reg (local) && flag_stack_reuse != SR_NONE) { - tree clobber = build_constructor (type, NULL); + tree clobber = build_clobber (type); gimple *clobber_stmt; - TREE_THIS_VOLATILE (clobber) = 1; clobber_stmt = gimple_build_assign (local, clobber); gimple_seq_add_stmt (cleanup, clobber_stmt); } diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 94543de..0f703be 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -2988,8 +2988,7 @@ expand_omp_for_generic (struct omp_region *region, true, GSI_SAME_STMT); if (arr && !TREE_STATIC (arr)) { - tree clobber = build_constructor (TREE_TYPE (arr), NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (TREE_TYPE (arr)); gsi_insert_before (&gsi, gimple_build_assign (arr, clobber), GSI_SAME_STMT); } @@ -3356,8 +3355,7 @@ expand_omp_for_generic (struct omp_region *region, if (fd->ordered) { tree arr = counts[fd->ordered]; - tree clobber = build_constructor (TREE_TYPE (arr), NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (TREE_TYPE (arr)); gsi_insert_after (&gsi, gimple_build_assign (arr, clobber), GSI_SAME_STMT); } diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 444610b..5db182c 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -4044,8 +4044,7 @@ lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, DECL_ATTRIBUTES (ivar) = tree_cons (get_identifier ("omp simt private"), NULL, DECL_ATTRIBUTES (ivar)); sctx->simt_eargs.safe_push (build1 (ADDR_EXPR, ptype, ivar)); - tree clobber = build_constructor (type, NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (type); gimple *g = gimple_build_assign (ivar, clobber); gimple_seq_add_stmt (&sctx->simt_dlist, g); } @@ -5939,8 +5938,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } if (tskred_avar) { - tree clobber = build_constructor (TREE_TYPE (tskred_avar), NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (TREE_TYPE (tskred_avar)); gimple_seq_add_stmt (ilist, gimple_build_assign (tskred_avar, clobber)); } @@ -7896,8 +7894,7 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (ctx->record_type) { gimple_stmt_iterator gsi = gsi_start (bind_body_tail); - tree clobber = build_constructor (ctx->record_type, NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (ctx->record_type); gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl, clobber), GSI_SAME_STMT); } @@ -11029,8 +11026,7 @@ lower_depend_clauses (tree *pclauses, gimple_seq *iseq, gimple_seq *oseq) OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array); OMP_CLAUSE_CHAIN (c) = *pclauses; *pclauses = c; - tree clobber = build_constructor (type, NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (type); g = gimple_build_assign (array, clobber); gimple_seq_add_stmt (oseq, g); } @@ -11165,8 +11161,7 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (ctx->record_type) { - tree clobber = build_constructor (TREE_TYPE (ctx->sender_decl), NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (TREE_TYPE (ctx->sender_decl)); gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl, clobber)); } @@ -11911,16 +11906,13 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) &initlist, true, NULL_TREE); gimple_seq_add_seq (&ilist, initlist); - tree clobber = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, i)), - NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (TREE_TYPE (TREE_VEC_ELT (t, i))); gimple_seq_add_stmt (&olist, gimple_build_assign (TREE_VEC_ELT (t, i), clobber)); } - tree clobber = build_constructor (ctx->record_type, NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (ctx->record_type); gimple_seq_add_stmt (&olist, gimple_build_assign (ctx->sender_decl, clobber)); } diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c index da788d9..32eacf7 100644 --- a/gcc/omp-offload.c +++ b/gcc/omp-offload.c @@ -1855,8 +1855,7 @@ ompdevlow_adjust_simt_enter (gimple_stmt_iterator *gsi, bool *regimplify) { gcc_assert (gimple_call_internal_p (exit_stmt, IFN_GOMP_SIMT_EXIT)); gimple_stmt_iterator exit_gsi = gsi_for_stmt (exit_stmt); - tree clobber = build_constructor (rectype, NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (rectype); exit_stmt = gimple_build_assign (build_simple_mem_ref (simtrec), clobber); gsi_insert_before (&exit_gsi, exit_stmt, GSI_SAME_STMT); } diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index e4ae1b0..500037c 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -5016,9 +5016,8 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id) tree *varp = id->decl_map->get (p); if (varp && VAR_P (*varp) && !is_gimple_reg (*varp)) { - tree clobber = build_constructor (TREE_TYPE (*varp), NULL); + tree clobber = build_clobber (TREE_TYPE (*varp)); gimple *clobber_stmt; - TREE_THIS_VOLATILE (clobber) = 1; clobber_stmt = gimple_build_assign (*varp, clobber); gimple_set_location (clobber_stmt, gimple_location (stmt)); gsi_insert_before (&stmt_gsi, clobber_stmt, GSI_SAME_STMT); @@ -5086,9 +5085,8 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id) && !is_gimple_reg (id->retvar) && !stmt_ends_bb_p (stmt)) { - tree clobber = build_constructor (TREE_TYPE (id->retvar), NULL); + tree clobber = build_clobber (TREE_TYPE (id->retvar)); gimple *clobber_stmt; - TREE_THIS_VOLATILE (clobber) = 1; clobber_stmt = gimple_build_assign (id->retvar, clobber); gimple_set_location (clobber_stmt, gimple_location (old_stmt)); gsi_insert_after (&stmt_gsi, clobber_stmt, GSI_SAME_STMT); @@ -5134,9 +5132,8 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id) && !TREE_THIS_VOLATILE (id->retvar) && !is_gimple_reg (id->retvar)) { - tree clobber = build_constructor (TREE_TYPE (id->retvar), NULL); + tree clobber = build_clobber (TREE_TYPE (id->retvar)); gimple *clobber_stmt; - TREE_THIS_VOLATILE (clobber) = 1; clobber_stmt = gimple_build_assign (id->retvar, clobber); gimple_set_location (clobber_stmt, gimple_location (stmt)); gsi_replace (&stmt_gsi, clobber_stmt, false); diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index ba6d540..c462ca4 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -3028,8 +3028,7 @@ clobber_subtree (struct access *access, gimple_stmt_iterator *gsi, if (access->grp_to_be_replaced) { tree rep = get_access_replacement (access); - tree clobber = build_constructor (access->type, NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (access->type); gimple *stmt = gimple_build_assign (rep, clobber); if (insert_after) diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 311918b..a8d0738 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -2093,9 +2093,7 @@ insert_clobber_before_stack_restore (tree saved_val, tree var, FOR_EACH_IMM_USE_STMT (stmt, iter, saved_val) if (gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE)) { - clobber = build_constructor (TREE_TYPE (var), - NULL); - TREE_THIS_VOLATILE (clobber) = 1; + clobber = build_clobber (TREE_TYPE (var)); clobber_stmt = gimple_build_assign (var, clobber); i = gsi_for_stmt (stmt); diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index b4b5c90..24dd8b3 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -2016,9 +2016,7 @@ execute_update_addresses_taken (void) /* In ASAN_MARK (UNPOISON, &b, ...) the variable is uninitialized. Avoid dependencies on previous out of scope value. */ - tree clobber - = build_constructor (TREE_TYPE (var), NULL); - TREE_THIS_VOLATILE (clobber) = 1; + tree clobber = build_clobber (TREE_TYPE (var)); gimple *g = gimple_build_assign (var, clobber); gsi_replace (&gsi, g, GSI_SAME_STMT); } -- cgit v1.1 From d7326aaf20871a81feb39673d78922c1bc83efec Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 26 Sep 2019 20:51:27 +0000 Subject: xtensa: fix PR target/91880 Xtensa hwloop_optimize segfaults when zero overhead loop is about to be inserted as the first instruction of the function. Insert zero overhead loop instruction into new basic block before the loop when basic block that precedes the loop is empty. 2019-09-26 Max Filippov gcc/ * config/xtensa/xtensa.c (hwloop_optimize): Insert zero overhead loop instruction into new basic block before the loop when basic block that precedes the loop is empty. gcc/testsuite/ * gcc.target/xtensa/pr91880.c: New test case. * gcc.target/xtensa/xtensa.exp: New test suite. From-SVN: r276166 --- gcc/ChangeLog | 6 +++++ gcc/config/xtensa/xtensa.c | 5 ++-- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.target/xtensa/pr91880.c | 10 ++++++++ gcc/testsuite/gcc.target/xtensa/xtensa.exp | 41 ++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/xtensa/pr91880.c create mode 100644 gcc/testsuite/gcc.target/xtensa/xtensa.exp (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 416bf63..3d12337 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-26 Max Filippov + + * config/xtensa/xtensa.c (hwloop_optimize): Insert zero overhead + loop instruction into new basic block before the loop when basic + block that precedes the loop is empty. + 2019-09-26 Jakub Jelinek * function.c (gimplify_parameters): Use build_clobber function. diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c index 3c129fd..9453f0c 100644 --- a/gcc/config/xtensa/xtensa.c +++ b/gcc/config/xtensa/xtensa.c @@ -4230,7 +4230,9 @@ hwloop_optimize (hwloop_info loop) seq = get_insns (); - if (!single_succ_p (entry_bb) || vec_safe_length (loop->incoming) > 1) + entry_after = BB_END (entry_bb); + if (!single_succ_p (entry_bb) || vec_safe_length (loop->incoming) > 1 + || !entry_after) { basic_block new_bb; edge e; @@ -4251,7 +4253,6 @@ hwloop_optimize (hwloop_info loop) } else { - entry_after = BB_END (entry_bb); while (DEBUG_INSN_P (entry_after) || (NOTE_P (entry_after) && NOTE_KIND (entry_after) != NOTE_INSN_BASIC_BLOCK)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2d78fdd..7cdc8f0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-26 Max Filippov + + * gcc.target/xtensa/pr91880.c: New test case. + * gcc.target/xtensa/xtensa.exp: New test suite. + 2019-09-26 Will Schmidt * gcc.target/powerpc/pure-builtin-redundant-load.c: New. diff --git a/gcc/testsuite/gcc.target/xtensa/pr91880.c b/gcc/testsuite/gcc.target/xtensa/pr91880.c new file mode 100644 index 0000000..f4895a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/pr91880.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fomit-frame-pointer -fno-tree-vectorize" } */ + +void foo (unsigned int n, char *a, char *b) +{ + int i; + + for (i = 0; i <= n - 1; ++i) + a[i] = b[i]; +} diff --git a/gcc/testsuite/gcc.target/xtensa/xtensa.exp b/gcc/testsuite/gcc.target/xtensa/xtensa.exp new file mode 100644 index 0000000..8720327 --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/xtensa.exp @@ -0,0 +1,41 @@ +# Copyright (C) 2019 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an Xtensa target. +if ![istarget xtensa*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish -- cgit v1.1 From 0900e29cdbc533fecf2a311447bbde17f101bbd6 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 26 Sep 2019 21:43:51 +0000 Subject: charset.c (UCS_LIMIT): New macro. * charset.c (UCS_LIMIT): New macro. (ucn_valid_in_identifier): Use it instead of a hardcoded constant. (_cpp_valid_ucn): Issue a pedantic warning for UCNs larger than UCS_LIMIT outside of identifiers in C and in C++2a or later. From-SVN: r276167 --- gcc/testsuite/ChangeLog | 8 ++++++++ gcc/testsuite/g++.dg/cpp/ucn-1.C | 2 ++ gcc/testsuite/g++.dg/cpp2a/ucn1.C | 7 +++++++ gcc/testsuite/gcc.dg/attr-alias-5.c | 2 +- gcc/testsuite/gcc.dg/cpp/ucs.c | 6 ++++-- gcc/testsuite/gcc.dg/cpp/utf8-5byte-1.c | 2 +- 6 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/ucn1.C (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7cdc8f0..82607de 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-09-26 Eric Botcazou + + * gcc.dg/cpp/ucs.c: Add test for new warning and adjust. + * gcc.dg/cpp/utf8-5byte-1.c: Add -w to the options. + * gcc.dg/attr-alias-5.c: Likewise. + * g++.dg/cpp/ucn-1.C: Add test for new warning. + * g++.dg/cpp2a/ucn1.C: New test. + 2019-09-26 Max Filippov * gcc.target/xtensa/pr91880.c: New test case. diff --git a/gcc/testsuite/g++.dg/cpp/ucn-1.C b/gcc/testsuite/g++.dg/cpp/ucn-1.C index d929078..9596a42 100644 --- a/gcc/testsuite/g++.dg/cpp/ucn-1.C +++ b/gcc/testsuite/g++.dg/cpp/ucn-1.C @@ -12,4 +12,6 @@ int main() int c\u0024c; // { dg-error "not valid in an identifier" "" { target { powerpc-ibm-aix* } } } U"\uD800"; // { dg-error "not a valid universal character" } + + U'\U00110000'; // { dg-warning "outside" "110000 outside UCS" { target c++2a } } } diff --git a/gcc/testsuite/g++.dg/cpp2a/ucn1.C b/gcc/testsuite/g++.dg/cpp2a/ucn1.C new file mode 100644 index 0000000..e73c77d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/ucn1.C @@ -0,0 +1,7 @@ +// { dg-do compile } +// { dg-options "-std=c++2a" } + +int main() +{ + U'\U00110000'; // { dg-warning "outside" "110000 outside UCS" } +} diff --git a/gcc/testsuite/gcc.dg/attr-alias-5.c b/gcc/testsuite/gcc.dg/attr-alias-5.c index 91e63f8..a65fe0b 100644 --- a/gcc/testsuite/gcc.dg/attr-alias-5.c +++ b/gcc/testsuite/gcc.dg/attr-alias-5.c @@ -1,7 +1,7 @@ /* Verify diagnostics for aliases to strings containing extended identifiers or bad characters. */ /* { dg-do compile } */ -/* { dg-options "-std=gnu99" } */ +/* { dg-options "-std=gnu99 -w" } */ /* { dg-require-alias "" } */ /* { dg-require-ascii-locale "" } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ diff --git a/gcc/testsuite/gcc.dg/cpp/ucs.c b/gcc/testsuite/gcc.dg/cpp/ucs.c index 4f76fa9..cac83f3 100644 --- a/gcc/testsuite/gcc.dg/cpp/ucs.c +++ b/gcc/testsuite/gcc.dg/cpp/ucs.c @@ -39,7 +39,7 @@ #endif #if WCHAR_MAX >= 0x7ffffff -# if L'\U1234abcd' != 0x1234abcd +# if L'\U1234abcd' != 0x1234abcd /* { dg-warning "outside" "" } */ # error bad long ucs /* { dg-bogus "bad" "bad U1234abcd evaluation" } */ # endif #endif @@ -49,7 +49,7 @@ void foo () int c; c = L'\ubad'; /* { dg-error "incomplete" "incomplete UCN 1" } */ - c = L"\U1234"[0]; /* { dg-error "incomplete" "incompete UCN 2" } */ + c = L"\U1234"[0]; /* { dg-error "incomplete" "incomplete UCN 2" } */ c = L'\u000x'; /* { dg-error "incomplete" "non-hex digit in UCN" } */ /* If sizeof(HOST_WIDE_INT) > sizeof(wchar_t), we can get a multi-character @@ -64,4 +64,6 @@ void foo () c = '\u0025'; /* { dg-error "not a valid" "0025 invalid UCN" } */ c = L"\uD800"[0]; /* { dg-error "not a valid" "D800 invalid UCN" } */ c = L'\U0000DFFF'; /* { dg-error "not a valid" "DFFF invalid UCN" } */ + + c = L'\U00110000'; /* { dg-warning "outside" "110000 outside UCS" } */ } diff --git a/gcc/testsuite/gcc.dg/cpp/utf8-5byte-1.c b/gcc/testsuite/gcc.dg/cpp/utf8-5byte-1.c index 7f96a56..50e6c05 100644 --- a/gcc/testsuite/gcc.dg/cpp/utf8-5byte-1.c +++ b/gcc/testsuite/gcc.dg/cpp/utf8-5byte-1.c @@ -1,7 +1,7 @@ /* Test for bug in conversions from 5-byte UTF-8 sequences in cpplib. */ /* { dg-do run { target { 4byte_wchar_t } } } */ -/* { dg-options "-std=gnu99" } */ +/* { dg-options "-std=gnu99 -w" } */ extern void abort (void); extern void exit (int); -- cgit v1.1 From 09704140c7f3e4341d66a32e40359c4d146a4350 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 27 Sep 2019 00:16:20 +0000 Subject: Daily bump. From-SVN: r276172 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 1c14e6d..cdcc7ba 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190926 +20190927 -- cgit v1.1 From 639a28ba6e0e5807ae062475f35cc6895e32ef17 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Fri, 27 Sep 2019 01:59:55 +0000 Subject: set DECL_SIZE_UNIT for zero-sized fields Zero-sized fields do not get processed by finish_record_type: they're removed from the field list before and reinserted after, so their DECL_SIZE_UNIT remains unset, causing the translation of assignment statements with use_memset_p, in quite unusual circumstances, to use a NULL_TREE as the memset length. This patch sets DECL_SIZE_UNIT for the zero-sized fields, that don't go through language-independent layout, in language-specific layout. for gcc/ada/ChangeLog * gcc-interface/decl.c (components_to_record): Set DECL_SIZE_UNIT for zero-sized fields. From-SVN: r276173 --- gcc/ada/ChangeLog | 5 +++++ gcc/ada/gcc-interface/decl.c | 1 + 2 files changed, 6 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index a5f3843..8e5a19b 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-09-26 Alexandre Oliva + + * gcc-interface/decl.c (components_to_record): Set + DECL_SIZE_UNIT for zero-sized fields. + 2019-09-26 Arnaud Charlet * osint.adb (OS_Time_To_GNAT_Time): Remove dependency on To_C/To_Ada diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 67b938e..77c6c9f 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -7928,6 +7928,7 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, if (DECL_SIZE (gnu_field) && integer_zerop (DECL_SIZE (gnu_field))) { + DECL_SIZE_UNIT (gnu_field) = size_zero_node; DECL_FIELD_OFFSET (gnu_field) = size_zero_node; SET_DECL_OFFSET_ALIGN (gnu_field, BIGGEST_ALIGNMENT); DECL_FIELD_BIT_OFFSET (gnu_field) = bitsize_zero_node; -- cgit v1.1 From 76bb5af63db66ccaee0f0ae59783eda972d0db83 Mon Sep 17 00:00:00 2001 From: Yuliang Wang Date: Fri, 27 Sep 2019 08:10:30 +0000 Subject: [AArch64][SVE2] Shift-Right Accumulate combine patterns This patch adds combining support for SVE2's shift-right accumulate instructions. 2019-09-27 Yuliang Wang gcc/ * config/aarch64/aarch64-sve2.md (aarch64_sve2_sra): New combine pattern. gcc/testsuite/ * gcc.target/aarch64/sve2/shracc_1.c: New test. From-SVN: r276174 --- gcc/ChangeLog | 5 +++ gcc/config/aarch64/aarch64-sve2.md | 19 ++++++++++++ gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c | 39 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3d12337..64cc0a9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-27 Yuliang Wang + + * config/aarch64/aarch64-sve2.md (aarch64_sve2_sra): + New combine pattern. + 2019-09-26 Max Filippov * config/xtensa/xtensa.c (hwloop_optimize): Insert zero overhead diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md index ee9acdc..b018f5b 100644 --- a/gcc/config/aarch64/aarch64-sve2.md +++ b/gcc/config/aarch64/aarch64-sve2.md @@ -123,3 +123,22 @@ } ) +;; Unpredicated signed / unsigned shift-right accumulate. +(define_insn_and_rewrite "*aarch64_sve2_sra" + [(set (match_operand:SVE_I 0 "register_operand" "=w") + (plus:SVE_I + (unspec:SVE_I + [(match_operand 4) + (SHIFTRT:SVE_I + (match_operand:SVE_I 2 "register_operand" "w") + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm" "Dr"))] + UNSPEC_PRED_X) + (match_operand:SVE_I 1 "register_operand" "0")))] + "TARGET_SVE2" + "sra\t%0., %2., #%3" + "&& !CONSTANT_P (operands[4])" + { + operands[4] = CONSTM1_RTX (mode); + } +) + diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 82607de..84670ec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-09-27 Yuliang Wang + + * gcc.target/aarch64/sve2/shracc_1.c: New test. + 2019-09-26 Eric Botcazou * gcc.dg/cpp/ucs.c: Add test for new warning and adjust. diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c new file mode 100644 index 0000000..5535c7d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-details --save-temps" } */ + +#include + +#define SHRACC(TYPE,SHIFT) \ +void __attribute__ ((noinline, noclone)) \ +f_##TYPE##_##SHIFT \ + (TYPE *restrict a, TYPE *restrict b, int n) \ +{ \ + for (int i = 0; i < n; i++) \ + a[i] += b[i] >> (SHIFT); \ +} + +SHRACC (int8_t, 5); +SHRACC (int16_t, 14); +SHRACC (int32_t, 19); +SHRACC (int64_t, 27); + +SHRACC (uint8_t, 2); +SHRACC (uint16_t, 6); +SHRACC (uint32_t, 24); +SHRACC (uint64_t, 53); + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 8 "vect" } } */ + +/* { dg-final { scan-assembler-not {\tasr\t} } } */ +/* { dg-final { scan-assembler-not {\tlsr\t} } } */ +/* { dg-final { scan-assembler-not {\tadd\t} } } */ + +/* { dg-final { scan-assembler-times {\tssra\tz[0-9]+\.b, z[0-9]+\.b, #5\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tssra\tz[0-9]+\.h, z[0-9]+\.h, #14\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tssra\tz[0-9]+\.s, z[0-9]+\.s, #19\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tssra\tz[0-9]+\.d, z[0-9]+\.d, #27\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tusra\tz[0-9]+\.b, z[0-9]+\.b, #2\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tusra\tz[0-9]+\.h, z[0-9]+\.h, #6\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tusra\tz[0-9]+\.s, z[0-9]+\.s, #24\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tusra\tz[0-9]+\.d, z[0-9]+\.d, #53\n} 1 } } */ -- cgit v1.1 From 18908a56e18f15f84a91a4529923dd0878b2294f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 27 Sep 2019 08:21:37 +0000 Subject: Fix reduc_index==1 handling for COND_REDUCTION (PR91909) The then/else order of the VEC_COND_EXPRs created by vect_create_epilog_for_reduction meeds to line up with the main VEC_COND_EXPR. 2019-09-27 Richard Sandiford gcc/ PR tree-optimization/91909 * tree-vect-loop.c (vect_create_epilog_for_reduction): Take a reduc_index parameter. When handling COND_REDUCTION, make sure that the reduction phi operand is in the correct arm of the VEC_COND_EXPR. (vectorizable_reduction): Pass reduc_index to the above. From-SVN: r276175 --- gcc/ChangeLog | 9 +++++++++ gcc/tree-vect-loop.c | 22 +++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 64cc0a9..fe6b333 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2019-09-27 Richard Sandiford + + PR tree-optimization/91909 + * tree-vect-loop.c (vect_create_epilog_for_reduction): Take a + reduc_index parameter. When handling COND_REDUCTION, make sure + that the reduction phi operand is in the correct arm of the + VEC_COND_EXPR. + (vectorizable_reduction): Pass reduc_index to the above. + 2019-09-27 Yuliang Wang * config/aarch64/aarch64-sve2.md (aarch64_sve2_sra): diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 237d28b..f5df534 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -4235,6 +4235,8 @@ get_initial_defs_for_reduction (slp_tree slp_node, INDUC_CODE is the code for epilog reduction if INTEGER_INDUC_COND_REDUCTION. NEUTRAL_OP is the value given by neutral_op_for_slp_reduction; it is null if this is not an SLP reduction + REDUC_INDEX says which rhs operand of the STMT_INFO is the reduction phi + (counting from 0) This function: 1. Creates the reduction def-use cycles: sets the arguments for @@ -4285,7 +4287,7 @@ vect_create_epilog_for_reduction (vec vect_defs, bool double_reduc, slp_tree slp_node, slp_instance slp_node_instance, - tree neutral_op) + tree neutral_op, int reduc_index) { tree induc_val = NULL_TREE; stmt_vec_info prev_phi_info; @@ -4469,11 +4471,17 @@ vect_create_epilog_for_reduction (vec vect_defs, tree ccompare = unshare_expr (gimple_assign_rhs1 (vec_stmt)); /* Create a conditional, where the condition is taken from vec_stmt - (CCOMPARE), then is the induction index (INDEX_BEFORE_INCR) and - else is the phi (NEW_PHI_TREE). */ - tree index_cond_expr = build3 (VEC_COND_EXPR, cr_index_vector_type, - ccompare, indx_before_incr, - new_phi_tree); + (CCOMPARE). The then and else values mirror the main VEC_COND_EXPR: + the reduction phi corresponds to NEW_PHI_TREE and the new values + correspond to INDEX_BEFORE_INCR. */ + gcc_assert (reduc_index >= 1); + tree index_cond_expr; + if (reduc_index == 2) + index_cond_expr = build3 (VEC_COND_EXPR, cr_index_vector_type, + ccompare, indx_before_incr, new_phi_tree); + else + index_cond_expr = build3 (VEC_COND_EXPR, cr_index_vector_type, + ccompare, new_phi_tree, indx_before_incr); induction_index = make_ssa_name (cr_index_vector_type); gimple *index_condition = gimple_build_assign (induction_index, index_cond_expr); @@ -7159,7 +7167,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vect_create_epilog_for_reduction (vect_defs, stmt_info, reduc_def_phi, orig_code, epilog_copies, reduc_fn, phis, double_reduc, slp_node, slp_node_instance, - neutral_op); + neutral_op, reduc_index); return true; } -- cgit v1.1 From c6447c2014b76b5c077a07712a7f0b0aaa2e14d4 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 27 Sep 2019 08:39:16 +0000 Subject: [C][C++] Allow targets to check calls to BUILT_IN_MD functions For SVE, we'd like the frontends to check calls to target-specific built-in functions in the same way that they already do for "normal" builtins. This patch adds a target hook for that and extends check_builtin_function_arguments accordingly. A slight complication is that when TARGET_RESOLVE_OVERLOADED_BUILTIN has resolved an overload, it can use build_function_call_vec to build the call to the underlying non-overloaded function decl. This in turn coerces the arguments to the function type and then calls check_builtin_function_arguments to check the final call. If the target does find a problem in this final call, it can be useful to refer to the original overloaded function decl in diagnostics, since that's what the user wrote. The patch therefore passes the original decl as a final optional parameter to build_function_call_vec. 2019-09-27 Richard Sandiford gcc/ * target.def (check_builtin_call): New target hook. * doc/tm.texi.in (TARGET_CHECK_BUILTIN_CALL): New @hook. * doc/tm.texi: Regenerate. gcc/c-family/ * c-common.h (build_function_call_vec): Take the original function decl as an optional final parameter. (check_builtin_function_arguments): Take the original function decl. * c-common.c (check_builtin_function_arguments): Likewise. Handle all built-in functions, not just BUILT_IN_NORMAL ones. Use targetm.check_builtin_call to check BUILT_IN_MD functions. gcc/c/ * c-typeck.c (build_function_call_vec): Take the original function decl as an optional final parameter. Pass all built-in calls to check_builtin_function_arguments. gcc/cp/ * cp-tree.h (build_cxx_call): Take the original function decl as an optional final parameter. (cp_build_function_call_vec): Likewise. * call.c (build_cxx_call): Likewise. Pass all built-in calls to check_builtin_function_arguments. * typeck.c (build_function_call_vec): Take the original function decl as an optional final parameter and pass it to cp_build_function_call_vec. (cp_build_function_call_vec): Take the original function decl as an optional final parameter and pass it to build_cxx_call. From-SVN: r276176 --- gcc/ChangeLog | 6 ++++++ gcc/c-family/ChangeLog | 9 +++++++++ gcc/c-family/c-common.c | 18 +++++++++++++++--- gcc/c-family/c-common.h | 5 +++-- gcc/c/ChangeLog | 6 ++++++ gcc/c/c-typeck.c | 13 +++++++++---- gcc/cp/ChangeLog | 13 +++++++++++++ gcc/cp/call.c | 10 +++++++--- gcc/cp/cp-tree.h | 6 ++++-- gcc/cp/typeck.c | 16 +++++++++------- gcc/doc/tm.texi | 15 +++++++++++++++ gcc/doc/tm.texi.in | 2 ++ gcc/target.def | 18 ++++++++++++++++++ 13 files changed, 116 insertions(+), 21 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fe6b333..b6a19c4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-27 Richard Sandiford + * target.def (check_builtin_call): New target hook. + * doc/tm.texi.in (TARGET_CHECK_BUILTIN_CALL): New @hook. + * doc/tm.texi: Regenerate. + +2019-09-27 Richard Sandiford + PR tree-optimization/91909 * tree-vect-loop.c (vect_create_epilog_for_reduction): Take a reduc_index parameter. When handling COND_REDUCTION, make sure diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 93bdf3e0..7b10957 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2019-09-27 Richard Sandiford + + * c-common.h (build_function_call_vec): Take the original + function decl as an optional final parameter. + (check_builtin_function_arguments): Take the original function decl. + * c-common.c (check_builtin_function_arguments): Likewise. + Handle all built-in functions, not just BUILT_IN_NORMAL ones. + Use targetm.check_builtin_call to check BUILT_IN_MD functions. + 2019-09-15 Jason Merrill * c-warn.c (warn_logical_operator): Strip location wrappers. Don't diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 3756219..7169813 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5856,15 +5856,27 @@ builtin_function_validate_nargs (location_t loc, tree fndecl, int nargs, /* Verifies the NARGS arguments ARGS to the builtin function FNDECL. Returns false if there was an error, otherwise true. LOC is the location of the function; ARG_LOC is a vector of locations of the - arguments. */ + arguments. If FNDECL is the result of resolving an overloaded + target built-in, ORIG_FNDECL is the original function decl, + otherwise it is null. */ bool check_builtin_function_arguments (location_t loc, vec arg_loc, - tree fndecl, int nargs, tree *args) + tree fndecl, tree orig_fndecl, + int nargs, tree *args) { - if (!fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) + if (!fndecl_built_in_p (fndecl)) return true; + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) + return (!targetm.check_builtin_call + || targetm.check_builtin_call (loc, arg_loc, fndecl, + orig_fndecl, nargs, args)); + + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND) + return true; + + gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL); switch (DECL_FUNCTION_CODE (fndecl)) { case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX: diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index a9f4d0c..c1554f3 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -818,7 +818,7 @@ extern void check_function_arguments_recurse (void (*) void *, tree, unsigned HOST_WIDE_INT); extern bool check_builtin_function_arguments (location_t, vec, - tree, int, tree *); + tree, tree, int, tree *); extern void check_function_format (const_tree, tree, int, tree *, vec *); extern bool attribute_fallthrough_p (tree); @@ -995,7 +995,8 @@ extern bool c_switch_covers_all_cases_p (splay_tree, tree); extern tree build_function_call (location_t, tree, tree); extern tree build_function_call_vec (location_t, vec, tree, - vec *, vec *); + vec *, vec *, + tree = NULL_TREE); extern tree resolve_overloaded_builtin (location_t, tree, vec *); diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 9665549..718e5b8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2019-09-27 Richard Sandiford + + * c-typeck.c (build_function_call_vec): Take the original function + decl as an optional final parameter. Pass all built-in calls to + check_builtin_function_arguments. + 2019-09-20 Eric Botcazou PR c/91815 diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index d4e12eb..cc13fdc 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3003,6 +3003,8 @@ inform_declaration (tree decl) } /* Build a function call to function FUNCTION with parameters PARAMS. + If FUNCTION is the result of resolving an overloaded target built-in, + ORIG_FUNDECL is the original function decl, otherwise it is null. ORIGTYPES, if not NULL, is a vector of types; each element is either NULL or the original type of the corresponding element in PARAMS. The original type may differ from TREE_TYPE of the @@ -3013,7 +3015,7 @@ inform_declaration (tree decl) tree build_function_call_vec (location_t loc, vec arg_loc, tree function, vec *params, - vec *origtypes) + vec *origtypes, tree orig_fundecl) { tree fntype, fundecl = NULL_TREE; tree name = NULL_TREE, result; @@ -3033,6 +3035,8 @@ build_function_call_vec (location_t loc, vec arg_loc, if (flag_tm) tm_malloc_replacement (function); fundecl = function; + if (!orig_fundecl) + orig_fundecl = fundecl; /* Atomic functions have type checking/casting already done. They are often rewritten and don't match the original parameter list. */ if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9)) @@ -3110,9 +3114,10 @@ build_function_call_vec (location_t loc, vec arg_loc, argarray = vec_safe_address (params); /* Check that arguments to builtin functions match the expectations. */ - if (fundecl && fndecl_built_in_p (fundecl, BUILT_IN_NORMAL) - && !check_builtin_function_arguments (loc, arg_loc, fundecl, nargs, - argarray)) + if (fundecl + && fndecl_built_in_p (fundecl) + && !check_builtin_function_arguments (loc, arg_loc, fundecl, + orig_fundecl, nargs, argarray)) return error_mark_node; /* Check that the arguments to the function are valid. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1d30cef..3a3ef9e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2019-09-27 Richard Sandiford + + * cp-tree.h (build_cxx_call): Take the original function decl + as an optional final parameter. + (cp_build_function_call_vec): Likewise. + * call.c (build_cxx_call): Likewise. Pass all built-in calls to + check_builtin_function_arguments. + * typeck.c (build_function_call_vec): Take the original function + decl as an optional final parameter and pass it to + cp_build_function_call_vec. + (cp_build_function_call_vec): Take the original function + decl as an optional final parameter and pass it to build_cxx_call. + 2019-09-25 Marek Polacek PR c++/91877 - ICE with converting member of packed struct. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 45b984e..5ccf3b8 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9105,12 +9105,14 @@ maybe_warn_class_memaccess (location_t loc, tree fndecl, } /* Build and return a call to FN, using NARGS arguments in ARGARRAY. + If FN is the result of resolving an overloaded target built-in, + ORIG_FNDECL is the original function decl, otherwise it is null. This function performs no overload resolution, conversion, or other high-level operations. */ tree build_cxx_call (tree fn, int nargs, tree *argarray, - tsubst_flags_t complain) + tsubst_flags_t complain, tree orig_fndecl) { tree fndecl; @@ -9120,11 +9122,13 @@ build_cxx_call (tree fn, int nargs, tree *argarray, SET_EXPR_LOCATION (fn, loc); fndecl = get_callee_fndecl (fn); + if (!orig_fndecl) + orig_fndecl = fndecl; /* Check that arguments to builtin functions match the expectations. */ if (fndecl && !processing_template_decl - && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) + && fndecl_built_in_p (fndecl)) { int i; @@ -9134,7 +9138,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray, argarray[i] = maybe_constant_value (argarray[i]); if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl, - nargs, argarray)) + orig_fndecl, nargs, argarray)) return error_mark_node; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9c0f394..8fc3fc1 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6257,7 +6257,8 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool, tsubst_flags_t); extern tree in_charge_arg_for_name (tree); extern tree build_cxx_call (tree, int, tree *, - tsubst_flags_t); + tsubst_flags_t, + tree = NULL_TREE); extern bool is_std_init_list (tree); extern bool is_list_ctor (tree); extern void validate_conversion_obstack (void); @@ -7391,7 +7392,8 @@ extern tree get_member_function_from_ptrfunc (tree *, tree, tsubst_flags_t); extern tree cp_build_function_call_nary (tree, tsubst_flags_t, ...) ATTRIBUTE_SENTINEL; extern tree cp_build_function_call_vec (tree, vec **, - tsubst_flags_t); + tsubst_flags_t, + tree = NULL_TREE); extern tree build_x_binary_op (const op_location_t &, enum tree_code, tree, enum tree_code, tree, diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index f427c4f..d549450 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3773,11 +3773,11 @@ build_function_call (location_t /*loc*/, tree build_function_call_vec (location_t /*loc*/, vec /*arg_loc*/, tree function, vec *params, - vec * /*origtypes*/) + vec * /*origtypes*/, tree orig_function) { vec *orig_params = params; tree ret = cp_build_function_call_vec (function, ¶ms, - tf_warning_or_error); + tf_warning_or_error, orig_function); /* cp_build_function_call_vec can reallocate PARAMS by adding default arguments. That should never happen here. Verify @@ -3818,13 +3818,15 @@ cp_build_function_call_nary (tree function, tsubst_flags_t complain, ...) return ret; } -/* Build a function call using a vector of arguments. PARAMS may be - NULL if there are no parameters. This changes the contents of - PARAMS. */ +/* Build a function call using a vector of arguments. + If FUNCTION is the result of resolving an overloaded target built-in, + ORIG_FNDECL is the original function decl, otherwise it is null. + PARAMS may be NULL if there are no parameters. This changes the + contents of PARAMS. */ tree cp_build_function_call_vec (tree function, vec **params, - tsubst_flags_t complain) + tsubst_flags_t complain, tree orig_fndecl) { tree fntype, fndecl; int is_method; @@ -3949,7 +3951,7 @@ cp_build_function_call_vec (tree function, vec **params, bool warned_p = check_function_arguments (input_location, fndecl, fntype, nargs, argarray, NULL); - ret = build_cxx_call (function, nargs, argarray, complain); + ret = build_cxx_call (function, nargs, argarray, complain, orig_fndecl); if (warned_p) { diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 0250cf5..a86c210 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -11567,6 +11567,21 @@ another @code{CALL_EXPR}. @var{arglist} really has type @samp{VEC(tree,gc)*} @end deftypefn +@deftypefn {Target Hook} bool TARGET_CHECK_BUILTIN_CALL (location_t @var{loc}, vec @var{arg_loc}, tree @var{fndecl}, tree @var{orig_fndecl}, unsigned int @var{nargs}, tree *@var{args}) +Perform semantic checking on a call to a machine-specific built-in +function after its arguments have been constrained to the function +signature. Return true if the call is valid, otherwise report an error +and return false. + +This hook is called after @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}. +The call was originally to built-in function @var{orig_fndecl}, +but after the optional @code{TARGET_RESOLVE_OVERLOADED_BUILTIN} +step is now to built-in function @var{fndecl}. @var{loc} is the +location of the call and @var{args} is an array of function arguments, +of which there are @var{nargs}. @var{arg_loc} specifies the location +of each argument. +@end deftypefn + @deftypefn {Target Hook} tree TARGET_FOLD_BUILTIN (tree @var{fndecl}, int @var{n_args}, tree *@var{argp}, bool @var{ignore}) Fold a call to a machine specific built-in function that was set up by @samp{TARGET_INIT_BUILTINS}. @var{fndecl} is the declaration of the diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 0b77dd8..06dfcda 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -7938,6 +7938,8 @@ to by @var{ce_info}. @hook TARGET_RESOLVE_OVERLOADED_BUILTIN +@hook TARGET_CHECK_BUILTIN_CALL + @hook TARGET_FOLD_BUILTIN @hook TARGET_GIMPLE_FOLD_BUILTIN diff --git a/gcc/target.def b/gcc/target.def index 0160913..f9446fa 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2397,6 +2397,24 @@ another @code{CALL_EXPR}.\n\ @var{arglist} really has type @samp{VEC(tree,gc)*}", tree, (unsigned int /*location_t*/ loc, tree fndecl, void *arglist), NULL) +DEFHOOK +(check_builtin_call, + "Perform semantic checking on a call to a machine-specific built-in\n\ +function after its arguments have been constrained to the function\n\ +signature. Return true if the call is valid, otherwise report an error\n\ +and return false.\n\ +\n\ +This hook is called after @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}.\n\ +The call was originally to built-in function @var{orig_fndecl},\n\ +but after the optional @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}\n\ +step is now to built-in function @var{fndecl}. @var{loc} is the\n\ +location of the call and @var{args} is an array of function arguments,\n\ +of which there are @var{nargs}. @var{arg_loc} specifies the location\n\ +of each argument.", + bool, (location_t loc, vec arg_loc, tree fndecl, + tree orig_fndecl, unsigned int nargs, tree *args), + NULL) + /* Fold a target-specific builtin to a tree valid for both GIMPLE and GENERIC. */ DEFHOOK -- cgit v1.1 From 6d4d616a782d5be693ea9575f69d5ebf450be090 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 27 Sep 2019 08:47:21 +0000 Subject: [AArch64] Split built-in function codes into major and minor codes It was easier to add the SVE ACLE support without enumerating every function at build time. This in turn meant that it was easier if the SVE builtins occupied a distinct numberspace from the existing AArch64 ones, which *are* enumerated at build time. This patch therefore divides the built-in functions codes into "major" and "minor" codes. At present the major code is just "general", but the SVE patch will add "SVE" as well. Also, it was convenient to put the SVE ACLE support in its own file, so the patch makes aarch64.c provide the frontline target hooks directly, forwarding to the other files for the real work. The reason for organising the files this way is that aarch64.c needs to define the target hook macros whatever happens, and having aarch64.c macros forward to aarch64-builtins.c functions and aarch64-bulitins.c functions forward to the SVE file seemed a bit indirect. Doing things the way the patch does them puts aarch64-builtins.c and the SVE code on more of an equal footing. The aarch64_(general_)gimple_fold_builtin change is mostly just reindentation. 2019-09-27 Richard Sandiford gcc/ * config/aarch64/aarch64-protos.h (aarch64_builtin_class): New enum. (AARCH64_BUILTIN_SHIFT, AARCH64_BUILTIN_CLASS): New constants. (aarch64_gimple_fold_builtin, aarch64_mangle_builtin_type) (aarch64_fold_builtin, aarch64_init_builtins, aarch64_expand_builtin): (aarch64_builtin_decl, aarch64_builtin_rsqrt): Delete. (aarch64_general_mangle_builtin_type, aarch64_general_init_builtins): (aarch64_general_fold_builtin, aarch64_general_gimple_fold_builtin): (aarch64_general_expand_builtin, aarch64_general_builtin_decl): (aarch64_general_builtin_rsqrt): Declare. * config/aarch64/aarch64-builtins.c (aarch64_general_add_builtin): New function. (aarch64_mangle_builtin_type): Rename to... (aarch64_general_mangle_builtin_type): ...this. (aarch64_init_fcmla_laneq_builtins, aarch64_init_simd_builtins) (aarch64_init_crc32_builtins, aarch64_init_builtin_rsqrt) (aarch64_init_pauth_hint_builtins, aarch64_init_tme_builtins): Use aarch64_general_add_builtin instead of add_builtin_function. (aarch64_init_builtins): Rename to... (aarch64_general_init_builtins): ...this. Use aarch64_general_add_builtin instead of add_builtin_function. (aarch64_builtin_decl): Rename to... (aarch64_general_builtin_decl): ...this and remove the unused arguments. (aarch64_expand_builtin): Rename to... (aarch64_general_expand_builtin): ...this and remove the unused arguments. (aarch64_builtin_rsqrt): Rename to... (aarch64_general_builtin_rsqrt): ...this. (aarch64_fold_builtin): Rename to... (aarch64_general_fold_builtin): ...this. Take the function subcode and return type as arguments. Remove the "ignored" argument. (aarch64_gimple_fold_builtin): Rename to... (aarch64_general_gimple_fold_builtin): ...this. Take the function subcode and gcall as arguments, and return the new function call. * config/aarch64/aarch64.c (aarch64_init_builtins) (aarch64_fold_builtin, aarch64_gimple_fold_builtin) (aarch64_expand_builtin, aarch64_builtin_decl): New functions. (aarch64_builtin_reciprocal): Call aarch64_general_builtin_rsqrt instead of aarch64_builtin_rsqrt. (aarch64_mangle_type): Call aarch64_general_mangle_builtin_type instead of aarch64_mangle_builtin_type. From-SVN: r276177 --- gcc/ChangeLog | 44 +++++ gcc/config/aarch64/aarch64-builtins.c | 304 ++++++++++++++++------------------ gcc/config/aarch64/aarch64-protos.h | 35 ++-- gcc/config/aarch64/aarch64.c | 84 +++++++++- 4 files changed, 296 insertions(+), 171 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b6a19c4..8d142db 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,49 @@ 2019-09-27 Richard Sandiford + * config/aarch64/aarch64-protos.h (aarch64_builtin_class): New enum. + (AARCH64_BUILTIN_SHIFT, AARCH64_BUILTIN_CLASS): New constants. + (aarch64_gimple_fold_builtin, aarch64_mangle_builtin_type) + (aarch64_fold_builtin, aarch64_init_builtins, aarch64_expand_builtin): + (aarch64_builtin_decl, aarch64_builtin_rsqrt): Delete. + (aarch64_general_mangle_builtin_type, aarch64_general_init_builtins): + (aarch64_general_fold_builtin, aarch64_general_gimple_fold_builtin): + (aarch64_general_expand_builtin, aarch64_general_builtin_decl): + (aarch64_general_builtin_rsqrt): Declare. + * config/aarch64/aarch64-builtins.c (aarch64_general_add_builtin): + New function. + (aarch64_mangle_builtin_type): Rename to... + (aarch64_general_mangle_builtin_type): ...this. + (aarch64_init_fcmla_laneq_builtins, aarch64_init_simd_builtins) + (aarch64_init_crc32_builtins, aarch64_init_builtin_rsqrt) + (aarch64_init_pauth_hint_builtins, aarch64_init_tme_builtins): Use + aarch64_general_add_builtin instead of add_builtin_function. + (aarch64_init_builtins): Rename to... + (aarch64_general_init_builtins): ...this. Use + aarch64_general_add_builtin instead of add_builtin_function. + (aarch64_builtin_decl): Rename to... + (aarch64_general_builtin_decl): ...this and remove the unused + arguments. + (aarch64_expand_builtin): Rename to... + (aarch64_general_expand_builtin): ...this and remove the unused + arguments. + (aarch64_builtin_rsqrt): Rename to... + (aarch64_general_builtin_rsqrt): ...this. + (aarch64_fold_builtin): Rename to... + (aarch64_general_fold_builtin): ...this. Take the function subcode + and return type as arguments. Remove the "ignored" argument. + (aarch64_gimple_fold_builtin): Rename to... + (aarch64_general_gimple_fold_builtin): ...this. Take the function + subcode and gcall as arguments, and return the new function call. + * config/aarch64/aarch64.c (aarch64_init_builtins) + (aarch64_fold_builtin, aarch64_gimple_fold_builtin) + (aarch64_expand_builtin, aarch64_builtin_decl): New functions. + (aarch64_builtin_reciprocal): Call aarch64_general_builtin_rsqrt + instead of aarch64_builtin_rsqrt. + (aarch64_mangle_type): Call aarch64_general_mangle_builtin_type + instead of aarch64_mangle_builtin_type. + +2019-09-27 Richard Sandiford + * target.def (check_builtin_call): New target hook. * doc/tm.texi.in (TARGET_CHECK_BUILTIN_CALL): New @hook. * doc/tm.texi: Regenerate. diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c index 9f26104..e02ece8 100644 --- a/gcc/config/aarch64/aarch64-builtins.c +++ b/gcc/config/aarch64/aarch64-builtins.c @@ -556,6 +556,17 @@ static tree aarch64_simd_intXI_type_node = NULL_TREE; tree aarch64_fp16_type_node = NULL_TREE; tree aarch64_fp16_ptr_type_node = NULL_TREE; +/* Wrapper around add_builtin_function. NAME is the name of the built-in + function, TYPE is the function type, and CODE is the function subcode + (relative to AARCH64_BUILTIN_GENERAL). */ +static tree +aarch64_general_add_builtin (const char *name, tree type, unsigned int code) +{ + code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_GENERAL; + return add_builtin_function (name, type, code, BUILT_IN_MD, + NULL, NULL_TREE); +} + static const char * aarch64_mangle_builtin_scalar_type (const_tree type) { @@ -594,7 +605,7 @@ aarch64_mangle_builtin_vector_type (const_tree type) } const char * -aarch64_mangle_builtin_type (const_tree type) +aarch64_general_mangle_builtin_type (const_tree type) { const char *mangle; /* Walk through all the AArch64 builtins types tables to filter out the @@ -825,8 +836,7 @@ aarch64_init_fcmla_laneq_builtins (void) = aarch64_simd_builtin_std_type (SImode, qualifier_lane_pair_index); tree ftype = build_function_type_list (argtype, argtype, argtype, quadtype, lanetype, NULL_TREE); - tree fndecl = add_builtin_function (d->name, ftype, d->fcode, - BUILT_IN_MD, NULL, NULL_TREE); + tree fndecl = aarch64_general_add_builtin (d->name, ftype, d->fcode); aarch64_builtin_decls[d->fcode] = fndecl; } @@ -855,10 +865,10 @@ aarch64_init_simd_builtins (void) size_type_node, intSI_type_node, NULL); - aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] = - add_builtin_function ("__builtin_aarch64_im_lane_boundsi", lane_check_fpr, - AARCH64_SIMD_BUILTIN_LANE_CHECK, BUILT_IN_MD, - NULL, NULL_TREE); + aarch64_builtin_decls[AARCH64_SIMD_BUILTIN_LANE_CHECK] + = aarch64_general_add_builtin ("__builtin_aarch64_im_lane_boundsi", + lane_check_fpr, + AARCH64_SIMD_BUILTIN_LANE_CHECK); for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++) { @@ -956,8 +966,7 @@ aarch64_init_simd_builtins (void) snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s", d->name); - fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD, - NULL, NULL_TREE); + fndecl = aarch64_general_add_builtin (namebuf, ftype, fcode); aarch64_builtin_decls[fcode] = fndecl; } @@ -977,8 +986,7 @@ aarch64_init_crc32_builtins () tree argtype = aarch64_simd_builtin_std_type (d->mode, qualifier_unsigned); tree ftype = build_function_type_list (usi_type, usi_type, argtype, NULL_TREE); - tree fndecl = add_builtin_function (d->name, ftype, d->fcode, - BUILT_IN_MD, NULL, NULL_TREE); + tree fndecl = aarch64_general_add_builtin (d->name, ftype, d->fcode); aarch64_builtin_decls[d->fcode] = fndecl; } @@ -1018,8 +1026,8 @@ aarch64_init_builtin_rsqrt (void) for (; bdd < bdd_end; bdd++) { ftype = build_function_type_list (bdd->type_node, bdd->type_node, NULL_TREE); - fndecl = add_builtin_function (bdd->builtin_name, - ftype, bdd->function_code, BUILT_IN_MD, NULL, NULL_TREE); + fndecl = aarch64_general_add_builtin (bdd->builtin_name, + ftype, bdd->function_code); aarch64_builtin_decls[bdd->function_code] = fndecl; } } @@ -1053,25 +1061,25 @@ aarch64_init_pauth_hint_builtins (void) = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE); aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIA1716] - = add_builtin_function ("__builtin_aarch64_autia1716", ftype_pointer_auth, - AARCH64_PAUTH_BUILTIN_AUTIA1716, BUILT_IN_MD, NULL, - NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_autia1716", + ftype_pointer_auth, + AARCH64_PAUTH_BUILTIN_AUTIA1716); aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIA1716] - = add_builtin_function ("__builtin_aarch64_pacia1716", ftype_pointer_auth, - AARCH64_PAUTH_BUILTIN_PACIA1716, BUILT_IN_MD, NULL, - NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_pacia1716", + ftype_pointer_auth, + AARCH64_PAUTH_BUILTIN_PACIA1716); aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIB1716] - = add_builtin_function ("__builtin_aarch64_autib1716", ftype_pointer_auth, - AARCH64_PAUTH_BUILTIN_AUTIB1716, BUILT_IN_MD, NULL, - NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_autib1716", + ftype_pointer_auth, + AARCH64_PAUTH_BUILTIN_AUTIB1716); aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIB1716] - = add_builtin_function ("__builtin_aarch64_pacib1716", ftype_pointer_auth, - AARCH64_PAUTH_BUILTIN_PACIB1716, BUILT_IN_MD, NULL, - NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_pacib1716", + ftype_pointer_auth, + AARCH64_PAUTH_BUILTIN_PACIB1716); aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI] - = add_builtin_function ("__builtin_aarch64_xpaclri", ftype_pointer_strip, - AARCH64_PAUTH_BUILTIN_XPACLRI, BUILT_IN_MD, NULL, - NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_xpaclri", + ftype_pointer_strip, + AARCH64_PAUTH_BUILTIN_XPACLRI); } /* Initialize the transactional memory extension (TME) builtins. */ @@ -1086,25 +1094,26 @@ aarch64_init_tme_builtins (void) = build_function_type_list (void_type_node, uint64_type_node, NULL); aarch64_builtin_decls[AARCH64_TME_BUILTIN_TSTART] - = add_builtin_function ("__builtin_aarch64_tstart", ftype_uint64_void, - AARCH64_TME_BUILTIN_TSTART, BUILT_IN_MD, - NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_tstart", + ftype_uint64_void, + AARCH64_TME_BUILTIN_TSTART); aarch64_builtin_decls[AARCH64_TME_BUILTIN_TTEST] - = add_builtin_function ("__builtin_aarch64_ttest", ftype_uint64_void, - AARCH64_TME_BUILTIN_TTEST, BUILT_IN_MD, - NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_ttest", + ftype_uint64_void, + AARCH64_TME_BUILTIN_TTEST); aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCOMMIT] - = add_builtin_function ("__builtin_aarch64_tcommit", ftype_void_void, - AARCH64_TME_BUILTIN_TCOMMIT, BUILT_IN_MD, - NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_tcommit", + ftype_void_void, + AARCH64_TME_BUILTIN_TCOMMIT); aarch64_builtin_decls[AARCH64_TME_BUILTIN_TCANCEL] - = add_builtin_function ("__builtin_aarch64_tcancel", ftype_void_uint64, - AARCH64_TME_BUILTIN_TCANCEL, BUILT_IN_MD, - NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_tcancel", + ftype_void_uint64, + AARCH64_TME_BUILTIN_TCANCEL); } +/* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */ void -aarch64_init_builtins (void) +aarch64_general_init_builtins (void) { tree ftype_set_fpr = build_function_type_list (void_type_node, unsigned_type_node, NULL); @@ -1112,17 +1121,21 @@ aarch64_init_builtins (void) = build_function_type_list (unsigned_type_node, NULL); aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPCR] - = add_builtin_function ("__builtin_aarch64_get_fpcr", ftype_get_fpr, - AARCH64_BUILTIN_GET_FPCR, BUILT_IN_MD, NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_get_fpcr", + ftype_get_fpr, + AARCH64_BUILTIN_GET_FPCR); aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPCR] - = add_builtin_function ("__builtin_aarch64_set_fpcr", ftype_set_fpr, - AARCH64_BUILTIN_SET_FPCR, BUILT_IN_MD, NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_set_fpcr", + ftype_set_fpr, + AARCH64_BUILTIN_SET_FPCR); aarch64_builtin_decls[AARCH64_BUILTIN_GET_FPSR] - = add_builtin_function ("__builtin_aarch64_get_fpsr", ftype_get_fpr, - AARCH64_BUILTIN_GET_FPSR, BUILT_IN_MD, NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_get_fpsr", + ftype_get_fpr, + AARCH64_BUILTIN_GET_FPSR); aarch64_builtin_decls[AARCH64_BUILTIN_SET_FPSR] - = add_builtin_function ("__builtin_aarch64_set_fpsr", ftype_set_fpr, - AARCH64_BUILTIN_SET_FPSR, BUILT_IN_MD, NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_set_fpsr", + ftype_set_fpr, + AARCH64_BUILTIN_SET_FPSR); aarch64_init_fp16_types (); @@ -1135,8 +1148,8 @@ aarch64_init_builtins (void) tree ftype_jcvt = build_function_type_list (intSI_type_node, double_type_node, NULL); aarch64_builtin_decls[AARCH64_JSCVT] - = add_builtin_function ("__builtin_aarch64_jcvtzs", ftype_jcvt, - AARCH64_JSCVT, BUILT_IN_MD, NULL, NULL_TREE); + = aarch64_general_add_builtin ("__builtin_aarch64_jcvtzs", ftype_jcvt, + AARCH64_JSCVT); /* Initialize pointer authentication builtins which are backed by instructions in NOP encoding space. @@ -1151,8 +1164,9 @@ aarch64_init_builtins (void) aarch64_init_tme_builtins (); } +/* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */ tree -aarch64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +aarch64_general_builtin_decl (unsigned code, bool) { if (code >= AARCH64_BUILTIN_MAX) return error_mark_node; @@ -1593,17 +1607,11 @@ aarch64_expand_builtin_tme (int fcode, tree exp, rtx target) return target; } -/* Expand an expression EXP that calls a built-in function, +/* Expand an expression EXP that calls built-in function FCODE, with result going to TARGET if that's convenient. */ rtx -aarch64_expand_builtin (tree exp, - rtx target, - rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, - int ignore ATTRIBUTE_UNUSED) +aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target) { - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - int fcode = DECL_MD_FUNCTION_CODE (fndecl); int icode; rtx pat, op0; tree arg0; @@ -1880,7 +1888,7 @@ aarch64_builtin_vectorized_function (unsigned int fn, tree type_out, /* Return builtin for reciprocal square root. */ tree -aarch64_builtin_rsqrt (unsigned int fn) +aarch64_general_builtin_rsqrt (unsigned int fn) { if (fn == AARCH64_SIMD_BUILTIN_UNOP_sqrtv2df) return aarch64_builtin_decls[AARCH64_BUILTIN_RSQRT_V2DF]; @@ -1895,13 +1903,14 @@ aarch64_builtin_rsqrt (unsigned int fn) #define VAR1(T, N, MAP, A) \ case AARCH64_SIMD_BUILTIN_##T##_##N##A: +/* Try to fold a call to the built-in function with subcode FCODE. The + function is passed the N_ARGS arguments in ARGS and it returns a value + of type TYPE. Return the new expression on success and NULL_TREE on + failure. */ tree -aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args, - bool ignore ATTRIBUTE_UNUSED) +aarch64_general_fold_builtin (unsigned int fcode, tree type, + unsigned int n_args ATTRIBUTE_UNUSED, tree *args) { - int fcode = DECL_MD_FUNCTION_CODE (fndecl); - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - switch (fcode) { BUILTIN_VDQF (UNOP, abs, 2) @@ -1917,109 +1926,90 @@ aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args, return NULL_TREE; } -bool -aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) +/* Try to fold STMT, given that it's a call to the built-in function with + subcode FCODE. Return the new statement on success and null on + failure. */ +gimple * +aarch64_general_gimple_fold_builtin (unsigned int fcode, gcall *stmt) { - bool changed = false; - gimple *stmt = gsi_stmt (*gsi); - tree call = gimple_call_fn (stmt); - tree fndecl; gimple *new_stmt = NULL; - - if (call) + unsigned nargs = gimple_call_num_args (stmt); + tree *args = (nargs > 0 + ? gimple_call_arg_ptr (stmt, 0) + : &error_mark_node); + + /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int + and unsigned int; it will distinguish according to the types of + the arguments to the __builtin. */ + switch (fcode) { - fndecl = gimple_call_fndecl (stmt); - if (fndecl) + BUILTIN_VALL (UNOP, reduc_plus_scal_, 10) + new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS, + 1, args[0]); + gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); + break; + BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10) + BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10) + new_stmt = gimple_build_call_internal (IFN_REDUC_MAX, + 1, args[0]); + gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); + break; + BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10) + BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10) + new_stmt = gimple_build_call_internal (IFN_REDUC_MIN, + 1, args[0]); + gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); + break; + BUILTIN_GPF (BINOP, fmulx, 0) { - int fcode = DECL_MD_FUNCTION_CODE (fndecl); - unsigned nargs = gimple_call_num_args (stmt); - tree *args = (nargs > 0 - ? gimple_call_arg_ptr (stmt, 0) - : &error_mark_node); - - /* We use gimple's IFN_REDUC_(PLUS|MIN|MAX)s for float, signed int - and unsigned int; it will distinguish according to the types of - the arguments to the __builtin. */ - switch (fcode) + gcc_assert (nargs == 2); + bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST; + bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST; + if (a0_cst_p || a1_cst_p) { - BUILTIN_VALL (UNOP, reduc_plus_scal_, 10) - new_stmt = gimple_build_call_internal (IFN_REDUC_PLUS, - 1, args[0]); - gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); - break; - BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10) - BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10) - new_stmt = gimple_build_call_internal (IFN_REDUC_MAX, - 1, args[0]); - gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); - break; - BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10) - BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10) - new_stmt = gimple_build_call_internal (IFN_REDUC_MIN, - 1, args[0]); - gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); - break; - BUILTIN_GPF (BINOP, fmulx, 0) + if (a0_cst_p && a1_cst_p) { - gcc_assert (nargs == 2); - bool a0_cst_p = TREE_CODE (args[0]) == REAL_CST; - bool a1_cst_p = TREE_CODE (args[1]) == REAL_CST; - if (a0_cst_p || a1_cst_p) - { - if (a0_cst_p && a1_cst_p) - { - tree t0 = TREE_TYPE (args[0]); - real_value a0 = (TREE_REAL_CST (args[0])); - real_value a1 = (TREE_REAL_CST (args[1])); - if (real_equal (&a1, &dconst0)) - std::swap (a0, a1); - /* According to real_equal (), +0 equals -0. */ - if (real_equal (&a0, &dconst0) && real_isinf (&a1)) - { - real_value res = dconst2; - res.sign = a0.sign ^ a1.sign; - new_stmt = - gimple_build_assign (gimple_call_lhs (stmt), - REAL_CST, - build_real (t0, res)); - } - else - new_stmt = - gimple_build_assign (gimple_call_lhs (stmt), - MULT_EXPR, - args[0], args[1]); - } - else /* a0_cst_p ^ a1_cst_p. */ - { - real_value const_part = a0_cst_p - ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]); - if (!real_equal (&const_part, &dconst0) - && !real_isinf (&const_part)) - new_stmt = - gimple_build_assign (gimple_call_lhs (stmt), - MULT_EXPR, args[0], args[1]); - } - } - if (new_stmt) + tree t0 = TREE_TYPE (args[0]); + real_value a0 = (TREE_REAL_CST (args[0])); + real_value a1 = (TREE_REAL_CST (args[1])); + if (real_equal (&a1, &dconst0)) + std::swap (a0, a1); + /* According to real_equal (), +0 equals -0. */ + if (real_equal (&a0, &dconst0) && real_isinf (&a1)) { - gimple_set_vuse (new_stmt, gimple_vuse (stmt)); - gimple_set_vdef (new_stmt, gimple_vdef (stmt)); + real_value res = dconst2; + res.sign = a0.sign ^ a1.sign; + new_stmt = gimple_build_assign (gimple_call_lhs (stmt), + REAL_CST, + build_real (t0, res)); } - break; + else + new_stmt = gimple_build_assign (gimple_call_lhs (stmt), + MULT_EXPR, + args[0], args[1]); } - default: - break; + else /* a0_cst_p ^ a1_cst_p. */ + { + real_value const_part = a0_cst_p + ? TREE_REAL_CST (args[0]) : TREE_REAL_CST (args[1]); + if (!real_equal (&const_part, &dconst0) + && !real_isinf (&const_part)) + new_stmt = gimple_build_assign (gimple_call_lhs (stmt), + MULT_EXPR, args[0], + args[1]); + } + } + if (new_stmt) + { + gimple_set_vuse (new_stmt, gimple_vuse (stmt)); + gimple_set_vdef (new_stmt, gimple_vdef (stmt)); } + break; } + default: + break; } - - if (new_stmt) - { - gsi_replace (gsi, new_stmt, true); - changed = true; - } - - return changed; + return new_stmt; } void diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 1c1aac7..a870eb7 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -433,6 +433,22 @@ enum aarch64_svpattern { }; #undef AARCH64_SVENUM +/* It's convenient to divide the built-in function codes into groups, + rather than having everything in a single enum. This type enumerates + those groups. */ +enum aarch64_builtin_class +{ + AARCH64_BUILTIN_GENERAL +}; + +/* Built-in function codes are structured so that the low + AARCH64_BUILTIN_SHIFT bits contain the aarch64_builtin_class + and the upper bits contain a group-specific subcode. */ +const unsigned int AARCH64_BUILTIN_SHIFT = 1; + +/* Mask that selects the aarch64_builtin_class part of a function code. */ +const unsigned int AARCH64_BUILTIN_CLASS = (1 << AARCH64_BUILTIN_SHIFT) - 1; + void aarch64_post_cfi_startproc (void); poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned); int aarch64_get_condition_code (rtx); @@ -459,7 +475,6 @@ bool aarch64_float_const_rtx_p (rtx); bool aarch64_function_arg_regno_p (unsigned); bool aarch64_fusion_enabled_p (enum aarch64_fusion_pairs); bool aarch64_gen_cpymemqi (rtx *); -bool aarch64_gimple_fold_builtin (gimple_stmt_iterator *); bool aarch64_is_extend_from_extract (scalar_int_mode, rtx, rtx); bool aarch64_is_long_call_p (rtx); bool aarch64_is_noplt_call_p (rtx); @@ -517,7 +532,6 @@ bool aarch64_symbolic_address_p (rtx); bool aarch64_uimm12_shift (HOST_WIDE_INT); bool aarch64_use_return_insn_p (void); bool aarch64_use_simple_return_insn_p (void); -const char *aarch64_mangle_builtin_type (const_tree); const char *aarch64_output_casesi (rtx *); enum aarch64_symbol_type aarch64_classify_symbol (rtx, HOST_WIDE_INT); @@ -544,7 +558,6 @@ rtx aarch64_simd_vect_par_cnst_half (machine_mode, int, bool); rtx aarch64_gen_stepped_int_parallel (unsigned int, int, int); bool aarch64_stepped_int_parallel_p (rtx, int); rtx aarch64_tls_get_addr (void); -tree aarch64_fold_builtin (tree, int, tree *, bool); unsigned aarch64_dbx_register_number (unsigned); unsigned aarch64_trampoline_size (void); void aarch64_asm_output_labelref (FILE *, const char *); @@ -639,18 +652,16 @@ bool aarch64_prepare_sve_int_fma (rtx *, rtx_code); bool aarch64_prepare_sve_cond_int_fma (rtx *, rtx_code); #endif /* RTX_CODE */ -void aarch64_init_builtins (void); - bool aarch64_process_target_attr (tree); void aarch64_override_options_internal (struct gcc_options *); -rtx aarch64_expand_builtin (tree exp, - rtx target, - rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, - int ignore ATTRIBUTE_UNUSED); -tree aarch64_builtin_decl (unsigned, bool ATTRIBUTE_UNUSED); -tree aarch64_builtin_rsqrt (unsigned int); +const char *aarch64_general_mangle_builtin_type (const_tree); +void aarch64_general_init_builtins (void); +tree aarch64_general_fold_builtin (unsigned int, tree, unsigned int, tree *); +gimple *aarch64_general_gimple_fold_builtin (unsigned int, gcall *); +rtx aarch64_general_expand_builtin (unsigned int, tree, rtx); +tree aarch64_general_builtin_decl (unsigned, bool); +tree aarch64_general_builtin_rsqrt (unsigned int); tree aarch64_builtin_vectorized_function (unsigned int, tree, tree); extern void aarch64_split_combinev16qi (rtx operands[3]); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 71d44de..81d0f2b 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -11646,6 +11646,79 @@ aarch64_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED, return aarch64_tune_params.memmov_cost; } +/* Implement TARGET_INIT_BUILTINS. */ +static void +aarch64_init_builtins () +{ + aarch64_general_init_builtins (); +} + +/* Implement TARGET_FOLD_BUILTIN. */ +static tree +aarch64_fold_builtin (tree fndecl, int nargs, tree *args, bool) +{ + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return aarch64_general_fold_builtin (subcode, type, nargs, args); + } + gcc_unreachable (); +} + +/* Implement TARGET_GIMPLE_FOLD_BUILTIN. */ +static bool +aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) +{ + gcall *stmt = as_a (gsi_stmt (*gsi)); + tree fndecl = gimple_call_fndecl (stmt); + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + gimple *new_stmt = NULL; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + new_stmt = aarch64_general_gimple_fold_builtin (subcode, stmt); + break; + } + + if (!new_stmt) + return false; + + gsi_replace (gsi, new_stmt, true); + return true; +} + +/* Implement TARGET_EXPAND_BUILTIN. */ +static rtx +aarch64_expand_builtin (tree exp, rtx target, rtx, machine_mode, int) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return aarch64_general_expand_builtin (subcode, exp, target); + } + gcc_unreachable (); +} + +/* Implement TARGET_BUILTIN_DECL. */ +static tree +aarch64_builtin_decl (unsigned int code, bool initialize_p) +{ + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return aarch64_general_builtin_decl (subcode, initialize_p); + } + gcc_unreachable (); +} + /* Return true if it is safe and beneficial to use the approximate rsqrt optabs to optimize 1.0/sqrt. */ @@ -11669,7 +11742,14 @@ aarch64_builtin_reciprocal (tree fndecl) if (!use_rsqrt_p (mode)) return NULL_TREE; - return aarch64_builtin_rsqrt (DECL_MD_FUNCTION_CODE (fndecl)); + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return aarch64_general_builtin_rsqrt (subcode); + } + gcc_unreachable (); } /* Emit instruction sequence to compute either the approximate square root @@ -15081,7 +15161,7 @@ aarch64_mangle_type (const_tree type) /* Mangle AArch64-specific internal types. TYPE_NAME is non-NULL_TREE for builtin types. */ if (TYPE_NAME (type) != NULL) - return aarch64_mangle_builtin_type (type); + return aarch64_general_mangle_builtin_type (type); /* Use the default mangling. */ return NULL; -- cgit v1.1 From 2ae8a2c9426d91fd3bd97ff73f0a0d252c3f94f1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 27 Sep 2019 12:28:48 +0200 Subject: re PR tree-optimization/91885 (ICE when compiling SPEC 2017 blender benchmark with -O3 -fprofile-generate) PR tree-optimization/91885 * gcc.dg/pr91885.c (__int64_t): Change from long to long long. (__uint64_t): Change from unsigned long to unsigned long long. From-SVN: r276178 --- gcc/ChangeLog | 5 ++--- gcc/testsuite/ChangeLog | 6 ++++++ gcc/testsuite/gcc.dg/pr91885.c | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8d142db..1723b98 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -188,9 +188,8 @@ 2019-09-26 Martin Liska PR tree-optimization/91885 - * tree-vectorizer.c (try_vectorize_loop_1): - Add TODO_update_ssa_only_virtuals similarly to what slp - pass does. + * tree-vectorizer.c (try_vectorize_loop_1): Add + TODO_update_ssa_only_virtuals similarly to what slp pass does. 2019-09-26 Richard Sandiford diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 84670ec..8f83df9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-09-27 Jakub Jelinek + + PR tree-optimization/91885 + * gcc.dg/pr91885.c (__int64_t): Change from long to long long. + (__uint64_t): Change from unsigned long to unsigned long long. + 2019-09-27 Yuliang Wang * gcc.target/aarch64/sve2/shracc_1.c: New test. diff --git a/gcc/testsuite/gcc.dg/pr91885.c b/gcc/testsuite/gcc.dg/pr91885.c index 934e8d3..35be32b 100644 --- a/gcc/testsuite/gcc.dg/pr91885.c +++ b/gcc/testsuite/gcc.dg/pr91885.c @@ -2,8 +2,8 @@ /* { dg-options "-O3 -fprofile-generate" } */ /* { dg-require-profiling "-fprofile-generate" } */ -typedef signed long int __int64_t; -typedef unsigned long int __uint64_t; +typedef signed long long int __int64_t; +typedef unsigned long long int __uint64_t; typedef __int64_t int64_t; typedef __uint64_t uint64_t; inline void -- cgit v1.1 From 67cb34efd8696f2710d8f818d4e25da818a9bff9 Mon Sep 17 00:00:00 2001 From: Manfred Schwarb Date: Fri, 27 Sep 2019 14:53:23 +0200 Subject: associate_48.f90: Fix a dg directive. 2019-09-27 Manfred Schwarb * gfortran.dg/associate_48.f90: Fix a dg directive. * gfortran.dg/auto_in_equiv_1.f90: Ditto. * gfortran.dg/auto_in_equiv_2.f90: Ditto. * gfortran.dg/lto/pr87689_0.f: Ditto. From-SVN: r276179 --- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/gfortran.dg/associate_48.f90 | 2 +- gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 | 2 +- gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 | 2 +- gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90 | 2 +- gcc/testsuite/gfortran.dg/lto/pr87689_0.f | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8f83df9..d53d67a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-09-27 Manfred Schwarb + + * gfortran.dg/associate_48.f90: Fix a dg directive. + * gfortran.dg/auto_in_equiv_1.f90: Ditto. + * gfortran.dg/auto_in_equiv_2.f90: Ditto. + * gfortran.dg/lto/pr87689_0.f: Ditto. + 2019-09-27 Jakub Jelinek PR tree-optimization/91885 diff --git a/gcc/testsuite/gfortran.dg/associate_48.f90 b/gcc/testsuite/gfortran.dg/associate_48.f90 index 5ce3a49..06aaea2 100644 --- a/gcc/testsuite/gfortran.dg/associate_48.f90 +++ b/gcc/testsuite/gfortran.dg/associate_48.f90 @@ -1,4 +1,4 @@ -! { dg=do run } +! { dg-do run } ! ! Test the fix for PR90498. ! diff --git a/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 b/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 index 61bfd07..bf6e0c6 100644 --- a/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 +++ b/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 @@ -1,4 +1,4 @@ -! { dg-compile } +! { dg-do compile } ! Contributed by Mark Eggleston program test diff --git a/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 b/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 index 406e718..e40c0f1 100644 --- a/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 +++ b/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 @@ -1,4 +1,4 @@ -! { dg-run } +! { dg-do run } ! { dg-options "-fdec-static" } ! Contributed by Mark Eggleston diff --git a/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90 b/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90 index c67aa8c..57c384d 100644 --- a/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90 +++ b/gcc/testsuite/gfortran.dg/auto_in_equiv_3.f90 @@ -1,4 +1,4 @@ -! { dg-run } +! { dg-do run } ! { dg-options "-fdec-static -fno-automatic" } ! Contributed by Mark Eggleston diff --git a/gcc/testsuite/gfortran.dg/lto/pr87689_0.f b/gcc/testsuite/gfortran.dg/lto/pr87689_0.f index 5beee93..22e75f7 100644 --- a/gcc/testsuite/gfortran.dg/lto/pr87689_0.f +++ b/gcc/testsuite/gfortran.dg/lto/pr87689_0.f @@ -1,4 +1,4 @@ -! { dg-lto-run } +! { dg-lto-do run } ! PR 87689 - this used to fail for POWER, plus it used to ! give warnings about mismatches with LTO. ! Original test case by Judicaël Grasset. -- cgit v1.1 From 29f26978866f32bddd656847441a3a953ffd7a21 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 27 Sep 2019 13:19:58 +0000 Subject: tree-vectorizer.h (_stmt_vec_info::reduc_fn): New. 2019-09-27 Richard Biener * tree-vectorizer.h (_stmt_vec_info::reduc_fn): New. (STMT_VINFO_REDUC_FN): Likewise. * tree-vectorizer.c (vec_info::new_stmt_vec_info): Initialize STMT_VINFO_REDUC_FN. * tree-vect-loop.c (vect_is_simple_reduction): Fix STMT_VINFO_REDUC_IDX for condition reductions. (vect_create_epilog_for_reduction): Compute all required state from the stmt to be vectorized. (vectorizable_reduction): Simplify vect_create_epilog_for_reduction invocation and remove then dead code. For single def-use chains record only a single vector stmt. From-SVN: r276180 --- gcc/ChangeLog | 14 +++++ gcc/tree-vect-loop.c | 148 +++++++++++++++++++++++--------------------------- gcc/tree-vectorizer.c | 1 + gcc/tree-vectorizer.h | 3 + 4 files changed, 86 insertions(+), 80 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1723b98..0258bfc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2019-09-27 Richard Biener + + * tree-vectorizer.h (_stmt_vec_info::reduc_fn): New. + (STMT_VINFO_REDUC_FN): Likewise. + * tree-vectorizer.c (vec_info::new_stmt_vec_info): Initialize + STMT_VINFO_REDUC_FN. + * tree-vect-loop.c (vect_is_simple_reduction): Fix STMT_VINFO_REDUC_IDX + for condition reductions. + (vect_create_epilog_for_reduction): Compute all required state + from the stmt to be vectorized. + (vectorizable_reduction): Simplify vect_create_epilog_for_reduction + invocation and remove then dead code. For single def-use chains + record only a single vector stmt. + 2019-09-27 Richard Sandiford * config/aarch64/aarch64-protos.h (aarch64_builtin_class): New enum. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index f5df534..2947b02 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -3070,7 +3070,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, || !flow_bb_inside_loop_p (loop, gimple_bb (def1_info->stmt)) || vect_valid_reduction_input_p (def1_info))) { - STMT_VINFO_REDUC_IDX (def_stmt_info) = 1; + STMT_VINFO_REDUC_IDX (def_stmt_info) = 1 + (code == COND_EXPR ? 1 : 0); if (dump_enabled_p ()) report_vect_op (MSG_NOTE, def_stmt, "detected reduction: "); return def_stmt_info; @@ -3083,7 +3083,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, stmt_vec_info phi_info, || !flow_bb_inside_loop_p (loop, gimple_bb (def2_info->stmt)) || vect_valid_reduction_input_p (def2_info))) { - STMT_VINFO_REDUC_IDX (def_stmt_info) = 0; + STMT_VINFO_REDUC_IDX (def_stmt_info) = 0 + (code == COND_EXPR ? 1 : 0); if (dump_enabled_p ()) report_vect_op (MSG_NOTE, def_stmt, "detected reduction: "); return def_stmt_info; @@ -4212,38 +4212,15 @@ get_initial_defs_for_reduction (slp_tree slp_node, Create code at the loop-epilog to finalize the result of a reduction computation. - VECT_DEFS is list of vector of partial results, i.e., the lhs's of vector - reduction statements. STMT_INFO is the scalar reduction stmt that is being vectorized. - NCOPIES is > 1 in case the vectorization factor (VF) is bigger than the - number of elements that we can fit in a vectype (nunits). In this case - we have to generate more than one vector stmt - i.e - we need to "unroll" - the vector stmt by a factor VF/nunits. For more details see documentation - in vectorizable_operation. - REDUC_FN is the internal function for the epilog reduction. - REDUCTION_PHIS is a list of the phi-nodes that carry the reduction - computation. - REDUC_INDEX is the index of the operand in the right hand side of the - statement that is defined by REDUCTION_PHI. - DOUBLE_REDUC is TRUE if double reduction phi nodes should be handled. SLP_NODE is an SLP node containing a group of reduction statements. The first one in this group is STMT_INFO. - INDUC_VAL is for INTEGER_INDUC_COND_REDUCTION the value to use for the case - when the COND_EXPR is never true in the loop. For MAX_EXPR, it needs to - be smaller than any value of the IV in the loop, for MIN_EXPR larger than - any value of the IV in the loop. - INDUC_CODE is the code for epilog reduction if INTEGER_INDUC_COND_REDUCTION. - NEUTRAL_OP is the value given by neutral_op_for_slp_reduction; it is - null if this is not an SLP reduction + SLP_NODE_INSTANCE is the SLP node instance containing SLP_NODE REDUC_INDEX says which rhs operand of the STMT_INFO is the reduction phi (counting from 0) This function: - 1. Creates the reduction def-use cycles: sets the arguments for - REDUCTION_PHIS: - The loop-entry argument is the vectorized initial-value of the reduction. - The loop-latch argument is taken from VECT_DEFS - the vector of partial - sums. + 1. Completes the reduction def-use cycles. 2. "Reduces" each vector of partial results VECT_DEFS into a single result, by calling the function specified by REDUC_FN if available, or by other means (whole-vector shifts or a scalar loop). @@ -4253,7 +4230,7 @@ get_initial_defs_for_reduction (slp_tree slp_node, The flow at the entry to this function: loop: - vec_def = phi # REDUCTION_PHI + vec_def = phi # REDUCTION_PHI VECT_DEF = vector_stmt # vectorized form of STMT_INFO s_loop = scalar_stmt # (scalar) STMT_INFO loop_exit: @@ -4278,22 +4255,37 @@ get_initial_defs_for_reduction (slp_tree slp_node, */ static void -vect_create_epilog_for_reduction (vec vect_defs, - stmt_vec_info stmt_info, - gimple *reduc_def_stmt, - enum tree_code code, - int ncopies, internal_fn reduc_fn, - vec reduction_phis, - bool double_reduc, +vect_create_epilog_for_reduction (stmt_vec_info stmt_info, slp_tree slp_node, - slp_instance slp_node_instance, - tree neutral_op, int reduc_index) + slp_instance slp_node_instance) { + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + gphi *reduc_def_stmt + = as_a (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info))->stmt); + enum tree_code code = STMT_VINFO_REDUC_CODE (stmt_info); + internal_fn reduc_fn = STMT_VINFO_REDUC_FN (stmt_info); + tree neutral_op = NULL_TREE; + if (slp_node) + neutral_op + = neutral_op_for_slp_reduction (slp_node_instance->reduc_phis, code, + REDUC_GROUP_FIRST_ELEMENT (stmt_info)); + bool double_reduc = false; + if (nested_in_vect_loop_p (LOOP_VINFO_LOOP (loop_vinfo), stmt_info)) + { + tree def_arg + = PHI_ARG_DEF_FROM_EDGE (reduc_def_stmt, + loop_preheader_edge + (LOOP_VINFO_LOOP (loop_vinfo)->inner)); + stmt_vec_info def_arg_stmt_info = loop_vinfo->lookup_def (def_arg); + if (def_arg_stmt_info + && (STMT_VINFO_DEF_TYPE (def_arg_stmt_info) + == vect_double_reduction_def)) + double_reduc = true; + } tree induc_val = NULL_TREE; stmt_vec_info prev_phi_info; tree vectype; machine_mode mode; - loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); class loop *loop = LOOP_VINFO_LOOP (loop_vinfo), *outer_loop = NULL; basic_block exit_bb; tree scalar_dest; @@ -4380,15 +4372,32 @@ vect_create_epilog_for_reduction (vec vect_defs, } /* Set phi nodes latch arguments. */ - FOR_EACH_VEC_ELT (reduction_phis, i, phi_info) + unsigned vec_num = 1; + int ncopies = 0; + if (slp_node) + vec_num = SLP_TREE_VEC_STMTS (slp_node_instance->reduc_phis).length (); + for (unsigned i = 0; i < vec_num; i++) { - tree def = vect_defs[i]; - for (j = 0; j < ncopies; j++) + if (slp_node) + { + def = gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt); + phi_info = SLP_TREE_VEC_STMTS (slp_node_instance->reduc_phis)[i]; + } + else + { + def = gimple_get_lhs (STMT_VINFO_VEC_STMT (stmt_info)->stmt); + phi_info = STMT_VINFO_VEC_STMT (loop_vinfo->lookup_stmt (reduc_def_stmt)); + } + for (ncopies = 0;; ncopies++) { /* Set the loop-latch arg for the reduction-phi. */ - if (j != 0) + if (ncopies != 0) { + if (slp_node) + break; phi_info = STMT_VINFO_RELATED_STMT (phi_info); + if (!phi_info) + break; def = vect_get_vec_def_for_stmt_copy (loop_vinfo, def); } @@ -4474,9 +4483,9 @@ vect_create_epilog_for_reduction (vec vect_defs, (CCOMPARE). The then and else values mirror the main VEC_COND_EXPR: the reduction phi corresponds to NEW_PHI_TREE and the new values correspond to INDEX_BEFORE_INCR. */ - gcc_assert (reduc_index >= 1); + gcc_assert (STMT_VINFO_REDUC_IDX (stmt_info) >= 1); tree index_cond_expr; - if (reduc_index == 2) + if (STMT_VINFO_REDUC_IDX (stmt_info) == 2) index_cond_expr = build3 (VEC_COND_EXPR, cr_index_vector_type, ccompare, indx_before_incr, new_phi_tree); else @@ -4527,9 +4536,13 @@ vect_create_epilog_for_reduction (vec vect_defs, exit_bb = single_exit (loop)->dest; prev_phi_info = NULL; - new_phis.create (vect_defs.length ()); - FOR_EACH_VEC_ELT (vect_defs, i, def) + new_phis.create (slp_node ? vec_num : ncopies); + for (unsigned i = 0; i < vec_num; i++) { + if (slp_node) + def = gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt); + else + def = gimple_get_lhs (STMT_VINFO_VEC_STMT (stmt_info)->stmt); for (j = 0; j < ncopies; j++) { tree new_def = copy_ssa_name (def); @@ -4554,7 +4567,7 @@ vect_create_epilog_for_reduction (vec vect_defs, { loop = outer_loop; exit_bb = single_exit (loop)->dest; - inner_phis.create (vect_defs.length ()); + inner_phis.create (slp_node ? vec_num : ncopies); FOR_EACH_VEC_ELT (new_phis, i, phi) { stmt_vec_info phi_info = loop_vinfo->lookup_stmt (phi); @@ -5932,7 +5945,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, bool is_simple_use; int i; int ncopies; - int epilog_copies; stmt_vec_info prev_stmt_info, prev_phi_info; bool single_defuse_cycle = false; stmt_vec_info new_stmt_info = NULL; @@ -5947,8 +5959,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, auto_vec vec_oprnds0; auto_vec vec_oprnds1; auto_vec vec_oprnds2; - auto_vec vect_defs; - auto_vec phis; int vec_num; tree def0, tem; tree cr_index_scalar_type = NULL_TREE, cr_index_vector_type = NULL_TREE; @@ -6705,6 +6715,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, OPTIMIZE_FOR_SPEED)) reduc_fn = IFN_REDUC_MAX; } + STMT_VINFO_REDUC_FN (stmt_info) = reduc_fn; if (reduction_type != EXTRACT_LAST_REDUCTION && (!nested_cycle || double_reduc) @@ -6898,12 +6909,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) && vect_stmt_to_vectorize (use_stmt_info) == stmt_info) - { - single_defuse_cycle = true; - epilog_copies = 1; - } - else - epilog_copies = ncopies; + single_defuse_cycle = true; /* If the reduction stmt is one of the patterns that have lane reduction embedded we cannot handle the case of ! single_defuse_cycle. */ @@ -7002,16 +7008,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vec_oprnds2.create (1); } - phis.create (vec_num); - vect_defs.create (vec_num); - if (!slp_node) - vect_defs.quick_push (NULL_TREE); - - if (slp_node) - phis.splice (SLP_TREE_VEC_STMTS (slp_node_instance->reduc_phis)); - else - phis.quick_push (STMT_VINFO_VEC_STMT (reduc_def_info)); - for (j = 0; j < ncopies; j++) { if (code == COND_EXPR) @@ -7140,15 +7136,10 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } if (slp_node) - { - SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt_info); - vect_defs.quick_push (new_temp); - } - else - vect_defs[0] = new_temp; + SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt_info); } - if (slp_node) + if (slp_node || single_defuse_cycle) continue; if (j == 0) @@ -7159,15 +7150,12 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, prev_stmt_info = new_stmt_info; } + if (single_defuse_cycle && !slp_node) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt_info; + /* Finalize the reduction-phi (set its arguments) and create the epilog reduction code. */ - if ((!single_defuse_cycle || code == COND_EXPR) && !slp_node) - vect_defs[0] = gimple_get_lhs ((*vec_stmt)->stmt); - - vect_create_epilog_for_reduction (vect_defs, stmt_info, reduc_def_phi, - orig_code, epilog_copies, reduc_fn, phis, - double_reduc, slp_node, slp_node_instance, - neutral_op, reduc_index); + vect_create_epilog_for_reduction (stmt_info, slp_node, slp_node_instance); return true; } diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 50d508d..800c99f 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -640,6 +640,7 @@ vec_info::new_stmt_vec_info (gimple *stmt) STMT_VINFO_VEC_REDUCTION_TYPE (res) = TREE_CODE_REDUCTION; STMT_VINFO_VEC_COND_REDUC_CODE (res) = ERROR_MARK; STMT_VINFO_REDUC_CODE (res) = ERROR_MARK; + STMT_VINFO_REDUC_FN (res) = IFN_LAST; STMT_VINFO_REDUC_IDX (res) = -1; STMT_VINFO_SLP_VECT_ONLY (res) = false; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 1ab4af7..d9171c0 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -951,6 +951,8 @@ public: /* The original reduction code, to be used in the epilogue. */ enum tree_code reduc_code; + /* An internal function we should use in the epilogue. */ + internal_fn reduc_fn; /* On a stmt participating in the reduction the index of the operand on the reduction SSA cycle. */ @@ -1079,6 +1081,7 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) #define STMT_VINFO_NUM_SLP_USES(S) (S)->num_slp_uses #define STMT_VINFO_REDUC_TYPE(S) (S)->reduc_type #define STMT_VINFO_REDUC_CODE(S) (S)->reduc_code +#define STMT_VINFO_REDUC_FN(S) (S)->reduc_fn #define STMT_VINFO_REDUC_DEF(S) (S)->reduc_def #define STMT_VINFO_SLP_VECT_ONLY(S) (S)->slp_vect_only_p -- cgit v1.1 From 88e032f105da53ef628f0eecd1f5a6fc372d022b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 27 Sep 2019 17:48:51 +0200 Subject: re PR target/91919 (arm-linux-eabi ICE with building kernel) PR target/91919 * config/arm/arm.md (mlal): Remove SE wrappers around operands of SImode MULT. * gcc.c-torture/compile/pr91919.c: New.test From-SVN: r276183 --- gcc/ChangeLog | 6 ++++++ gcc/config/arm/arm.md | 4 ++-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.c-torture/compile/pr91919.c | 7 +++++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr91919.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0258bfc..8e4e143 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-27 Jakub Jelinek + + PR target/91919 + * config/arm/arm.md (mlal): Remove SE wrappers around operands + of SImode MULT. + 2019-09-27 Richard Biener * tree-vectorizer.h (_stmt_vec_info::reduc_fn): New. diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index d3ee59a..f861c72 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1812,8 +1812,8 @@ [(set (match_operand:SI 0 "s_register_operand" "=r,&r") (plus:SI (mult:SI - (SE:DI (match_operand:SI 4 "s_register_operand" "%r,r")) - (SE:DI (match_operand:SI 5 "s_register_operand" "r,r"))) + (match_operand:SI 4 "s_register_operand" "%r,r") + (match_operand:SI 5 "s_register_operand" "r,r")) (match_operand:SI 1 "s_register_operand" "0,0"))) (set (match_operand:SI 2 "s_register_operand" "=r,&r") (plus:SI diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d53d67a..8386c33 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-27 Jakub Jelinek + + PR target/91919 + * gcc.c-torture/compile/pr91919.c: New.test + 2019-09-27 Manfred Schwarb * gfortran.dg/associate_48.f90: Fix a dg directive. diff --git a/gcc/testsuite/gcc.c-torture/compile/pr91919.c b/gcc/testsuite/gcc.c-torture/compile/pr91919.c new file mode 100644 index 0000000..9d0c95e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr91919.c @@ -0,0 +1,7 @@ +/* PR target/91919 */ + +unsigned int +foo (unsigned int x, int y) +{ + return (x * 3355443200ULL + (y * 1801439851ULL >> 29) >> 25); +} -- cgit v1.1 From df435456846445e0939197af4bc19e813d6ef8c4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 27 Sep 2019 17:32:27 +0000 Subject: compiler: fix brace formatting Just happened to notice this one. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/197698 From-SVN: r276186 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/types.cc | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 330c458..574d33d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d81ff42c367cce2110ccf5ddbadb6cc9bdf94e28 +d1fa6c34e56eade6fb5b6291f0a727b1a12bf6f1 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0ada841..eeae9fa4 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -965,12 +965,13 @@ Type::get_backend(Gogo* gogo) if (this->btype_ != NULL) return this->btype_; - if (this->named_type() != NULL && this->named_type()->is_alias()) { - Btype* bt = this->unalias()->get_backend(gogo); - if (gogo != NULL && gogo->named_types_are_converted()) - this->btype_ = bt; - return bt; - } + if (this->named_type() != NULL && this->named_type()->is_alias()) + { + Btype* bt = this->unalias()->get_backend(gogo); + if (gogo != NULL && gogo->named_types_are_converted()) + this->btype_ = bt; + return bt; + } if (this->forward_declaration_type() != NULL || this->named_type() != NULL) -- cgit v1.1 From 51c3b7c6ec20262f2a4698f42e533c28d2c38a87 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 27 Sep 2019 17:34:58 +0000 Subject: compiler: only check whether struct or array types are big Fetching the size of a type typically involves a hash table lookup, and is generally non-trivial. The escape analysis code calls is_big more than one might expect. So only fetch the size if we need it. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/197699 From-SVN: r276187 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/escape.cc | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 574d33d..871a3ee 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d1fa6c34e56eade6fb5b6291f0a727b1a12bf6f1 +27d1f3031197428b5745d09c167f982d638b8776 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index db3afc7..91f43a6 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -511,16 +511,28 @@ Node::is_big(Escape_context* context) const || t->is_abstract()) return false; - int64_t size; - bool ok = t->backend_type_size(context->gogo(), &size); - bool big = ok && (size < 0 || size > 10 * 1024 * 1024); + bool big = false; + if (t->struct_type() != NULL + || (t->array_type() != NULL && !t->is_slice_type())) + { + int64_t size; + bool ok = t->backend_type_size(context->gogo(), &size); + big = ok && (size < 0 || size > 10 * 1024 * 1024); + } if (this->expr() != NULL) { if (this->expr()->allocation_expression() != NULL) { - ok = t->deref()->backend_type_size(context->gogo(), &size); - big = big || size <= 0 || size >= (1 << 16); + Type* pt = t->deref(); + if (pt->struct_type() != NULL + || (pt->array_type() != NULL && !pt->is_slice_type())) + { + int64_t size; + bool ok = pt->backend_type_size(context->gogo(), &size); + if (ok) + big = big || size <= 0 || size >= (1 << 16); + } } else if (this->expr()->call_expression() != NULL) { -- cgit v1.1 From 37ed4c3269f940a3a064e320331aed38890fb8c0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 27 Sep 2019 17:51:43 +0000 Subject: compiler: don't read known type, simplify Import::finalize_methods With the current export format, if we already know the type, we don't have to read and parse the definition. We only use the finalizer in Import::finalize_methods, so make it a local variable. To match Finalize_methods::type, only put struct types into real_for_named. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/197700 From-SVN: r276188 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/import.cc | 40 ++++++++++++++++++++++------------------ gcc/go/gofrontend/import.h | 4 ---- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 871a3ee..1e6ca6f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -27d1f3031197428b5745d09c167f982d638b8776 +9112ea664ed9ee5f108158a913812adaf03edf6e The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index bbc8d7d..c63ae24 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -290,16 +290,10 @@ Import::Import(Stream* stream, Location location) : gogo_(NULL), stream_(stream), location_(location), package_(NULL), add_to_globals_(false), packages_(), type_data_(), type_pos_(0), type_offsets_(), builtin_types_((- SMALLEST_BUILTIN_CODE) + 1), - types_(), finalizer_(NULL), version_(EXPORT_FORMAT_UNKNOWN) + types_(), version_(EXPORT_FORMAT_UNKNOWN) { } -Import::~Import() -{ - if (this->finalizer_ != NULL) - delete this->finalizer_; -} - // Import the data in the associated stream. Package* @@ -692,16 +686,22 @@ Import::read_types() void Import::finalize_methods() { - if (this->finalizer_ == NULL) - this->finalizer_ = new Finalize_methods(gogo_); + Finalize_methods finalizer(this->gogo_); Unordered_set(Type*) real_for_named; for (size_t i = 1; i < this->types_.size(); i++) { Type* type = this->types_[i]; if (type != NULL && type->named_type() != NULL) { - this->finalizer_->type(type); - real_for_named.insert(type->named_type()->real_type()); + finalizer.type(type); + + // If the real type is a struct type, we don't want to + // finalize its methods. For a named type defined as a + // struct type, we only want to finalize the methods of the + // named type. This is like Finalize_methods::type. + Type* real_type = type->named_type()->real_type(); + if (real_type->struct_type() != NULL) + real_for_named.insert(real_type); } } for (size_t i = 1; i < this->types_.size(); i++) @@ -710,7 +710,7 @@ Import::finalize_methods() if (type != NULL && type->named_type() == NULL && real_for_named.find(type) == real_for_named.end()) - this->finalizer_->type(type); + finalizer.type(type); } } @@ -1105,12 +1105,12 @@ Import::read_named_type(int index) type = this->types_[index]; else { - type = this->read_type(); - if (no->is_type_declaration()) { // We can define the type now. + type = this->read_type(); + no = package->add_type(type_name, type, this->location_); Named_type* ntype = no->type_value(); @@ -1127,14 +1127,18 @@ Import::read_named_type(int index) } else if (no->is_type()) { - // We have seen this type before. FIXME: it would be a good - // idea to check that the two imported types are identical, - // but we have not finalized the methods yet, which means - // that we can not reliably compare interface types. + // We have seen this type before. type = no->type_value(); // Don't change the visibility of the existing type. + + // For older export versions, we need to skip the type + // definition in the stream. + if (this->version_ < EXPORT_FORMAT_V3) + this->read_type(); } + else + go_unreachable(); this->types_[index] = type; diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index a78e48b..b12b3b8 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -208,8 +208,6 @@ class Import : public Import_expression // Constructor. Import(Stream*, Location); - virtual ~Import(); - // Register the builtin types. void register_builtin_types(Gogo*); @@ -450,8 +448,6 @@ class Import : public Import_expression std::vector builtin_types_; // Mapping from exported type codes to Type structures. std::vector types_; - // Helper for finalizing methods. - Finalize_methods* finalizer_; // Version of export data we're reading. Export_data_version version_; }; -- cgit v1.1 From 975d043ff6b6f8a9e9ff0be799701fc1d842bb83 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 27 Sep 2019 18:12:56 +0000 Subject: Make cgraph_node::get_fun const gcc/ChangeLog: * cgraph.c (cgraph_node::get_fun): Make const. * cgraph.h (cgraph_node::get_fun): Likewise. From-SVN: r276190 --- gcc/ChangeLog | 5 +++++ gcc/cgraph.c | 4 ++-- gcc/cgraph.h | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8e4e143..05ba915 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-27 David Malcolm + + * cgraph.c (cgraph_node::get_fun): Make const. + * cgraph.h (cgraph_node::get_fun): Likewise. + 2019-09-27 Jakub Jelinek PR target/91919 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 331b363..8615e2e 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -3602,9 +3602,9 @@ cgraph_node::get_body (void) /* Return the DECL_STRUCT_FUNCTION of the function. */ struct function * -cgraph_node::get_fun (void) +cgraph_node::get_fun () const { - cgraph_node *node = this; + const cgraph_node *node = this; struct function *fun = DECL_STRUCT_FUNCTION (node->decl); while (!fun && node->clone_of) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 1da6cab..195e6e9 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1142,7 +1142,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node void release_body (bool keep_arguments = false); /* Return the DECL_STRUCT_FUNCTION of the function. */ - struct function *get_fun (void); + struct function *get_fun () const; /* cgraph_node is no longer nested function; update cgraph accordingly. */ void unnest (void); -- cgit v1.1 From c872f1506d46ceba10776d0ebc86b4126273a419 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 27 Sep 2019 14:19:55 -0400 Subject: cp-tree.h (class iloc_sentinel): New. * cp-tree.h (class iloc_sentinel): New. We didn't already have a sentinel for input_location, and while temp_override would work, it would also happily set input_location to 0, which breaks things that try to look up the associated filename. * decl.c (grokdeclarator, finish_enum_value_list): Use it. * mangle.c (mangle_decl_string): Use it. * pt.c (perform_typedefs_access_check): Use it. From-SVN: r276191 --- gcc/cp/ChangeLog | 7 +++++++ gcc/cp/cp-tree.h | 18 ++++++++++++++++++ gcc/cp/decl.c | 15 +++++---------- gcc/cp/mangle.c | 4 +--- gcc/cp/pt.c | 5 +---- 5 files changed, 32 insertions(+), 17 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3a3ef9e..8e92d91 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2019-09-27 Jason Merrill + + * cp-tree.h (class iloc_sentinel): New. + * decl.c (grokdeclarator, finish_enum_value_list): Use it. + * mangle.c (mangle_decl_string): Use it. + * pt.c (perform_typedefs_access_check): Use it. + 2019-09-27 Richard Sandiford * cp-tree.h (build_cxx_call): Take the original function decl diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8fc3fc1..be1a44e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1762,6 +1762,24 @@ public: ~warning_sentinel() { flag = val; } }; +/* RAII sentinel to temporarily override input_location. This will not set + input_location to UNKNOWN_LOCATION or BUILTINS_LOCATION. */ + +class iloc_sentinel +{ + location_t saved_loc; +public: + iloc_sentinel (location_t loc): saved_loc (input_location) + { + if (loc >= RESERVED_LOCATION_COUNT) + input_location = loc; + } + ~iloc_sentinel () + { + input_location = saved_loc; + } +}; + /* RAII sentinel that saves the value of a variable, optionally overrides it right away, and restores its value when the sentinel id destructed. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b753796..67c4521 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10523,7 +10523,6 @@ grokdeclarator (const cp_declarator *declarator, bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit); bool late_return_type_p = false; bool array_parameter_p = false; - location_t saved_loc = input_location; tree reqs = NULL_TREE; signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed); @@ -11514,9 +11513,10 @@ grokdeclarator (const cp_declarator *declarator, /* Declaring a function type. */ - input_location = declspecs->locations[ds_type_spec]; - abstract_virtuals_error (ACU_RETURN, type); - input_location = saved_loc; + { + iloc_sentinel ils (declspecs->locations[ds_type_spec]); + abstract_virtuals_error (ACU_RETURN, type); + } /* Pick up type qualifiers which should be applied to `this'. */ memfn_quals = declarator->u.function.qualifiers; @@ -15061,11 +15061,8 @@ finish_enum_value_list (tree enumtype) type of the enumeration. */ for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values)) { - location_t saved_location; - decl = TREE_VALUE (values); - saved_location = input_location; - input_location = DECL_SOURCE_LOCATION (decl); + iloc_sentinel ils (DECL_SOURCE_LOCATION (decl)); if (fixed_underlying_type_p) /* If the enumeration type has a fixed underlying type, we already checked all of the enumerator values. */ @@ -15074,8 +15071,6 @@ finish_enum_value_list (tree enumtype) value = perform_implicit_conversion (underlying_type, DECL_INITIAL (decl), tf_warning_or_error); - input_location = saved_location; - /* Do not clobber shared ints. */ if (value != error_mark_node) { diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 4d6f580..a9333b8 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3791,7 +3791,6 @@ static tree mangle_decl_string (const tree decl) { tree result; - location_t saved_loc = input_location; tree saved_fn = NULL_TREE; bool template_p = false; @@ -3809,7 +3808,7 @@ mangle_decl_string (const tree decl) current_function_decl = NULL_TREE; } } - input_location = DECL_SOURCE_LOCATION (decl); + iloc_sentinel ils (DECL_SOURCE_LOCATION (decl)); start_mangling (decl); @@ -3828,7 +3827,6 @@ mangle_decl_string (const tree decl) pop_tinst_level (); current_function_decl = saved_fn; } - input_location = saved_loc; return result; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e5d6498..5a2dfbb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10941,7 +10941,6 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, static void perform_typedefs_access_check (tree tmpl, tree targs) { - location_t saved_location; unsigned i; qualified_typedef_usage_t *iter; @@ -10950,7 +10949,6 @@ perform_typedefs_access_check (tree tmpl, tree targs) && TREE_CODE (tmpl) != FUNCTION_DECL)) return; - saved_location = input_location; FOR_EACH_VEC_SAFE_ELT (get_types_needing_access_check (tmpl), i, iter) { tree type_decl = iter->typedef_decl; @@ -10966,12 +10964,11 @@ perform_typedefs_access_check (tree tmpl, tree targs) /* Make access check error messages point to the location of the use of the typedef. */ - input_location = iter->locus; + iloc_sentinel ils (iter->locus); perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl, tf_warning_or_error); } - input_location = saved_location; } static tree -- cgit v1.1 From 1a120ec124a76ef2bf658f8f11d8ecb58f766a0d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 27 Sep 2019 14:23:10 -0400 Subject: constexpr.c (cxx_fold_indirect_ref): Use similar_type_p. * constexpr.c (cxx_fold_indirect_ref): Use similar_type_p. Merging the similar_type_p change to the concepts branch broke a cmcstl2 testcase; investigating led me to this small testcase which has always failed on trunk. (cxx_eval_indirect_ref): Likewise. Improve error location. From-SVN: r276192 --- gcc/cp/ChangeLog | 3 +++ gcc/cp/constexpr.c | 38 +++++++++++---------------- gcc/testsuite/g++.dg/cpp0x/constexpr-const2.C | 6 +++++ 3 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-const2.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8e92d91..20f543e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,8 @@ 2019-09-27 Jason Merrill + * constexpr.c (cxx_fold_indirect_ref): Use similar_type_p. + (cxx_eval_indirect_ref): Likewise. Improve error location. + * cp-tree.h (class iloc_sentinel): New. * decl.c (grokdeclarator, finish_enum_value_list): Use it. * mangle.c (mangle_decl_string): Use it. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 58db691..cb5484f 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3388,7 +3388,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) if (TREE_CODE (op) == CONST_DECL) return DECL_INITIAL (op); /* *&p => p; make sure to handle *&"str"[cst] here. */ - if (same_type_ignoring_tlq_and_bounds_p (optype, type)) + if (similar_type_p (optype, type)) { tree fop = fold_read_from_constant_string (op); if (fop) @@ -3398,8 +3398,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) } /* *(foo *)&fooarray => fooarray[0] */ else if (TREE_CODE (optype) == ARRAY_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (optype)))) + && similar_type_p (type, TREE_TYPE (optype))) { tree type_domain = TYPE_DOMAIN (optype); tree min_val = size_zero_node; @@ -3410,13 +3409,11 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) } /* *(foo *)&complexfoo => __real__ complexfoo */ else if (TREE_CODE (optype) == COMPLEX_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (optype)))) + && similar_type_p (type, TREE_TYPE (optype))) return fold_build1_loc (loc, REALPART_EXPR, type, op); /* *(foo *)&vectorfoo => BIT_FIELD_REF */ else if (VECTOR_TYPE_P (optype) - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (optype)))) + && similar_type_p (type, TREE_TYPE (optype))) { tree part_width = TYPE_SIZE (type); tree index = bitsize_int (0); @@ -3440,8 +3437,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) if (TREE_CODE (field) == FIELD_DECL && TREE_TYPE (field) != error_mark_node && integer_zerop (byte_position (field)) - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (field), type))) + && similar_type_p (TREE_TYPE (field), type)) return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE); } } @@ -3460,8 +3456,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF */ if (VECTOR_TYPE_P (op00type) - && same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)) + && similar_type_p (type, TREE_TYPE (op00type)) /* POINTER_PLUS_EXPR second operand is sizetype, unsigned, but we want to treat offsets with MSB set as negative. For the code below negative offsets are invalid and @@ -3486,8 +3481,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) } /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ else if (TREE_CODE (op00type) == COMPLEX_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)))) + && similar_type_p (type, TREE_TYPE (op00type))) { if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)), const_op01)) @@ -3495,8 +3489,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) } /* ((foo *)&fooarray)[1] => fooarray[1] */ else if (TREE_CODE (op00type) == ARRAY_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)))) + && similar_type_p (type, TREE_TYPE (op00type))) { tree type_domain = TYPE_DOMAIN (op00type); tree min_val = size_zero_node; @@ -3531,8 +3524,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) if (TREE_CODE (field) == FIELD_DECL && TREE_TYPE (field) != error_mark_node && tree_int_cst_equal (byte_position (field), op01) - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (field), type))) + && similar_type_p (TREE_TYPE (field), type)) return fold_build3 (COMPONENT_REF, type, op00, field, NULL_TREE); } @@ -3540,8 +3532,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (TREE_TYPE (subtype))))) + && similar_type_p (type, TREE_TYPE (TREE_TYPE (subtype)))) { tree type_domain; tree min_val = size_zero_node; @@ -3611,13 +3602,14 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, STRIP_NOPS (sub); if (TREE_CODE (sub) == ADDR_EXPR) { - gcc_assert (!same_type_ignoring_top_level_qualifiers_p + gcc_assert (!similar_type_p (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); /* DR 1188 says we don't have to deal with this. */ if (!ctx->quiet) - error ("accessing value of %qE through a %qT glvalue in a " - "constant expression", build_fold_indirect_ref (sub), - TREE_TYPE (t)); + error_at (cp_expr_loc_or_input_loc (t), + "accessing value of %qE through a %qT glvalue in a " + "constant expression", build_fold_indirect_ref (sub), + TREE_TYPE (t)); *non_constant_p = true; return t; } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-const2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-const2.C new file mode 100644 index 0000000..7aa16a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-const2.C @@ -0,0 +1,6 @@ +// { dg-do compile { target c++11 } } + +int i = 42; +constexpr int *p = &i; +constexpr int const *const *q = &p; +constexpr int const *r = *q; -- cgit v1.1 From 26a23d11ed473563344d16a5b643795628e1b990 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 27 Sep 2019 18:24:44 +0000 Subject: Const-correctness fixes for fibonacci_heap.h gcc/ChangeLog: * fibonacci_heap.h (fibonacci_heap::empty): Make const. (fibonacci_heap::nodes): Likewise. (fibonacci_heap::min_key): Likewise. (fibonacci_heap::min): Likewise. From-SVN: r276193 --- gcc/ChangeLog | 7 +++++++ gcc/fibonacci_heap.h | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 05ba915..37037ab 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-27 David Malcolm + * fibonacci_heap.h (fibonacci_heap::empty): Make const. + (fibonacci_heap::nodes): Likewise. + (fibonacci_heap::min_key): Likewise. + (fibonacci_heap::min): Likewise. + +2019-09-27 David Malcolm + * cgraph.c (cgraph_node::get_fun): Make const. * cgraph.h (cgraph_node::get_fun): Likewise. diff --git a/gcc/fibonacci_heap.h b/gcc/fibonacci_heap.h index 6e0a216..3bd0a9f 100644 --- a/gcc/fibonacci_heap.h +++ b/gcc/fibonacci_heap.h @@ -162,19 +162,19 @@ public: fibonacci_node_t *insert (K key, V *data); /* Return true if no entry is present. */ - bool empty () + bool empty () const { return m_nodes == 0; } /* Return the number of nodes. */ - size_t nodes () + size_t nodes () const { return m_nodes; } /* Return minimal key presented in the heap. */ - K min_key () + K min_key () const { if (m_min == NULL) gcc_unreachable (); @@ -206,7 +206,7 @@ public: V *extract_min (bool release = true); /* Return value associated with minimum node in the heap. */ - V *min () + V *min () const { if (m_min == NULL) return NULL; -- cgit v1.1 From 576113abdb10ebdd141cdd3adb6884973c3d3c1d Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 27 Sep 2019 19:23:39 +0000 Subject: [Darwin, PPC, Mode Iterators 3/n] Update macho_correct_pic. Drop the expander and use a mode expander on the define_insn for macho_correct_pic instead. gcc/ChangeLog: 2019-09-27 Iain Sandoe * config/rs6000/darwin.md (@macho_correct_pic_): New, replaces the expander and two define_insn entries. (@reload_macho_picbase_): Update gen_macho_correct_pic call. * config/rs6000/rs6000.md (builtin_setjmp_receiver): Likewise. From-SVN: r276196 --- gcc/ChangeLog | 8 +++++++ gcc/config/rs6000/darwin.md | 51 +++++++++++---------------------------------- gcc/config/rs6000/rs6000.md | 3 ++- 3 files changed, 22 insertions(+), 40 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 37037ab..c935cf3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-27 Iain Sandoe + + * config/rs6000/darwin.md (@macho_correct_pic_): New, + replaces the expander and two define_insn entries. + (@reload_macho_picbase_): Update gen_macho_correct_pic + call. + * config/rs6000/rs6000.md (builtin_setjmp_receiver): Likewise. + 2019-09-27 David Malcolm * fibonacci_heap.h (fibonacci_heap::empty): Make const. diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md index a5c5a3a..b2a52d8 100644 --- a/gcc/config/rs6000/darwin.md +++ b/gcc/config/rs6000/darwin.md @@ -216,6 +216,16 @@ You should have received a copy of the GNU General Public License (match_dup 2))] "") +(define_insn "@macho_correct_pic_" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (plus:P (match_operand:P 1 "gpc_reg_operand" "r") + (unspec:P [(match_operand:P 2 "immediate_operand" "s") + (match_operand:P 3 "immediate_operand" "s")] + UNSPEC_MPIC_CORRECT)))] + "DEFAULT_ABI == ABI_DARWIN" + "addis %0,%1,ha16(%2-%3)\n\taddi %0,%0,lo16(%2-%3)" + [(set_attr "length" "8")]) + (define_insn "@load_macho_picbase_" [(set (reg:P LR_REGNO) (unspec:P [(match_operand:P 0 "immediate_operand" "s") @@ -232,44 +242,6 @@ You should have received a copy of the GNU General Public License [(set_attr "type" "branch") (set_attr "cannot_copy" "yes")]) -(define_expand "macho_correct_pic" - [(set (match_operand 0 "") - (plus (match_operand 1 "") - (unspec [(match_operand 2 "") - (match_operand 3 "")] - UNSPEC_MPIC_CORRECT)))] - "DEFAULT_ABI == ABI_DARWIN" -{ - if (TARGET_32BIT) - emit_insn (gen_macho_correct_pic_si (operands[0], operands[1], operands[2], - operands[3])); - else - emit_insn (gen_macho_correct_pic_di (operands[0], operands[1], operands[2], - operands[3])); - - DONE; -}) - -(define_insn "macho_correct_pic_si" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r") - (plus:SI (match_operand:SI 1 "gpc_reg_operand" "r") - (unspec:SI [(match_operand:SI 2 "immediate_operand" "s") - (match_operand:SI 3 "immediate_operand" "s")] - UNSPEC_MPIC_CORRECT)))] - "DEFAULT_ABI == ABI_DARWIN" - "addis %0,%1,ha16(%2-%3)\n\taddi %0,%0,lo16(%2-%3)" - [(set_attr "length" "8")]) - -(define_insn "macho_correct_pic_di" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r") - (plus:DI (match_operand:DI 1 "gpc_reg_operand" "r") - (unspec:DI [(match_operand:DI 2 "immediate_operand" "s") - (match_operand:DI 3 "immediate_operand" "s")] - 16)))] - "DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT" - "addis %0,%1,ha16(%2-%3)\n\taddi %0,%0,lo16(%2-%3)" - [(set_attr "length" "8")]) - (define_insn "@reload_macho_picbase_" [(set (reg:P LR_REGNO) (unspec:P [(match_operand:P 0 "immediate_operand" "s") @@ -316,7 +288,8 @@ You should have received a copy of the GNU General Public License emit_insn (gen_reload_macho_picbase (Pmode, tmplrtx)); emit_move_insn (picreg, gen_rtx_REG (Pmode, LR_REGNO)); - emit_insn (gen_macho_correct_pic (picreg, picreg, picrtx, tmplrtx)); + emit_insn (gen_macho_correct_pic (Pmode, picreg, picreg, + picrtx, tmplrtx)); } else /* Not using PIC reg, no reload needed. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index c5443ba..46167e5 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -10055,7 +10055,8 @@ emit_insn (gen_load_macho_picbase (Pmode, tmplabrtx)); emit_move_insn (picreg, gen_rtx_REG (Pmode, LR_REGNO)); - emit_insn (gen_macho_correct_pic (picreg, picreg, picrtx, tmplabrtx)); + emit_insn (gen_macho_correct_pic (Pmode, picreg, picreg, + picrtx, tmplabrtx)); } else #endif -- cgit v1.1 From 00798c58439037e3de959c3a003d6f4251eb93c6 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 27 Sep 2019 22:13:00 +0200 Subject: re PR middle-end/91920 (ggc 9.2.0 failing openmp compile on ppc64le) PR middle-end/91920 * gimplify.c (omp_default_clause): Predetermine DECL_IN_CONSTANT_POOL variables as shared. * c-c++-common/gomp/pr91920.c: New test. From-SVN: r276211 --- gcc/ChangeLog | 6 ++++++ gcc/gimplify.c | 2 ++ gcc/testsuite/ChangeLog | 5 ++++- gcc/testsuite/c-c++-common/gomp/pr91920.c | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/pr91920.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c935cf3..29f56d5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-27 Jakub Jelinek + + PR middle-end/91920 + * gimplify.c (omp_default_clause): Predetermine DECL_IN_CONSTANT_POOL + variables as shared. + 2019-09-27 Iain Sandoe * config/rs6000/darwin.md (@macho_correct_pic_): New, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 623cdbf..88d6571 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -7132,6 +7132,8 @@ omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl, kind = lang_hooks.decls.omp_predetermined_sharing (decl); if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED) default_kind = kind; + else if (VAR_P (decl) && TREE_STATIC (decl) && DECL_IN_CONSTANT_POOL (decl)) + default_kind = OMP_CLAUSE_DEFAULT_SHARED; switch (default_kind) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8386c33..9aee20c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,7 +1,10 @@ 2019-09-27 Jakub Jelinek + PR middle-end/91920 + * c-c++-common/gomp/pr91920.c: New test. + PR target/91919 - * gcc.c-torture/compile/pr91919.c: New.test + * gcc.c-torture/compile/pr91919.c: New test. 2019-09-27 Manfred Schwarb diff --git a/gcc/testsuite/c-c++-common/gomp/pr91920.c b/gcc/testsuite/c-c++-common/gomp/pr91920.c new file mode 100644 index 0000000..604fd59 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr91920.c @@ -0,0 +1,19 @@ +/* PR middle-end/91920 */ + +void bar (float *); + +void +foo (void) +{ + int i; + float f[3] = { 0.0f, 0.0f, 0.0f }; +#pragma omp parallel for default(none) reduction(+:f[:3]) + for (i = 0; i < 1000; i++) + { + int j; + float k[3] = { 0.25f, 0.5f, 0.75f }; + for (j = 0; j < 3; j++) + f[j] += k[j]; + } + bar (f); +} -- cgit v1.1 From 59bc434a3327ce58f7afcd1e9209eeb2da714960 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 27 Sep 2019 22:14:24 +0200 Subject: re PR c++/88203 (assert does not compile with OpenMP's pragma omp parallel for default(none)) PR c++/88203 c-family/ * c-common.h (c_omp_predefined_variable): Declare. * c-omp.c (c_omp_predefined_variable): New function. (c_omp_predetermined_sharing): Return OMP_CLAUSE_DEFAULT_SHARED for predefined variables. c/ * c-parser.c (c_parser_predefined_identifier): New function. (c_parser_postfix_expression): Use it. (c_parser_omp_variable_list): Parse predefined identifiers. * c-typeck.c (c_finish_omp_clauses): Allow predefined variables in shared and firstprivate clauses, even when they are predetermined shared. cp/ * parser.c (cp_parser_omp_var_list_no_open): Parse predefined variables. * semantics.c (finish_omp_clauses): Allow predefined variables in shared and firstprivate clauses, even when they are predetermined shared. * cp-gimplify.c (cxx_omp_predetermined_sharing_1): Return OMP_CLAUSE_DEFAULT_SHARED for predefined variables. testsuite/ * c-c++-common/gomp/pr88203-1.c: New test. * c-c++-common/gomp/pr88203-2.c: New test. * c-c++-common/gomp/pr88203-3.c: New test. From-SVN: r276212 --- gcc/c-family/ChangeLog | 8 +++ gcc/c-family/c-common.h | 1 + gcc/c-family/c-omp.c | 22 ++++++ gcc/c/ChangeLog | 10 +++ gcc/c/c-parser.c | 104 ++++++++++++++++++---------- gcc/c/c-typeck.c | 7 ++ gcc/cp/ChangeLog | 11 +++ gcc/cp/cp-gimplify.c | 3 + gcc/cp/parser.c | 8 +++ gcc/cp/semantics.c | 7 ++ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/c-c++-common/gomp/pr88203-1.c | 61 ++++++++++++++++ gcc/testsuite/c-c++-common/gomp/pr88203-2.c | 65 +++++++++++++++++ gcc/testsuite/c-c++-common/gomp/pr88203-3.c | 28 ++++++++ 14 files changed, 302 insertions(+), 38 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/pr88203-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/pr88203-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/pr88203-3.c (limited to 'gcc') diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 7b10957..9334ed5 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,11 @@ +2019-09-27 Jakub Jelinek + + PR c++/88203 + * c-common.h (c_omp_predefined_variable): Declare. + * c-omp.c (c_omp_predefined_variable): New function. + (c_omp_predetermined_sharing): Return OMP_CLAUSE_DEFAULT_SHARED + for predefined variables. + 2019-09-27 Richard Sandiford * c-common.h (build_function_call_vec): Take the original diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c1554f3..1e13aaa 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1187,6 +1187,7 @@ extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask, tree, tree *); extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); extern void c_omp_declare_simd_clauses_to_decls (tree, tree); +extern bool c_omp_predefined_variable (tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); /* Return next tree in the chain for chain_next walking of tree nodes. */ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 10f7c4e..0048289 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -2083,6 +2083,25 @@ c_omp_declare_simd_clauses_to_decls (tree fndecl, tree clauses) } } +/* Return true for __func__ and similar function-local predefined + variables (which are in OpenMP predetermined shared, allowed in + shared/firstprivate clauses). */ + +bool +c_omp_predefined_variable (tree decl) +{ + if (VAR_P (decl) + && DECL_ARTIFICIAL (decl) + && TREE_READONLY (decl) + && TREE_STATIC (decl) + && DECL_NAME (decl) + && (DECL_NAME (decl) == ridpointers[RID_C99_FUNCTION_NAME] + || DECL_NAME (decl) == ridpointers[RID_FUNCTION_NAME] + || DECL_NAME (decl) == ridpointers[RID_PRETTY_FUNCTION_NAME])) + return true; + return false; +} + /* True if OpenMP sharing attribute of DECL is predetermined. */ enum omp_clause_default_kind @@ -2096,5 +2115,8 @@ c_omp_predetermined_sharing (tree decl) && INTEGRAL_TYPE_P (TREE_TYPE (decl))) return OMP_CLAUSE_DEFAULT_SHARED; + if (c_omp_predefined_variable (decl)) + return OMP_CLAUSE_DEFAULT_SHARED; + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 718e5b8..fa0bbc8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,13 @@ +2019-09-27 Jakub Jelinek + + PR c++/88203 + * c-parser.c (c_parser_predefined_identifier): New function. + (c_parser_postfix_expression): Use it. + (c_parser_omp_variable_list): Parse predefined identifiers. + * c-typeck.c (c_finish_omp_clauses): Allow predefined variables + in shared and firstprivate clauses, even when they are predetermined + shared. + 2019-09-27 Richard Sandiford * c-typeck.c (build_function_call_vec): Take the original function diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6070502..c8afab2 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -8049,6 +8049,41 @@ enum tgmath_parm_kind tgmath_fixed, tgmath_real, tgmath_complex }; +/* Helper function for c_parser_postfix_expression. Parse predefined + identifiers. */ + +static struct c_expr +c_parser_predefined_identifier (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_FUNCTION_NAME: + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " + "identifier", "__FUNCTION__"); + break; + case RID_PRETTY_FUNCTION_NAME: + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " + "identifier", "__PRETTY_FUNCTION__"); + break; + case RID_C99_FUNCTION_NAME: + pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support " + "%<__func__%> predefined identifier"); + break; + default: + gcc_unreachable (); + } + + struct c_expr expr; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, + c_parser_peek_token (parser)->value); + set_c_expr_source_range (&expr, loc, loc); + c_parser_consume_token (parser); + return expr; +} + /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2, C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to call c_parser_postfix_expression_after_paren_type on encountering them. @@ -8269,31 +8304,9 @@ c_parser_postfix_expression (c_parser *parser) switch (c_parser_peek_token (parser)->keyword) { case RID_FUNCTION_NAME: - pedwarn (loc, OPT_Wpedantic, "ISO C does not support " - "%<__FUNCTION__%> predefined identifier"); - expr.value = fname_decl (loc, - c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); - break; case RID_PRETTY_FUNCTION_NAME: - pedwarn (loc, OPT_Wpedantic, "ISO C does not support " - "%<__PRETTY_FUNCTION__%> predefined identifier"); - expr.value = fname_decl (loc, - c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); - break; case RID_C99_FUNCTION_NAME: - pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support " - "%<__func__%> predefined identifier"); - expr.value = fname_decl (loc, - c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); + expr = c_parser_predefined_identifier (parser); break; case RID_VA_ARG: { @@ -11997,15 +12010,9 @@ c_parser_omp_variable_list (c_parser *parser, { auto_vec tokens; unsigned int tokens_avail = 0; + bool first = true; - if (kind != OMP_CLAUSE_DEPEND - && (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID)) - c_parser_error (parser, "expected identifier"); - - while (kind == OMP_CLAUSE_DEPEND - || (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID)) + while (1) { bool array_section_p = false; if (kind == OMP_CLAUSE_DEPEND) @@ -12026,6 +12033,7 @@ c_parser_omp_variable_list (c_parser *parser, break; c_parser_consume_token (parser); + first = false; continue; } @@ -12076,16 +12084,35 @@ c_parser_omp_variable_list (c_parser *parser, parser->tokens_avail = tokens.length (); } - tree t = lookup_name (c_parser_peek_token (parser)->value); + tree t = NULL_TREE; - if (t == NULL_TREE) + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) { - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - t = error_mark_node; - } + t = lookup_name (c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); + if (t == NULL_TREE) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_KEYWORD) + && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME + || (c_parser_peek_token (parser)->keyword + == RID_PRETTY_FUNCTION_NAME) + || (c_parser_peek_token (parser)->keyword + == RID_C99_FUNCTION_NAME))) + t = c_parser_predefined_identifier (parser).value; + else + { + if (first) + c_parser_error (parser, "expected identifier"); + break; + } if (t == error_mark_node) ; @@ -12223,6 +12250,7 @@ c_parser_omp_variable_list (c_parser *parser, break; c_parser_consume_token (parser); + first = false; } return list; diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index cc13fdc..c733950 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -14822,6 +14822,13 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_DEFAULT_UNSPECIFIED: break; case OMP_CLAUSE_DEFAULT_SHARED: + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + && c_omp_predefined_variable (t)) + /* The __func__ variable and similar function-local + predefined variables may be listed in a shared or + firstprivate clause. */ + break; share_name = "shared"; break; case OMP_CLAUSE_DEFAULT_PRIVATE: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 20f543e..8ea2a84 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2019-09-27 Jakub Jelinek + + PR c++/88203 + * parser.c (cp_parser_omp_var_list_no_open): Parse predefined + variables. + * semantics.c (finish_omp_clauses): Allow predefined variables in + shared and firstprivate clauses, even when they are predetermined + shared. + * cp-gimplify.c (cxx_omp_predetermined_sharing_1): Return + OMP_CLAUSE_DEFAULT_SHARED for predefined variables. + 2019-09-27 Jason Merrill * constexpr.c (cxx_fold_indirect_ref): Use similar_type_p. diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 49fa47a..8bda736 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2055,6 +2055,9 @@ cxx_omp_predetermined_sharing_1 (tree decl) tree ctx = CP_DECL_CONTEXT (decl); if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx)) return OMP_CLAUSE_DEFAULT_SHARED; + + if (c_omp_predefined_variable (decl)) + return OMP_CLAUSE_DEFAULT_SHARED; } /* this may not be specified in data-sharing clauses, still we need diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 44082f7..018a03d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -32736,6 +32736,14 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, decl = TREE_OPERAND (decl, 0); cp_lexer_consume_token (parser->lexer); } + else if (cp_parser_is_keyword (token, RID_FUNCTION_NAME) + || cp_parser_is_keyword (token, RID_PRETTY_FUNCTION_NAME) + || cp_parser_is_keyword (token, RID_C99_FUNCTION_NAME)) + { + cp_id_kind idk; + decl = cp_parser_primary_expression (parser, false, false, false, + &idk); + } else { name = cp_parser_id_expression (parser, /*template_p=*/false, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 7563248..5a8c4d2 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7967,6 +7967,13 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_DEFAULT_UNSPECIFIED: break; case OMP_CLAUSE_DEFAULT_SHARED: + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + && c_omp_predefined_variable (t)) + /* The __func__ variable and similar function-local predefined + variables may be listed in a shared or firstprivate + clause. */ + break; if (VAR_P (t) && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE && TREE_STATIC (t) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9aee20c..163e38d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-09-27 Jakub Jelinek + PR c++/88203 + * c-c++-common/gomp/pr88203-1.c: New test. + * c-c++-common/gomp/pr88203-2.c: New test. + * c-c++-common/gomp/pr88203-3.c: New test. + PR middle-end/91920 * c-c++-common/gomp/pr91920.c: New test. diff --git a/gcc/testsuite/c-c++-common/gomp/pr88203-1.c b/gcc/testsuite/c-c++-common/gomp/pr88203-1.c new file mode 100644 index 0000000..54a6864 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr88203-1.c @@ -0,0 +1,61 @@ +/* PR c++/88203 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99" { target c } } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +void foo (const char *); +#pragma omp declare target to (foo) + +void +f1 (void) +{ + #pragma omp parallel default(none) + foo (__func__); +} + +void +f2 (void) +{ + #pragma omp parallel default(none) shared(__func__) + foo (__func__); +} + +void +f3 (void) +{ + #pragma omp parallel default(none) firstprivate(__func__) + foo (__func__); +} + +void +f4 (void) +{ + foo (__func__); + #pragma omp parallel default(none) + foo (__func__); +} + +void +f5 (void) +{ + foo (__func__); + #pragma omp parallel default(none) shared(__func__) + foo (__func__); +} + +void +f6 (void) +{ + foo (__func__); + #pragma omp parallel default(none) firstprivate(__func__) + foo (__func__); +} + +void +f7 (void) +{ + #pragma omp target map(to: __func__) + foo (__func__); + #pragma omp task depend(inout:__func__) + foo (__func__); +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr88203-2.c b/gcc/testsuite/c-c++-common/gomp/pr88203-2.c new file mode 100644 index 0000000..90c4a72 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr88203-2.c @@ -0,0 +1,65 @@ +/* PR c++/88203 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=gnu99" { target c } } */ +/* { dg-additional-options "-std=gnu++11" { target c++ } } */ + +void foo (const char *, const char *); +#pragma omp declare target to (foo) + +void +f1 (void) +{ + #pragma omp parallel default(none) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f2 (void) +{ + #pragma omp parallel default(none) shared(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) shared(__FUNCTION__) firstprivate(__PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f3 (void) +{ + #pragma omp parallel default(none) firstprivate(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) firstprivate(__FUNCTION__), shared(__PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f4 (void) +{ + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f5 (void) +{ + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) shared(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f6 (void) +{ + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) firstprivate(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f7 (void) +{ + #pragma omp target map(to: __FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp task depend(inout:__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr88203-3.c b/gcc/testsuite/c-c++-common/gomp/pr88203-3.c new file mode 100644 index 0000000..6a9585d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr88203-3.c @@ -0,0 +1,28 @@ +/* PR c++/88203 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99" { target c } } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +void foo (const char *); +#pragma omp declare target to (foo) + +void +f1 (void) +{ + #pragma omp parallel for lastprivate (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'lastprivate'" } */ + for (int i = 0; i < 2; i++) + foo (__func__); + #pragma omp parallel private (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'private'" } */ + foo (__func__); +} + +void +f2 (void) +{ + foo (__func__); + #pragma omp parallel default(none) private (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'private'" } */ + foo (__func__); + #pragma omp parallel for default(none) lastprivate (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'lastprivate'" } */ + for (int i = 0; i < 2; i++) + foo (__func__); +} -- cgit v1.1 From e9085da52881d6d4e1f7cce485b0fd0cb7567579 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 27 Sep 2019 21:24:42 +0000 Subject: Regenerate `configure' scripts for `uclinuxfdpiceabi' libtool.m4 update A change made with r275564 ("[ARM/FDPIC v6 02/24] [ARM] FDPIC: Handle arm*-*-uclinuxfdpiceabi in configure scripts") to libtool.m4 has not regenerated all the `configure' scripts affected. Fix it. gcc/ * configure: Regenerate. libatomic/ * configure: Regenerate. libbacktrace/ * configure: Regenerate. libcc1/ * configure: Regenerate. libffi/ * configure: Regenerate. libgfortran/ * configure: Regenerate. libgomp/ * configure: Regenerate. libhsail-rt/ * configure: Regenerate. libitm/ * configure: Regenerate. libobjc/ * configure: Regenerate. liboffloadmic/ * configure: Regenerate. libphobos/ * configure: Regenerate. libquadmath/ * configure: Regenerate. libsanitizer/ * configure: Regenerate. libssp/ * configure: Regenerate. libstdc++-v3/ * configure: Regenerate. libvtv/ * configure: Regenerate. lto-plugin/ * configure: Regenerate. zlib/ * configure: Regenerate. From-SVN: r276213 --- gcc/ChangeLog | 4 ++++ gcc/configure | 22 ++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 29f56d5..ae7c8dd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2019-09-27 Maciej W. Rozycki + + * configure: Regenerate. + 2019-09-27 Jakub Jelinek PR middle-end/91920 diff --git a/gcc/configure b/gcc/configure index 22cf194..f90472d 100755 --- a/gcc/configure +++ b/gcc/configure @@ -13783,7 +13783,7 @@ irix5* | irix6* | nonstopux*) ;; # This must be Linux ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu) +linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) lt_cv_deplibs_check_method=pass_all ;; @@ -16594,7 +16594,7 @@ _LT_EOF archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in @@ -18125,7 +18125,12 @@ linux*oldld* | linux*aout* | linux*coff*) ;; # This must be Linux ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu) + +# uclinux* changes (here and below) have been submitted to the libtool +# project, but have not yet been accepted: they are GCC-local changes +# for the time being. (See +# https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) version_type=linux need_lib_prefix=no need_version=no @@ -18814,7 +18819,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18817 "configure" +#line 18822 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18920,7 +18925,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18923 "configure" +#line 18928 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -21785,7 +21790,12 @@ linux*oldld* | linux*aout* | linux*coff*) ;; # This must be Linux ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu) + +# uclinux* changes (here and below) have been submitted to the libtool +# project, but have not yet been accepted: they are GCC-local changes +# for the time being. (See +# https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) version_type=linux need_lib_prefix=no need_version=no -- cgit v1.1 From 222e8cb6ca0110e4311be640459d4cb790a6b83d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 28 Sep 2019 00:16:24 +0000 Subject: Daily bump. From-SVN: r276227 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index cdcc7ba..2087f60 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190927 +20190928 -- cgit v1.1 From 6e81d34ea2d144cf48ec89cc9df8c4a479d675ec Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 28 Sep 2019 00:16:57 +0000 Subject: compiler: resolve importing ambiguity for more complex function calls Tweak the exporter for inlinable function bodies to work around a problem with importing of function calls whose function expressions are not simple function names. In the bug in question, the function body exporter was writing out a function call of the form (*(*FuncTyp)(var))(arg) which produced an export data representation of *$convert(, var)(x) which is hard to parse unambiguously. Fix: change the export data emitter to introduce parens around the function expression for more complex calls. Testcase for this bug is in CL 197217. Fixes golang/go#34503. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/197122 From-SVN: r276228 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 1e6ca6f..3f2c3dc 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -9112ea664ed9ee5f108158a913812adaf03edf6e +10a1671d94ddc0c39f2f4b039e5ea33358f414c0 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 7d8963e..a72ba24 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -12373,7 +12373,12 @@ Call_expression::do_inlining_cost() const void Call_expression::do_export(Export_function_body* efb) const { + bool simple_call = (this->fn_->func_expression() != NULL); + if (!simple_call) + efb->write_c_string("("); this->fn_->export_expression(efb); + if (!simple_call) + efb->write_c_string(")"); this->export_arguments(efb); } -- cgit v1.1 From b164999002575eaca7f032c2374d2a04531be72f Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 28 Sep 2019 16:42:14 +0930 Subject: Fix endian issue in pr91656 testcases PR testsuite/91676 PR rtl-optimization/91656 * gcc.dg/torture/pr91656-1.c: Correct for big and pdp endian. * gcc.dg/torture/pr91656-2.c: Likewise. * gcc.dg/torture/pr91656-3.c: Likewise. From-SVN: r276236 --- gcc/testsuite/ChangeLog | 8 ++++++++ gcc/testsuite/gcc.dg/torture/pr91656-1.c | 10 ++++++++++ gcc/testsuite/gcc.dg/torture/pr91656-2.c | 10 ++++++++++ gcc/testsuite/gcc.dg/torture/pr91656-3.c | 7 +++++++ 4 files changed, 35 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 163e38d..8fadb03e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-09-28 Alan Modra + + PR testsuite/91676 + PR rtl-optimization/91656 + * gcc.dg/torture/pr91656-1.c: Correct for big and pdp endian. + * gcc.dg/torture/pr91656-2.c: Likewise. + * gcc.dg/torture/pr91656-3.c: Likewise. + 2019-09-27 Jakub Jelinek PR c++/88203 diff --git a/gcc/testsuite/gcc.dg/torture/pr91656-1.c b/gcc/testsuite/gcc.dg/torture/pr91656-1.c index 6c1e73c7..fae17de 100644 --- a/gcc/testsuite/gcc.dg/torture/pr91656-1.c +++ b/gcc/testsuite/gcc.dg/torture/pr91656-1.c @@ -6,7 +6,17 @@ int a, b, c, d, e; static __attribute__ ((__noipa__)) int foo (int i) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ __builtin_memmove (&i, &e, 1); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + __builtin_memmove ((char *) &i + sizeof (i) - 1, + (char *) &e + sizeof (e) - 1, 1); +#elif __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__ + __builtin_memmove ((char *) &i + sizeof (i) - 2, + (char *) &e + sizeof (e) - 2, 1); +#else +#error "endian unknown?" +#endif if (a > 0) i /= e; e /= 5; diff --git a/gcc/testsuite/gcc.dg/torture/pr91656-2.c b/gcc/testsuite/gcc.dg/torture/pr91656-2.c index 90374be..29a619b 100644 --- a/gcc/testsuite/gcc.dg/torture/pr91656-2.c +++ b/gcc/testsuite/gcc.dg/torture/pr91656-2.c @@ -12,7 +12,17 @@ d (u16 g) { u64 f = __builtin_bswap64 (c); f = g == a; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ __builtin_memmove (&f, &e, 1); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + __builtin_memmove ((char *) &f + sizeof (f) - 1, + (char *) &e + sizeof (e) - 1, 1); +#elif __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__ + __builtin_memmove ((char *) &f + sizeof (f) - 2, + (char *) &e + sizeof (e) - 2, 1); +#else +#error "endian unknown?" +#endif e >>= b; return a + f; } diff --git a/gcc/testsuite/gcc.dg/torture/pr91656-3.c b/gcc/testsuite/gcc.dg/torture/pr91656-3.c index 8e65d24..f84e51a 100644 --- a/gcc/testsuite/gcc.dg/torture/pr91656-3.c +++ b/gcc/testsuite/gcc.dg/torture/pr91656-3.c @@ -10,7 +10,14 @@ int d (u16 e, u64 f) { b |= e; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ __builtin_memset (&f, e, 2); +#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ \ + || __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__) + __builtin_memset ((char *) &f + sizeof (f) - 2, e, 2); +#else +#error "endian unknown?" +#endif a = (u16) - e >= 2 ? : __builtin_popcountll (f); return a + c; } -- cgit v1.1 From 2664bcb87601c9f77c61dea1583166c9dbb135a3 Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Sat, 28 Sep 2019 08:33:31 +0000 Subject: re PR target/80672 (gcc/config/sh/sh.c:716: prefer compare to find.) gcc/ 2019-09-28 Oleg Endo PR target/80672 * config/sh/sh.c (parse_validate_atomic_model_option): Use std::string::compare instead of std::string::find. From-SVN: r276240 --- gcc/ChangeLog | 6 ++++++ gcc/config/sh/sh.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ae7c8dd..459fbe5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-28 Oleg Endo + + PR target/80672 + * config/sh/sh.c (parse_validate_atomic_model_option): Use + std::string::compare instead of std::string::find. + 2019-09-27 Maciej W. Rozycki * configure: Regenerate. diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index e3eea10..5c4598f 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -734,7 +734,7 @@ got_mode_name:; { if (tokens[i] == "strict") ret.strict = true; - else if (tokens[i].find ("gbr-offset=") == 0) + else if (!tokens[i].compare (0, strlen ("gbr-offset="), "gbr-offset=")) { std::string offset_str = tokens[i].substr (strlen ("gbr-offset=")); ret.tcb_gbr_offset = integral_argument (offset_str.c_str ()); -- cgit v1.1 From c57a385006790d814e1f9ac4f4235a787c6c6e30 Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Sat, 28 Sep 2019 08:53:27 +0000 Subject: re PR target/86805 (sh port needs updating for CVE-2017-5753) gcc/ 2019-09-28 Oleg Endo PR target/86805 * config/sh/sh.c (TARGET_HAVE_SPECULATION_SAFE_VALUE): Define. From-SVN: r276244 --- gcc/ChangeLog | 5 +++++ gcc/config/sh/sh.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 459fbe5..0dd3720 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-09-28 Oleg Endo + PR target/86805 + * config/sh/sh.c (TARGET_HAVE_SPECULATION_SAFE_VALUE): Define. + +2019-09-28 Oleg Endo + PR target/80672 * config/sh/sh.c (parse_validate_atomic_model_option): Use std::string::compare instead of std::string::find. diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 5c4598f..34c4c8f 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -661,6 +661,9 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_CONSTANT_ALIGNMENT #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings +#undef TARGET_HAVE_SPECULATION_SAFE_VALUE +#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed + struct gcc_target targetm = TARGET_INITIALIZER; -- cgit v1.1 From 028c9b3be468a5dbd27e3190b14d60b04ea02ff4 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Sat, 28 Sep 2019 11:36:36 +0000 Subject: PR c++/91923 - failure-to-SFINAE with class type NTTP in C++17. * pt.c (invalid_nontype_parm_type_p): Only emit errors when tf_error. * g++.dg/cpp0x/nontype5.C: New test. From-SVN: r276248 --- gcc/cp/ChangeLog | 6 ++++++ gcc/cp/pt.c | 5 +++-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp0x/nontype5.C | 17 +++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/nontype5.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8ea2a84..895ebd9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-09-28 Marek Polacek + + PR c++/91923 - failure-to-SFINAE with class type NTTP in C++17. + * pt.c (invalid_nontype_parm_type_p): Only emit errors when + tf_error. + 2019-09-27 Jakub Jelinek PR c++/88203 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5a2dfbb..44b3618 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -25232,8 +25232,9 @@ invalid_nontype_parm_type_p (tree type, tsubst_flags_t complain) { if (cxx_dialect < cxx2a) { - error ("non-type template parameters of class type only available " - "with %<-std=c++2a%> or %<-std=gnu++2a%>"); + if (complain & tf_error) + error ("non-type template parameters of class type only available " + "with %<-std=c++2a%> or %<-std=gnu++2a%>"); return true; } if (dependent_type_p (type)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8fadb03e..617fc99 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-28 Marek Polacek + + PR c++/91923 - failure-to-SFINAE with class type NTTP in C++17. + * g++.dg/cpp0x/nontype5.C: New test. + 2019-09-28 Alan Modra PR testsuite/91676 diff --git a/gcc/testsuite/g++.dg/cpp0x/nontype5.C b/gcc/testsuite/g++.dg/cpp0x/nontype5.C new file mode 100644 index 0000000..c311345 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nontype5.C @@ -0,0 +1,17 @@ +// PR c++/91923 - failure-to-SFINAE with class type NTTP in C++17. +// { dg-do compile { target c++11 } } + +template +constexpr bool is_integral_(...) { + return false; +} +template +constexpr bool is_integral_(long) { + return true; +} + +static_assert(is_integral_(42), ""); +static_assert(!is_integral_(42), ""); + +struct S {}; +static_assert(!is_integral_(42), ""); -- cgit v1.1 From 7cf66a2dbe8017f59d2b28e8db3de8067efcc43e Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Sat, 28 Sep 2019 11:46:33 +0000 Subject: PR c++/91921 - stray warning with -Woverloaded-virtual. * class.c (warn_hidden): Only emit the second part of -Woverloaded-virtual if the first part was issued. Use inform instead warning_at. * g++.dg/warn/Woverloaded-2.C: New. * g++.dg/warn/Woverloaded-2.h: New. * g++.dg/warn/pr61945.C: Turn dg-warning into dg-message. * g++.old-deja/g++.mike/warn6.C: Likewise. * g++.old-deja/g++.warn/virt1.C: Likewise. From-SVN: r276249 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/class.c | 10 +++++----- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/g++.dg/warn/Woverloaded-2.C | 9 +++++++++ gcc/testsuite/g++.dg/warn/Woverloaded-2.h | 6 ++++++ gcc/testsuite/g++.dg/warn/pr61945.C | 2 +- gcc/testsuite/g++.old-deja/g++.mike/warn6.C | 6 +++--- gcc/testsuite/g++.old-deja/g++.warn/virt1.C | 2 +- 8 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Woverloaded-2.C create mode 100644 gcc/testsuite/g++.dg/warn/Woverloaded-2.h (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 895ebd9..c30d704 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,10 @@ 2019-09-28 Marek Polacek + PR c++/91921 - stray warning with -Woverloaded-virtual. + * class.c (warn_hidden): Only emit the second part of + -Woverloaded-virtual if the first part was issued. Use inform instead + warning_at. + PR c++/91923 - failure-to-SFINAE with class type NTTP in C++17. * pt.c (invalid_nontype_parm_type_p): Only emit errors when tf_error. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 59a3d1a..3838f76 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2914,12 +2914,12 @@ warn_hidden (tree t) FOR_EACH_VEC_ELT (base_fndecls, j, base_fndecl) if (base_fndecl) { + auto_diagnostic_group d; /* Here we know it is a hider, and no overrider exists. */ - warning_at (location_of (base_fndecl), - OPT_Woverloaded_virtual, - "%qD was hidden", base_fndecl); - warning_at (location_of (fns), - OPT_Woverloaded_virtual, " by %qD", fns); + if (warning_at (location_of (base_fndecl), + OPT_Woverloaded_virtual, + "%qD was hidden", base_fndecl)) + inform (location_of (fns), " by %qD", fns); } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 617fc99..104a83b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2019-09-28 Marek Polacek + PR c++/91921 - stray warning with -Woverloaded-virtual. + * g++.dg/warn/Woverloaded-2.C: New. + * g++.dg/warn/Woverloaded-2.h: New. + * g++.dg/warn/pr61945.C: Turn dg-warning into dg-message. + * g++.old-deja/g++.mike/warn6.C: Likewise. + * g++.old-deja/g++.warn/virt1.C: Likewise. + PR c++/91923 - failure-to-SFINAE with class type NTTP in C++17. * g++.dg/cpp0x/nontype5.C: New test. diff --git a/gcc/testsuite/g++.dg/warn/Woverloaded-2.C b/gcc/testsuite/g++.dg/warn/Woverloaded-2.C new file mode 100644 index 0000000..84d65de --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Woverloaded-2.C @@ -0,0 +1,9 @@ +// PR c++/91921 - stray warning with -Woverloaded-virtual. +// { dg-options "-Woverloaded-virtual" } + +#include "Woverloaded-2.h" + +struct B : A +{ + void f(int); +}; diff --git a/gcc/testsuite/g++.dg/warn/Woverloaded-2.h b/gcc/testsuite/g++.dg/warn/Woverloaded-2.h new file mode 100644 index 0000000..b9e15b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Woverloaded-2.h @@ -0,0 +1,6 @@ +#pragma GCC system_header + +struct A +{ + virtual void f(); +}; diff --git a/gcc/testsuite/g++.dg/warn/pr61945.C b/gcc/testsuite/g++.dg/warn/pr61945.C index 5584d84..3d40581 100644 --- a/gcc/testsuite/g++.dg/warn/pr61945.C +++ b/gcc/testsuite/g++.dg/warn/pr61945.C @@ -7,5 +7,5 @@ class A { }; class B : A { template - void foo (); // { dg-warning "by .B::foo\\(\\)." } + void foo (); // { dg-message "by .B::foo\\(\\)." } }; diff --git a/gcc/testsuite/g++.old-deja/g++.mike/warn6.C b/gcc/testsuite/g++.old-deja/g++.mike/warn6.C index 9c694d6..26759cf 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/warn6.C +++ b/gcc/testsuite/g++.old-deja/g++.mike/warn6.C @@ -30,13 +30,13 @@ struct D : public B, public B2, public B3 { virtual void bothsame(int); - virtual void bothdiff(int); // { dg-warning "" } + virtual void bothdiff(int); // { dg-message "" } virtual void both2same(int); virtual void both2same(float); - virtual void both12diff(int); // { dg-warning "" } + virtual void both12diff(int); // { dg-message "" } - virtual void bothfardiff(int); // { dg-warning "" } + virtual void bothfardiff(int); // { dg-message "" } }; diff --git a/gcc/testsuite/g++.old-deja/g++.warn/virt1.C b/gcc/testsuite/g++.old-deja/g++.warn/virt1.C index 4550dd5..c68de8a 100644 --- a/gcc/testsuite/g++.old-deja/g++.warn/virt1.C +++ b/gcc/testsuite/g++.old-deja/g++.warn/virt1.C @@ -6,5 +6,5 @@ struct A { }; struct B: public A { - void f(int); // { dg-warning "" } by this + void f(int); // { dg-message "" } by this }; -- cgit v1.1 From 406c9a1173f79dc0fb3231edb51690c1dd73f6a0 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Sat, 28 Sep 2019 15:35:37 +0000 Subject: PR c++/91889 - follow-up fix for DR 2352. * call.c (involves_qualification_conversion_p): New function. (direct_reference_binding): Build a ck_qual if the conversion would involve a qualification conversion. (convert_like_real): Strip the conversion created by the ck_qual in direct_reference_binding. * g++.dg/cpp0x/ref-bind3.C: Add dg-error. * g++.dg/cpp0x/ref-bind4.C: New test. * g++.dg/cpp0x/ref-bind5.C: New test. * g++.dg/cpp0x/ref-bind6.C: New test. * g++.old-deja/g++.pt/spec35.C: Revert earlier change. From-SVN: r276251 --- gcc/cp/ChangeLog | 7 ++++ gcc/cp/call.c | 46 ++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 7 ++++ gcc/testsuite/g++.dg/cpp0x/ref-bind3.C | 24 ++++++------- gcc/testsuite/g++.dg/cpp0x/ref-bind4.C | 56 ++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/ref-bind5.C | 17 +++++++++ gcc/testsuite/g++.dg/cpp0x/ref-bind6.C | 12 +++++++ gcc/testsuite/g++.old-deja/g++.pt/spec35.C | 8 ++--- 8 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind5.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-bind6.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c30d704..a1e520a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2019-09-28 Marek Polacek + PR c++/91889 - follow-up fix for DR 2352. + * call.c (involves_qualification_conversion_p): New function. + (direct_reference_binding): Build a ck_qual if the conversion + would involve a qualification conversion. + (convert_like_real): Strip the conversion created by the ck_qual + in direct_reference_binding. + PR c++/91921 - stray warning with -Woverloaded-virtual. * class.c (warn_hidden): Only emit the second part of -Woverloaded-virtual if the first part was issued. Use inform instead diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 5ccf3b8..56dcbd3 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1555,6 +1555,27 @@ reference_compatible_p (tree t1, tree t2) return true; } +/* Return true if converting FROM to TO would involve a qualification + conversion. */ + +static bool +involves_qualification_conversion_p (tree to, tree from) +{ + /* If we're not convering a pointer to another one, we won't get + a qualification conversion. */ + if (!((TYPE_PTR_P (to) && TYPE_PTR_P (from)) + || (TYPE_PTRDATAMEM_P (to) && TYPE_PTRDATAMEM_P (from)))) + return false; + + conversion *conv = standard_conversion (to, from, NULL_TREE, + /*c_cast_p=*/false, 0, tf_none); + for (conversion *t = conv; t; t = next_conversion (t)) + if (t->kind == ck_qual) + return true; + + return false; +} + /* A reference of the indicated TYPE is being bound directly to the expression represented by the implicit conversion sequence CONV. Return a conversion sequence for this binding. */ @@ -1598,6 +1619,19 @@ direct_reference_binding (tree type, conversion *conv) That way, convert_like knows not to generate a temporary. */ conv->need_temporary_p = false; } + else if (involves_qualification_conversion_p (t, conv->type)) + /* Represent the qualification conversion. After DR 2352 + #1 and #2 were indistinguishable conversion sequences: + + void f(int*); // #1 + void f(const int* const &); // #2 + void g(int* p) { f(p); } + + because the types "int *" and "const int *const" are + reference-related and we were binding both directly and they + had the same rank. To break it up, we add a ck_qual under the + ck_ref_bind so that conversion sequence ranking chooses #1. */ + conv = build_conv (ck_qual, t, conv); return build_conv (ck_ref_bind, type, conv); } @@ -7342,6 +7376,18 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, { tree ref_type = totype; + /* direct_reference_binding might have inserted a ck_qual under + this ck_ref_bind for the benefit of conversion sequence ranking. + Ignore the conversion; we'll create our own below. */ + if (next_conversion (convs)->kind == ck_qual) + { + gcc_assert (same_type_p (TREE_TYPE (expr), + next_conversion (convs)->type)); + /* Strip the cast created by the ck_qual; cp_build_addr_expr + below expects an lvalue. */ + STRIP_NOPS (expr); + } + if (convs->bad_p && !next_conversion (convs)->bad_p) { tree extype = TREE_TYPE (expr); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 104a83b..ecdce9b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2019-09-28 Marek Polacek + PR c++/91889 - follow-up fix for DR 2352. + * g++.dg/cpp0x/ref-bind3.C: Add dg-error. + * g++.dg/cpp0x/ref-bind4.C: New test. + * g++.dg/cpp0x/ref-bind5.C: New test. + * g++.dg/cpp0x/ref-bind6.C: New test. + * g++.old-deja/g++.pt/spec35.C: Revert earlier change. + PR c++/91921 - stray warning with -Woverloaded-virtual. * g++.dg/warn/Woverloaded-2.C: New. * g++.dg/warn/Woverloaded-2.h: New. diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C index 16e1bfe..b2c85ec 100644 --- a/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind3.C @@ -1,22 +1,18 @@ // PR c++/91844 - Implement CWG 2352, Similar types and reference binding. // { dg-do compile { target c++11 } } -template int f (const T *const &); // (1) -template int f (T *const &); // (2) -template int f (T *); // (3) - -/* Before CWG 2352, (2) was a better match than (1), but (2) and (3) were - equally good, so there was an ambiguity. (2) was better than (1) because - (1) required a qualification conversion whereas (2) didn't. But with this - CWG, (1) no longer requires a qualification conversion, because the types - "const int* const" and "int *" are now considered reference-related and we - bind directly, and (1) is more specialized than (2). And (1) is also a - better match than (3). */ +template int f (const T *const &); // 1 +template int f (T *const &); // 2 +template int f (T *); // 3 +/* There's an ambiguity: (2) is a better match than (1) because + (1) requires a qualification conversion whereas (2) doesn't, but + (2) and (3) are indistinguishable conversion sequences. */ + void g (int *p, const int *q, const int *const r) { - f (p); // calls (1) - f (q); // calls (1) - f (r); // calls (1) + f (p); // { dg-error "call of overloaded" } + f (q); + f (r); } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C new file mode 100644 index 0000000..85ac9fb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind4.C @@ -0,0 +1,56 @@ +// PR c++/91889 - follow-up fix for DR 2352. +// { dg-do compile { target c++11 } } + +int i; + +void f1 (int *); +void f1 (const int *const &); + +void f2 (int *); +void f2 (const int *&); + +void f3 (const int *); +void f3 (int *const &); + +void f4 (int *&); +void f4 (int *const &); + +void f5 (const int *&); +void f5 (int *const &); + +void f6 (int *const &); +void f6 (const int *const &); + +void f7 (int **const); +void f7 (const int *const *const &); + +void f8 (const int *const *); +void f8 (const int *const *const &); + +void f9 (int *const *); +void f9 (const int *const *const &); + +void +g (int *p, const int *pc, const int **q) +{ + f1 (p); + f1 (pc); + f2 (p); + f2 (pc); + f3 (p); + f3 (pc); + f4 (p); + f5 (p); + f5 (pc); + f6 (p); + f6 (pc); + f7 (q); + /* [over.ics.rank] + + --S1 and S2 differ only in their qualification conversion and yield + similar types T1 and T2 (_conv.qual_), respectively, and the cv- + qualification signature of type T1 is a proper subset of the cv- + qualification signature of type T2 */ + f8 (q); + f9 (q); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind5.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind5.C new file mode 100644 index 0000000..d528b87 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind5.C @@ -0,0 +1,17 @@ +// PR c++/91889 - follow-up fix for DR 2352. +// { dg-do compile { target c++11 } } + +template struct A { typedef U *type; }; +struct B { + typedef A::type node_ptr; +}; +struct C { + typedef B::node_ptr node_ptr; + typedef A::type const_node_ptr; +}; +struct { + void to_value_ptr(C::node_ptr) {}; + void to_value_ptr(const C::const_node_ptr &); +} b; +C::node_ptr a; +void fn1() { b.to_value_ptr(a); } diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-bind6.C b/gcc/testsuite/g++.dg/cpp0x/ref-bind6.C new file mode 100644 index 0000000..c85a5cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-bind6.C @@ -0,0 +1,12 @@ +// PR c++/91889 - follow-up fix for DR 2352. +// { dg-do compile { target c++11 } } + +template struct A { + A(const T &); +}; + +struct { + int *m; +} a; + +void fn1() { A(a.m); } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C index 93e953d..1debf91 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C @@ -14,9 +14,9 @@ template int Foo (T &); // { dg-message "note" } candidate template int Qux (T); // { dg-message "note" } template int Qux (T const &); // { dg-message "note" } candidate -template int Bar (T const *const &); -template int Bar (T *const &); -template int Bar (T *); +template int Bar (T const *const &); // { dg-message "note" } +template int Bar (T *const &); // { dg-message "note" } candidate +template int Bar (T *); // { dg-message "note" } candidate template int Baz (T *const &); // { dg-message "note" } template int Baz (T *); // { dg-message "note" } candidate @@ -24,7 +24,7 @@ template int Baz (T *); // { dg-message "note" } candi int Baz (int const *ptr, int *ptr2) { Baz (ptr2); // { dg-error "ambiguous" } - Bar (ptr2); + Bar (ptr2); // { dg-error "ambiguous" } Foo (ptr2); // { dg-error "ambiguous" } Qux (ptr2); // { dg-error "ambiguous" } return 0; -- cgit v1.1 From 036aa59282d3084076e78216c6ba8e5291dc29f7 Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Sat, 28 Sep 2019 16:26:43 +0000 Subject: re PR fortran/91864 (ICE in gfc_check_do_variable, at fortran/parse.c:4405) 2019-09-28 Steven G. Kargl PR fortran/91864 * gcc/fortran/io.c (match_io_element): An inquiry parameter cannot be read into. * gcc/fortran/match.c (gfc_match_allocate): An inquiry parameter can be neither an allocate-object nor stat variable. (gfc_match_deallocate): An inquiry parameter cannot be deallocated. 2019-09-28 Steven G. Kargl PR fortran/91864 * gcc/testsuite/gfortran.dg/pr91864.f90 From-SVN: r276253 --- gcc/fortran/ChangeLog | 9 +++++++++ gcc/fortran/io.c | 13 +++++++++++-- gcc/fortran/match.c | 18 ++++++++++++++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/pr91864.f90 | 22 ++++++++++++++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr91864.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 1c1997f..d5a17da 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,12 @@ +2019-09-28 Steven G. Kargl + + PR fortran/91864 + * gcc/fortran/io.c (match_io_element): An inquiry parameter cannot be + read into. + * gcc/fortran/match.c (gfc_match_allocate): An inquiry parameter + can be neither an allocate-object nor stat variable. + (gfc_match_deallocate): An inquiry parameter cannot be deallocated. + 2019-09-26 Alessandro Fanfarillo * trans-array.c (structure_alloc_comps): diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c index bb64560..9ae06b1f 100644 --- a/gcc/fortran/io.c +++ b/gcc/fortran/io.c @@ -3657,7 +3657,17 @@ match_io_element (io_kind k, gfc_code **cpp) { m = gfc_match_variable (&expr, 0); if (m == MATCH_NO) - gfc_error ("Expected variable in READ statement at %C"); + { + gfc_error ("Expecting variable in READ statement at %C"); + m = MATCH_ERROR; + } + + if (m == MATCH_YES && expr->expr_type == EXPR_CONSTANT) + { + gfc_error ("Expecting variable or io-implied-do in READ statement " + "at %L", &expr->where); + m = MATCH_ERROR; + } if (m == MATCH_YES && expr->expr_type == EXPR_VARIABLE @@ -3667,7 +3677,6 @@ match_io_element (io_kind k, gfc_code **cpp) &expr->where); m = MATCH_ERROR; } - } else { diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index 9b9dbf1..83b1189 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -4242,6 +4242,12 @@ gfc_match_allocate (void) if (m == MATCH_ERROR) goto cleanup; + if (tail->expr->expr_type == EXPR_CONSTANT) + { + gfc_error ("Unexpected constant at %C"); + goto cleanup; + } + if (gfc_check_do_variable (tail->expr->symtree)) goto cleanup; @@ -4374,6 +4380,12 @@ alloc_opt_list: tmp = NULL; saw_stat = true; + if (stat->expr_type == EXPR_CONSTANT) + { + gfc_error ("STAT tag at %L cannot be a constant", &stat->where); + goto cleanup; + } + if (gfc_check_do_variable (stat->symtree)) goto cleanup; @@ -4650,6 +4662,12 @@ gfc_match_deallocate (void) if (m == MATCH_NO) goto syntax; + if (tail->expr->expr_type == EXPR_CONSTANT) + { + gfc_error ("Unexpected constant at %C"); + goto cleanup; + } + if (gfc_check_do_variable (tail->expr->symtree)) goto cleanup; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ecdce9b..8d8ba5d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-28 Steven G. Kargl + + PR fortran/91864 + * gcc/testsuite/gfortran.dg/pr91864.f90 + 2019-09-28 Marek Polacek PR c++/91889 - follow-up fix for DR 2352. diff --git a/gcc/testsuite/gfortran.dg/pr91864.f90 b/gcc/testsuite/gfortran.dg/pr91864.f90 new file mode 100644 index 0000000..a17187d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91864.f90 @@ -0,0 +1,22 @@ +program p + integer :: i + read (*,*) i%kind ! { dg-error "Expecting variable or io-implied-do" } +end + +subroutine t + integer, allocatable :: x(:) + integer :: stat + allocate (x(3), stat=stat%kind) ! { dg-error "cannot be a constant" } +end + +subroutine u + integer, allocatable :: x(:) + integer :: stat + allocate (x(3), stat%kind=stat) ! { dg-error "Unexpected constant" } +end + +subroutine v + integer, allocatable :: x(:) + integer :: stat + deallocate (x, stat%kind=stat) ! { dg-error "Unexpected constant" } +end -- cgit v1.1 From 4c59710186081ed4b2d34ccda1190d43454543db Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Sat, 28 Sep 2019 17:10:34 +0000 Subject: re PR fortran/91802 (ICE in mio_name_expr_t, at fortran/module.c:2141) 2019-09-28 Steven G. Kargl PR fortran/91802 * decl.c (attr_decl1): Check if rank+corank > 15. 2019-09-28 Steven G. Kargl PR fortran/91802 * gfortran.dg/pr91802.f90: New test. From-SVN: r276254 --- gcc/fortran/ChangeLog | 5 +++++ gcc/fortran/decl.c | 9 +++++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/pr91802.f90 | 9 +++++++++ 4 files changed, 28 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/pr91802.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d5a17da..3d40c9a 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2019-09-28 Steven G. Kargl + + PR fortran/91802 + * decl.c (attr_decl1): Check if rank+corank > 15. + 2019-09-28 Steven G. Kargl PR fortran/91864 diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 278882d..31b2336 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -8468,6 +8468,15 @@ attr_decl1 (void) goto cleanup; } + /* Check F2018:C822. */ + if (sym->attr.dimension && sym->attr.codimension + && sym->as && sym->as->rank + sym->as->corank > 15) + { + gfc_error ("rank + corank of %qs exceeds 15 at %C", sym->name); + m = MATCH_ERROR; + goto cleanup; + } + if (sym->attr.cray_pointee && sym->as != NULL) { /* Fix the array spec. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8d8ba5d..5592df3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-28 Steven G. Kargl + + PR fortran/91802 + * gfortran.dg/pr91802.f90: New test. + 2019-09-28 Steven G. Kargl PR fortran/91864 diff --git a/gcc/testsuite/gfortran.dg/pr91802.f90 b/gcc/testsuite/gfortran.dg/pr91802.f90 new file mode 100644 index 0000000..277d61a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91802.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } +! { dg-options "-fcoarray=single" } +! Code contributed by Gerhard Steinmetz +! PR fortran/91802 +module m + real :: x + dimension :: x(1,2,1,2,1,2,1,2) + codimension :: x[1,2,1,2,1,2,1,*] ! { dg-error "exceeds 15" } +end -- cgit v1.1 From 23cb6f8e0c0b462c13fbc01d5d6777d6b49bfaa7 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sat, 28 Sep 2019 19:32:31 +0000 Subject: [Darwin, PPC, Mode Iterators 4/n] Update macho_high. Drop the expander and use a mode iterator on the define_insn for @macho_high_ instead. gcc/ChangeLog: 2019-09-28 Iain Sandoe * config/darwin.c (gen_macho_high): Amend to include the mode argument. (machopic_indirect_data_reference): Amend gen_macho_high call to include mode argument. (machopic_legitimize_pic_address): Likewise. * config/rs6000/rs6000.c (rs6000_legitimize_address): * config/rs6000/darwin.md (@macho_high_): New, replaces the macho_high expander and two define_insn entries. From-SVN: r276256 --- gcc/ChangeLog | 11 +++++++++++ gcc/config/darwin.c | 7 ++++--- gcc/config/rs6000/darwin.md | 29 +++++------------------------ gcc/config/rs6000/rs6000.c | 4 ++-- 4 files changed, 22 insertions(+), 29 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0dd3720..88fed01 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-09-28 Iain Sandoe + + * config/darwin.c (gen_macho_high): Amend to include the mode + argument. + (machopic_indirect_data_reference): Amend gen_macho_high call + to include mode argument. + (machopic_legitimize_pic_address): Likewise. + * config/rs6000/rs6000.c (rs6000_legitimize_address): + * config/rs6000/darwin.md (@macho_high_): New, replaces + the macho_high expander and two define_insn entries. + 2019-09-28 Oleg Endo PR target/86805 diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 3e4bbff..1f72c07 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "lto-section-names.h" #include "intl.h" +#include "optabs.h" /* Darwin supports a feature called fix-and-continue, which is used for rapid turn around debugging. When code is compiled with the @@ -108,7 +109,7 @@ section * darwin_sections[NUM_DARWIN_SECTIONS]; /* While we transition to using in-tests instead of ifdef'd code. */ #if !HAVE_lo_sum -#define gen_macho_high(a,b) (a) +#define gen_macho_high(m,a,b) (a) #define gen_macho_low(a,b,c) (a) #endif @@ -654,7 +655,7 @@ machopic_indirect_data_reference (rtx orig, rtx reg) { /* Create a new register for CSE opportunities. */ rtx hi_reg = (!can_create_pseudo_p () ? reg : gen_reg_rtx (Pmode)); - emit_insn (gen_macho_high (hi_reg, orig)); + emit_insn (gen_macho_high (Pmode, hi_reg, orig)); emit_insn (gen_macho_low (reg, hi_reg, orig)); return reg; } @@ -858,7 +859,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) rtx asym = XEXP (orig, 0); rtx mem; - emit_insn (gen_macho_high (temp_reg, asym)); + emit_insn (gen_macho_high (Pmode, temp_reg, asym)); mem = gen_const_mem (GET_MODE (orig), gen_rtx_LO_SUM (Pmode, temp_reg, copy_rtx (asym))); diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md index b2a52d8..0c63a31 100644 --- a/gcc/config/rs6000/darwin.md +++ b/gcc/config/rs6000/darwin.md @@ -150,31 +150,12 @@ You should have received a copy of the GNU General Public License stfd %0,lo16(%2)(%1)" [(set_attr "type" "store")]) -;; Mach-O PIC trickery. -(define_expand "macho_high" - [(set (match_operand 0 "") - (high (match_operand 1 "")))] - "TARGET_MACHO" -{ - if (TARGET_64BIT) - emit_insn (gen_macho_high_di (operands[0], operands[1])); - else - emit_insn (gen_macho_high_si (operands[0], operands[1])); +;; Mach-O PIC. - DONE; -}) - -(define_insn "macho_high_si" - [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") - (high:SI (match_operand 1 "" "")))] - "TARGET_MACHO && ! TARGET_64BIT" - "lis %0,ha16(%1)") - - -(define_insn "macho_high_di" - [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r") - (high:DI (match_operand 1 "" "")))] - "TARGET_MACHO && TARGET_64BIT" +(define_insn "@macho_high_" + [(set (match_operand:P 0 "gpc_reg_operand" "=b*r") + (high:P (match_operand 1 "" "")))] + "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN)" "lis %0,ha16(%1)") (define_expand "macho_low" diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 81aec9c..f136dcb 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -7978,7 +7978,7 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, if (TARGET_ELF) emit_insn (gen_elf_high (reg, x)); else - emit_insn (gen_macho_high (reg, x)); + emit_insn (gen_macho_high (Pmode, reg, x)); return gen_rtx_LO_SUM (Pmode, reg, x); } else if (TARGET_TOC @@ -9691,7 +9691,7 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) return; } #endif - emit_insn (gen_macho_high (target, operands[1])); + emit_insn (gen_macho_high (Pmode, target, operands[1])); emit_insn (gen_macho_low (operands[0], target, operands[1])); return; } -- cgit v1.1 From e834b8adb62210af17533345c97636a0fa0d7eea Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 29 Sep 2019 00:16:32 +0000 Subject: Daily bump. From-SVN: r276264 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 2087f60..244a194 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190928 +20190929 -- cgit v1.1 From 59784d3851fccda86fcdf2cdee5a3c3ca231a2d3 Mon Sep 17 00:00:00 2001 From: Jerry DeLisle Date: Sun, 29 Sep 2019 02:35:58 +0000 Subject: re PR fortran/91802 (ICE in mio_name_expr_t, at fortran/module.c:2141) 2019-09-28 Jerry DeLisle PR fortran/91802 * decl.c (attr_decl1): Return MATCH_ERROR without free to avoid bad expression type in free_expr0() ICE in rank+corank check. From-SVN: r276265 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/decl.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 3d40c9a..0b87006 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2019-09-28 Jerry DeLisle + + PR fortran/91802 + * decl.c (attr_decl1): Return MATCH_ERROR without free to avoid + bad expression type in free_expr0() ICE in rank+corank check. + 2019-09-28 Steven G. Kargl PR fortran/91802 diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 31b2336..b6add1c 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -8474,7 +8474,7 @@ attr_decl1 (void) { gfc_error ("rank + corank of %qs exceeds 15 at %C", sym->name); m = MATCH_ERROR; - goto cleanup; + return m; } if (sym->attr.cray_pointee && sym->as != NULL) -- cgit v1.1 From 51df413634b4dac2fc5e538a13c8f8624903c59e Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Sun, 29 Sep 2019 05:08:14 +0000 Subject: This patch is to add the support for float from/to long conversion vectorization on port rs6000. gcc/ChangeLog 2019-09-29 Kewen Lin * config/rs6000/vsx.md (vec_pack[su]_float_v2di): New define_expand. (vec_unpack_[su]fix_trunc_hi_v4sf): Likewise. (vec_unpack_[su]fix_trunc_lo_v4sf): Likewise. gcc/testsuite/ChangeLog 2019-09-29 Kewen Lin * gcc.target/powerpc/conv-vectorize-1.c: New test. * gcc.target/powerpc/conv-vectorize-2.c: New test. From-SVN: r276266 --- gcc/ChangeLog | 6 +++ gcc/config/rs6000/vsx.md | 45 ++++++++++++++++++++++ gcc/testsuite/ChangeLog | 5 +++ .../gcc.target/powerpc/conv-vectorize-1.c | 37 ++++++++++++++++++ .../gcc.target/powerpc/conv-vectorize-2.c | 37 ++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 gcc/testsuite/gcc.target/powerpc/conv-vectorize-1.c create mode 100644 gcc/testsuite/gcc.target/powerpc/conv-vectorize-2.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88fed01..9714e98 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-29 Kewen Lin + + * config/rs6000/vsx.md (vec_pack[su]_float_v2di): New define_expand. + (vec_unpack_[su]fix_trunc_hi_v4sf): Likewise. + (vec_unpack_[su]fix_trunc_lo_v4sf): Likewise. + 2019-09-28 Iain Sandoe * config/darwin.c (gen_macho_high): Amend to include the mode diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 91f5fed..3cc1277 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -5544,3 +5544,48 @@ operands[SFBOOL_TMP_VSX_DI] = gen_rtx_REG (DImode, regno_tmp_vsx); operands[SFBOOL_MTVSR_D_V4SF] = gen_rtx_REG (V4SFmode, regno_mtvsr_d); }) + +;; Support signed/unsigned long long to float conversion vectorization. +;; Note that any_float (pc) here is just for code attribute . +(define_expand "vec_pack_float_v2di" + [(match_operand:V4SF 0 "vfloat_operand") + (match_operand:V2DI 1 "vint_operand") + (match_operand:V2DI 2 "vint_operand") + (any_float (pc))] + "TARGET_VSX" +{ + rtx r1 = gen_reg_rtx (V4SFmode); + rtx r2 = gen_reg_rtx (V4SFmode); + emit_insn (gen_vsx_xvcvxdsp (r1, operands[1])); + emit_insn (gen_vsx_xvcvxdsp (r2, operands[2])); + rs6000_expand_extract_even (operands[0], r1, r2); + DONE; +}) + +;; Support float to signed/unsigned long long conversion vectorization. +;; Note that any_fix (pc) here is just for code attribute . +(define_expand "vec_unpack_fix_trunc_hi_v4sf" + [(match_operand:V2DI 0 "vint_operand") + (match_operand:V4SF 1 "vfloat_operand") + (any_fix (pc))] + "TARGET_VSX" +{ + rtx reg = gen_reg_rtx (V4SFmode); + rs6000_expand_interleave (reg, operands[1], operands[1], BYTES_BIG_ENDIAN); + emit_insn (gen_vsx_xvcvspxds (operands[0], reg)); + DONE; +}) + +;; Note that any_fix (pc) here is just for code attribute . +(define_expand "vec_unpack_fix_trunc_lo_v4sf" + [(match_operand:V2DI 0 "vint_operand") + (match_operand:V4SF 1 "vfloat_operand") + (any_fix (pc))] + "TARGET_VSX" +{ + rtx reg = gen_reg_rtx (V4SFmode); + rs6000_expand_interleave (reg, operands[1], operands[1], !BYTES_BIG_ENDIAN); + emit_insn (gen_vsx_xvcvspxds (operands[0], reg)); + DONE; +}) + diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5592df3..d0d2cb0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-29 Kewen Lin + + * gcc.target/powerpc/conv-vectorize-1.c: New test. + * gcc.target/powerpc/conv-vectorize-2.c: New test. + 2019-09-28 Steven G. Kargl PR fortran/91802 diff --git a/gcc/testsuite/gcc.target/powerpc/conv-vectorize-1.c b/gcc/testsuite/gcc.target/powerpc/conv-vectorize-1.c new file mode 100644 index 0000000..d96db14 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/conv-vectorize-1.c @@ -0,0 +1,37 @@ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-O2 -ftree-vectorize -mvsx" } */ + +/* Test vectorizer can exploit vector conversion instructions to convert + unsigned/signed long long to float. */ + +#include + +#define SIZE 32 +#define ALIGN 16 + +float sflt_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); +float uflt_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); + +unsigned long long ulong_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); +signed long long slong_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); + +void +convert_slong_to_float (void) +{ + size_t i; + + for (i = 0; i < SIZE; i++) + sflt_array[i] = (float) slong_array[i]; +} + +void +convert_ulong_to_float (void) +{ + size_t i; + + for (i = 0; i < SIZE; i++) + uflt_array[i] = (float) ulong_array[i]; +} + +/* { dg-final { scan-assembler {\mxvcvsxdsp\M} } } */ +/* { dg-final { scan-assembler {\mxvcvuxdsp\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/conv-vectorize-2.c b/gcc/testsuite/gcc.target/powerpc/conv-vectorize-2.c new file mode 100644 index 0000000..5dd5dea --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/conv-vectorize-2.c @@ -0,0 +1,37 @@ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-O2 -ftree-vectorize -mvsx" } */ + +/* Test vectorizer can exploit vector conversion instructions to convert + float to unsigned/signed long long. */ + +#include + +#define SIZE 32 +#define ALIGN 16 + +float sflt_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); +float uflt_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); + +unsigned long long ulong_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); +signed long long slong_array[SIZE] __attribute__ ((__aligned__ (ALIGN))); + +void +convert_float_to_slong (void) +{ + size_t i; + + for (i = 0; i < SIZE; i++) + slong_array[i] = (signed long long) sflt_array[i]; +} + +void +convert_float_to_ulong (void) +{ + size_t i; + + for (i = 0; i < SIZE; i++) + ulong_array[i] = (unsigned long long) uflt_array[i]; +} + +/* { dg-final { scan-assembler {\mxvcvspsxds\M} } } */ +/* { dg-final { scan-assembler {\mxvcvspuxds\M} } } */ -- cgit v1.1 From b19d2e5e1a895ee5e331c20f7eec02f3081b3d79 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Sun, 29 Sep 2019 09:18:22 +0000 Subject: vec_perm cost to 1 for non-Power7 VSX architectures gcc/ChangeLog 2019-09-29 Kewen Lin * config/rs6000/rs6000.c (rs6000_builtin_vectorization_cost): Lower vec_perm cost to 1 for non-Power7 VSX architectures. From-SVN: r276267 --- gcc/ChangeLog | 5 +++++ gcc/config/rs6000/rs6000.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9714e98..2c7a847 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-09-29 Kewen Lin + * config/rs6000/rs6000.c (rs6000_builtin_vectorization_cost): Lower + vec_perm cost to 1 for non-Power7 VSX architectures. + +2019-09-29 Kewen Lin + * config/rs6000/vsx.md (vec_pack[su]_float_v2di): New define_expand. (vec_unpack_[su]fix_trunc_hi_v4sf): Likewise. (vec_unpack_[su]fix_trunc_lo_v4sf): Likewise. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index f136dcb..a344153 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -4774,7 +4774,8 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, return 1; case vec_perm: - if (TARGET_VSX) + /* Power7 has only one permute unit, make it a bit expensive. */ + if (TARGET_VSX && rs6000_tune == PROCESSOR_POWER7) return 3; else return 1; -- cgit v1.1 From ae517a31c9508d9b0424e7a057d05840cf2caaf5 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 29 Sep 2019 12:06:40 +0200 Subject: re PR bootstrap/90543 (Build failure on MINGW for gcc-9.1.0) PR bootstrap/90543 * optc-save-gen.awk: Fix up printing string option differences. From-SVN: r276268 --- gcc/ChangeLog | 5 +++++ gcc/optc-save-gen.awk | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2c7a847..e94f638 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-29 Jakub Jelinek + + PR bootstrap/90543 + * optc-save-gen.awk: Fix up printing string option differences. + 2019-09-29 Kewen Lin * config/rs6000/rs6000.c (rs6000_builtin_vectorization_cost): Lower diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk index 74096bc..cf1c368 100644 --- a/gcc/optc-save-gen.awk +++ b/gcc/optc-save-gen.awk @@ -332,7 +332,7 @@ for (i = 0; i < n_opt_string; i++) { print " indent_to, \"\","; print " \"" name "\","; print " ptr1->x_" name " ? ptr1->x_" name " : \"(null)\","; - print " ptr2->x_" name " ? ptr1->x_" name " : \"(null)\");"; + print " ptr2->x_" name " ? ptr2->x_" name " : \"(null)\");"; print ""; } -- cgit v1.1 From 56b070e3bbc4364f86357d6651fe1391464db6d6 Mon Sep 17 00:00:00 2001 From: Paul Thomas Date: Sun, 29 Sep 2019 10:12:42 +0000 Subject: re PR fortran/91726 (ICE in gfc_conv_array_ref, at fortran/trans-array.c:3612) 2019-09-29 Paul Thomas PR fortran/91726 * resolve.c (gfc_expr_to_initialize): Bail out with a copy of the original expression if the array ref is a scalar and the array_spec has corank. * trans-array.c (gfc_conv_array_ref): Such expressions are OK even if the array ref codimen is zero. * trans-expr.c (gfc_get_class_from_expr): New function taken from gfc_get_vptr_from_expr. (gfc_get_vptr_from_expr): Call new function. * trans-stmt.c (trans_associate_var): If one of these is a target expression, extract the class expression from the target and copy its fields to a new target variable. * trans.h : Add prototype for gfc_get_class_from_expr. 2019-09-29 Paul Thomas PR fortran/91726 * gfortran.dg/coarray_poly_9.f90 : New test. From-SVN: r276269 --- gcc/fortran/ChangeLog | 18 ++++++++++++- gcc/fortran/resolve.c | 4 +++ gcc/fortran/trans-array.c | 3 ++- gcc/fortran/trans-expr.c | 23 ++++++++++++++--- gcc/fortran/trans-stmt.c | 36 ++++++++++++++++++++++++++ gcc/fortran/trans.h | 1 + gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gfortran.dg/coarray_poly_9.f90 | 38 ++++++++++++++++++++++++++++ 8 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/coarray_poly_9.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 0b87006..8fc5625 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,19 @@ +2019-09-29 Paul Thomas + + PR fortran/91726 + * resolve.c (gfc_expr_to_initialize): Bail out with a copy of + the original expression if the array ref is a scalar and the + array_spec has corank. + * trans-array.c (gfc_conv_array_ref): Such expressions are OK + even if the array ref codimen is zero. + * trans-expr.c (gfc_get_class_from_expr): New function taken + from gfc_get_vptr_from_expr. + (gfc_get_vptr_from_expr): Call new function. + * trans-stmt.c (trans_associate_var): If one of these is a + target expression, extract the class expression from the target + and copy its fields to a new target variable. + * trans.h : Add prototype for gfc_get_class_from_expr. + 2019-09-28 Jerry DeLisle PR fortran/91802 @@ -14,7 +30,7 @@ PR fortran/91864 * gcc/fortran/io.c (match_io_element): An inquiry parameter cannot be read into. - * gcc/fortran/match.c (gfc_match_allocate): An inquiry parameter + * gcc/fortran/match.c (gfc_match_allocate): An inquiry parameter can be neither an allocate-object nor stat variable. (gfc_match_deallocate): An inquiry parameter cannot be deallocated. diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index f1de7dd..e8d0566 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -7433,6 +7433,10 @@ gfc_expr_to_initialize (gfc_expr *e) for (ref = result->ref; ref; ref = ref->next) if (ref->type == REF_ARRAY && ref->next == NULL) { + if (ref->u.ar.dimen == 0 + && ref->u.ar.as && ref->u.ar.as->corank) + return result; + ref->u.ar.type = AR_FULL; for (i = 0; i < ref->u.ar.dimen; i++) diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 07c4d7e..437892a 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -3609,7 +3609,8 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_expr *expr, if (ar->dimen == 0) { - gcc_assert (ar->codimen || sym->attr.select_rank_temporary); + gcc_assert (ar->codimen || sym->attr.select_rank_temporary + || (ar->as && ar->as->corank)); if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se->expr))) se->expr = build_fold_indirect_ref (gfc_conv_array_data (se->expr)); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 2adc112..61db4e3 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -472,11 +472,11 @@ gfc_reset_len (stmtblock_t *block, gfc_expr *expr) } -/* Obtain the vptr of the last class reference in an expression. +/* Obtain the last class reference in an expression. Return NULL_TREE if no class reference is found. */ tree -gfc_get_vptr_from_expr (tree expr) +gfc_get_class_from_expr (tree expr) { tree tmp; tree type; @@ -487,7 +487,7 @@ gfc_get_vptr_from_expr (tree expr) while (type) { if (GFC_CLASS_TYPE_P (type)) - return gfc_class_vptr_get (tmp); + return tmp; if (type != TYPE_CANONICAL (type)) type = TYPE_CANONICAL (type); else @@ -501,6 +501,23 @@ gfc_get_vptr_from_expr (tree expr) tmp = build_fold_indirect_ref_loc (input_location, tmp); if (GFC_CLASS_TYPE_P (TREE_TYPE (tmp))) + return tmp; + + return NULL_TREE; +} + + +/* Obtain the vptr of the last class reference in an expression. + Return NULL_TREE if no class reference is found. */ + +tree +gfc_get_vptr_from_expr (tree expr) +{ + tree tmp; + + tmp = gfc_get_class_from_expr (expr); + + if (tmp != NULL_TREE) return gfc_class_vptr_get (tmp); return NULL_TREE; diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 856a171..e3ea38a 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -2099,7 +2099,43 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) } else { + tree ctree = gfc_get_class_from_expr (se.expr); tmp = TREE_TYPE (sym->backend_decl); + + /* Coarray scalar component expressions can emerge from + the front end as array elements of the _data field. */ + if (sym->ts.type == BT_CLASS + && e->ts.type == BT_CLASS && e->rank == 0 + && !GFC_CLASS_TYPE_P (TREE_TYPE (se.expr)) && ctree) + { + tree stmp; + tree dtmp; + + se.expr = ctree; + dtmp = TREE_TYPE (TREE_TYPE (sym->backend_decl)); + ctree = gfc_create_var (dtmp, "class"); + + stmp = gfc_class_data_get (se.expr); + gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (stmp))); + + /* Set the fields of the target class variable. */ + stmp = gfc_conv_descriptor_data_get (stmp); + dtmp = gfc_class_data_get (ctree); + stmp = fold_convert (TREE_TYPE (dtmp), stmp); + gfc_add_modify (&se.pre, dtmp, stmp); + stmp = gfc_class_vptr_get (se.expr); + dtmp = gfc_class_vptr_get (ctree); + stmp = fold_convert (TREE_TYPE (dtmp), stmp); + gfc_add_modify (&se.pre, dtmp, stmp); + if (UNLIMITED_POLY (sym)) + { + stmp = gfc_class_len_get (se.expr); + dtmp = gfc_class_len_get (ctree); + stmp = fold_convert (TREE_TYPE (dtmp), stmp); + gfc_add_modify (&se.pre, dtmp, stmp); + } + se.expr = ctree; + } tmp = gfc_build_addr_expr (tmp, se.expr); } diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 84793dc..6ebb71d 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -442,6 +442,7 @@ tree gfc_vptr_final_get (tree); tree gfc_vptr_deallocate_get (tree); void gfc_reset_vptr (stmtblock_t *, gfc_expr *); void gfc_reset_len (stmtblock_t *, gfc_expr *); +tree gfc_get_class_from_expr (tree); tree gfc_get_vptr_from_expr (tree); tree gfc_get_class_array_ref (tree, tree, tree, bool); tree gfc_copy_class_to_class (tree, tree, tree, bool); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0d2cb0..a23c728 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-29 Paul Thomas + + PR fortran/91726 + * gfortran.dg/coarray_poly_9.f90 : New test. + 2019-09-29 Kewen Lin * gcc.target/powerpc/conv-vectorize-1.c: New test. diff --git a/gcc/testsuite/gfortran.dg/coarray_poly_9.f90 b/gcc/testsuite/gfortran.dg/coarray_poly_9.f90 new file mode 100644 index 0000000..ea2a942 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/coarray_poly_9.f90 @@ -0,0 +1,38 @@ +! { dg-do run } +! { dg-options "-fcoarray=single" } +! +! Test the fix for PR91726. +! +! Contributed by Gerhardt Steinmetz +! +module m + type s + class(*), allocatable :: a[:] ! This ICEd + end type + type t + class(*), allocatable :: a(:)[:] ! This was OK + end type +end + + use m + call foo + call bar +contains + subroutine foo + type (s) :: a + integer(4) :: i = 42_4 + allocate (a%a[*], source = i) ! This caused runtime segfaults + select type (z => a%a) ! ditto + type is (integer(4)) + if (z .ne. 42_4) stop 1 + end select + end subroutine + subroutine bar ! Arrays always worked + type (t) :: a + allocate (a%a(3)[*], source = [1_4, 2_4, 3_4]) + select type (z => a%a) + type is (integer(4)) + if (any (z .ne. [1_4, 2_4, 3_4])) stop 2 + end select + end subroutine +end -- cgit v1.1 From c4770ba091d96aea469c79067b549bbc8f8c7c63 Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Sun, 29 Sep 2019 16:19:58 +0000 Subject: re PR fortran/91714 (Accepts type statement without delimiter in free form) 2019-09-29 Steven G. Kargl PR fortran/91714 * decl.c (gfc_match_decl_type_spec): Issue errors for a few mangled types. 2019-09-29 Steven G. Kargl PR fortran/91714 * gfortran.dg/dec_type_print_3.f90: Update dg-error regex. * gfortran.dg/pr91714.f90: New test. From-SVN: r276270 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/decl.c | 22 ++++++++++++++++++++-- gcc/testsuite/ChangeLog | 6 ++++++ gcc/testsuite/gfortran.dg/dec_type_print_3.f90 | 4 ++-- gcc/testsuite/gfortran.dg/pr91714.f90 | 10 ++++++++++ 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr91714.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8fc5625..d4f39cc 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2019-09-29 Steven G. Kargl + + PR fortran/91714 + * decl.c (gfc_match_decl_type_spec): Issue errors for a few + mangled types. + 2019-09-29 Paul Thomas PR fortran/91726 diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index b6add1c..3ba61a0 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -4444,6 +4444,7 @@ get_kind: gfc_next_ascii_char (); return MATCH_YES; } + gfc_error ("Malformed type-spec at %C"); return MATCH_NO; } } @@ -4457,7 +4458,10 @@ get_kind: } if (matched_type && gfc_match_char (')') != MATCH_YES) - return MATCH_ERROR; + { + gfc_error ("Malformed type-spec at %C"); + return MATCH_ERROR; + } /* Defer association of the KIND expression of function results until after USE and IMPORT statements. */ @@ -10240,6 +10244,20 @@ gfc_match_derived_decl (void) return MATCH_ERROR; } + /* In free source form, need to check for TYPE XXX as oppose to TYPEXXX. + But, we need to simply return for TYPE(. */ + if (m == MATCH_NO && gfc_current_form == FORM_FREE) + { + char c = gfc_peek_ascii_char (); + if (c == '(') + return m; + if (!gfc_is_whitespace (c)) + { + gfc_error ("Mangled derived type definition at %C"); + return MATCH_NO; + } + } + m = gfc_match (" %n ", name); if (m != MATCH_YES) return m; @@ -10247,7 +10265,7 @@ gfc_match_derived_decl (void) /* Make sure that we don't identify TYPE IS (...) as a parameterized derived type named 'is'. TODO Expand the check, when 'name' = "is" by matching " (tname) " - and checking if this is a(n intrinsic) typename. his picks up + and checking if this is a(n intrinsic) typename. This picks up misplaced TYPE IS statements such as in select_type_1.f03. */ if (gfc_peek_ascii_char () == '(') { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a23c728..052fd2e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-09-29 Steven G. Kargl + + PR fortran/91714 + * gfortran.dg/dec_type_print_3.f90: Update dg-error regex. + * gfortran.dg/pr91714.f90: New test. + 2019-09-29 Paul Thomas PR fortran/91726 diff --git a/gcc/testsuite/gfortran.dg/dec_type_print_3.f90 b/gcc/testsuite/gfortran.dg/dec_type_print_3.f90 index 409e991..27f117d 100644 --- a/gcc/testsuite/gfortran.dg/dec_type_print_3.f90 +++ b/gcc/testsuite/gfortran.dg/dec_type_print_3.f90 @@ -8,9 +8,9 @@ include 'dec_type_print.f90' -! { dg-error "Invalid character in name" "" { target *-*-* } 52 } +! { dg-error "Mangled derived type definition" "" { target *-*-* } 52 } ! { dg-error "Invalid character in name" "" { target *-*-* } 53 } -! { dg-error "Invalid character in name" "" { target *-*-* } 54 } +! { dg-error "Mangled derived type definition" "" { target *-*-* } 54 } ! { dg-error "Invalid character in name" "" { target *-*-* } 55 } ! { dg-error "Invalid character in name" "" { target *-*-* } 56 } ! { dg-error "Invalid character in name" "" { target *-*-* } 57 } diff --git a/gcc/testsuite/gfortran.dg/pr91714.f90 b/gcc/testsuite/gfortran.dg/pr91714.f90 new file mode 100644 index 0000000..8b855d9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91714.f90 @@ -0,0 +1,10 @@ +! { dg-do compile } +! Contributed by Gerhard Steinmetz +program p + typea ! { dg-error "Mangled derived type" } + integer b + end type ! { dg-error "Expecting END PROGRAM" } + type(a) :: c ! { dg-error "is being used before it" } + c = a(1) + print *, c +end -- cgit v1.1 From 7a40dd5a26ee497e80c86c939542de96d5e2a474 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 29 Sep 2019 19:09:13 +0000 Subject: [Darwin, PPC, Mode Iterators 5/n] Update macho_low. Replace the define_expand and two define_insns with a single @macho_low_ and update callers. gcc/ChangeLog: 2019-09-29 Iain Sandoe * config/darwin.c (gen_macho_low):Amend to include the mode argument. (machopic_indirect_data_reference): Amend gen_macho_low call to include mode argument * config/rs6000/rs6000.c (emit_move): Likewise. Amend a comment. * config/rs6000/darwin.md (@macho_low_): New, replaces the macho_high expander and two define_insn entries. From-SVN: r276271 --- gcc/ChangeLog | 10 ++++++++++ gcc/config/darwin.c | 4 ++-- gcc/config/rs6000/darwin.md | 29 ++++------------------------- gcc/config/rs6000/rs6000.c | 5 ++++- 4 files changed, 20 insertions(+), 28 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e94f638..864dc69 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-09-29 Iain Sandoe + + * config/darwin.c (gen_macho_low):Amend to include the mode + argument. + (machopic_indirect_data_reference): Amend gen_macho_low call + to include mode argument + * config/rs6000/rs6000.c (emit_move): Likewise. Amend a comment. + * config/rs6000/darwin.md (@macho_low_): New, replaces + the macho_high expander and two define_insn entries. + 2019-09-29 Jakub Jelinek PR bootstrap/90543 diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 1f72c07..3a1be5a 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -110,7 +110,7 @@ section * darwin_sections[NUM_DARWIN_SECTIONS]; /* While we transition to using in-tests instead of ifdef'd code. */ #if !HAVE_lo_sum #define gen_macho_high(m,a,b) (a) -#define gen_macho_low(a,b,c) (a) +#define gen_macho_low(m,a,b,c) (a) #endif /* True if we're setting __attribute__ ((ms_struct)). */ @@ -656,7 +656,7 @@ machopic_indirect_data_reference (rtx orig, rtx reg) /* Create a new register for CSE opportunities. */ rtx hi_reg = (!can_create_pseudo_p () ? reg : gen_reg_rtx (Pmode)); emit_insn (gen_macho_high (Pmode, hi_reg, orig)); - emit_insn (gen_macho_low (reg, hi_reg, orig)); + emit_insn (gen_macho_low (Pmode, reg, hi_reg, orig)); return reg; } else if (DARWIN_X86) diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md index 0c63a31..3994447 100644 --- a/gcc/config/rs6000/darwin.md +++ b/gcc/config/rs6000/darwin.md @@ -158,32 +158,11 @@ You should have received a copy of the GNU General Public License "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN)" "lis %0,ha16(%1)") -(define_expand "macho_low" - [(set (match_operand 0 "") - (lo_sum (match_operand 1 "") - (match_operand 2 "")))] - "TARGET_MACHO" -{ - if (TARGET_64BIT) - emit_insn (gen_macho_low_di (operands[0], operands[1], operands[2])); - else - emit_insn (gen_macho_low_si (operands[0], operands[1], operands[2])); - - DONE; -}) - -(define_insn "macho_low_si" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r") - (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") - (match_operand 2 "" "")))] - "TARGET_MACHO && ! TARGET_64BIT" - "la %0,lo16(%2)(%1)") - -(define_insn "macho_low_di" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r") - (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b") +(define_insn "@macho_low_" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b") (match_operand 2 "" "")))] - "TARGET_MACHO && TARGET_64BIT" + "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN)" "la %0,lo16(%2)(%1)") (define_split diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index a344153..1eb1317 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -9682,6 +9682,8 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) if (DEFAULT_ABI == ABI_DARWIN) { #if TARGET_MACHO + /* This is not PIC code, but could require the subset of + indirections used by mdynamic-no-pic. */ if (MACHO_DYNAMIC_NO_PIC_P) { /* Take care of any required data indirection. */ @@ -9693,7 +9695,8 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) } #endif emit_insn (gen_macho_high (Pmode, target, operands[1])); - emit_insn (gen_macho_low (operands[0], target, operands[1])); + emit_insn (gen_macho_low (Pmode, operands[0], + target, operands[1])); return; } -- cgit v1.1 From 3262dde64c162a520fbe8bae6bd4372411f6a790 Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Sun, 29 Sep 2019 19:12:08 +0000 Subject: re PR fortran/91641 (ICE in gfc_conv_is_contiguous_expr, at fortran/trans-intrinsic.c:2857) 2019-09-29 Steven G. Kargl PR fortran/91641 * check.c (gfc_check_is_contiguous): null() cannot be an actual argument to is_contiguous(). 2019-09-29 Steven G. Kargl PR fortran/91641 * gfortran.dg/pr91641.f90: New test. From-SVN: r276272 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/check.c | 9 ++++++++- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/pr91641.f90 | 7 +++++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/pr91641.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d4f39cc..694fc32 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,11 @@ 2019-09-29 Steven G. Kargl + PR fortran/91641 + * check.c (gfc_check_is_contiguous): null() cannot be an actual + argument to is_contiguous(). + +2019-09-29 Steven G. Kargl + PR fortran/91714 * decl.c (gfc_match_decl_type_spec): Issue errors for a few mangled types. diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index a04f9fb..98203bc 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -7098,6 +7098,14 @@ gfc_check_ttynam_sub (gfc_expr *unit, gfc_expr *name) bool gfc_check_is_contiguous (gfc_expr *array) { + if (array->expr_type == EXPR_NULL + && array->symtree->n.sym->attr.pointer == 1) + { + gfc_error ("Actual argument at %L of %qs intrinsic shall be an " + "associated pointer", &array->where, gfc_current_intrinsic); + return false; + } + if (!array_check (array, 0)) return false; @@ -7105,7 +7113,6 @@ gfc_check_is_contiguous (gfc_expr *array) } - bool gfc_check_isatty (gfc_expr *unit) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 052fd2e..43dc4ce 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-09-29 Steven G. Kargl + PR fortran/91641 + * gfortran.dg/pr91641.f90: New test. + +2019-09-29 Steven G. Kargl + PR fortran/91714 * gfortran.dg/dec_type_print_3.f90: Update dg-error regex. * gfortran.dg/pr91714.f90: New test. diff --git a/gcc/testsuite/gfortran.dg/pr91641.f90 b/gcc/testsuite/gfortran.dg/pr91641.f90 new file mode 100644 index 0000000..1970824 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91641.f90 @@ -0,0 +1,7 @@ +! { dg-do compile } +! PR fortran/91641 +! Code conyributed by Gerhard Steinmetz +program p + real, pointer :: z(:) + print *, is_contiguous (null(z)) ! { dg-error "shall be an associated" } +end -- cgit v1.1 From 65403f15ecaef8a9d4384b467b9fbc486ea7bc93 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 30 Sep 2019 00:16:51 +0000 Subject: Daily bump. From-SVN: r276276 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 244a194..afc3f20 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190929 +20190930 -- cgit v1.1 From 6a556ba414832a4ec9b1ea66d2a40940ba74706e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 30 Sep 2019 09:26:58 +0200 Subject: re PR target/91931 (ICE in decompose, at rtl.h:2277) PR target/91931 * config/i386/i386-expand.c (ix86_expand_adjust_ufix_to_sfix_si): Use gen_int_mode instead of GEN_INT. * gcc.target/i386/pr91931.c: New test. From-SVN: r276294 --- gcc/ChangeLog | 8 +++++++- gcc/config/i386/i386-expand.c | 2 +- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/i386/pr91931.c | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr91931.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 864dc69..c93ea90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,12 @@ +2019-09-30 Jakub Jelinek + + PR target/91931 + * config/i386/i386-expand.c (ix86_expand_adjust_ufix_to_sfix_si): Use + gen_int_mode instead of GEN_INT. + 2019-09-29 Iain Sandoe - * config/darwin.c (gen_macho_low):Amend to include the mode + * config/darwin.c (gen_macho_low): Amend to include the mode argument. (machopic_indirect_data_reference): Amend gen_macho_low call to include mode argument diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index 22c2823..5e377d6 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -1694,7 +1694,7 @@ ix86_expand_adjust_ufix_to_sfix_si (rtx val, rtx *xorp) OPTAB_DIRECT); else { - rtx two31 = GEN_INT (HOST_WIDE_INT_1U << 31); + rtx two31 = gen_int_mode (HOST_WIDE_INT_1U << 31, SImode); two31 = ix86_build_const_vector (intmode, 1, two31); *xorp = expand_simple_binop (intmode, AND, gen_lowpart (intmode, tmp[0]), diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 43dc4ce..85e718e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-30 Jakub Jelinek + + PR target/91931 + * gcc.target/i386/pr91931.c: New test. + 2019-09-29 Steven G. Kargl PR fortran/91641 diff --git a/gcc/testsuite/gcc.target/i386/pr91931.c b/gcc/testsuite/gcc.target/i386/pr91931.c new file mode 100644 index 0000000..f39b22e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr91931.c @@ -0,0 +1,5 @@ +/* PR target/91931 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -ftree-loop-vectorize -mavx -mno-avx2" } */ + +#include "../../gcc.dg/vect/pr32216.c" -- cgit v1.1 From 15bbad92434a184a0baac0c93c7111e6e7fcd9c2 Mon Sep 17 00:00:00 2001 From: Andreas Tobler Date: Mon, 30 Sep 2019 09:54:52 +0200 Subject: config.gcc: Use the secure-plt on FreeBSD 13 and upwards for 32-bit PowerPC. 2019-09-30 Andreas Tobler * config.gcc: Use the secure-plt on FreeBSD 13 and upwards for 32-bit PowerPC. Define TARGET_FREEBSD32_SECURE_PLT for 64-bit PowerPC. * config/rs6000/t-freebsd64: Make use of the above define and build the 32-bit libraries with secure-plt. From-SVN: r276295 --- gcc/ChangeLog | 8 ++++++++ gcc/config.gcc | 6 ++++++ gcc/config/rs6000/t-freebsd64 | 3 +++ 3 files changed, 17 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c93ea90..099d1b9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-30 Andreas Tobler + + * config.gcc: Use the secure-plt on FreeBSD 13 and upwards for + 32-bit PowerPC. + Define TARGET_FREEBSD32_SECURE_PLT for 64-bit PowerPC. + * config/rs6000/t-freebsd64: Make use of the above define and build + the 32-bit libraries with secure-plt. + 2019-09-30 Jakub Jelinek PR target/91931 diff --git a/gcc/config.gcc b/gcc/config.gcc index 69d0a02..481bc95 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2687,8 +2687,14 @@ powerpc*-*-freebsd*) tm_file="${tm_file} rs6000/default64.h rs6000/freebsd64.h" tmake_file="${tmake_file} rs6000/t-freebsd64" extra_options="${extra_options} rs6000/linux64.opt" + if test $fbsd_major -ge 13; then + tm_defines="${tm_defines} TARGET_FREEBSD32_SECURE_PLT=1" + fi ;; *) + if test $fbsd_major -ge 13; then + tm_file="rs6000/secureplt.h ${tm_file}" + fi tm_file="${tm_file} rs6000/freebsd.h" ;; esac diff --git a/gcc/config/rs6000/t-freebsd64 b/gcc/config/rs6000/t-freebsd64 index 3f44bfe..dd0d5bb 100644 --- a/gcc/config/rs6000/t-freebsd64 +++ b/gcc/config/rs6000/t-freebsd64 @@ -27,3 +27,6 @@ MULTILIB_EXTRA_OPTS = fPIC mstrict-align MULTILIB_EXCEPTIONS = MULTILIB_OSDIRNAMES = ../lib32 +SECURE_PLT = $(if $(filter TARGET_FREEBSD32_SECURE_PLT=1, $(tm_defines)),msecure-plt) + +MULTILIB_EXTRA_OPTS += $(SECURE_PLT) -- cgit v1.1 From be525d9221f61c17e0fa34823ffd1624b0f8518a Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Mon, 30 Sep 2019 10:18:59 +0200 Subject: [PR 91853] Prevent IPA-SRA ICEs on type-mismatched calls 2019-09-30 Martin Jambor PR ipa/91853 * tree-inline.c (force_value_to_type): New function. (setup_one_parameter): Use force_value_to_type to convert type. * tree-inline.c (force_value_to_type): Declare. * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): Deal with register type mismatches. testsuite/ * gcc.dg/ipa/pr91853.c: New test. From-SVN: r276296 --- gcc/ChangeLog | 9 +++++++++ gcc/ipa-param-manipulation.c | 11 ++++++++-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/ipa/pr91853.c | 30 ++++++++++++++++++++++++++++ gcc/tree-inline.c | 41 ++++++++++++++++++++++---------------- gcc/tree-inline.h | 1 + 6 files changed, 78 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/pr91853.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 099d1b9..4a76e2f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2019-09-30 Martin Jambor + + PR ipa/91853 + * tree-inline.c (force_value_to_type): New function. + (setup_one_parameter): Use force_value_to_type to convert type. + * tree-inline.c (force_value_to_type): Declare. + * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): Deal + with register type mismatches. + 2019-09-30 Andreas Tobler * config.gcc: Use the secure-plt on FreeBSD 13 and upwards for diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index 913b96f..bbf6467 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -651,8 +651,15 @@ ipa_param_adjustments::modify_call (gcall *stmt, bool deref_base = false; unsigned int deref_align = 0; if (TREE_CODE (base) != ADDR_EXPR - && POINTER_TYPE_P (TREE_TYPE (base))) - off = build_int_cst (apm->alias_ptr_type, apm->unit_offset); + && is_gimple_reg_type (TREE_TYPE (base))) + { + /* Detect type mismatches in calls in invalid programs and make a + poor attempt to gracefully convert them so that we don't ICE. */ + if (!POINTER_TYPE_P (TREE_TYPE (base))) + base = force_value_to_type (ptr_type_node, base); + + off = build_int_cst (apm->alias_ptr_type, apm->unit_offset); + } else { bool addrof; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 85e718e..84139ef 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-30 Martin Jambor + + PR ipa/91853 + * gcc.dg/ipa/pr91853.c: New test. + 2019-09-30 Jakub Jelinek PR target/91931 diff --git a/gcc/testsuite/gcc.dg/ipa/pr91853.c b/gcc/testsuite/gcc.dg/ipa/pr91853.c new file mode 100644 index 0000000..4bad780 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr91853.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "--param ipa-cp-value-list-size=0 -Os -fno-inline" } */ + +struct _wincore +{ + int y; + int width; +}; +int a; +void fn2 (void); +static int fn1 (dpy, winInfo) struct _XDisplay *dpy; +struct _wincore *winInfo; +{ + a = winInfo->width; + fn2 (); +} + +void fn4 (int, int, int); +static int fn3 (dpy, winInfo, visrgn) struct _XDisplay *dpy; +int winInfo, visrgn; +{ + int b = fn1 (0, winInfo); + fn4 (0, 0, visrgn); +} + +int +fn5 (event) struct _XEvent *event; +{ + fn3 (0, 0, 0); +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 500037c..d6920f4 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -3333,6 +3333,29 @@ insert_init_stmt (copy_body_data *id, basic_block bb, gimple *init_stmt) } } +/* Deal with mismatched formal/actual parameters, in a rather brute-force way + if need be (which should only be necessary for invalid programs). Attempt + to convert VAL to TYPE and return the result if it is possible, just return + a zero constant of the given type if it fails. */ + +tree +force_value_to_type (tree type, tree value) +{ + /* If we can match up types by promotion/demotion do so. */ + if (fold_convertible_p (type, value)) + return fold_convert (type, value); + + /* ??? For valid programs we should not end up here. + Still if we end up with truly mismatched types here, fall back + to using a VIEW_CONVERT_EXPR or a literal zero to not leak invalid + GIMPLE to the following passes. */ + if (!is_gimple_reg_type (TREE_TYPE (value)) + || TYPE_SIZE (type) == TYPE_SIZE (TREE_TYPE (value))) + return fold_build1 (VIEW_CONVERT_EXPR, type, value); + else + return build_zero_cst (type); +} + /* Initialize parameter P with VALUE. If needed, produce init statement at the end of BB. When BB is NULL, we return init statement to be output later. */ @@ -3349,23 +3372,7 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn, if (value && value != error_mark_node && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value))) - { - /* If we can match up types by promotion/demotion do so. */ - if (fold_convertible_p (TREE_TYPE (p), value)) - rhs = fold_convert (TREE_TYPE (p), value); - else - { - /* ??? For valid programs we should not end up here. - Still if we end up with truly mismatched types here, fall back - to using a VIEW_CONVERT_EXPR or a literal zero to not leak invalid - GIMPLE to the following passes. */ - if (!is_gimple_reg_type (TREE_TYPE (value)) - || TYPE_SIZE (TREE_TYPE (p)) == TYPE_SIZE (TREE_TYPE (value))) - rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value); - else - rhs = build_zero_cst (TREE_TYPE (p)); - } - } + rhs = force_value_to_type (TREE_TYPE (p), value); /* Make an equivalent VAR_DECL. Note that we must NOT remap the type here since the type of this decl must be visible to the calling diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h index 87a149c..b226dc0 100644 --- a/gcc/tree-inline.h +++ b/gcc/tree-inline.h @@ -250,6 +250,7 @@ extern tree copy_fn (tree, tree&, tree&); extern const char *copy_forbidden (struct function *fun); extern tree copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy); extern tree copy_decl_to_var (tree, copy_body_data *); +extern tree force_value_to_type (tree type, tree value); /* This is in tree-inline.c since the routine uses data structures from the inliner. */ -- cgit v1.1 From 61362d9d18916bd5b694385982cf4a02b7537b0e Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 30 Sep 2019 11:59:16 +0000 Subject: gimple.c (gimple_get_lhs): For PHIs return the result. 2019-09-30 Richard Biener * gimple.c (gimple_get_lhs): For PHIs return the result. * tree-vectorizer.h (vectorizable_live_operation): Also get the SLP instance as argument. * tree-vect-loop.c (vect_analyze_loop_operations): Also handle double-reduction PHIs with vectorizable_lc_phi. (vect_analyze_loop_operations): Adjust. (vect_create_epilog_for_reduction): Remove all code not dealing with reduction LC PHI or epilogue generation. (vectorizable_live_operation): Call vect_create_epilog_for_reduction for live stmts of reductions. * tree-vect-stmts.c (vectorizable_condition): When !for_reduction do not handle defs that are not vect_internal_def. (can_vectorize_live_stmts): Adjust. (vect_analyze_stmt): When the vectorized stmt defined a value used on backedges adjust the backedge uses of vectorized PHIs. From-SVN: r276299 --- gcc/ChangeLog | 18 ++++ gcc/gimple.c | 2 + gcc/tree-vect-loop.c | 292 +++++++++++++------------------------------------- gcc/tree-vect-stmts.c | 89 +++++++++++---- gcc/tree-vectorizer.h | 3 +- 5 files changed, 167 insertions(+), 237 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4a76e2f..7583de8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2019-09-30 Richard Biener + + * gimple.c (gimple_get_lhs): For PHIs return the result. + * tree-vectorizer.h (vectorizable_live_operation): Also get the + SLP instance as argument. + * tree-vect-loop.c (vect_analyze_loop_operations): Also handle + double-reduction PHIs with vectorizable_lc_phi. + (vect_analyze_loop_operations): Adjust. + (vect_create_epilog_for_reduction): Remove all code not dealing + with reduction LC PHI or epilogue generation. + (vectorizable_live_operation): Call vect_create_epilog_for_reduction + for live stmts of reductions. + * tree-vect-stmts.c (vectorizable_condition): When !for_reduction + do not handle defs that are not vect_internal_def. + (can_vectorize_live_stmts): Adjust. + (vect_analyze_stmt): When the vectorized stmt defined a value + used on backedges adjust the backedge uses of vectorized PHIs. + 2019-09-30 Martin Jambor PR ipa/91853 diff --git a/gcc/gimple.c b/gcc/gimple.c index af62c8b..8e828a5 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1797,6 +1797,8 @@ gimple_get_lhs (const gimple *stmt) return gimple_assign_lhs (stmt); else if (code == GIMPLE_CALL) return gimple_call_lhs (stmt); + else if (code == GIMPLE_PHI) + return gimple_phi_result (stmt); else return NULL_TREE; } diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 2947b02..69cd683 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -1526,7 +1526,9 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) != vect_used_in_outer_by_reduction)) return opt_result::failure_at (phi, "unsupported phi\n"); - if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def + if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def + || (STMT_VINFO_DEF_TYPE (stmt_info) + == vect_double_reduction_def)) && !vectorizable_lc_phi (stmt_info, NULL, NULL)) return opt_result::failure_at (phi, "unsupported phi\n"); } @@ -1564,8 +1566,8 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) if (ok && STMT_VINFO_LIVE_P (stmt_info) && !PURE_SLP_STMT (stmt_info)) - ok = vectorizable_live_operation (stmt_info, NULL, NULL, -1, NULL, - &cost_vec); + ok = vectorizable_live_operation (stmt_info, NULL, NULL, NULL, + -1, NULL, &cost_vec); if (!ok) return opt_result::failure_at (phi, @@ -4260,6 +4262,20 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, slp_instance slp_node_instance) { loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + /* For double reductions we need to get at the inner loop reduction + stmt which has the meta info attached. Our stmt_info is that of the + loop-closed PHI of the inner loop which we remember as + def for the reduction PHI generation. */ + bool double_reduc = false; + stmt_vec_info rdef_info = stmt_info; + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def) + { + gcc_assert (!slp_node); + double_reduc = true; + stmt_info = loop_vinfo->lookup_def (gimple_phi_arg_def + (stmt_info->stmt, 0)); + stmt_info = vect_stmt_to_vectorize (stmt_info); + } gphi *reduc_def_stmt = as_a (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info))->stmt); enum tree_code code = STMT_VINFO_REDUC_CODE (stmt_info); @@ -4269,20 +4285,6 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, neutral_op = neutral_op_for_slp_reduction (slp_node_instance->reduc_phis, code, REDUC_GROUP_FIRST_ELEMENT (stmt_info)); - bool double_reduc = false; - if (nested_in_vect_loop_p (LOOP_VINFO_LOOP (loop_vinfo), stmt_info)) - { - tree def_arg - = PHI_ARG_DEF_FROM_EDGE (reduc_def_stmt, - loop_preheader_edge - (LOOP_VINFO_LOOP (loop_vinfo)->inner)); - stmt_vec_info def_arg_stmt_info = loop_vinfo->lookup_def (def_arg); - if (def_arg_stmt_info - && (STMT_VINFO_DEF_TYPE (def_arg_stmt_info) - == vect_double_reduction_def)) - double_reduc = true; - } - tree induc_val = NULL_TREE; stmt_vec_info prev_phi_info; tree vectype; machine_mode mode; @@ -4298,23 +4300,20 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, gimple *epilog_stmt = NULL; gimple *exit_phi; tree bitsize; - tree adjustment_def = NULL; - tree expr, def, initial_def = NULL; + tree expr, def; tree orig_name, scalar_result; imm_use_iterator imm_iter, phi_imm_iter; use_operand_p use_p, phi_use_p; gimple *use_stmt; bool nested_in_vect_loop = false; auto_vec new_phis; - auto_vec inner_phis; int j, i; auto_vec scalar_results; - unsigned int group_size = 1, k, ratio; + unsigned int group_size = 1, k; auto_vec phis; bool slp_reduc = false; bool direct_slp_reduc; tree new_phi_result; - stmt_vec_info inner_phi = NULL; tree induction_index = NULL_TREE; if (slp_node) @@ -4327,28 +4326,15 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, nested_in_vect_loop = true; gcc_assert (!slp_node); } + gcc_assert (!nested_in_vect_loop || double_reduc); vectype = STMT_VINFO_VECTYPE (stmt_info); gcc_assert (vectype); mode = TYPE_MODE (vectype); - /* 1. Create the reduction def-use cycle: - Set the backedge argument of REDUCTION_PHIS, i.e., transform - - loop: - vec_def = phi # REDUCTION_PHI - VECT_DEF = vector_stmt # vectorized form of STMT - ... - - into: - - loop: - vec_def = phi # REDUCTION_PHI - VECT_DEF = vector_stmt # vectorized form of STMT - ... - - (in case of SLP, do it for all the phis). */ - + tree initial_def = NULL; + tree induc_val = NULL_TREE; + tree adjustment_def = NULL; if (slp_node) ; else @@ -4357,9 +4343,8 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, of the reduction variable. */ initial_def = PHI_ARG_DEF_FROM_EDGE (reduc_def_stmt, loop_preheader_edge (loop)); - /* Optimize: if initial_def is for REDUC_MAX smaller than the base - and we can't use zero for induc_val, use initial_def. Similarly - for REDUC_MIN and initial_def larger than the base. */ + /* Optimize: for induction condition reduction, if we can't use zero + for induc_val, use initial_def. */ if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION) induc_val = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (stmt_info); @@ -4371,50 +4356,26 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, adjustment_def = STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (stmt_info); } - /* Set phi nodes latch arguments. */ - unsigned vec_num = 1; - int ncopies = 0; + unsigned vec_num; + int ncopies; if (slp_node) - vec_num = SLP_TREE_VEC_STMTS (slp_node_instance->reduc_phis).length (); - for (unsigned i = 0; i < vec_num; i++) { - if (slp_node) - { - def = gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt); - phi_info = SLP_TREE_VEC_STMTS (slp_node_instance->reduc_phis)[i]; - } - else + vec_num = SLP_TREE_VEC_STMTS (slp_node_instance->reduc_phis).length (); + ncopies = 1; + } + else + { + vec_num = 1; + ncopies = 0; + phi_info = STMT_VINFO_VEC_STMT (loop_vinfo->lookup_stmt (reduc_def_stmt)); + do { - def = gimple_get_lhs (STMT_VINFO_VEC_STMT (stmt_info)->stmt); - phi_info = STMT_VINFO_VEC_STMT (loop_vinfo->lookup_stmt (reduc_def_stmt)); + ncopies++; + phi_info = STMT_VINFO_RELATED_STMT (phi_info); } - for (ncopies = 0;; ncopies++) - { - /* Set the loop-latch arg for the reduction-phi. */ - if (ncopies != 0) - { - if (slp_node) - break; - phi_info = STMT_VINFO_RELATED_STMT (phi_info); - if (!phi_info) - break; - def = vect_get_vec_def_for_stmt_copy (loop_vinfo, def); - } - - gphi *phi = as_a (phi_info->stmt); - add_phi_arg (phi, def, loop_latch_edge (loop), UNKNOWN_LOCATION); - - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "transform reduction: created def-use cycle: %G%G", - phi, SSA_NAME_DEF_STMT (def)); - } + while (phi_info); } - /* For vectorizing nested cycles the above is all we need to do. */ - if (nested_in_vect_loop && !double_reduc) - return; - /* For cond reductions we want to create a new vector (INDEX_COND_EXPR) which is updated with the current index of the loop for every match of the original loop's cond_expr (VEC_STMT). This results in a vector @@ -4533,7 +4494,8 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, /* 2.1 Create new loop-exit-phis to preserve loop-closed form: v_out1 = phi Store them in NEW_PHIS. */ - + if (double_reduc) + loop = outer_loop; exit_bb = single_exit (loop)->dest; prev_phi_info = NULL; new_phis.create (slp_node ? vec_num : ncopies); @@ -4542,7 +4504,7 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, if (slp_node) def = gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt); else - def = gimple_get_lhs (STMT_VINFO_VEC_STMT (stmt_info)->stmt); + def = gimple_get_lhs (STMT_VINFO_VEC_STMT (rdef_info)->stmt); for (j = 0; j < ncopies; j++) { tree new_def = copy_ssa_name (def); @@ -4561,37 +4523,6 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, } } - /* The epilogue is created for the outer-loop, i.e., for the loop being - vectorized. Create exit phis for the outer loop. */ - if (double_reduc) - { - loop = outer_loop; - exit_bb = single_exit (loop)->dest; - inner_phis.create (slp_node ? vec_num : ncopies); - FOR_EACH_VEC_ELT (new_phis, i, phi) - { - stmt_vec_info phi_info = loop_vinfo->lookup_stmt (phi); - tree new_result = copy_ssa_name (PHI_RESULT (phi)); - gphi *outer_phi = create_phi_node (new_result, exit_bb); - SET_PHI_ARG_DEF (outer_phi, single_exit (loop)->dest_idx, - PHI_RESULT (phi)); - prev_phi_info = loop_vinfo->add_stmt (outer_phi); - inner_phis.quick_push (phi_info); - new_phis[i] = outer_phi; - while (STMT_VINFO_RELATED_STMT (phi_info)) - { - phi_info = STMT_VINFO_RELATED_STMT (phi_info); - new_result = copy_ssa_name (PHI_RESULT (phi_info->stmt)); - outer_phi = create_phi_node (new_result, exit_bb); - SET_PHI_ARG_DEF (outer_phi, single_exit (loop)->dest_idx, - PHI_RESULT (phi_info->stmt)); - stmt_vec_info outer_phi_info = loop_vinfo->add_stmt (outer_phi); - STMT_VINFO_RELATED_STMT (prev_phi_info) = outer_phi_info; - prev_phi_info = outer_phi_info; - } - } - } - exit_gsi = gsi_after_labels (exit_bb); /* 2.2 Get the relevant tree-code to use in the epilog for schemes 2,3 @@ -5381,23 +5312,10 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, correspond to the first vector stmt, etc. (RATIO is equal to (REDUC_GROUP_SIZE / number of new vector stmts)). */ if (group_size > new_phis.length ()) - { - ratio = group_size / new_phis.length (); - gcc_assert (!(group_size % new_phis.length ())); - } - else - ratio = 1; + gcc_assert (!(group_size % new_phis.length ())); - stmt_vec_info epilog_stmt_info = NULL; for (k = 0; k < group_size; k++) { - if (k % ratio == 0) - { - epilog_stmt_info = loop_vinfo->lookup_stmt (new_phis[k / ratio]); - if (double_reduc) - inner_phi = inner_phis[k / ratio]; - } - if (slp_reduc) { stmt_vec_info scalar_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[k]; @@ -5408,84 +5326,6 @@ vect_create_epilog_for_reduction (stmt_vec_info stmt_info, scalar_dest = gimple_assign_lhs (scalar_stmt_info->stmt); } - if (outer_loop) - { - phis.create (3); - /* Find the loop-closed-use at the loop exit of the original scalar - result. (The reduction result is expected to have two immediate uses - - one at the latch block, and one at the loop exit). */ - FOR_EACH_IMM_USE_FAST (use_p, imm_iter, scalar_dest) - if (!flow_bb_inside_loop_p (loop, gimple_bb (USE_STMT (use_p))) - && !is_gimple_debug (USE_STMT (use_p))) - phis.safe_push (USE_STMT (use_p)); - - /* While we expect to have found an exit_phi because of loop-closed-ssa - form we can end up without one if the scalar cycle is dead. */ - - FOR_EACH_VEC_ELT (phis, i, exit_phi) - { - stmt_vec_info exit_phi_vinfo - = loop_vinfo->lookup_stmt (exit_phi); - gphi *vect_phi; - - if (double_reduc) - STMT_VINFO_VEC_STMT (exit_phi_vinfo) = inner_phi; - else - STMT_VINFO_VEC_STMT (exit_phi_vinfo) = epilog_stmt_info; - if (!double_reduc - || STMT_VINFO_DEF_TYPE (exit_phi_vinfo) - != vect_double_reduction_def) - continue; - - /* Handle double reduction: - - stmt1: s1 = phi - double reduction phi (outer loop) - stmt2: s3 = phi - (regular) reduc phi (inner loop) - stmt3: s4 = use (s3) - (regular) reduc stmt (inner loop) - stmt4: s2 = phi - double reduction stmt (outer loop) - - At that point the regular reduction (stmt2 and stmt3) is - already vectorized, as well as the exit phi node, stmt4. - Here we vectorize the phi node of double reduction, stmt1, and - update all relevant statements. */ - - /* Go through all the uses of s2 to find double reduction phi - node, i.e., stmt1 above. */ - orig_name = PHI_RESULT (exit_phi); - FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, orig_name) - { - stmt_vec_info use_stmt_vinfo; - basic_block bb = gimple_bb (use_stmt); - - /* Check that USE_STMT is really double reduction phi - node. */ - if (gimple_code (use_stmt) != GIMPLE_PHI - || gimple_phi_num_args (use_stmt) != 2 - || bb->loop_father != outer_loop) - continue; - use_stmt_vinfo = loop_vinfo->lookup_stmt (use_stmt); - if (!use_stmt_vinfo - || STMT_VINFO_DEF_TYPE (use_stmt_vinfo) - != vect_double_reduction_def) - continue; - - /* Set the outer loop vector phi args. The PHI node - itself was created in vectorizable_reduction. */ - vect_phi = as_a - (STMT_VINFO_VEC_STMT (use_stmt_vinfo)->stmt); - - /* Update phi node argument with vs2. */ - add_phi_arg (vect_phi, PHI_RESULT (inner_phi->stmt), - loop_latch_edge (outer_loop), UNKNOWN_LOCATION); - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "created double reduction phi node: %G", - vect_phi); - } - } - phis.release (); - } - if (nested_in_vect_loop) { if (double_reduc) @@ -7153,10 +6993,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, if (single_defuse_cycle && !slp_node) STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt_info; - /* Finalize the reduction-phi (set its arguments) and create the - epilog reduction code. */ - vect_create_epilog_for_reduction (stmt_info, slp_node, slp_node_instance); - return true; } @@ -7172,10 +7008,8 @@ vectorizable_lc_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt, || gimple_phi_num_args (stmt_info->stmt) != 1) return false; - /* To handle the nested_cycle_def for double-reductions we have to - refactor epilogue generation more. */ if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def - /* && STMT_VINFO_DEF_TYPE (stmt_info) != vect_double_reduction_def */) + && STMT_VINFO_DEF_TYPE (stmt_info) != vect_double_reduction_def) return false; if (!vec_stmt) /* transformation not required. */ @@ -7833,8 +7667,8 @@ vectorizable_induction (stmt_vec_info stmt_info, bool vectorizable_live_operation (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, - slp_tree slp_node, int slp_index, - stmt_vec_info *vec_stmt, + slp_tree slp_node, slp_instance slp_node_instance, + int slp_index, stmt_vec_info *vec_stmt, stmt_vector_for_cost *) { loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); @@ -7851,8 +7685,34 @@ vectorizable_live_operation (stmt_vec_info stmt_info, gcc_assert (STMT_VINFO_LIVE_P (stmt_info)); - if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def) - return false; + /* The last stmt of a reduction is live and vectorized via + vect_create_epilog_for_reduction. vectorizable_reduction assessed + validity so just trigger the transform here. */ + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def) + { + if (!vec_stmt) + return true; + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def) + { + if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION) + return true; + if (slp_node) + { + /* For reduction chains the meta-info is attached to + the group leader. */ + if (REDUC_GROUP_FIRST_ELEMENT (stmt_info)) + stmt_info = REDUC_GROUP_FIRST_ELEMENT (stmt_info); + /* For SLP reductions we vectorize the epilogue for + all involved stmts together. */ + else if (slp_index != 0) + return true; + } + } + vect_create_epilog_for_reduction (stmt_info, slp_node, + slp_node_instance); + return true; + } /* FORNOW. CHECKME. */ if (nested_in_vect_loop_p (loop, stmt_info)) diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 5734068..7fcd2fa 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -9809,19 +9809,17 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, tree vec_cmp_type; bool masked = false; + if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) + return false; + if (for_reduction && STMT_SLP_TYPE (stmt_info)) return false; vect_reduction_type reduction_type = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info); - if (reduction_type == TREE_CODE_REDUCTION) + if (!for_reduction) { - if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) - return false; - - if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def - && !(STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle - && for_reduction)) + if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def) return false; /* FORNOW: not yet supported. */ @@ -10472,7 +10470,8 @@ vectorizable_comparison (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, static bool can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, - slp_tree slp_node, stmt_vec_info *vec_stmt, + slp_tree slp_node, slp_instance slp_node_instance, + stmt_vec_info *vec_stmt, stmt_vector_for_cost *cost_vec) { if (slp_node) @@ -10482,13 +10481,15 @@ can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info) { if (STMT_VINFO_LIVE_P (slp_stmt_info) - && !vectorizable_live_operation (slp_stmt_info, gsi, slp_node, i, + && !vectorizable_live_operation (slp_stmt_info, gsi, slp_node, + slp_node_instance, i, vec_stmt, cost_vec)) return false; } } else if (STMT_VINFO_LIVE_P (stmt_info) - && !vectorizable_live_operation (stmt_info, gsi, slp_node, -1, + && !vectorizable_live_operation (stmt_info, gsi, slp_node, + slp_node_instance, -1, vec_stmt, cost_vec)) return false; @@ -10704,7 +10705,9 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize, need extra handling, except for vectorizable reductions. */ if (!bb_vinfo && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type - && !can_vectorize_live_stmts (stmt_info, NULL, node, NULL, cost_vec)) + && STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type + && !can_vectorize_live_stmts (stmt_info, NULL, node, node_instance, + NULL, cost_vec)) return opt_result::failure_at (stmt_info->stmt, "not vectorized:" " live stmt not supported: %G", @@ -10878,19 +10881,65 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } } - /* Handle stmts whose DEF is used outside the loop-nest that is - being vectorized. */ - if (STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type) + if (vec_stmt) + STMT_VINFO_VEC_STMT (stmt_info) = vec_stmt; + + if (STMT_VINFO_TYPE (stmt_info) == store_vec_info_type) + return is_store; + + /* If this stmt defines a value used on a backedge, update the + vectorized PHIs. */ + stmt_vec_info orig_stmt_info = vect_orig_stmt (stmt_info); + if (!slp_node && STMT_VINFO_REDUC_DEF (orig_stmt_info) + && STMT_VINFO_REDUC_TYPE (orig_stmt_info) != FOLD_LEFT_REDUCTION + && is_a (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt)) + { + gphi *phi = as_a (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt); + if (dominated_by_p (CDI_DOMINATORS, + gimple_bb (orig_stmt_info->stmt), gimple_bb (phi))) + { + edge e = loop_latch_edge (gimple_bb (phi)->loop_father); + stmt_vec_info phi_info + = STMT_VINFO_VEC_STMT (STMT_VINFO_REDUC_DEF (orig_stmt_info)); + stmt_vec_info vec_stmt = STMT_VINFO_VEC_STMT (stmt_info); + do + { + add_phi_arg (as_a (phi_info->stmt), + gimple_get_lhs (vec_stmt->stmt), e, + gimple_phi_arg_location (phi, e->dest_idx)); + phi_info = STMT_VINFO_RELATED_STMT (phi_info); + vec_stmt = STMT_VINFO_RELATED_STMT (vec_stmt); + } + while (phi_info); + gcc_assert (!vec_stmt); + } + } + else if (slp_node && STMT_VINFO_REDUC_DEF (orig_stmt_info) + /* Going back and forth via STMT_VINFO_REDUC_DEF gets us to the + stmt with the reduction meta in case of reduction groups. */ + && (STMT_VINFO_REDUC_TYPE + (STMT_VINFO_REDUC_DEF (STMT_VINFO_REDUC_DEF (orig_stmt_info))) + != FOLD_LEFT_REDUCTION) + && slp_node != slp_node_instance->reduc_phis) { - done = can_vectorize_live_stmts (stmt_info, gsi, slp_node, &vec_stmt, - NULL); - gcc_assert (done); + slp_tree phi_node = slp_node_instance->reduc_phis; + gphi *phi = as_a (SLP_TREE_SCALAR_STMTS (phi_node)[0]->stmt); + edge e = loop_latch_edge (gimple_bb (phi)->loop_father); + gcc_assert (SLP_TREE_VEC_STMTS (phi_node).length () + == SLP_TREE_VEC_STMTS (slp_node).length ()); + for (unsigned i = 0; i < SLP_TREE_VEC_STMTS (phi_node).length (); ++i) + add_phi_arg (as_a (SLP_TREE_VEC_STMTS (phi_node)[i]->stmt), + gimple_get_lhs (SLP_TREE_VEC_STMTS (slp_node)[i]->stmt), + e, gimple_phi_arg_location (phi, e->dest_idx)); } - if (vec_stmt) - STMT_VINFO_VEC_STMT (stmt_info) = vec_stmt; + /* Handle stmts whose DEF is used outside the loop-nest that is + being vectorized. */ + done = can_vectorize_live_stmts (stmt_info, gsi, slp_node, + slp_node_instance, &vec_stmt, NULL); + gcc_assert (done); - return is_store; + return false; } diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index d9171c0..462a968 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1649,7 +1649,8 @@ extern class loop *vect_transform_loop (loop_vec_info); extern opt_loop_vec_info vect_analyze_loop_form (class loop *, vec_info_shared *); extern bool vectorizable_live_operation (stmt_vec_info, gimple_stmt_iterator *, - slp_tree, int, stmt_vec_info *, + slp_tree, slp_instance, int, + stmt_vec_info *, stmt_vector_for_cost *); extern bool vectorizable_reduction (stmt_vec_info, gimple_stmt_iterator *, stmt_vec_info *, slp_tree, slp_instance, -- cgit v1.1 From 26ca7d1b24478324969eae0d171ad698926c8541 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Mon, 30 Sep 2019 13:49:13 +0000 Subject: Add initial support for prefixed/PC-relative addressing. 2019-09-30 Michael Meissner * config/rs6000/predicates.md (pcrel_address): Delete predicate. (pcrel_local_address): Replace pcrel_address predicate, use the new function address_to_insn_form. (pcrel_external_address): Replace with new implementation using address_to_insn_form.. (prefixed_mem_operand): Delete predicate which is now unused. (pcrel_external_mem_operand): Delete predicate which is now unused. * config/rs6000/rs6000-protos.h (enum insn_form): New enumeration. (enum non_prefixed): New enumeration. (address_to_insn_form): New declaration. (prefixed_load_p): New declaration. (prefixed_store_p): New declaration. (prefixed_paddi_p): New declaration. (rs6000_asm_output_opcode): New declaration. (rs6000_final_prescan_insn): Move declaration and update calling signature. (address_is_prefixed): New helper inline function. * config/rs6000/rs6000.c(print_operand_address): Check for either PC-relative local symbols or PC-relative external symbols. (rs6000_emit_move): Support loading PC-relative addresses. (mode_supports_prefixed_address_p): Delete, no longer used. (rs6000_prefixed_address_mode_p): Delete, no longer used. (address_to_insn_form): New function to decode an address format. (reg_to_non_prefixed): New function to identify what the non-prefixed memory instruction format is for a register. (prefixed_load_p): New function to identify prefixed loads. (prefixed_store_p): New function to identify prefixed stores. (prefixed_paddi_p): New function to identify prefixed load immediates. (next_insn_prefixed_p): New static state variable. (rs6000_final_prescan_insn): New function to determine if an insn uses a prefixed instruction. (rs6000_asm_output_opcode): New function to emit 'p' in front of a prefixed instruction. * config/rs6000/rs6000.h (FINAL_PRESCAN_INSN): New target hook. (ASM_OUTPUT_OPCODE): New target hook. * config/rs6000/rs6000.md (prefixed): New insn attribute for prefixed instructions. (prefixed_length): New insn attribute for the size of prefixed instructions. (non_prefixed_length): New insn attribute for the size of non-prefixed instructions. (pcrel_local_addr): New insn to load up a local PC-relative address. (pcrel_extern_addr): New insn to load up an external PC-relative address. (mov_64bit_dm): Split the alternatives for loading 0.0 to a GPR and loading a 128-bit floating point type to a GPR. From-SVN: r276300 --- gcc/ChangeLog | 53 +++++ gcc/config/rs6000/predicates.md | 102 +++------ gcc/config/rs6000/rs6000-protos.h | 63 +++++- gcc/config/rs6000/rs6000.c | 461 ++++++++++++++++++++++++++++++++------ gcc/config/rs6000/rs6000.h | 21 ++ gcc/config/rs6000/rs6000.md | 84 ++++++- 6 files changed, 631 insertions(+), 153 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7583de8..74f08cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,56 @@ +2019-09-30 Michael Meissner + + * config/rs6000/predicates.md (pcrel_address): Delete predicate. + (pcrel_local_address): Replace pcrel_address predicate, use the + new function address_to_insn_form. + (pcrel_external_address): Replace with new implementation using + address_to_insn_form.. + (prefixed_mem_operand): Delete predicate which is now unused. + (pcrel_external_mem_operand): Delete predicate which is now + unused. + * config/rs6000/rs6000-protos.h (enum insn_form): New + enumeration. + (enum non_prefixed): New enumeration. + (address_to_insn_form): New declaration. + (prefixed_load_p): New declaration. + (prefixed_store_p): New declaration. + (prefixed_paddi_p): New declaration. + (rs6000_asm_output_opcode): New declaration. + (rs6000_final_prescan_insn): Move declaration and update calling + signature. + (address_is_prefixed): New helper inline function. + * config/rs6000/rs6000.c(print_operand_address): Check for either + PC-relative local symbols or PC-relative external symbols. + (rs6000_emit_move): Support loading PC-relative addresses. + (mode_supports_prefixed_address_p): Delete, no longer used. + (rs6000_prefixed_address_mode_p): Delete, no longer used. + (address_to_insn_form): New function to decode an address format. + (reg_to_non_prefixed): New function to identify what the + non-prefixed memory instruction format is for a register. + (prefixed_load_p): New function to identify prefixed loads. + (prefixed_store_p): New function to identify prefixed stores. + (prefixed_paddi_p): New function to identify prefixed load + immediates. + (next_insn_prefixed_p): New static state variable. + (rs6000_final_prescan_insn): New function to determine if an insn + uses a prefixed instruction. + (rs6000_asm_output_opcode): New function to emit 'p' in front of a + prefixed instruction. + * config/rs6000/rs6000.h (FINAL_PRESCAN_INSN): New target hook. + (ASM_OUTPUT_OPCODE): New target hook. + * config/rs6000/rs6000.md (prefixed): New insn attribute for + prefixed instructions. + (prefixed_length): New insn attribute for the size of prefixed + instructions. + (non_prefixed_length): New insn attribute for the size of + non-prefixed instructions. + (pcrel_local_addr): New insn to load up a local PC-relative + address. + (pcrel_extern_addr): New insn to load up an external PC-relative + address. + (mov_64bit_dm): Split the alternatives for loading 0.0 to a + GPR and loading a 128-bit floating point type to a GPR. + 2019-09-30 Richard Biener * gimple.c (gimple_get_lhs): For PHIs return the result. diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 9368bdd..345d9c3 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1625,82 +1625,7 @@ return GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_TOCREL; }) -;; Return true if the operand is a pc-relative address. -(define_predicate "pcrel_address" - (match_code "label_ref,symbol_ref,const") -{ - if (!rs6000_pcrel_p (cfun)) - return false; - - if (GET_CODE (op) == CONST) - op = XEXP (op, 0); - - /* Validate offset. */ - if (GET_CODE (op) == PLUS) - { - rtx op0 = XEXP (op, 0); - rtx op1 = XEXP (op, 1); - - if (!CONST_INT_P (op1) || !SIGNED_34BIT_OFFSET_P (INTVAL (op1))) - return false; - - op = op0; - } - - if (LABEL_REF_P (op)) - return true; - - return (SYMBOL_REF_P (op) && SYMBOL_REF_LOCAL_P (op)); -}) - -;; Return true if the operand is an external symbol whose address can be loaded -;; into a register using: -;; PLD reg,label@pcrel@got -;; -;; The linker will either optimize this to either a PADDI if the label is -;; defined locally in another module or a PLD of the address if the label is -;; defined in another module. - -(define_predicate "pcrel_external_address" - (match_code "symbol_ref,const") -{ - if (!rs6000_pcrel_p (cfun)) - return false; - - if (GET_CODE (op) == CONST) - op = XEXP (op, 0); - - /* Validate offset. */ - if (GET_CODE (op) == PLUS) - { - rtx op0 = XEXP (op, 0); - rtx op1 = XEXP (op, 1); - - if (!CONST_INT_P (op1) || !SIGNED_34BIT_OFFSET_P (INTVAL (op1))) - return false; - - op = op0; - } - - return (SYMBOL_REF_P (op) && !SYMBOL_REF_LOCAL_P (op)); -}) - -;; Return 1 if op is a prefixed memory operand. -(define_predicate "prefixed_mem_operand" - (match_code "mem") -{ - return rs6000_prefixed_address_mode_p (XEXP (op, 0), GET_MODE (op)); -}) - -;; Return 1 if op is a memory operand to an external variable when we -;; support pc-relative addressing and the PCREL_OPT relocation to -;; optimize references to it. -(define_predicate "pcrel_external_mem_operand" - (match_code "mem") -{ - return pcrel_external_address (XEXP (op, 0), Pmode); -}) - + ;; Match the first insn (addis) in fusing the combination of addis and loads to ;; GPR registers on power8. (define_predicate "fusion_gpr_addis" @@ -1857,3 +1782,28 @@ return 0; }) + + +;; Return true if the operand is a PC-relative address of a local symbol or a +;; label that can be used directly in a memory operation. +(define_predicate "pcrel_local_address" + (match_code "label_ref,symbol_ref,const") +{ + enum insn_form iform = address_to_insn_form (op, mode, NON_PREFIXED_DEFAULT); + return iform == INSN_FORM_PCREL_LOCAL; +}) + +;; Return true if the operand is a PC-relative external symbol whose address +;; can be loaded into a register. +(define_predicate "pcrel_external_address" + (match_code "symbol_ref,const") +{ + enum insn_form iform = address_to_insn_form (op, mode, NON_PREFIXED_DEFAULT); + return iform == INSN_FORM_PCREL_EXTERNAL; +}) + +;; Return true if the address is PC-relative and the symbol is either local or +;; external. +(define_predicate "pcrel_local_or_external_address" + (ior (match_operand 0 "pcrel_local_address") + (match_operand 0 "pcrel_external_address"))) diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 06e40d9..c51b768 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -154,7 +154,66 @@ extern align_flags rs6000_loop_align (rtx); extern void rs6000_split_logical (rtx [], enum rtx_code, bool, bool, bool); extern bool rs6000_pcrel_p (struct function *); extern bool rs6000_fndecl_pcrel_p (const_tree); -extern bool rs6000_prefixed_address_mode_p (rtx, machine_mode); + +/* Different PowerPC instruction formats that are used by GCC. There are + various other instruction formats used by the PowerPC hardware, but these + formats are not currently used by GCC. */ + +enum insn_form { + INSN_FORM_BAD, /* Bad instruction format. */ + INSN_FORM_BASE_REG, /* Base register only. */ + INSN_FORM_D, /* Reg + 16-bit numeric offset. */ + INSN_FORM_DS, /* Reg + offset, bottom 2 bits must be 0. */ + INSN_FORM_DQ, /* Reg + offset, bottom 4 bits must be 0. */ + INSN_FORM_X, /* Base register + index register. */ + INSN_FORM_UPDATE, /* Address updates base register. */ + INSN_FORM_LO_SUM, /* Reg + offset using symbol. */ + INSN_FORM_PREFIXED_NUMERIC, /* Reg + 34 bit numeric offset. */ + INSN_FORM_PCREL_LOCAL, /* PC-relative local symbol. */ + INSN_FORM_PCREL_EXTERNAL /* PC-relative external symbol. */ +}; + +/* Instruction format for the non-prefixed version of a load or store. This is + used to determine if a 16-bit offset is valid to be used with a non-prefixed + (traditional) instruction or if the bottom bits of the offset cannot be used + with a DS or DQ instruction format, and GCC has to use a prefixed + instruction for the load or store. */ + +enum non_prefixed_form { + NON_PREFIXED_DEFAULT, /* Use the default. */ + NON_PREFIXED_D, /* All 16-bits are valid. */ + NON_PREFIXED_DS, /* Bottom 2 bits must be 0. */ + NON_PREFIXED_DQ, /* Bottom 4 bits must be 0. */ + NON_PREFIXED_X /* No offset memory form exists. */ +}; + +extern enum insn_form address_to_insn_form (rtx, machine_mode, + enum non_prefixed_form); +extern bool prefixed_load_p (rtx_insn *); +extern bool prefixed_store_p (rtx_insn *); +extern bool prefixed_paddi_p (rtx_insn *); +extern void rs6000_asm_output_opcode (FILE *); +extern void rs6000_final_prescan_insn (rtx_insn *, rtx [], int); + +/* Return true if the address can be used for a prefixed load, store, or add + immediate instructions that cannot be used with a non-prefixed instruction. + For example, using a numeric offset that is not valid for the non-prefixed + instruction or a PC-relative reference to a local symbol would return true, + but an address with an offset of 64 would not return true. + + References to external PC-relative symbols aren't allowed, because GCC has + to load the address into a register and then issue a separate load or + store. */ + +static inline bool +address_is_prefixed (rtx addr, + machine_mode mode, + enum non_prefixed_form non_prefixed) +{ + enum insn_form iform = address_to_insn_form (addr, mode, non_prefixed); + return (iform == INSN_FORM_PREFIXED_NUMERIC + || iform == INSN_FORM_PCREL_LOCAL); +} #endif /* RTX_CODE */ #ifdef TREE_CODE @@ -234,8 +293,6 @@ extern void rs6000_d_target_versions (void); const char * rs6000_xcoff_strip_dollar (const char *); #endif -void rs6000_final_prescan_insn (rtx_insn *, rtx *operand, int num_operands); - extern unsigned char rs6000_class_max_nregs[][LIM_REG_CLASSES]; extern unsigned char rs6000_hard_regno_nregs[][FIRST_PSEUDO_REGISTER]; diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 1eb1317..d6e1fea 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -9640,6 +9640,14 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) return; } + /* Use the default pattern for loading up PC-relative addresses. */ + if (TARGET_PCREL && mode == Pmode + && pcrel_local_or_external_address (operands[1], Pmode)) + { + emit_insn (gen_rtx_SET (operands[0], operands[1])); + return; + } + if (DEFAULT_ABI == ABI_V4 && mode == Pmode && mode == SImode && flag_pic == 1 && got_operand (operands[1], mode)) @@ -13082,8 +13090,8 @@ print_operand_address (FILE *file, rtx x) if (REG_P (x)) fprintf (file, "0(%s)", reg_names[ REGNO (x) ]); - /* Is it a pc-relative address? */ - else if (pcrel_address (x, Pmode)) + /* Is it a PC-relative address? */ + else if (TARGET_PCREL && pcrel_local_or_external_address (x, VOIDmode)) { HOST_WIDE_INT offset; @@ -13103,7 +13111,10 @@ print_operand_address (FILE *file, rtx x) if (offset) fprintf (file, "%+" PRId64, offset); - fputs ("@pcrel", file); + if (SYMBOL_REF_P (x) && !SYMBOL_REF_LOCAL_P (x)) + fprintf (file, "@got"); + + fprintf (file, "@pcrel"); } else if (SYMBOL_REF_P (x) || GET_CODE (x) == CONST || GET_CODE (x) == LABEL_REF) @@ -13588,71 +13599,6 @@ rs6000_pltseq_template (rtx *operands, int which) return str; } #endif - -/* Helper function to return whether a MODE can do prefixed loads/stores. - VOIDmode is used when we are loading the pc-relative address into a base - register, but we are not using it as part of a memory operation. As modes - add support for prefixed memory, they will be added here. */ - -static bool -mode_supports_prefixed_address_p (machine_mode mode) -{ - return mode == VOIDmode; -} - -/* Function to return true if ADDR is a valid prefixed memory address that uses - mode MODE. */ - -bool -rs6000_prefixed_address_mode_p (rtx addr, machine_mode mode) -{ - if (!TARGET_PREFIXED_ADDR || !mode_supports_prefixed_address_p (mode)) - return false; - - /* Check for PC-relative addresses. */ - if (pcrel_address (addr, Pmode)) - return true; - - /* Check for prefixed memory addresses that have a large numeric offset, - or an offset that can't be used for a DS/DQ-form memory operation. */ - if (GET_CODE (addr) == PLUS) - { - rtx op0 = XEXP (addr, 0); - rtx op1 = XEXP (addr, 1); - - if (!base_reg_operand (op0, Pmode) || !CONST_INT_P (op1)) - return false; - - HOST_WIDE_INT value = INTVAL (op1); - if (!SIGNED_34BIT_OFFSET_P (value)) - return false; - - /* Offset larger than 16-bits? */ - if (!SIGNED_16BIT_OFFSET_P (value)) - return true; - - /* DQ instruction (bottom 4 bits must be 0) for vectors. */ - HOST_WIDE_INT mask; - if (GET_MODE_SIZE (mode) >= 16) - mask = 15; - - /* DS instruction (bottom 2 bits must be 0). For 32-bit integers, we - need to use DS instructions if we are sign-extending the value with - LWA. For 32-bit floating point, we need DS instructions to load and - store values to the traditional Altivec registers. */ - else if (GET_MODE_SIZE (mode) >= 4) - mask = 3; - - /* QImode/HImode has no restrictions. */ - else - return true; - - /* Return true if we must use a prefixed instruction. */ - return (value & mask) != 0; - } - - return false; -} #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO /* Emit an assembler directive to set symbol visibility for DECL to @@ -24617,6 +24563,385 @@ rs6000_pcrel_p (struct function *fn) return rs6000_fndecl_pcrel_p (fn->decl); } + +/* Given an address (ADDR), a mode (MODE), and what the format of the + non-prefixed address (NON_PREFIXED_FORMAT) is, return the instruction format + for the address. */ + +enum insn_form +address_to_insn_form (rtx addr, + machine_mode mode, + enum non_prefixed_form non_prefixed_format) +{ + /* Single register is easy. */ + if (REG_P (addr) || SUBREG_P (addr)) + return INSN_FORM_BASE_REG; + + /* If the non prefixed instruction format doesn't support offset addressing, + make sure only indexed addressing is allowed. + + We special case SDmode so that the register allocator does not try to move + SDmode through GPR registers, but instead uses the 32-bit integer load and + store instructions for the floating point registers. */ + if (non_prefixed_format == NON_PREFIXED_X || (mode == SDmode && TARGET_DFP)) + { + if (GET_CODE (addr) != PLUS) + return INSN_FORM_BAD; + + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + if (!REG_P (op0) && !SUBREG_P (op0)) + return INSN_FORM_BAD; + + if (!REG_P (op1) && !SUBREG_P (op1)) + return INSN_FORM_BAD; + + return INSN_FORM_X; + } + + /* Deal with update forms. */ + if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC) + return INSN_FORM_UPDATE; + + /* Handle PC-relative symbols and labels. Check for both local and external + symbols. Assume labels are always local. */ + if (TARGET_PCREL) + { + if (SYMBOL_REF_P (addr) && !SYMBOL_REF_LOCAL_P (addr)) + return INSN_FORM_PCREL_EXTERNAL; + + if (SYMBOL_REF_P (addr) || LABEL_REF_P (addr)) + return INSN_FORM_PCREL_LOCAL; + } + + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + /* Recognize LO_SUM addresses used with TOC and 32-bit addressing. */ + if (GET_CODE (addr) == LO_SUM) + return INSN_FORM_LO_SUM; + + /* Everything below must be an offset address of some form. */ + if (GET_CODE (addr) != PLUS) + return INSN_FORM_BAD; + + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + /* Check for indexed addresses. */ + if (REG_P (op1) || SUBREG_P (op1)) + { + if (REG_P (op0) || SUBREG_P (op0)) + return INSN_FORM_X; + + return INSN_FORM_BAD; + } + + if (!CONST_INT_P (op1)) + return INSN_FORM_BAD; + + HOST_WIDE_INT offset = INTVAL (op1); + if (!SIGNED_34BIT_OFFSET_P (offset)) + return INSN_FORM_BAD; + + /* Check for local and external PC-relative addresses. Labels are always + local. */ + if (TARGET_PCREL) + { + if (SYMBOL_REF_P (op0) && !SYMBOL_REF_LOCAL_P (op0)) + return INSN_FORM_PCREL_EXTERNAL; + + if (SYMBOL_REF_P (op0) || LABEL_REF_P (op0)) + return INSN_FORM_PCREL_LOCAL; + } + + /* If it isn't PC-relative, the address must use a base register. */ + if (!REG_P (op0) && !SUBREG_P (op0)) + return INSN_FORM_BAD; + + /* Large offsets must be prefixed. */ + if (!SIGNED_16BIT_OFFSET_P (offset)) + { + if (TARGET_PREFIXED_ADDR) + return INSN_FORM_PREFIXED_NUMERIC; + + return INSN_FORM_BAD; + } + + /* We have a 16-bit offset, see what default instruction format to use. */ + if (non_prefixed_format == NON_PREFIXED_DEFAULT) + { + unsigned size = GET_MODE_SIZE (mode); + + /* On 64-bit systems, assume 64-bit integers need to use DS form + addresses (for LD/STD). VSX vectors need to use DQ form addresses + (for LXV and STXV). TImode is problematical in that its normal usage + is expected to be GPRs where it wants a DS instruction format, but if + it goes into the vector registers, it wants a DQ instruction + format. */ + if (TARGET_POWERPC64 && size >= 8 && GET_MODE_CLASS (mode) == MODE_INT) + non_prefixed_format = NON_PREFIXED_DS; + + else if (TARGET_VSX && size >= 16 + && (VECTOR_MODE_P (mode) || FLOAT128_VECTOR_P (mode))) + non_prefixed_format = NON_PREFIXED_DQ; + + else + non_prefixed_format = NON_PREFIXED_D; + } + + /* Classify the D/DS/DQ-form addresses. */ + switch (non_prefixed_format) + { + /* Instruction format D, all 16 bits are valid. */ + case NON_PREFIXED_D: + return INSN_FORM_D; + + /* Instruction format DS, bottom 2 bits must be 0. */ + case NON_PREFIXED_DS: + if ((offset & 3) == 0) + return INSN_FORM_DS; + + else if (TARGET_PREFIXED_ADDR) + return INSN_FORM_PREFIXED_NUMERIC; + + else + return INSN_FORM_BAD; + + /* Instruction format DQ, bottom 4 bits must be 0. */ + case NON_PREFIXED_DQ: + if ((offset & 15) == 0) + return INSN_FORM_DQ; + + else if (TARGET_PREFIXED_ADDR) + return INSN_FORM_PREFIXED_NUMERIC; + + else + return INSN_FORM_BAD; + + default: + break; + } + + return INSN_FORM_BAD; +} + +/* Helper function to take a REG and a MODE and turn it into the non-prefixed + instruction format (D/DS/DQ) used for offset memory. */ + +static enum non_prefixed_form +reg_to_non_prefixed (rtx reg, machine_mode mode) +{ + /* If it isn't a register, use the defaults. */ + if (!REG_P (reg) && !SUBREG_P (reg)) + return NON_PREFIXED_DEFAULT; + + unsigned int r = reg_or_subregno (reg); + + /* If we have a pseudo, use the default instruction format. */ + if (!HARD_REGISTER_NUM_P (r)) + return NON_PREFIXED_DEFAULT; + + unsigned size = GET_MODE_SIZE (mode); + + /* FPR registers use D-mode for scalars, and DQ-mode for vectors, IEEE + 128-bit floating point, and 128-bit integers. */ + if (FP_REGNO_P (r)) + { + if (mode == SFmode || size == 8 || FLOAT128_2REG_P (mode)) + return NON_PREFIXED_D; + + else if (size < 8) + return NON_PREFIXED_X; + + else if (TARGET_VSX && size >= 16 + && (VECTOR_MODE_P (mode) + || FLOAT128_VECTOR_P (mode) + || mode == TImode || mode == CTImode)) + return NON_PREFIXED_DQ; + + else + return NON_PREFIXED_DEFAULT; + } + + /* Altivec registers use DS-mode for scalars, and DQ-mode for vectors, IEEE + 128-bit floating point, and 128-bit integers. */ + else if (ALTIVEC_REGNO_P (r)) + { + if (mode == SFmode || size == 8 || FLOAT128_2REG_P (mode)) + return NON_PREFIXED_DS; + + else if (size < 8) + return NON_PREFIXED_X; + + else if (TARGET_VSX && size >= 16 + && (VECTOR_MODE_P (mode) + || FLOAT128_VECTOR_P (mode) + || mode == TImode || mode == CTImode)) + return NON_PREFIXED_DQ; + + else + return NON_PREFIXED_DEFAULT; + } + + /* GPR registers use DS-mode for 64-bit items on 64-bit systems, and D-mode + otherwise. Assume that any other register, such as LR, CRs, etc. will go + through the GPR registers for memory operations. */ + else if (TARGET_POWERPC64 && size >= 8) + return NON_PREFIXED_DS; + + return NON_PREFIXED_D; +} + + +/* Whether a load instruction is a prefixed instruction. This is called from + the prefixed attribute processing. */ + +bool +prefixed_load_p (rtx_insn *insn) +{ + /* Validate the insn to make sure it is a normal load insn. */ + extract_insn_cached (insn); + if (recog_data.n_operands < 2) + return false; + + rtx reg = recog_data.operand[0]; + rtx mem = recog_data.operand[1]; + + if (!REG_P (reg) && !SUBREG_P (reg)) + return false; + + if (!MEM_P (mem)) + return false; + + /* Prefixed load instructions do not support update or indexed forms. */ + if (get_attr_indexed (insn) == INDEXED_YES + || get_attr_update (insn) == UPDATE_YES) + return false; + + /* LWA uses the DS format instead of the D format that LWZ uses. */ + enum non_prefixed_form non_prefixed; + machine_mode reg_mode = GET_MODE (reg); + machine_mode mem_mode = GET_MODE (mem); + + if (mem_mode == SImode && reg_mode == DImode + && get_attr_sign_extend (insn) == SIGN_EXTEND_YES) + non_prefixed = NON_PREFIXED_DS; + + else + non_prefixed = reg_to_non_prefixed (reg, mem_mode); + + return address_is_prefixed (XEXP (mem, 0), mem_mode, non_prefixed); +} + +/* Whether a store instruction is a prefixed instruction. This is called from + the prefixed attribute processing. */ + +bool +prefixed_store_p (rtx_insn *insn) +{ + /* Validate the insn to make sure it is a normal store insn. */ + extract_insn_cached (insn); + if (recog_data.n_operands < 2) + return false; + + rtx mem = recog_data.operand[0]; + rtx reg = recog_data.operand[1]; + + if (!REG_P (reg) && !SUBREG_P (reg)) + return false; + + if (!MEM_P (mem)) + return false; + + /* Prefixed store instructions do not support update or indexed forms. */ + if (get_attr_indexed (insn) == INDEXED_YES + || get_attr_update (insn) == UPDATE_YES) + return false; + + machine_mode mem_mode = GET_MODE (mem); + enum non_prefixed_form non_prefixed = reg_to_non_prefixed (reg, mem_mode); + return address_is_prefixed (XEXP (mem, 0), mem_mode, non_prefixed); +} + +/* Whether a load immediate or add instruction is a prefixed instruction. This + is called from the prefixed attribute processing. */ + +bool +prefixed_paddi_p (rtx_insn *insn) +{ + rtx set = single_set (insn); + if (!set) + return false; + + rtx dest = SET_DEST (set); + rtx src = SET_SRC (set); + + if (!REG_P (dest) && !SUBREG_P (dest)) + return false; + + /* Is this a load immediate that can't be done with a simple ADDI or + ADDIS? */ + if (CONST_INT_P (src)) + return (satisfies_constraint_eI (src) + && !satisfies_constraint_I (src) + && !satisfies_constraint_L (src)); + + /* Is this a PADDI instruction that can't be done with a simple ADDI or + ADDIS? */ + if (GET_CODE (src) == PLUS) + { + rtx op1 = XEXP (src, 1); + + return (CONST_INT_P (op1) + && satisfies_constraint_eI (op1) + && !satisfies_constraint_I (op1) + && !satisfies_constraint_L (op1)); + } + + /* If not, is it a load of a PC-relative address? */ + if (!TARGET_PCREL || GET_MODE (dest) != Pmode) + return false; + + if (!SYMBOL_REF_P (src) && !LABEL_REF_P (src) && GET_CODE (src) != CONST) + return false; + + enum insn_form iform = address_to_insn_form (src, Pmode, + NON_PREFIXED_DEFAULT); + + return (iform == INSN_FORM_PCREL_EXTERNAL || iform == INSN_FORM_PCREL_LOCAL); +} + +/* Whether the next instruction needs a 'p' prefix issued before the + instruction is printed out. */ +static bool next_insn_prefixed_p; + +/* Define FINAL_PRESCAN_INSN if some processing needs to be done before + outputting the assembler code. On the PowerPC, we remember if the current + insn is a prefixed insn where we need to emit a 'p' before the insn. + + In addition, if the insn is part of a PC-relative reference to an external + label optimization, this is recorded also. */ +void +rs6000_final_prescan_insn (rtx_insn *insn, rtx [], int) +{ + next_insn_prefixed_p = (get_attr_prefixed (insn) != PREFIXED_NO); + return; +} + +/* Define ASM_OUTPUT_OPCODE to do anything special before emitting an opcode. + We use it to emit a 'p' for prefixed insns that is set in + FINAL_PRESCAN_INSN. */ +void +rs6000_asm_output_opcode (FILE *stream) +{ + if (next_insn_prefixed_p) + fprintf (stream, "p"); + + return; +} + + #ifdef HAVE_GAS_HIDDEN # define USE_HIDDEN_LINKONCE 1 #else diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 8f5c70e..0156448 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2547,3 +2547,24 @@ typedef struct GTY(()) machine_function IN_RANGE ((VALUE), \ -(HOST_WIDE_INT_1 << 33), \ (HOST_WIDE_INT_1 << 33) - 1 - (EXTRA)) + +/* Define this if some processing needs to be done before outputting the + assembler code. On the PowerPC, we remember if the current insn is a normal + prefixed insn where we need to emit a 'p' before the insn. */ +#define FINAL_PRESCAN_INSN(INSN, OPERANDS, NOPERANDS) \ +do \ + { \ + if (TARGET_PREFIXED_ADDR) \ + rs6000_final_prescan_insn (INSN, OPERANDS, NOPERANDS); \ + } \ +while (0) + +/* Do anything special before emitting an opcode. We use it to emit a 'p' for + prefixed insns that is set in FINAL_PRESCAN_INSN. */ +#define ASM_OUTPUT_OPCODE(STREAM, OPCODE) \ + do \ + { \ + if (TARGET_PREFIXED_ADDR) \ + rs6000_asm_output_opcode (STREAM); \ + } \ + while (0) diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 46167e5..4f27f13 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -256,8 +256,49 @@ ;; Is copying of this instruction disallowed? (define_attr "cannot_copy" "no,yes" (const_string "no")) -;; Length of the instruction (in bytes). -(define_attr "length" "" (const_int 4)) + +;; Whether an insn is a prefixed insn, and an initial 'p' should be printed +;; before the instruction. A prefixed instruction has a prefix instruction +;; word that extends the immediate value of the instructions from 12-16 bits to +;; 34 bits. The macro ASM_OUTPUT_OPCODE emits a leading 'p' for prefixed +;; insns. The default "length" attribute will also be adjusted by default to +;; be 12 bytes. +(define_attr "prefixed" "no,yes" + (cond [(ior (match_test "!TARGET_PREFIXED_ADDR") + (match_test "!NONJUMP_INSN_P (insn)")) + (const_string "no") + + (eq_attr "type" "load,fpload,vecload") + (if_then_else (match_test "prefixed_load_p (insn)") + (const_string "yes") + (const_string "no")) + + (eq_attr "type" "store,fpstore,vecstore") + (if_then_else (match_test "prefixed_store_p (insn)") + (const_string "yes") + (const_string "no")) + + (eq_attr "type" "integer,add") + (if_then_else (match_test "prefixed_paddi_p (insn)") + (const_string "yes") + (const_string "no"))] + + (const_string "no"))) + +;; Length in bytes of instructions that use prefixed addressing and length in +;; bytes of instructions that does not use prefixed addressing. This allows +;; both lengths to be defined as constants, and the length attribute can pick +;; the size as appropriate. +(define_attr "prefixed_length" "" (const_int 12)) +(define_attr "non_prefixed_length" "" (const_int 4)) + +;; Length of the instruction (in bytes). Prefixed insns are 8 bytes, but the +;; assembler might issue need to issue a NOP so that the prefixed instruction +;; does not cross a cache boundary, which makes them possibly 12 bytes. +(define_attr "length" "" + (if_then_else (eq_attr "prefixed" "yes") + (attr "prefixed_length") + (attr "non_prefixed_length"))) ;; Processor type -- this attribute must exactly match the processor_type ;; enumeration in rs6000-opts.h. @@ -7713,9 +7754,18 @@ ;; not swapped like they are for TImode or TFmode. Subregs therefore are ;; problematical. Don't allow direct move for this case. +;; FPR load FPR store FPR move FPR zero GPR load +;; GPR zero GPR store GPR move MFVSRD MTVSRD + (define_insn_and_split "*mov_64bit_dm" - [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r,r,d") - (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,,r,Y,r,d,r"))] + [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" + "=m, d, d, d, Y, + r, r, r, r, d") + + (match_operand:FMOVE128_FPR 1 "input_operand" + "d, m, d, , r, + , Y, r, d, r"))] + "TARGET_HARD_FLOAT && TARGET_POWERPC64 && FLOAT128_2REG_P (mode) && (mode != TDmode || WORDS_BIG_ENDIAN) && (gpc_reg_operand (operands[0], mode) @@ -7724,8 +7774,8 @@ "&& reload_completed" [(pc)] { rs6000_split_multireg_move (operands[0], operands[1]); DONE; } - [(set_attr "length" "8,8,8,8,12,12,8,8,8") - (set_attr "isa" "*,*,*,*,*,*,*,p8v,p8v")]) + [(set_attr "length" "8") + (set_attr "isa" "*,*,*,*,*,*,*,*,p8v,p8v")]) (define_insn_and_split "*movtd_64bit_nodm" [(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r") @@ -9874,6 +9924,28 @@ operands[6] = gen_rtx_PARALLEL (VOIDmode, p); }) +;; Load up a PC-relative address. Print_operand_address will append a @pcrel +;; to the symbol or label. +(define_insn "*pcrel_local_addr" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operand:DI 1 "pcrel_local_address"))] + "TARGET_PCREL" + "la %0,%a1" + [(set_attr "prefixed" "yes")]) + +;; Load up a PC-relative address to an external symbol. If the symbol and the +;; program are both defined in the main program, the linker will optimize this +;; to a PADDI. Otherwise, it will create a GOT address that is relocated by +;; the dynamic linker and loaded up. Print_operand_address will append a +;; @got@pcrel to the symbol. +(define_insn "*pcrel_extern_addr" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operand:DI 1 "pcrel_external_address"))] + "TARGET_PCREL" + "ld %0,%a1" + [(set_attr "prefixed" "yes") + (set_attr "type" "load")]) + ;; TOC register handling. ;; Code to initialize the TOC register... -- cgit v1.1 From 9343bf99b5e36fa11b723aafa282fd5900a5e525 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 14:49:07 +0000 Subject: [C] Print ", ..." rather than ", ..." in diagnostics pp_separate_with inserts a space after the separator, so there's no need to add whitespace before "..." as well. 2019-09-30 Richard Sandiford gcc/c-family/ * c-pretty-print.c (pp_c_parameter_type_list): Avoid printing two spaces between a comma and "...". gcc/testsuite/ * gcc.dg/Wincompatible-pointer-types-1.c (f1): Expect only one space between the comma and "...". From-SVN: r276302 --- gcc/c-family/ChangeLog | 5 +++++ gcc/c-family/c-pretty-print.c | 2 +- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 9334ed5..d0973dd 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2019-09-30 Richard Sandiford + + * c-pretty-print.c (pp_c_parameter_type_list): Avoid printing + two spaces between a comma and "...". + 2019-09-27 Jakub Jelinek PR c++/88203 diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c index 3e25624..e5cad67 100644 --- a/gcc/c-family/c-pretty-print.c +++ b/gcc/c-family/c-pretty-print.c @@ -525,7 +525,7 @@ pp_c_parameter_type_list (c_pretty_printer *pp, tree t) if (!first && !parms) { pp_separate_with (pp, ','); - pp_c_ws_string (pp, "..."); + pp_string (pp, "..."); } } pp_c_right_paren (pp); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 84139ef..868b4aa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-09-30 Richard Sandiford + + * gcc.dg/Wincompatible-pointer-types-1.c (f1): Expect only one + space between the comma and "...". + 2019-09-30 Martin Jambor PR ipa/91853 diff --git a/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c b/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c index 9ffdc2e..4ae7b1d 100644 --- a/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c +++ b/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c @@ -7,6 +7,6 @@ int f1 (void) { int (*x) (); - x = f; /* { dg-error "assignment to 'int \\(\\*\\)\\(\\)' from incompatible pointer type 'void \\(\\*\\)\\(int, \.\.\.\\)'" } */ + x = f; /* { dg-error "assignment to 'int \\(\\*\\)\\(\\)' from incompatible pointer type 'void \\(\\*\\)\\(int, \.\.\.\\)'" } */ return x (1); } -- cgit v1.1 From 20fa157e674d0175f8c2717683462cdaded4d5be Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 30 Sep 2019 14:56:33 +0000 Subject: Introduce rtx_alloca, alloca_raw_REG and alloca_rtx_fmt_* When one passes short-lived fake rtxes to backends in order to test their capabilities, it might be beneficial to allocate these rtxes on stack in order to reduce the load on GC. Provide macro counterparts of some of the gen_* functions for that purpose. gcc/ChangeLog: 2019-09-30 Ilya Leoshkevich * emit-rtl.c (init_raw_REG): New function. (gen_raw_REG): Use init_raw_REG. * gengenrtl.c (gendef): Emit init_* functions and alloca_* macros. * rtl.c (rtx_alloc_stat_v): Use rtx_init. * rtl.h (rtx_init): New function. (rtx_alloca): New function. (init_raw_REG): New function. (alloca_raw_REG): New macro. From-SVN: r276303 --- gcc/ChangeLog | 12 +++++++++++ gcc/emit-rtl.c | 15 +++++++++++--- gcc/gengenrtl.c | 62 +++++++++++++++++++++++++++++++++++++++++++-------------- gcc/rtl.c | 7 +------ gcc/rtl.h | 12 +++++++++++ 5 files changed, 84 insertions(+), 24 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 74f08cc..e0acd9d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2019-09-30 Ilya Leoshkevich + + * emit-rtl.c (init_raw_REG): New function. + (gen_raw_REG): Use init_raw_REG. + * gengenrtl.c (gendef): Emit init_* functions and alloca_* + macros. + * rtl.c (rtx_alloc_stat_v): Use rtx_init. + * rtl.h (rtx_init): New function. + (rtx_alloca): New function. + (init_raw_REG): New function. + (alloca_raw_REG): New macro. + 2019-09-30 Michael Meissner * config/rs6000/predicates.md (pcrel_address): Delete predicate. diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index a667cda..783fdb9 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -466,6 +466,17 @@ set_mode_and_regno (rtx x, machine_mode mode, unsigned int regno) set_regno_raw (x, regno, nregs); } +/* Initialize a fresh REG rtx with mode MODE and register REGNO. */ + +rtx +init_raw_REG (rtx x, machine_mode mode, unsigned int regno) +{ + set_mode_and_regno (x, mode, regno); + REG_ATTRS (x) = NULL; + ORIGINAL_REGNO (x) = regno; + return x; +} + /* Generate a new REG rtx. Make sure ORIGINAL_REGNO is set properly, and don't attempt to share with the various global pieces of rtl (such as frame_pointer_rtx). */ @@ -474,9 +485,7 @@ rtx gen_raw_REG (machine_mode mode, unsigned int regno) { rtx x = rtx_alloc (REG MEM_STAT_INFO); - set_mode_and_regno (x, mode, regno); - REG_ATTRS (x) = NULL; - ORIGINAL_REGNO (x) = regno; + init_raw_REG (x, mode, regno); return x; } diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c index 5c78fab..eebbc09 100644 --- a/gcc/gengenrtl.c +++ b/gcc/gengenrtl.c @@ -231,8 +231,7 @@ genmacro (int idx) puts (")"); } -/* Generate the code for the function to generate RTL whose - format is FORMAT. */ +/* Generate the code for functions to generate RTL whose format is FORMAT. */ static void gendef (const char *format) @@ -240,22 +239,18 @@ gendef (const char *format) const char *p; int i, j; - /* Start by writing the definition of the function name and the types + /* Write the definition of the init function name and the types of the arguments. */ - printf ("static inline rtx\ngen_rtx_fmt_%s_stat (RTX_CODE code, machine_mode mode", format); + puts ("static inline rtx"); + printf ("init_rtx_fmt_%s (rtx rt, machine_mode mode", format); for (p = format, i = 0; *p != 0; p++) if (*p != '0') printf (",\n\t%sarg%d", type_from_format (*p), i++); + puts (")"); - puts (" MEM_STAT_DECL)"); - - /* Now write out the body of the function itself, which allocates - the memory and initializes it. */ + /* Now write out the body of the init function itself. */ puts ("{"); - puts (" rtx rt;"); - puts (" rt = rtx_alloc (code PASS_MEM_STAT);\n"); - puts (" PUT_MODE_RAW (rt, mode);"); for (p = format, i = j = 0; *p ; ++p, ++i) @@ -266,16 +261,53 @@ gendef (const char *format) else printf (" %s (rt, %d) = arg%d;\n", accessor_from_format (*p), i, j++); - puts ("\n return rt;\n}\n"); + puts (" return rt;\n}\n"); + + /* Write the definition of the gen function name and the types + of the arguments. */ + + puts ("static inline rtx"); + printf ("gen_rtx_fmt_%s_stat (RTX_CODE code, machine_mode mode", format); + for (p = format, i = 0; *p != 0; p++) + if (*p != '0') + printf (",\n\t%sarg%d", type_from_format (*p), i++); + puts (" MEM_STAT_DECL)"); + + /* Now write out the body of the function itself, which allocates + the memory and initializes it. */ + puts ("{"); + puts (" rtx rt;\n"); + + puts (" rt = rtx_alloc (code PASS_MEM_STAT);"); + printf (" return init_rtx_fmt_%s (rt, mode", format); + for (p = format, i = 0; *p != 0; p++) + if (*p != '0') + printf (", arg%d", i++); + puts (");\n}\n"); + + /* Write the definition of gen macro. */ + printf ("#define gen_rtx_fmt_%s(c, m", format); for (p = format, i = 0; *p != 0; p++) if (*p != '0') - printf (", p%i",i++); - printf (")\\\n gen_rtx_fmt_%s_stat (c, m", format); + printf (", arg%d", i++); + printf (") \\\n gen_rtx_fmt_%s_stat ((c), (m)", format); for (p = format, i = 0; *p != 0; p++) if (*p != '0') - printf (", p%i",i++); + printf (", (arg%d)", i++); printf (" MEM_STAT_INFO)\n\n"); + + /* Write the definition of alloca macro. */ + + printf ("#define alloca_rtx_fmt_%s(c, m", format); + for (p = format, i = 0; *p != 0; p++) + if (*p != '0') + printf (", arg%d", i++); + printf (") \\\n init_rtx_fmt_%s (rtx_alloca ((c)), (m)", format); + for (p = format, i = 0; *p != 0; p++) + if (*p != '0') + printf (", (arg%d)", i++); + printf (")\n\n"); } /* Generate the documentation header for files we write. */ diff --git a/gcc/rtl.c b/gcc/rtl.c index d7b8e98..0be52d3 100644 --- a/gcc/rtl.c +++ b/gcc/rtl.c @@ -219,12 +219,7 @@ rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int extra) rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) + extra PASS_MEM_STAT); - /* We want to clear everything up to the FLD array. Normally, this - is one int, but we don't want to assume that and it isn't very - portable anyway; this is. */ - - memset (rt, 0, RTX_HDR_SIZE); - PUT_CODE (rt, code); + rtx_init (rt, code); if (GATHER_STATISTICS) { diff --git a/gcc/rtl.h b/gcc/rtl.h index 9cadac7..b75b3ed 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2957,6 +2957,15 @@ extern HOST_WIDE_INT get_stack_check_protect (void); /* In rtl.c */ extern rtx rtx_alloc (RTX_CODE CXX_MEM_STAT_INFO); +inline rtx +rtx_init (rtx rt, RTX_CODE code) +{ + memset (rt, 0, RTX_HDR_SIZE); + PUT_CODE (rt, code); + return rt; +} +#define rtx_alloca(code) \ + rtx_init ((rtx) alloca (RTX_CODE_SIZE ((code))), (code)) extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int); #define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ) #define const_wide_int_alloc(NWORDS) \ @@ -3823,7 +3832,10 @@ gen_rtx_INSN (machine_mode mode, rtx_insn *prev_insn, rtx_insn *next_insn, extern rtx gen_rtx_CONST_INT (machine_mode, HOST_WIDE_INT); extern rtx gen_rtx_CONST_VECTOR (machine_mode, rtvec); extern void set_mode_and_regno (rtx, machine_mode, unsigned int); +extern rtx init_raw_REG (rtx, machine_mode, unsigned int); extern rtx gen_raw_REG (machine_mode, unsigned int); +#define alloca_raw_REG(mode, regno) \ + init_raw_REG (rtx_alloca (REG), (mode), (regno)) extern rtx gen_rtx_REG (machine_mode, unsigned int); extern rtx gen_rtx_SUBREG (machine_mode, rtx, poly_uint64); extern rtx gen_rtx_MEM (machine_mode, rtx); -- cgit v1.1 From 4baad9863a5df7ec01b42afecd4170f4d58a1aac Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 30 Sep 2019 15:18:14 +0000 Subject: Remove the iq2000_select_section function the iq2000 backend - it never provided any useful functionality. PR target/59205 * config/iq2000/iq2000.c (iq2000_select_section): Delete. (TARGET_ASM_SELECT_SECTION): Remove definition. (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Allow definition. From-SVN: r276304 --- gcc/ChangeLog | 7 +++++++ gcc/config/iq2000/iq2000.c | 50 ---------------------------------------------- 2 files changed, 7 insertions(+), 50 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e0acd9d..6e453b9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-09-30 Nick Clifton + + PR target/59205 + * config/iq2000/iq2000.c (iq2000_select_section): Delete. + (TARGET_ASM_SELECT_SECTION): Remove definition. + (TARGET_HAVE_SWITCHABLE_BSS_SECTIONS): Allow definition. + 2019-09-30 Ilya Leoshkevich * emit-rtl.c (init_raw_REG): New function. diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c index 59c5132..bccafd5 100644 --- a/gcc/config/iq2000/iq2000.c +++ b/gcc/config/iq2000/iq2000.c @@ -157,7 +157,6 @@ static void iq2000_setup_incoming_varargs (cumulative_args_t, static bool iq2000_rtx_costs (rtx, machine_mode, int, int, int *, bool); static int iq2000_address_cost (rtx, machine_mode, addr_space_t, bool); -static section *iq2000_select_section (tree, int, unsigned HOST_WIDE_INT); static rtx iq2000_legitimize_address (rtx, rtx, machine_mode); static bool iq2000_pass_by_reference (cumulative_args_t, const function_arg_info &); @@ -197,17 +196,10 @@ static HOST_WIDE_INT iq2000_starting_frame_offset (void); #define TARGET_RTX_COSTS iq2000_rtx_costs #undef TARGET_ADDRESS_COST #define TARGET_ADDRESS_COST iq2000_address_cost -#undef TARGET_ASM_SELECT_SECTION -#define TARGET_ASM_SELECT_SECTION iq2000_select_section #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS iq2000_legitimize_address -/* The assembler supports switchable .bss sections, but - iq2000_select_section doesn't yet make use of them. */ -#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS -#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false - #undef TARGET_PRINT_OPERAND #define TARGET_PRINT_OPERAND iq2000_print_operand #undef TARGET_PRINT_OPERAND_ADDRESS @@ -2201,48 +2193,6 @@ iq2000_select_rtx_section (machine_mode mode, rtx x ATTRIBUTE_UNUSED, return mergeable_constant_section (mode, align, 0); } -/* Choose the section to use for DECL. RELOC is true if its value contains - any relocatable expression. - - Some of the logic used here needs to be replicated in - ENCODE_SECTION_INFO in iq2000.h so that references to these symbols - are done correctly. */ - -static section * -iq2000_select_section (tree decl, int reloc ATTRIBUTE_UNUSED, - unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) -{ - if (TARGET_EMBEDDED_DATA) - { - /* For embedded applications, always put an object in read-only data - if possible, in order to reduce RAM usage. */ - if ((TREE_CODE (decl) == VAR_DECL - && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl) - && DECL_INITIAL (decl) - && (DECL_INITIAL (decl) == error_mark_node - || TREE_CONSTANT (DECL_INITIAL (decl)))) - /* Deal with calls from output_constant_def_contents. */ - || TREE_CODE (decl) != VAR_DECL) - return readonly_data_section; - else - return data_section; - } - else - { - /* For hosted applications, always put an object in small data if - possible, as this gives the best performance. */ - if ((TREE_CODE (decl) == VAR_DECL - && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl) - && DECL_INITIAL (decl) - && (DECL_INITIAL (decl) == error_mark_node - || TREE_CONSTANT (DECL_INITIAL (decl)))) - /* Deal with calls from output_constant_def_contents. */ - || TREE_CODE (decl) != VAR_DECL) - return readonly_data_section; - else - return data_section; - } -} /* Return register to use for a function return value with VALTYPE for function FUNC. */ -- cgit v1.1 From 51051f474a768d285714d713f1b7535d6a139350 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 15:23:30 +0000 Subject: [AArch64] Strengthen aarch64_hard_regno_call_part_clobbered The aarch64_vector_pcs handling in aarch64_hard_regno_call_part_clobbered checks whether the mode might be bigger than 16 bytes, since on SVE targets the (non-SVE) vector PCS only guarantees that the low 16 bytes are preserved. But for multi-register modes, we should instead test whether each single-register part might be bigger than 16 bytes. (The size is always divided evenly between registers.) The testcase uses XImode as an example where this helps. 2019-09-30 Richard Sandiford gcc/ * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): For multi-registers modes, test how big each register part is. gcc/testsuite/ * gcc.target/aarch64/torture/simd-abi-8.c: New test. From-SVN: r276305 --- gcc/ChangeLog | 5 +++++ gcc/config/aarch64/aarch64.c | 13 ++++++++++--- gcc/testsuite/ChangeLog | 4 ++++ .../gcc.target/aarch64/torture/simd-abi-8.c | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6e453b9..830c93d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-09-30 Richard Sandiford + + * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): + For multi-registers modes, test how big each register part is. + 2019-09-30 Nick Clifton PR target/59205 diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 81d0f2b..29c070d 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1890,9 +1890,16 @@ static bool aarch64_hard_regno_call_part_clobbered (rtx_insn *insn, unsigned int regno, machine_mode mode) { - bool simd_p = insn && CALL_P (insn) && aarch64_simd_call_p (insn); - return FP_REGNUM_P (regno) - && maybe_gt (GET_MODE_SIZE (mode), simd_p ? 16 : 8); + if (FP_REGNUM_P (regno)) + { + bool simd_p = insn && CALL_P (insn) && aarch64_simd_call_p (insn); + poly_int64 per_register_size = GET_MODE_SIZE (mode); + unsigned int nregs = hard_regno_nregs (regno, mode); + if (nregs > 1) + per_register_size = exact_div (per_register_size, nregs); + return maybe_gt (per_register_size, simd_p ? 16 : 8); + } + return false; } /* Implement TARGET_RETURN_CALL_WITH_MAX_CLOBBERS. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 868b4aa..2ac61ff 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2019-09-30 Richard Sandiford + * gcc.target/aarch64/torture/simd-abi-8.c: New test. + +2019-09-30 Richard Sandiford + * gcc.dg/Wincompatible-pointer-types-1.c (f1): Expect only one space between the comma and "...". diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c new file mode 100644 index 0000000..6463f6c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ + +#include + +void __attribute__ ((aarch64_vector_pcs)) f (void); + +void +g (int64x2x4_t *ptr) +{ + register int64x2x4_t copy asm ("v8") = *ptr; + int64x2x4_t save; + asm volatile ("" : "=w" (save) : "0" (copy)); + f (); + *ptr = save; +} + +/* { dg-final { scan-assembler-times {\tld1\t} 1 } } */ +/* { dg-final { scan-assembler-times {\tst1\t} 1 } } */ -- cgit v1.1 From 0c88d078eba7f51d2e5fc76a630f7eb369c09c87 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 30 Sep 2019 15:27:14 +0000 Subject: Fix compile time warning about building the FRV backend by adding missing break statements to the switches in frv_register_move_cost. PR target/85978 * config/frv/frv.c (frv_register_move_cost): Add break statements to avoid falling through to the wrong cases. Tidy code. From-SVN: r276306 --- gcc/ChangeLog | 6 ++++++ gcc/config/frv/frv.c | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 830c93d..df8a3d2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-30 Nick Clifton + + PR target/85978 + * config/frv/frv.c (frv_register_move_cost): Add break statements + to avoid falling through to the wrong cases. Tidy code. + 2019-09-30 Richard Sandiford * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c index 223415e..6526e81 100644 --- a/gcc/config/frv/frv.c +++ b/gcc/config/frv/frv.c @@ -6686,7 +6686,6 @@ frv_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, case FDPIC_REGS: case FDPIC_FPTR_REGS: case FDPIC_CALL_REGS: - switch (to) { default: @@ -6700,7 +6699,6 @@ frv_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, case FDPIC_REGS: case FDPIC_FPTR_REGS: case FDPIC_CALL_REGS: - return LOW_COST; case FPR_REGS: @@ -6711,6 +6709,7 @@ frv_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, case SPR_REGS: return LOW_COST; } + break; case QUAD_FPR_REGS: switch (to) @@ -6734,6 +6733,7 @@ frv_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, case QUAD_FPR_REGS: return LOW_COST; } + break; case LCR_REG: case LR_REG: @@ -6751,9 +6751,9 @@ frv_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, case FDPIC_REGS: case FDPIC_FPTR_REGS: case FDPIC_CALL_REGS: - return MEDIUM_COST; } + break; case QUAD_ACC_REGS: case ACCG_REGS: @@ -6764,8 +6764,8 @@ frv_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, case QUAD_FPR_REGS: return MEDIUM_COST; - } + break; } return HIGH_COST; -- cgit v1.1 From bd785b44932274f7067105de417938597289962c Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:19:38 +0000 Subject: Add function_abi.{h,cc} This patch adds new structures and functions for handling multiple ABIs in a translation unit. The structures are: - predefined_function_abi: describes a static, predefined ABI - function_abi: describes either a predefined ABI or a local variant of one (e.g. taking -fipa-ra into account) The patch adds functions for getting the ABI from a given type or decl; a later patch will also add a function for getting the ABI of the target of a call insn. Although ABIs are about much more than call-clobber/saved choices, I wanted to keep the name general in case we add more ABI-related information in future. 2019-09-30 Richard Sandiford gcc/ * Makefile.in (OBJS): Add function-abi.o. (GTFILES): Add function-abi.h. * function-abi.cc: New file. * function-abi.h: Likewise. * emit-rtl.h (rtl_data::abi): New field. * function.c: Include function-abi.h. (prepare_function_start): Initialize crtl->abi. * read-rtl-function.c: Include regs.h and function-abi.h. (read_rtl_function_body): Initialize crtl->abi. (read_rtl_function_body_from_file_range): Likewise. * reginfo.c: Include function-abi.h. (init_reg_sets_1): Initialize default_function_abi. (globalize_reg): Call add_full_reg_clobber for each predefined ABI when making a register global. * target-globals.h (this_target_function_abi_info): Declare. (target_globals::function_abi_info): New field. (restore_target_globals): Copy it. * target-globals.c: Include function-abi.h. (default_target_globals): Initialize the function_abi_info field. (target_globals): Allocate it. (save_target_globals): Free it. From-SVN: r276307 --- gcc/ChangeLog | 24 +++++ gcc/Makefile.in | 2 + gcc/emit-rtl.h | 9 ++ gcc/function-abi.cc | 145 ++++++++++++++++++++++++++ gcc/function-abi.h | 269 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/function.c | 7 ++ gcc/read-rtl-function.c | 4 + gcc/reginfo.c | 9 +- gcc/target-globals.c | 4 + gcc/target-globals.h | 3 + 10 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 gcc/function-abi.cc create mode 100644 gcc/function-abi.h (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index df8a3d2..858f596 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2019-09-30 Richard Sandiford + + * Makefile.in (OBJS): Add function-abi.o. + (GTFILES): Add function-abi.h. + * function-abi.cc: New file. + * function-abi.h: Likewise. + * emit-rtl.h (rtl_data::abi): New field. + * function.c: Include function-abi.h. + (prepare_function_start): Initialize crtl->abi. + * read-rtl-function.c: Include regs.h and function-abi.h. + (read_rtl_function_body): Initialize crtl->abi. + (read_rtl_function_body_from_file_range): Likewise. + * reginfo.c: Include function-abi.h. + (init_reg_sets_1): Initialize default_function_abi. + (globalize_reg): Call add_full_reg_clobber for each predefined ABI + when making a register global. + * target-globals.h (this_target_function_abi_info): Declare. + (target_globals::function_abi_info): New field. + (restore_target_globals): Copy it. + * target-globals.c: Include function-abi.h. + (default_target_globals): Initialize the function_abi_info field. + (target_globals): Allocate it. + (save_target_globals): Free it. + 2019-09-30 Nick Clifton PR target/85978 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2cf0c79..d796c14 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1306,6 +1306,7 @@ OBJS = \ fold-const.o \ fold-const-call.o \ function.o \ + function-abi.o \ function-tests.o \ fwprop.o \ gcc-rich-location.o \ @@ -2523,6 +2524,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/libfuncs.h $(SYMTAB_H) \ $(srcdir)/real.h $(srcdir)/function.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \ $(srcdir)/fixed-value.h \ + $(srcdir)/function-abi.h \ $(srcdir)/output.h $(srcdir)/cfgloop.h $(srcdir)/cfg.h $(srcdir)/profile-count.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \ $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \ diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h index 7643bf9..320aab5 100644 --- a/gcc/emit-rtl.h +++ b/gcc/emit-rtl.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see class temp_slot; typedef class temp_slot *temp_slot_p; +class predefined_function_abi; /* Information mainlined about RTL representation of incoming arguments. */ struct GTY(()) incoming_args { @@ -64,6 +65,14 @@ struct GTY(()) rtl_data { struct function_subsections subsections; struct rtl_eh eh; + /* The ABI of the function, i.e. the interface it presents to its callers. + This is the ABI that should be queried to see which registers the + function needs to save before it uses them. + + Other functions (including those called by this function) might use + different ABIs. */ + const predefined_function_abi *GTY((skip)) abi; + /* For function.c */ /* # of bytes of outgoing arguments. If ACCUMULATE_OUTGOING_ARGS is diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc new file mode 100644 index 0000000..e7c8581 --- /dev/null +++ b/gcc/function-abi.cc @@ -0,0 +1,145 @@ +/* Information about fuunction binary interfaces. + Copyright (C) 2019 Free Software Foundation, Inc. + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "regs.h" +#include "function-abi.h" +#include "varasm.h" +#include "cgraph.h" + +target_function_abi_info default_target_function_abi_info; +#if SWITCHABLE_TARGET +target_function_abi_info *this_target_function_abi_info + = &default_target_function_abi_info; +#endif + +/* Initialize a predefined function ABI with the given values of + ID and FULL_REG_CLOBBERS. */ + +void +predefined_function_abi::initialize (unsigned int id, + const_hard_reg_set full_reg_clobbers) +{ + m_id = id; + m_initialized = true; + m_full_reg_clobbers = full_reg_clobbers; + + /* Set up the value of m_full_and_partial_reg_clobbers. + + If the ABI specifies that part of a hard register R is call-clobbered, + we should be able to find a single-register mode M for which + targetm.hard_regno_call_part_clobbered (NULL, R, M) is true. + In other words, it shouldn't be the case that R can hold all + single-register modes across a call, but can't hold part of + a multi-register mode. + + If that assumption doesn't hold for a future target, we would need + to change the interface of TARGET_HARD_REGNO_CALL_PART_CLOBBERED so + that it tells us which registers in a multi-register value are + actually clobbered. */ + m_full_and_partial_reg_clobbers = full_reg_clobbers; + for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i) + { + machine_mode mode = (machine_mode) i; + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (targetm.hard_regno_mode_ok (regno, mode) + && hard_regno_nregs (regno, mode) == 1 + && targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + SET_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno); + } + + /* For each mode MODE, work out which registers are unable to hold + any part of a MODE value across a call, i.e. those for which no + overlapping call-preserved (reg:MODE REGNO) exists. + + We assume that this can be flipped around to say that a call + preserves (reg:MODE REGNO) unless the register overlaps this set. + The usual reason for this being true is that if (reg:MODE REGNO) + contains a part-clobbered register, that register would be + part-clobbered regardless of which part of MODE it holds. + For example, if (reg:M 2) occupies two registers and if the + register 3 portion of it is part-clobbered, (reg:M 3) is usually + either invalid or also part-clobbered. */ + for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i) + { + machine_mode mode = (machine_mode) i; + m_mode_clobbers[i] = m_full_and_partial_reg_clobbers; + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (targetm.hard_regno_mode_ok (regno, mode) + && !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno) + && !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + remove_from_hard_reg_set (&m_mode_clobbers[i], mode, regno); + } + + /* Check that the assumptions above actually hold, i.e. that testing + for single-register modes makes sense, and that overlap tests for + mode_clobbers work as expected. */ + if (flag_checking) + for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i) + { + machine_mode mode = (machine_mode) i; + const_hard_reg_set all_clobbers = m_full_and_partial_reg_clobbers; + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (targetm.hard_regno_mode_ok (regno, mode) + && !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno) + && targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + gcc_assert (overlaps_hard_reg_set_p (all_clobbers, mode, regno) + && overlaps_hard_reg_set_p (m_mode_clobbers[i], + mode, regno)); + } +} + +/* If the ABI has been initialized, add REGNO to the set of registers + that can be completely altered by a call. */ + +void +predefined_function_abi::add_full_reg_clobber (unsigned int regno) +{ + if (!m_initialized) + return; + + SET_HARD_REG_BIT (m_full_reg_clobbers, regno); + SET_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno); + for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i) + SET_HARD_REG_BIT (m_mode_clobbers[i], regno); +} + +/* Return the predefined ABI used by functions with type TYPE. */ + +const predefined_function_abi & +fntype_abi (const_tree type) +{ + gcc_assert (FUNC_OR_METHOD_TYPE_P (type)); + return default_function_abi; +} + +/* Return the ABI of function decl FNDECL. */ + +function_abi +fndecl_abi (const_tree fndecl) +{ + gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL); + return fntype_abi (TREE_TYPE (fndecl)); +} diff --git a/gcc/function-abi.h b/gcc/function-abi.h new file mode 100644 index 0000000..05e502e --- /dev/null +++ b/gcc/function-abi.h @@ -0,0 +1,269 @@ +/* Information about fuunction binary interfaces. + Copyright (C) 2019 Free Software Foundation, Inc. + +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 +. */ + +#ifndef GCC_FUNCTION_ABI_H +#define GCC_FUNCTION_ABI_H + +/* Most targets use the same ABI for all functions in a translation + unit, but some targets support interoperability between several ABIs. + Each such ABI has a unique 0-based identifier, with 0 always being + the default choice of ABI. + + NUM_ABI_IDS is the maximum number of such ABIs that GCC can handle at once. + A bitfield with this number of bits can represent any combinaion of the + supported ABIs. */ +const size_t NUM_ABI_IDS = 8; + +/* Information about one of the target's predefined ABIs. */ +class predefined_function_abi +{ +public: + /* A target-specific identifier for this ABI. The value must be in + the range [0, NUM_ABI_IDS - 1]. */ + unsigned int id () const { return m_id; } + + /* True if this ABI has been initialized. */ + bool initialized_p () const { return m_initialized; } + + /* Return true if a function call is allowed to alter every bit of + register REGNO, so that the register contains an arbitrary value + on return. If so, the register cannot hold any part of a value + that is live across a call. */ + bool + clobbers_full_reg_p (unsigned int regno) const + { + return TEST_HARD_REG_BIT (m_full_reg_clobbers, regno); + } + + /* Return true if a function call is allowed to alter some or all bits + of register REGNO. + + This is true whenever clobbers_full_reg_p (REGNO) is true. It is + also true if, for example, the ABI says that a call must preserve the + low 32 or 64 bits of REGNO, but can clobber the upper bits of REGNO. + In the latter case, it is possible for REGNO to hold values that + are live across a call, provided that the value occupies only the + call-preserved part of the register. */ + bool + clobbers_at_least_part_of_reg_p (unsigned int regno) const + { + return TEST_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno); + } + + /* Return true if a function call is allowed to clobber at least part + of (reg:MODE REGNO). If so, it is not possible for the register + as a whole to be live across a call. */ + bool + clobbers_reg_p (machine_mode mode, unsigned int regno) const + { + return overlaps_hard_reg_set_p (m_mode_clobbers[mode], mode, regno); + } + + /* Return the set of registers that a function call is allowed to + alter completely, so that the registers contain arbitrary values + on return. This doesn't include registers that a call can only + partly clobber (as per TARGET_HARD_REGNO_CALL_PART_CLOBBERED). + + These registers cannot hold any part of a value that is live across + a call. */ + HARD_REG_SET full_reg_clobbers () const { return m_full_reg_clobbers; } + + /* Return the set of registers that a function call is allowed to alter + to some degree. For example, if an ABI says that a call must preserve + the low 32 or 64 bits of a register R, but can clobber the upper bits + of R, R would be in this set but not in full_reg_clobbers (). + + This set is a superset of full_reg_clobbers (). It is possible for a + register in full_and_partial_reg_clobbers () & ~full_reg_clobbers () + to contain values that are live across a call, provided that the live + value only occupies the call-preserved part of the register. */ + HARD_REG_SET + full_and_partial_reg_clobbers () const + { + return m_full_and_partial_reg_clobbers; + } + + /* Return the set of registers that cannot be used to hold a value of + mode MODE across a function call. That is: + + (reg:REGNO MODE) + + might be clobbered by a call whenever: + + overlaps_hard_reg_set (mode_clobbers (MODE), MODE, REGNO) + + In allocation terms, the registers in the returned set conflict + with any value of mode MODE that is live across a call. */ + HARD_REG_SET + mode_clobbers (machine_mode mode) const + { + return m_mode_clobbers[mode]; + } + + void initialize (unsigned int, const_hard_reg_set); + void add_full_reg_clobber (unsigned int); + +private: + unsigned int m_id : NUM_ABI_IDS; + unsigned int m_initialized : 1; + HARD_REG_SET m_full_reg_clobbers; + HARD_REG_SET m_full_and_partial_reg_clobbers; + HARD_REG_SET m_mode_clobbers[NUM_MACHINE_MODES]; +}; + +/* Describes either a predefined ABI or the ABI of a particular function. + In the latter case, the ABI might make use of extra function-specific + information, such as for -fipa-ra. */ +class function_abi +{ +public: + /* Initialize the structure for a general function with the given ABI. */ + function_abi (const predefined_function_abi &base_abi) + : m_base_abi (&base_abi), + m_mask (base_abi.full_and_partial_reg_clobbers ()) {} + + /* Initialize the structure for a function that has the given ABI and + that is known not to clobber registers outside MASK. */ + function_abi (const predefined_function_abi &base_abi, + const_hard_reg_set mask) + : m_base_abi (&base_abi), m_mask (mask) {} + + /* The predefined ABI from which this ABI is derived. */ + const predefined_function_abi &base_abi () const { return *m_base_abi; } + + /* The target-specific identifier of the predefined ABI. */ + unsigned int id () const { return m_base_abi->id (); } + + /* See the corresponding predefined_function_abi functions for + details about the following functions. */ + + HARD_REG_SET + full_reg_clobbers () const + { + return m_mask & m_base_abi->full_reg_clobbers (); + } + + HARD_REG_SET + full_and_partial_reg_clobbers () const + { + return m_mask & m_base_abi->full_and_partial_reg_clobbers (); + } + + HARD_REG_SET + mode_clobbers (machine_mode mode) const + { + return m_mask & m_base_abi->mode_clobbers (mode); + } + + bool + clobbers_full_reg_p (unsigned int regno) const + { + return (TEST_HARD_REG_BIT (m_mask, regno) + & m_base_abi->clobbers_full_reg_p (regno)); + } + + bool + clobbers_at_least_part_of_reg_p (unsigned int regno) const + { + return (TEST_HARD_REG_BIT (m_mask, regno) + & m_base_abi->clobbers_at_least_part_of_reg_p (regno)); + } + + bool + clobbers_reg_p (machine_mode mode, unsigned int regno) const + { + return overlaps_hard_reg_set_p (mode_clobbers (mode), mode, regno); + } + + bool + operator== (const function_abi &other) const + { + return m_base_abi == other.m_base_abi && m_mask == other.m_mask; + } + + bool + operator!= (const function_abi &other) const + { + return !operator== (other); + } + +protected: + const predefined_function_abi *m_base_abi; + HARD_REG_SET m_mask; +}; + +struct target_function_abi_info +{ + /* An array of all the target ABIs that are available in this + translation unit. Not all entries are used for all targets, + but the structures are relatively small, and using a fixed-size + array avoids extra indirection. + + There are various ways of getting an ABI descriptor: + + * fndecl_abi (FNDECL) is the ABI of function FNDECL. + + * fntype_abi (FNTYPE) is the ABI of a function with type FNTYPE. + + * crtl->abi is the ABI of the function that we are currently + compiling to rtl. + + * eh_edge_abi is the "ABI" used when taking an EH edge from an + exception-throwing statement to an exception handler. Catching + exceptions from calls can be treated as an abnormal return from + those calls, and this ABI therefore describes the ABI of functions + on such an abnormal return. Statements that throw non-call + exceptions can be treated as being implicitly wrapped in a call + that has such an abnormal return. + + At present, no target needs to support more than one EH ABI. + + * function_abis[N] is the ABI with identifier N. This can be useful + when referring back to ABIs that have been collected by number in + a bitmask, such as after walking function calls in a particular + region of code. + + * default_function_abi refers specifically to the target's default + choice of ABI, regardless of which (if any) functions actually + use it. This ABI and data derived from it do *not* provide + globally conservatively-correct information, so it is only + useful in very specific circumstances. */ + predefined_function_abi x_function_abis[NUM_ABI_IDS]; +}; + +extern target_function_abi_info default_target_function_abi_info; +#if SWITCHABLE_TARGET +extern target_function_abi_info *this_target_function_abi_info; +#else +#define this_target_function_abi_info (&default_target_function_abi_info) +#endif + +/* See the comment above x_function_abis for when these macros should be used. + At present, eh_edge_abi is always the default ABI, but that could change + in future if a target needs it to. */ +#define function_abis \ + (this_target_function_abi_info->x_function_abis) +#define default_function_abi \ + (this_target_function_abi_info->x_function_abis[0]) +#define eh_edge_abi default_function_abi + +extern const predefined_function_abi &fntype_abi (const_tree); +extern function_abi fndecl_abi (const_tree); + +#endif diff --git a/gcc/function.c b/gcc/function.c index 9c158ce..c3aa6a5 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "gimple.h" #include "options.h" +#include "function-abi.h" /* So we can assign to cfun in this file. */ #undef cfun @@ -4826,6 +4827,12 @@ static void prepare_function_start (void) { gcc_assert (!get_last_insn ()); + + if (in_dummy_function) + crtl->abi = &default_function_abi; + else + crtl->abi = &fndecl_abi (cfun->decl).base_abi (); + init_temp_slots (); init_emit (); init_varasm_status (); diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c index f41f54a..b87ea30 100644 --- a/gcc/read-rtl-function.c +++ b/gcc/read-rtl-function.c @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see #include "read-rtl-function.h" #include "selftest.h" #include "selftest-rtl.h" +#include "regs.h" +#include "function-abi.h" /* Forward decls. */ class function_reader; @@ -1611,6 +1613,7 @@ bool read_rtl_function_body (const char *path) { initialize_rtl (); + crtl->abi = &default_function_abi; init_emit (); init_varasm_status (); @@ -1644,6 +1647,7 @@ read_rtl_function_body_from_file_range (location_t start_loc, } initialize_rtl (); + crtl->abi = &fndecl_abi (cfun->decl).base_abi (); init_emit (); init_varasm_status (); diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 22d0e68..a3fbbe6 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "reload.h" #include "output.h" #include "tree-pass.h" +#include "function-abi.h" /* Maximum register number used in this function, plus one. */ @@ -419,6 +420,8 @@ init_reg_sets_1 (void) } } } + + default_function_abi.initialize (0, regs_invalidated_by_call); } /* Compute the table of register modes. @@ -728,7 +731,11 @@ globalize_reg (tree decl, int i) appropriate regs_invalidated_by_call bit, even if it's already set in fixed_regs. */ if (i != STACK_POINTER_REGNUM) - SET_HARD_REG_BIT (regs_invalidated_by_call, i); + { + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + for (unsigned int i = 0; i < NUM_ABI_IDS; ++i) + function_abis[i].add_full_reg_clobber (i); + } /* If already fixed, nothing else to do. */ if (fixed_regs[i]) diff --git a/gcc/target-globals.c b/gcc/target-globals.c index 8928fc1..359677e 100644 --- a/gcc/target-globals.c +++ b/gcc/target-globals.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "gcse.h" #include "bb-reorder.h" #include "lower-subreg.h" +#include "function-abi.h" #if SWITCHABLE_TARGET class target_globals default_target_globals = { @@ -48,6 +49,7 @@ class target_globals default_target_globals = { &default_target_rtl, &default_target_recog, &default_target_hard_regs, + &default_target_function_abi_info, &default_target_reload, &default_target_expmed, &default_target_optabs, @@ -70,6 +72,7 @@ save_target_globals (void) g->rtl = ggc_cleared_alloc (); g->recog = XCNEW (struct target_recog); g->hard_regs = XCNEW (struct target_hard_regs); + g->function_abi_info = XCNEW (struct target_function_abi_info); g->reload = XCNEW (struct target_reload); g->expmed = XCNEW (struct target_expmed); g->optabs = XCNEW (struct target_optabs); @@ -127,6 +130,7 @@ target_globals::~target_globals () XDELETE (regs); XDELETE (recog); XDELETE (hard_regs); + XDELETE (function_abi_info); XDELETE (reload); XDELETE (expmed); XDELETE (optabs); diff --git a/gcc/target-globals.h b/gcc/target-globals.h index ceb216a..9c42913 100644 --- a/gcc/target-globals.h +++ b/gcc/target-globals.h @@ -26,6 +26,7 @@ extern struct target_regs *this_target_regs; extern struct target_rtl *this_target_rtl; extern struct target_recog *this_target_recog; extern struct target_hard_regs *this_target_hard_regs; +extern struct target_function_abi_info *this_target_function_abi_info; extern struct target_reload *this_target_reload; extern struct target_expmed *this_target_expmed; extern struct target_optabs *this_target_optabs; @@ -48,6 +49,7 @@ public: struct target_rtl *rtl; struct target_recog *GTY((skip)) recog; struct target_hard_regs *GTY((skip)) hard_regs; + struct target_function_abi_info *GTY((skip)) function_abi_info; struct target_reload *GTY((skip)) reload; struct target_expmed *GTY((skip)) expmed; struct target_optabs *GTY((skip)) optabs; @@ -75,6 +77,7 @@ restore_target_globals (class target_globals *g) this_target_rtl = g->rtl; this_target_recog = g->recog; this_target_hard_regs = g->hard_regs; + this_target_function_abi_info = g->function_abi_info; this_target_reload = g->reload; this_target_expmed = g->expmed; this_target_optabs = g->optabs; -- cgit v1.1 From 002ffd3caa684c3eb30f8f53206439b7aa34b370 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:19:43 +0000 Subject: Add a target hook for getting an ABI from a function type This patch adds a target hook that allows targets to return the ABI associated with a particular function type. Generally, when multiple ABIs are in use, it must be possible to tell from a function type and its attributes which ABI it is using. 2019-09-30 Richard Sandiford gcc/ * target.def (fntype_abi): New target hook. * doc/tm.texi.in (TARGET_FNTYPE_ABI): Likewise. * doc/tm.texi: Regenerate. * target.h (predefined_function_abi): Declare. * function-abi.cc (fntype_abi): Call targetm.calls.fntype_abi, if defined. * config/aarch64/aarch64.h (ARM_PCS_SIMD): New arm_pcs value. * config/aarch64/aarch64.c: Include function-abi.h. (aarch64_simd_abi, aarch64_fntype_abi): New functions. (TARGET_FNTYPE_ABI): Define. From-SVN: r276308 --- gcc/ChangeLog | 13 +++++++++++++ gcc/config/aarch64/aarch64.c | 32 ++++++++++++++++++++++++++++++++ gcc/config/aarch64/aarch64.h | 1 + gcc/doc/tm.texi | 10 ++++++++++ gcc/doc/tm.texi.in | 5 +++++ gcc/function-abi.cc | 2 ++ gcc/target.def | 9 +++++++++ gcc/target.h | 3 +++ 8 files changed, 75 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 858f596..812dadb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2019-09-30 Richard Sandiford + * target.def (fntype_abi): New target hook. + * doc/tm.texi.in (TARGET_FNTYPE_ABI): Likewise. + * doc/tm.texi: Regenerate. + * target.h (predefined_function_abi): Declare. + * function-abi.cc (fntype_abi): Call targetm.calls.fntype_abi, + if defined. + * config/aarch64/aarch64.h (ARM_PCS_SIMD): New arm_pcs value. + * config/aarch64/aarch64.c: Include function-abi.h. + (aarch64_simd_abi, aarch64_fntype_abi): New functions. + (TARGET_FNTYPE_ABI): Define. + +2019-09-30 Richard Sandiford + * Makefile.in (OBJS): Add function-abi.o. (GTFILES): Add function-abi.h. * function-abi.cc: New file. diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 29c070d..211459c 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -74,6 +74,7 @@ #include "rtx-vector-builder.h" #include "intl.h" #include "expmed.h" +#include "function-abi.h" /* This file should be included last. */ #include "target-def.h" @@ -1365,6 +1366,24 @@ svpattern_token (enum aarch64_svpattern pattern) gcc_unreachable (); } +/* Return the descriptor of the SIMD ABI. */ + +static const predefined_function_abi & +aarch64_simd_abi (void) +{ + predefined_function_abi &simd_abi = function_abis[ARM_PCS_SIMD]; + if (!simd_abi.initialized_p ()) + { + HARD_REG_SET full_reg_clobbers + = default_function_abi.full_reg_clobbers (); + for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (FP_SIMD_SAVED_REGNUM_P (regno)) + CLEAR_HARD_REG_BIT (full_reg_clobbers, regno); + simd_abi.initialize (ARM_PCS_SIMD, full_reg_clobbers); + } + return simd_abi; +} + /* Generate code to enable conditional branches in functions over 1 MiB. */ const char * aarch64_gen_far_branch (rtx * operands, int pos_label, const char * dest, @@ -1810,6 +1829,16 @@ aarch64_hard_regno_mode_ok (unsigned regno, machine_mode mode) return false; } +/* Implement TARGET_FNTYPE_ABI. */ + +static const predefined_function_abi & +aarch64_fntype_abi (const_tree fntype) +{ + if (lookup_attribute ("aarch64_vector_pcs", TYPE_ATTRIBUTES (fntype))) + return aarch64_simd_abi (); + return default_function_abi; +} + /* Return true if this is a definition of a vectorized simd function. */ static bool @@ -21024,6 +21053,9 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_GET_MULTILIB_ABI_NAME #define TARGET_GET_MULTILIB_ABI_NAME aarch64_get_multilib_abi_name +#undef TARGET_FNTYPE_ABI +#define TARGET_FNTYPE_ABI aarch64_fntype_abi + #if CHECKING_P #undef TARGET_RUN_TARGET_SELFTESTS #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 7bbeed4..5aff106 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -783,6 +783,7 @@ enum aarch64_abi_type enum arm_pcs { ARM_PCS_AAPCS64, /* Base standard AAPCS for 64 bit. */ + ARM_PCS_SIMD, /* For aarch64_vector_pcs functions. */ ARM_PCS_UNKNOWN }; diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index a86c210..0f79d38 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1898,6 +1898,16 @@ must be defined. Modern ports should define @code{CALL_REALLY_USED_REGISTERS}. @cindex call-used register @cindex call-clobbered register @cindex call-saved register +@deftypefn {Target Hook} {const predefined_function_abi &} TARGET_FNTYPE_ABI (const_tree @var{type}) +Return the ABI used by a function with type @var{type}; see the +definition of @code{predefined_function_abi} for details of the ABI +descriptor. Targets only need to define this hook if they support +interoperability between several ABIs in the same translation unit. +@end deftypefn + +@cindex call-used register +@cindex call-clobbered register +@cindex call-saved register @deftypefn {Target Hook} bool TARGET_HARD_REGNO_CALL_PART_CLOBBERED (rtx_insn *@var{insn}, unsigned int @var{regno}, machine_mode @var{mode}) This hook should return true if @var{regno} is partly call-saved and partly call-clobbered, and if a value of mode @var{mode} would be partly diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 06dfcda..ed605c0 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -1709,6 +1709,11 @@ must be defined. Modern ports should define @code{CALL_REALLY_USED_REGISTERS}. @cindex call-used register @cindex call-clobbered register @cindex call-saved register +@hook TARGET_FNTYPE_ABI + +@cindex call-used register +@cindex call-clobbered register +@cindex call-saved register @hook TARGET_HARD_REGNO_CALL_PART_CLOBBERED @hook TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index e7c8581..c77989a 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -132,6 +132,8 @@ const predefined_function_abi & fntype_abi (const_tree type) { gcc_assert (FUNC_OR_METHOD_TYPE_P (type)); + if (targetm.calls.fntype_abi) + return targetm.calls.fntype_abi (type); return default_function_abi; } diff --git a/gcc/target.def b/gcc/target.def index f9446fa..803c7a3 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4943,6 +4943,15 @@ If this hook is not defined, then FUNCTION_VALUE_REGNO_P will be used.", bool, (const unsigned int regno), default_function_value_regno_p) +DEFHOOK +(fntype_abi, + "Return the ABI used by a function with type @var{type}; see the\n\ +definition of @code{predefined_function_abi} for details of the ABI\n\ +descriptor. Targets only need to define this hook if they support\n\ +interoperability between several ABIs in the same translation unit.", + const predefined_function_abi &, (const_tree type), + NULL) + /* ??? Documenting this hook requires a GFDL license grant. */ DEFHOOK_UNDOC (internal_arg_pointer, diff --git a/gcc/target.h b/gcc/target.h index a656930..9f80658 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -152,6 +152,9 @@ class _stmt_vec_info; /* This is defined in calls.h. */ class function_arg_info; +/* This is defined in function-abi.h. */ +class predefined_function_abi; + /* These are defined in tree-vect-stmts.c. */ extern tree stmt_vectype (class _stmt_vec_info *); extern bool stmt_in_inner_loop_p (class _stmt_vec_info *); -- cgit v1.1 From 5a5a3bc5fa14664be26748c11325021b6b6f8e74 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:19:49 +0000 Subject: Add a function for getting the ABI of a call insn target This patch replaces get_call_reg_set_usage with insn_callee_abi, which returns the ABI of the target of a call insn. The ABI's full_reg_clobbers corresponds to regs_invalidated_by_call, whereas many callers instead passed call_used_or_fixed_regs, i.e.: (regs_invalidated_by_call | fixed_reg_set) The patch slavishly preserves the "| fixed_reg_set" for these callers; later patches will clean this up. 2019-09-30 Richard Sandiford gcc/ * target.def (insn_callee_abi): New hook. (remove_extra_call_preserved_regs): Delete. * doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro. (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete. * doc/tm.texi: Regenerate. * targhooks.h (default_remove_extra_call_preserved_regs): Delete. * targhooks.c (default_remove_extra_call_preserved_regs): Delete. * config/aarch64/aarch64.c (aarch64_simd_call_p): Constify the insn argument. (aarch64_remove_extra_call_preserved_regs): Delete. (aarch64_insn_callee_abi): New function. (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete. (TARGET_INSN_CALLEE_ABI): New macro. * rtl.h (get_call_fndecl): Declare. (cgraph_rtl_info): Fix formatting. Tweak comment for function_used_regs. Remove function_used_regs_valid. * rtlanal.c (get_call_fndecl): Moved from final.c * function-abi.h (insn_callee_abi): Declare. (target_function_abi_info): Mention insn_callee_abi. * function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar way to get_call_reg_set_usage did. (insn_callee_abi): New function. * regs.h (get_call_reg_set_usage): Delete. * final.c: Include function-abi.h. (collect_fn_hard_reg_usage): Add fixed and stack registers to function_used_regs before the main loop rather than afterwards. Use insn_callee_abi instead of get_call_reg_set_usage. Exit early if function_used_regs ends up not being useful. (get_call_fndecl): Move to rtlanal.c (get_call_cgraph_rtl_info, get_call_reg_set_usage): Delete. * caller-save.c: Include function-abi.h. (setup_save_areas, save_call_clobbered_regs): Use insn_callee_abi instead of get_call_reg_set_usage. * cfgcleanup.c: Include function-abi.h. (old_insns_match_p): Use insn_callee_abi instead of get_call_reg_set_usage. * cgraph.h (cgraph_node::rtl_info): Take a const_tree instead of a tree. * cgraph.c (cgraph_node::rtl_info): Likewise. Initialize function_used_regs. * df-scan.c: Include function-abi.h. (df_get_call_refs): Use insn_callee_abi instead of get_call_reg_set_usage. * ira-lives.c: Include function-abi.h. (process_bb_node_lives): Use insn_callee_abi instead of get_call_reg_set_usage. * lra-lives.c: Include function-abi.h. (process_bb_lives): Use insn_callee_abi instead of get_call_reg_set_usage. * postreload.c: Include function-abi.h. (reload_combine): Use insn_callee_abi instead of get_call_reg_set_usage. * regcprop.c: Include function-abi.h. (copyprop_hardreg_forward_1): Use insn_callee_abi instead of get_call_reg_set_usage. * resource.c: Include function-abi.h. (mark_set_resources, mark_target_live_regs): Use insn_callee_abi instead of get_call_reg_set_usage. * var-tracking.c: Include function-abi.h. (dataflow_set_clear_at_call): Use insn_callee_abi instead of get_call_reg_set_usage. From-SVN: r276309 --- gcc/ChangeLog | 64 ++++++++++++++++++++++++++ gcc/caller-save.c | 16 +++++-- gcc/cfgcleanup.c | 10 +++-- gcc/cgraph.c | 7 ++- gcc/cgraph.h | 2 +- gcc/config/aarch64/aarch64.c | 23 ++++------ gcc/df-scan.c | 8 ++-- gcc/doc/tm.texi | 23 +++++----- gcc/doc/tm.texi.in | 4 +- gcc/final.c | 104 +++++++++---------------------------------- gcc/function-abi.cc | 25 ++++++++++- gcc/function-abi.h | 3 ++ gcc/ira-lives.c | 10 +++-- gcc/lra-lives.c | 9 ++-- gcc/postreload.c | 8 ++-- gcc/regcprop.c | 8 ++-- gcc/regs.h | 4 -- gcc/resource.c | 11 ++--- gcc/rtl.h | 10 ++--- gcc/rtlanal.c | 18 ++++++++ gcc/target.def | 27 ++++++----- gcc/targhooks.c | 5 --- gcc/targhooks.h | 2 - gcc/var-tracking.c | 7 ++- 24 files changed, 221 insertions(+), 187 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 812dadb..43c3455 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,69 @@ 2019-09-30 Richard Sandiford + * target.def (insn_callee_abi): New hook. + (remove_extra_call_preserved_regs): Delete. + * doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro. + (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete. + * doc/tm.texi: Regenerate. + * targhooks.h (default_remove_extra_call_preserved_regs): Delete. + * targhooks.c (default_remove_extra_call_preserved_regs): Delete. + * config/aarch64/aarch64.c (aarch64_simd_call_p): Constify the + insn argument. + (aarch64_remove_extra_call_preserved_regs): Delete. + (aarch64_insn_callee_abi): New function. + (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): Delete. + (TARGET_INSN_CALLEE_ABI): New macro. + * rtl.h (get_call_fndecl): Declare. + (cgraph_rtl_info): Fix formatting. Tweak comment for + function_used_regs. Remove function_used_regs_valid. + * rtlanal.c (get_call_fndecl): Moved from final.c + * function-abi.h (insn_callee_abi): Declare. + (target_function_abi_info): Mention insn_callee_abi. + * function-abi.cc (fndecl_abi): Handle flag_ipa_ra in a similar + way to get_call_reg_set_usage did. + (insn_callee_abi): New function. + * regs.h (get_call_reg_set_usage): Delete. + * final.c: Include function-abi.h. + (collect_fn_hard_reg_usage): Add fixed and stack registers to + function_used_regs before the main loop rather than afterwards. + Use insn_callee_abi instead of get_call_reg_set_usage. Exit early + if function_used_regs ends up not being useful. + (get_call_fndecl): Move to rtlanal.c + (get_call_cgraph_rtl_info, get_call_reg_set_usage): Delete. + * caller-save.c: Include function-abi.h. + (setup_save_areas, save_call_clobbered_regs): Use insn_callee_abi + instead of get_call_reg_set_usage. + * cfgcleanup.c: Include function-abi.h. + (old_insns_match_p): Use insn_callee_abi instead of + get_call_reg_set_usage. + * cgraph.h (cgraph_node::rtl_info): Take a const_tree instead of + a tree. + * cgraph.c (cgraph_node::rtl_info): Likewise. Initialize + function_used_regs. + * df-scan.c: Include function-abi.h. + (df_get_call_refs): Use insn_callee_abi instead of + get_call_reg_set_usage. + * ira-lives.c: Include function-abi.h. + (process_bb_node_lives): Use insn_callee_abi instead of + get_call_reg_set_usage. + * lra-lives.c: Include function-abi.h. + (process_bb_lives): Use insn_callee_abi instead of + get_call_reg_set_usage. + * postreload.c: Include function-abi.h. + (reload_combine): Use insn_callee_abi instead of + get_call_reg_set_usage. + * regcprop.c: Include function-abi.h. + (copyprop_hardreg_forward_1): Use insn_callee_abi instead of + get_call_reg_set_usage. + * resource.c: Include function-abi.h. + (mark_set_resources, mark_target_live_regs): Use insn_callee_abi + instead of get_call_reg_set_usage. + * var-tracking.c: Include function-abi.h. + (dataflow_set_clear_at_call): Use insn_callee_abi instead of + get_call_reg_set_usage. + +2019-09-30 Richard Sandiford + * target.def (fntype_abi): New target hook. * doc/tm.texi.in (TARGET_FNTYPE_ABI): Likewise. * doc/tm.texi: Regenerate. diff --git a/gcc/caller-save.c b/gcc/caller-save.c index b63e568..10b6737 100644 --- a/gcc/caller-save.c +++ b/gcc/caller-save.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "rtl-iter.h" #include "target.h" +#include "function-abi.h" #define MOVE_MAX_WORDS (MOVE_MAX / UNITS_PER_WORD) @@ -426,7 +427,9 @@ setup_save_areas (void) freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn)); REG_SET_TO_HARD_REG_SET (hard_regs_to_save, &chain->live_throughout); - get_call_reg_set_usage (insn, &used_regs, call_used_or_fixed_regs); + used_regs = insn_callee_abi (insn).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not be needed. */ + used_regs |= fixed_reg_set; /* Record all registers set in this call insn. These don't need to be saved. N.B. the call insn might set a subreg @@ -509,7 +512,10 @@ setup_save_areas (void) REG_SET_TO_HARD_REG_SET (hard_regs_to_save, &chain->live_throughout); - get_call_reg_set_usage (insn, &used_regs, call_used_or_fixed_regs); + used_regs = insn_callee_abi (insn).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not + be needed. */ + used_regs |= fixed_reg_set; /* Record all registers set in this call insn. These don't need to be saved. N.B. the call insn might set a subreg @@ -838,8 +844,10 @@ save_call_clobbered_regs (void) | this_insn_sets | hard_regs_saved); hard_regs_to_save &= savable_regs; - get_call_reg_set_usage (insn, &call_def_reg_set, - call_used_or_fixed_regs); + call_def_reg_set = insn_callee_abi (insn).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not + be needed. */ + call_def_reg_set |= fixed_reg_set; hard_regs_to_save &= call_def_reg_set; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 17fa1de..329fa0c 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see #include "dbgcnt.h" #include "rtl-iter.h" #include "regs.h" +#include "function-abi.h" #define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK) @@ -1226,10 +1227,11 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx_insn *i1, rtx_insn *i2) } } - HARD_REG_SET i1_used, i2_used; - - get_call_reg_set_usage (i1, &i1_used, call_used_or_fixed_regs); - get_call_reg_set_usage (i2, &i2_used, call_used_or_fixed_regs); + HARD_REG_SET i1_used = insn_callee_abi (i1).full_reg_clobbers (); + HARD_REG_SET i2_used = insn_callee_abi (i2).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not be needed. */ + i1_used |= fixed_reg_set; + i2_used |= fixed_reg_set; if (i1_used != i2_used) return dir_none; diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 8615e2e..19158f0 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1839,7 +1839,7 @@ cgraph_node::local_info (tree decl) /* Return local info for the compiled function. */ cgraph_rtl_info * -cgraph_node::rtl_info (tree decl) +cgraph_node::rtl_info (const_tree decl) { gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); cgraph_node *node = get (decl); @@ -1854,7 +1854,10 @@ cgraph_node::rtl_info (tree decl) return NULL; /* Allocate if it doesn't exist. */ if (node->rtl == NULL) - node->rtl = ggc_cleared_alloc (); + { + node->rtl = ggc_cleared_alloc (); + node->rtl->function_used_regs = reg_class_contents[ALL_REGS]; + } return node->rtl; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 195e6e9..c35b6b9 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1379,7 +1379,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node static cgraph_local_info *local_info (tree decl); /* Return local info for the compiled function. */ - static struct cgraph_rtl_info *rtl_info (tree); + static struct cgraph_rtl_info *rtl_info (const_tree); /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. Return NULL if there's no such node. */ diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 211459c..71cdce3 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1877,7 +1877,7 @@ aarch64_reg_save_mode (tree fndecl, unsigned regno) the function. */ static bool -aarch64_simd_call_p (rtx_insn *insn) +aarch64_simd_call_p (const rtx_insn *insn) { rtx symbol; rtx call; @@ -1895,20 +1895,14 @@ aarch64_simd_call_p (rtx_insn *insn) return aarch64_simd_decl_p (fndecl); } -/* Implement TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS. If INSN calls - a function that uses the SIMD ABI, take advantage of the extra - call-preserved registers that the ABI provides. */ +/* Implement TARGET_INSN_CALLEE_ABI. */ -void -aarch64_remove_extra_call_preserved_regs (rtx_insn *insn, - HARD_REG_SET *return_set) +const predefined_function_abi & +aarch64_insn_callee_abi (const rtx_insn *insn) { if (aarch64_simd_call_p (insn)) - { - for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (FP_SIMD_SAVED_REGNUM_P (regno)) - CLEAR_HARD_REG_BIT (*return_set, regno); - } + return aarch64_simd_abi (); + return default_function_abi; } /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. The callee only saves @@ -21004,9 +20998,8 @@ aarch64_libgcc_floating_mode_supported_p #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \ aarch64_hard_regno_call_part_clobbered -#undef TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS -#define TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS \ - aarch64_remove_extra_call_preserved_regs +#undef TARGET_INSN_CALLEE_ABI +#define TARGET_INSN_CALLEE_ABI aarch64_insn_callee_abi #undef TARGET_RETURN_CALL_WITH_MAX_CLOBBERS #define TARGET_RETURN_CALL_WITH_MAX_CLOBBERS \ diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 9b08bdc..7ca1050 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -35,7 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */ #include "dumpfile.h" #include "calls.h" - +#include "function-abi.h" /* The set of hard registers in eliminables[i].from. */ @@ -3088,13 +3088,11 @@ df_get_call_refs (class df_collection_rec *collection_rec, bool is_sibling_call; unsigned int i; HARD_REG_SET defs_generated; - HARD_REG_SET fn_reg_set_usage; CLEAR_HARD_REG_SET (defs_generated); df_find_hard_reg_defs (PATTERN (insn_info->insn), &defs_generated); is_sibling_call = SIBLING_CALL_P (insn_info->insn); - get_call_reg_set_usage (insn_info->insn, &fn_reg_set_usage, - regs_invalidated_by_call); + function_abi callee_abi = insn_callee_abi (insn_info->insn); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { @@ -3118,7 +3116,7 @@ df_get_call_refs (class df_collection_rec *collection_rec, NULL, bb, insn_info, DF_REF_REG_DEF, flags); } } - else if (TEST_HARD_REG_BIT (fn_reg_set_usage, i) + else if (callee_abi.clobbers_full_reg_p (i) /* no clobbers for regs that are the result of the call */ && !TEST_HARD_REG_BIT (defs_generated, i) && (!is_sibling_call diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 0f79d38..33997a5 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1905,6 +1905,17 @@ descriptor. Targets only need to define this hook if they support interoperability between several ABIs in the same translation unit. @end deftypefn +@deftypefn {Target Hook} {const predefined_function_abi &} TARGET_INSN_CALLEE_ABI (const rtx_insn *@var{insn}) +This hook returns a description of the ABI used by the target of +call instruction @var{insn}; see the definition of +@code{predefined_function_abi} for details of the ABI descriptor. +Only the global function @code{insn_callee_abi} should call this hook +directly. + +Targets only need to define this hook if they support +interoperability between several ABIs in the same translation unit. +@end deftypefn + @cindex call-used register @cindex call-clobbered register @cindex call-saved register @@ -1921,18 +1932,6 @@ The default implementation returns false, which is correct for targets that don't have partly call-clobbered registers. @end deftypefn -@deftypefn {Target Hook} void TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS (rtx_insn *@var{insn}, HARD_REG_SET *@var{used_regs}) -This hook removes registers from the set of call-clobbered registers - in @var{used_regs} if, contrary to the default rules, something guarantees - that @samp{insn} preserves those registers. For example, some targets - support variant ABIs in which functions preserve more registers than - normal functions would. Removing those extra registers from @var{used_regs} - can lead to better register allocation. - - The default implementation does nothing, which is always safe. - Defining the hook is purely an optimization. -@end deftypefn - @deftypefn {Target Hook} {rtx_insn *} TARGET_RETURN_CALL_WITH_MAX_CLOBBERS (rtx_insn *@var{call_1}, rtx_insn *@var{call_2}) This hook returns a pointer to the call that partially clobbers the most registers. If a platform supports multiple ABIs where the registers diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index ed605c0..55fb5d4 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -1711,13 +1711,13 @@ must be defined. Modern ports should define @code{CALL_REALLY_USED_REGISTERS}. @cindex call-saved register @hook TARGET_FNTYPE_ABI +@hook TARGET_INSN_CALLEE_ABI + @cindex call-used register @cindex call-clobbered register @cindex call-saved register @hook TARGET_HARD_REGNO_CALL_PART_CLOBBERED -@hook TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS - @hook TARGET_RETURN_CALL_WITH_MAX_CLOBBERS @hook TARGET_GET_MULTILIB_ABI_NAME diff --git a/gcc/final.c b/gcc/final.c index ae8ff22..7cf9ef1 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "rtl-iter.h" #include "print-rtl.h" +#include "function-abi.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data declarations. */ @@ -230,7 +231,6 @@ static int alter_cond (rtx); #endif static int align_fuzz (rtx, rtx, int, unsigned); static void collect_fn_hard_reg_usage (void); -static tree get_call_fndecl (rtx_insn *); /* Initialize data in final at the beginning of a compilation. */ @@ -4994,7 +4994,16 @@ collect_fn_hard_reg_usage (void) if (!targetm.call_fusage_contains_non_callee_clobbers) return; - CLEAR_HARD_REG_SET (function_used_regs); + /* Be conservative - mark fixed and global registers as used. */ + function_used_regs = fixed_reg_set; + +#ifdef STACK_REGS + /* Handle STACK_REGS conservatively, since the df-framework does not + provide accurate information for them. */ + + for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) + SET_HARD_REG_BIT (function_used_regs, i); +#endif for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn)) { @@ -5005,96 +5014,23 @@ collect_fn_hard_reg_usage (void) if (CALL_P (insn) && !self_recursive_call_p (insn)) - { - if (!get_call_reg_set_usage (insn, &insn_used_regs, - call_used_or_fixed_regs)) - return; - - function_used_regs |= insn_used_regs; - } + function_used_regs + |= insn_callee_abi (insn).full_and_partial_reg_clobbers (); find_all_hard_reg_sets (insn, &insn_used_regs, false); function_used_regs |= insn_used_regs; - } - /* Be conservative - mark fixed and global registers as used. */ - function_used_regs |= fixed_reg_set; - -#ifdef STACK_REGS - /* Handle STACK_REGS conservatively, since the df-framework does not - provide accurate information for them. */ - - for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) - SET_HARD_REG_BIT (function_used_regs, i); -#endif + if (hard_reg_set_subset_p (crtl->abi->full_and_partial_reg_clobbers (), + function_used_regs)) + return; + } - /* The information we have gathered is only interesting if it exposes a - register from the call_used_regs that is not used in this function. */ - if (hard_reg_set_subset_p (call_used_or_fixed_regs, function_used_regs)) - return; + /* Mask out fully-saved registers, so that they don't affect equality + comparisons between function_abis. */ + function_used_regs &= crtl->abi->full_and_partial_reg_clobbers (); node = cgraph_node::rtl_info (current_function_decl); gcc_assert (node != NULL); node->function_used_regs = function_used_regs; - node->function_used_regs_valid = 1; -} - -/* Get the declaration of the function called by INSN. */ - -static tree -get_call_fndecl (rtx_insn *insn) -{ - rtx note, datum; - - note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX); - if (note == NULL_RTX) - return NULL_TREE; - - datum = XEXP (note, 0); - if (datum != NULL_RTX) - return SYMBOL_REF_DECL (datum); - - return NULL_TREE; -} - -/* Return the cgraph_rtl_info of the function called by INSN. Returns NULL for - call targets that can be overwritten. */ - -static struct cgraph_rtl_info * -get_call_cgraph_rtl_info (rtx_insn *insn) -{ - tree fndecl; - - if (insn == NULL_RTX) - return NULL; - - fndecl = get_call_fndecl (insn); - if (fndecl == NULL_TREE - || !decl_binds_to_current_def_p (fndecl)) - return NULL; - - return cgraph_node::rtl_info (fndecl); -} - -/* Find hard registers used by function call instruction INSN, and return them - in REG_SET. Return DEFAULT_SET in REG_SET if not found. */ - -bool -get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set, - HARD_REG_SET default_set) -{ - if (flag_ipa_ra) - { - struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn); - if (node != NULL - && node->function_used_regs_valid) - { - *reg_set = node->function_used_regs & default_set; - return true; - } - } - *reg_set = default_set; - targetm.remove_extra_call_preserved_regs (insn, reg_set); - return false; } diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index c77989a..e2c35b6 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -143,5 +143,28 @@ function_abi fndecl_abi (const_tree fndecl) { gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL); - return fntype_abi (TREE_TYPE (fndecl)); + const predefined_function_abi &base_abi = fntype_abi (TREE_TYPE (fndecl)); + + if (flag_ipa_ra && decl_binds_to_current_def_p (fndecl)) + if (cgraph_rtl_info *info = cgraph_node::rtl_info (fndecl)) + return function_abi (base_abi, info->function_used_regs); + + return base_abi; +} + +/* Return the ABI of the function called by INSN. */ + +function_abi +insn_callee_abi (const rtx_insn *insn) +{ + gcc_assert (insn && CALL_P (insn)); + + if (flag_ipa_ra) + if (tree fndecl = get_call_fndecl (insn)) + return fndecl_abi (fndecl); + + if (targetm.calls.insn_callee_abi) + return targetm.calls.insn_callee_abi (insn); + + return default_function_abi; } diff --git a/gcc/function-abi.h b/gcc/function-abi.h index 05e502e..c8f3f29 100644 --- a/gcc/function-abi.h +++ b/gcc/function-abi.h @@ -224,6 +224,8 @@ struct target_function_abi_info * crtl->abi is the ABI of the function that we are currently compiling to rtl. + * insn_callee_abi (INSN) is the ABI used by the target of call insn INSN. + * eh_edge_abi is the "ABI" used when taking an EH edge from an exception-throwing statement to an exception handler. Catching exceptions from calls can be treated as an abnormal return from @@ -265,5 +267,6 @@ extern target_function_abi_info *this_target_function_abi_info; extern const predefined_function_abi &fntype_abi (const_tree); extern function_abi fndecl_abi (const_tree); +extern function_abi insn_callee_abi (const rtx_insn *); #endif diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c index 166bd7b..e24831a 100644 --- a/gcc/ira-lives.c +++ b/gcc/ira-lives.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "ira.h" #include "ira-int.h" #include "sparseset.h" +#include "function-abi.h" /* The code in this file is similar to one in global but the code works on the allocno basis and creates live ranges instead of @@ -1254,10 +1255,11 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) ira_object_t obj = ira_object_id_map[i]; a = OBJECT_ALLOCNO (obj); int num = ALLOCNO_NUM (a); - HARD_REG_SET this_call_used_reg_set; - - get_call_reg_set_usage (insn, &this_call_used_reg_set, - call_used_or_fixed_regs); + HARD_REG_SET this_call_used_reg_set + = insn_callee_abi (insn).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not be + needed. */ + this_call_used_reg_set |= fixed_reg_set; /* Don't allocate allocnos that cross setjmps or any call, if this function receives a nonlocal diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index 6f08159..b84d646 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "sparseset.h" #include "lra-int.h" #include "target.h" +#include "function-abi.h" /* Program points are enumerated by numbers from range 0..LRA_LIVE_MAX_POINT-1. There are approximately two times more @@ -931,9 +932,11 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) last_call_used_reg_set = call_used_or_fixed_regs; else { - HARD_REG_SET this_call_used_reg_set; - get_call_reg_set_usage (curr_insn, &this_call_used_reg_set, - call_used_or_fixed_regs); + HARD_REG_SET this_call_used_reg_set + = insn_callee_abi (curr_insn).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not + be needed. */ + this_call_used_reg_set |= fixed_reg_set; bool flush = (! hard_reg_set_empty_p (last_call_used_reg_set) && (last_call_used_reg_set diff --git a/gcc/postreload.c b/gcc/postreload.c index 73b0afa..467df7b 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "cselib.h" #include "tree-pass.h" #include "dbgcnt.h" +#include "function-abi.h" static int reload_cse_noop_set_p (rtx); static bool reload_cse_simplify (rtx_insn *, rtx); @@ -1330,9 +1331,10 @@ reload_combine (void) if (CALL_P (insn)) { rtx link; - HARD_REG_SET used_regs; - - get_call_reg_set_usage (insn, &used_regs, call_used_or_fixed_regs); + HARD_REG_SET used_regs = insn_callee_abi (insn).full_reg_clobbers (); + /* ??? This preserves traditional behavior; it might not be + needed. */ + used_regs |= fixed_reg_set; for (r = 0; r < FIRST_PSEUDO_REGISTER; r++) if (TEST_HARD_REG_BIT (used_regs, r)) diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 4dc82a7..4879063 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -35,6 +35,7 @@ #include "rtl-iter.h" #include "cfgrtl.h" #include "target.h" +#include "function-abi.h" /* The following code does forward propagation of hard register copies. The object is to eliminate as many dependencies as possible, so that @@ -1035,7 +1036,6 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) unsigned int set_nregs = 0; unsigned int regno; rtx exp; - HARD_REG_SET regs_invalidated_by_this_call; for (exp = CALL_INSN_FUNCTION_USAGE (insn); exp; exp = XEXP (exp, 1)) { @@ -1053,11 +1053,9 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) } } - get_call_reg_set_usage (insn, - ®s_invalidated_by_this_call, - regs_invalidated_by_call); + function_abi callee_abi = insn_callee_abi (insn); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((TEST_HARD_REG_BIT (regs_invalidated_by_this_call, regno) + if ((callee_abi.clobbers_full_reg_p (regno) || (targetm.hard_regno_call_part_clobbered (insn, regno, vd->e[regno].mode))) && (regno < set_regno || regno >= set_regno + set_nregs)) diff --git a/gcc/regs.h b/gcc/regs.h index 4634abc..821979e 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -383,8 +383,4 @@ range_in_hard_reg_set_p (const_hard_reg_set set, unsigned regno, int nregs) return true; } -/* Get registers used by given function call instruction. */ -extern bool get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set, - HARD_REG_SET default_set); - #endif /* GCC_REGS_H */ diff --git a/gcc/resource.c b/gcc/resource.c index 2d30e08..c66b6e3 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "resource.h" #include "insn-attr.h" #include "params.h" +#include "function-abi.h" /* This structure is used to record liveness information at the targets or fallthrough insns of branches. We will most likely need the information @@ -662,12 +663,10 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, { rtx_call_insn *call_insn = as_a (x); rtx link; - HARD_REG_SET regs; res->cc = res->memory = 1; - get_call_reg_set_usage (call_insn, ®s, regs_invalidated_by_call); - res->regs |= regs; + res->regs |= insn_callee_abi (call_insn).full_reg_clobbers (); for (link = CALL_INSN_FUNCTION_USAGE (call_insn); link; link = XEXP (link, 1)) @@ -1038,10 +1037,8 @@ mark_target_live_regs (rtx_insn *insns, rtx target_maybe_return, struct resource predicated instruction, or if the CALL is NORETURN. */ if (GET_CODE (PATTERN (real_insn)) != COND_EXEC) { - HARD_REG_SET regs_invalidated_by_this_call; - get_call_reg_set_usage (real_insn, - ®s_invalidated_by_this_call, - regs_invalidated_by_call); + HARD_REG_SET regs_invalidated_by_this_call + = insn_callee_abi (real_insn).full_reg_clobbers (); /* CALL clobbers all call-used regs that aren't fixed except sp, ap, and fp. Do this before setting the result of the call live. */ diff --git a/gcc/rtl.h b/gcc/rtl.h index b75b3ed..d798562 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -3447,6 +3447,7 @@ extern int rtx_unstable_p (const_rtx); extern bool rtx_varies_p (const_rtx, bool); extern bool rtx_addr_varies_p (const_rtx, bool); extern rtx get_call_rtx_from (const rtx_insn *); +extern tree get_call_fndecl (const rtx_insn *); extern HOST_WIDE_INT get_integer_term (const_rtx); extern rtx get_related_value (const_rtx); extern bool offset_within_block_p (const_rtx, HOST_WIDE_INT); @@ -4401,14 +4402,11 @@ extern tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER]; Available only for functions that has been already assembled. */ struct GTY(()) cgraph_rtl_info { - unsigned int preferred_incoming_stack_boundary; + unsigned int preferred_incoming_stack_boundary; - /* Call unsaved hard registers really used by the corresponding - function (including ones used by functions called by the - function). */ + /* Which registers the function clobbers, either directly or by + calling another function. */ HARD_REG_SET function_used_regs; - /* Set if function_used_regs is valid. */ - unsigned function_used_regs_valid: 1; }; /* If loads from memories of mode MODE always sign or zero extend, diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 28b399c..9c70eee 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -822,6 +822,24 @@ get_call_rtx_from (const rtx_insn *insn) return x; return NULL_RTX; } + +/* Get the declaration of the function called by INSN. */ + +tree +get_call_fndecl (const rtx_insn *insn) +{ + rtx note, datum; + + note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX); + if (note == NULL_RTX) + return NULL_TREE; + + datum = XEXP (note, 0); + if (datum != NULL_RTX) + return SYMBOL_REF_DECL (datum); + + return NULL_TREE; +} /* Return the value of the integer term in X, if one is apparent; otherwise return 0. diff --git a/gcc/target.def b/gcc/target.def index 803c7a3..adf7a96 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4952,6 +4952,19 @@ interoperability between several ABIs in the same translation unit.", const predefined_function_abi &, (const_tree type), NULL) +DEFHOOK +(insn_callee_abi, + "This hook returns a description of the ABI used by the target of\n\ +call instruction @var{insn}; see the definition of\n\ +@code{predefined_function_abi} for details of the ABI descriptor.\n\ +Only the global function @code{insn_callee_abi} should call this hook\n\ +directly.\n\ +\n\ +Targets only need to define this hook if they support\n\ +interoperability between several ABIs in the same translation unit.", + const predefined_function_abi &, (const rtx_insn *insn), + NULL) + /* ??? Documenting this hook requires a GFDL license grant. */ DEFHOOK_UNDOC (internal_arg_pointer, @@ -5834,20 +5847,6 @@ DEFHOOK const char *, (void), hook_constcharptr_void_null) -DEFHOOK -(remove_extra_call_preserved_regs, - "This hook removes registers from the set of call-clobbered registers\n\ - in @var{used_regs} if, contrary to the default rules, something guarantees\n\ - that @samp{insn} preserves those registers. For example, some targets\n\ - support variant ABIs in which functions preserve more registers than\n\ - normal functions would. Removing those extra registers from @var{used_regs}\n\ - can lead to better register allocation.\n\ - \n\ - The default implementation does nothing, which is always safe.\n\ - Defining the hook is purely an optimization.", - void, (rtx_insn *insn, HARD_REG_SET *used_regs), - default_remove_extra_call_preserved_regs) - /* Return the smallest number of different values for which it is best to use a jump-table instead of a tree of conditional branches. */ DEFHOOK diff --git a/gcc/targhooks.c b/gcc/targhooks.c index ed77afb..d2e3ff6 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -2363,9 +2363,4 @@ default_speculation_safe_value (machine_mode mode ATTRIBUTE_UNUSED, return result; } -void -default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *) -{ -} - #include "gt-targhooks.h" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 5aba676..d4c3563 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -281,7 +281,5 @@ extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *); extern bool default_have_speculation_safe_value (bool); extern bool speculation_safe_value_not_needed (bool); extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx); -extern void default_remove_extra_call_preserved_regs (rtx_insn *, - HARD_REG_SET *); #endif /* GCC_TARGHOOKS_H */ diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 6c26b61..3d069e4 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -116,6 +116,7 @@ #include "rtl-iter.h" #include "fibonacci_heap.h" #include "print-rtl.h" +#include "function-abi.h" typedef fibonacci_heap bb_heap_t; typedef fibonacci_node bb_heap_node_t; @@ -4900,12 +4901,10 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn) { unsigned int r; hard_reg_set_iterator hrsi; - HARD_REG_SET invalidated_regs; - get_call_reg_set_usage (call_insn, &invalidated_regs, - regs_invalidated_by_call); + function_abi callee_abi = insn_callee_abi (call_insn); - EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi) + EXECUTE_IF_SET_IN_HARD_REG_SET (callee_abi.full_reg_clobbers (), 0, r, hrsi) var_regno_delete (set, r); if (MAY_HAVE_DEBUG_BIND_INSNS) -- cgit v1.1 From 2a2e3a0dfcbe0861915f421d11b828f0c35023f0 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:19:52 +0000 Subject: [x86] Robustify vzeroupper handling across calls One of the effects of the function_abi series is to make -fipa-ra work for partially call-clobbered registers. E.g. if a call preserves only the low 32 bits of a register R, we handled the partial clobber separately from -fipa-ra, and so treated the upper bits of R as clobbered even if we knew that the target function doesn't touch R. "Fixing" this caused problems for the vzeroupper handling on x86. The pass that inserts the vzerouppers assumes that no 256-bit or 512-bit values are live across a call unless the call takes a 256-bit or 512-bit argument: /* Needed mode is set to AVX_U128_CLEAN if there are no 256bit or 512bit modes used in function arguments. */ This implicitly relies on: /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. The only ABI that saves SSE registers across calls is Win64 (thus no need to check the current ABI here), and with AVX enabled Win64 only guarantees that the low 16 bytes are saved. */ static bool ix86_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, unsigned int regno, machine_mode mode) { return SSE_REGNO_P (regno) && GET_MODE_SIZE (mode) > 16; } The comment suggests that this code is only needed for Win64 and that not testing for Win64 is just a simplification. But in practice it was needed for correctness on GNU/Linux and other targets too, since without it the RA would be able to keep 256-bit and 512-bit values in SSE registers across calls that are known not to clobber them. This patch conservatively treats calls as AVX_U128_ANY if the RA can see that some SSE registers are not touched by a call. There are then no regressions if the ix86_hard_regno_call_part_clobbered check is disabled for GNU/Linux (not something we should do, was just for testing). If in fact we want -fipa-ra to pretend that all functions clobber SSE registers above 128 bits, it'd certainly be possible to arrange that. But IMO that would be an optimisation decision, whereas what the patch is fixing is a correctness decision. So I think we should have this check even so. 2019-09-30 Richard Sandiford gcc/ * config/i386/i386.c: Include function-abi.h. (ix86_avx_u128_mode_needed): Treat function calls as AVX_U128_ANY if they preserve some 256-bit or 512-bit SSE registers. From-SVN: r276310 --- gcc/ChangeLog | 6 ++++++ gcc/config/i386/i386.c | 10 ++++++++++ 2 files changed, 16 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 43c3455..acdcd91 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * config/i386/i386.c: Include function-abi.h. + (ix86_avx_u128_mode_needed): Treat function calls as AVX_U128_ANY + if they preserve some 256-bit or 512-bit SSE registers. + +2019-09-30 Richard Sandiford + * target.def (insn_callee_abi): New hook. (remove_extra_call_preserved_regs): Delete. * doc/tm.texi.in (TARGET_INSN_CALLEE_ABI): New macro. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9a87413..a13aef8 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -95,6 +95,7 @@ along with GCC; see the file COPYING3. If not see #include "i386-builtins.h" #include "i386-expand.h" #include "i386-features.h" +#include "function-abi.h" /* This file should be included last. */ #include "target-def.h" @@ -13511,6 +13512,15 @@ ix86_avx_u128_mode_needed (rtx_insn *insn) } } + /* If the function is known to preserve some SSE registers, + RA and previous passes can legitimately rely on that for + modes wider than 256 bits. It's only safe to issue a + vzeroupper if all SSE registers are clobbered. */ + const function_abi &abi = insn_callee_abi (insn); + if (!hard_reg_set_subset_p (reg_class_contents[ALL_SSE_REGS], + abi.mode_clobbers (V4DImode))) + return AVX_U128_ANY; + return AVX_U128_CLEAN; } -- cgit v1.1 From 6ee2cc70024253d2670a4a317158b2a65251a1d1 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:19:59 +0000 Subject: Pass an ABI identifier to hard_regno_call_part_clobbered This patch replaces the rtx_insn argument to targetm.hard_regno_call_part_clobbered with an ABI identifier, since call insns are now just one possible way of getting an ABI handle. This in turn allows predefined_function_abi::initialize to do the right thing for non-default ABIs. The horrible ?: in need_for_call_save_p goes away in a later patch, with the series as a whole removing most direct calls to the hook in favour of function_abi operations. 2019-09-30 Richard Sandiford gcc/ * target.def (hard_regno_call_part_clobbered): Take an ABI identifier instead of an rtx_insn. * doc/tm.texi: Regenerate. * hooks.h (hook_bool_insn_uint_mode_false): Delete. (hook_bool_uint_uint_mode_false): New function. * hooks.c (hook_bool_insn_uint_mode_false): Delete. (hook_bool_uint_uint_mode_false): New function. * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): Take an ABI identifier instead of an rtx_insn. * config/avr/avr.c (avr_hard_regno_call_part_clobbered): Likewise. * config/i386/i386.c (ix86_hard_regno_call_part_clobbered): Likewise. * config/mips/mips.c (mips_hard_regno_call_part_clobbered): Likewise. * config/pru/pru.c (pru_hard_regno_call_part_clobbered): Likewise. * config/rs6000/rs6000.c (rs6000_hard_regno_call_part_clobbered): Likewise. * config/s390/s390.c (s390_hard_regno_call_part_clobbered): Likewise. * cselib.c: Include function-abi.h. (cselib_process_insn): Update call to targetm.hard_regno_call_part_clobbered, using insn_callee_abi to get the appropriate ABI identifier. * function-abi.cc (predefined_function_abi::initialize): Update call to targetm.hard_regno_call_part_clobbered. * ira-conflicts.c (ira_build_conflicts): Likewise. * ira-costs.c (ira_tune_allocno_costs): Likewise. * lra-constraints.c: Include function-abi.h. (need_for_call_save_p): Update call to targetm.hard_regno_call_part_clobbered, using insn_callee_abi to get the appropriate ABI identifier. * lra-lives.c (check_pseudos_live_through_calls): Likewise. * regcprop.c (copyprop_hardreg_forward_1): Update call to targetm.hard_regno_call_part_clobbered. * reginfo.c (choose_hard_reg_mode): Likewise. * regrename.c (check_new_reg_p): Likewise. * reload.c (find_equiv_reg): Likewise. * reload1.c (emit_reload_insns): Likewise. * sched-deps.c: Include function-abi.h. (deps_analyze_insn): Update call to targetm.hard_regno_call_part_clobbered, using insn_callee_abi to get the appropriate ABI identifier. * sel-sched.c (init_regs_for_mode, mark_unavailable_hard_regs): Update call to targetm.hard_regno_call_part_clobbered. * targhooks.c (default_dwarf_frame_reg_mode): Likewise. From-SVN: r276311 --- gcc/ChangeLog | 45 ++++++++++++++++++++++++++++++++++++++++++++ gcc/config/aarch64/aarch64.c | 5 +++-- gcc/config/avr/avr.c | 4 ++-- gcc/config/i386/i386.c | 4 ++-- gcc/config/mips/mips.c | 4 ++-- gcc/config/pru/pru.c | 4 ++-- gcc/config/rs6000/rs6000.c | 4 ++-- gcc/config/s390/s390.c | 4 ++-- gcc/cselib.c | 5 ++++- gcc/doc/tm.texi | 25 ++++++++++++++++-------- gcc/function-abi.cc | 8 ++++---- gcc/hooks.c | 3 +-- gcc/hooks.h | 2 +- gcc/ira-conflicts.c | 2 +- gcc/ira-costs.c | 2 +- gcc/lra-constraints.c | 4 +++- gcc/lra-lives.c | 4 ++-- gcc/regcprop.c | 2 +- gcc/reginfo.c | 10 +++++----- gcc/regrename.c | 4 ++-- gcc/reload.c | 4 ++-- gcc/reload1.c | 8 +++----- gcc/sched-deps.c | 6 ++++-- gcc/sel-sched.c | 4 ++-- gcc/target.def | 27 +++++++++++++++++--------- gcc/targhooks.c | 2 +- 26 files changed, 132 insertions(+), 64 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index acdcd91..59bfeb2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,50 @@ 2019-09-30 Richard Sandiford + * target.def (hard_regno_call_part_clobbered): Take an ABI + identifier instead of an rtx_insn. + * doc/tm.texi: Regenerate. + * hooks.h (hook_bool_insn_uint_mode_false): Delete. + (hook_bool_uint_uint_mode_false): New function. + * hooks.c (hook_bool_insn_uint_mode_false): Delete. + (hook_bool_uint_uint_mode_false): New function. + * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): + Take an ABI identifier instead of an rtx_insn. + * config/avr/avr.c (avr_hard_regno_call_part_clobbered): Likewise. + * config/i386/i386.c (ix86_hard_regno_call_part_clobbered): Likewise. + * config/mips/mips.c (mips_hard_regno_call_part_clobbered): Likewise. + * config/pru/pru.c (pru_hard_regno_call_part_clobbered): Likewise. + * config/rs6000/rs6000.c (rs6000_hard_regno_call_part_clobbered): + Likewise. + * config/s390/s390.c (s390_hard_regno_call_part_clobbered): Likewise. + * cselib.c: Include function-abi.h. + (cselib_process_insn): Update call to + targetm.hard_regno_call_part_clobbered, using insn_callee_abi + to get the appropriate ABI identifier. + * function-abi.cc (predefined_function_abi::initialize): Update call + to targetm.hard_regno_call_part_clobbered. + * ira-conflicts.c (ira_build_conflicts): Likewise. + * ira-costs.c (ira_tune_allocno_costs): Likewise. + * lra-constraints.c: Include function-abi.h. + (need_for_call_save_p): Update call to + targetm.hard_regno_call_part_clobbered, using insn_callee_abi + to get the appropriate ABI identifier. + * lra-lives.c (check_pseudos_live_through_calls): Likewise. + * regcprop.c (copyprop_hardreg_forward_1): Update call + to targetm.hard_regno_call_part_clobbered. + * reginfo.c (choose_hard_reg_mode): Likewise. + * regrename.c (check_new_reg_p): Likewise. + * reload.c (find_equiv_reg): Likewise. + * reload1.c (emit_reload_insns): Likewise. + * sched-deps.c: Include function-abi.h. + (deps_analyze_insn): Update call to + targetm.hard_regno_call_part_clobbered, using insn_callee_abi + to get the appropriate ABI identifier. + * sel-sched.c (init_regs_for_mode, mark_unavailable_hard_regs): Update + call to targetm.hard_regno_call_part_clobbered. + * targhooks.c (default_dwarf_frame_reg_mode): Likewise. + +2019-09-30 Richard Sandiford + * config/i386/i386.c: Include function-abi.h. (ix86_avx_u128_mode_needed): Treat function calls as AVX_U128_ANY if they preserve some 256-bit or 512-bit SSE registers. diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 71cdce3..ca4c183 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1910,12 +1910,13 @@ aarch64_insn_callee_abi (const rtx_insn *insn) clobbers the top 64 bits when restoring the bottom 64 bits. */ static bool -aarch64_hard_regno_call_part_clobbered (rtx_insn *insn, unsigned int regno, +aarch64_hard_regno_call_part_clobbered (unsigned int abi_id, + unsigned int regno, machine_mode mode) { if (FP_REGNUM_P (regno)) { - bool simd_p = insn && CALL_P (insn) && aarch64_simd_call_p (insn); + bool simd_p = (abi_id == ARM_PCS_SIMD); poly_int64 per_register_size = GET_MODE_SIZE (mode); unsigned int nregs = hard_regno_nregs (regno, mode); if (nregs > 1) diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 04fc00f..3ccff8e 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -12164,8 +12164,8 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. */ static bool -avr_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, - unsigned regno, machine_mode mode) +avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, + machine_mode mode) { /* FIXME: This hook gets called with MODE:REGNO combinations that don't represent valid hard registers like, e.g. HI:29. Returning TRUE diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a13aef8..8af4bc5 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -18794,8 +18794,8 @@ ix86_hard_regno_mode_ok (unsigned int regno, machine_mode mode) the low 16 bytes are saved. */ static bool -ix86_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, - unsigned int regno, machine_mode mode) +ix86_hard_regno_call_part_clobbered (unsigned int, unsigned int regno, + machine_mode mode) { return SSE_REGNO_P (regno) && GET_MODE_SIZE (mode) > 16; } diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index c682ebd..91dd94b 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -12928,8 +12928,8 @@ mips_hard_regno_scratch_ok (unsigned int regno) registers with MODE > 64 bits are part clobbered too. */ static bool -mips_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, - unsigned int regno, machine_mode mode) +mips_hard_regno_call_part_clobbered (unsigned int, unsigned int regno, + machine_mode mode) { if (TARGET_FLOATXX && hard_regno_nregs (regno, mode) == 1 diff --git a/gcc/config/pru/pru.c b/gcc/config/pru/pru.c index 416399e..16d1451 100644 --- a/gcc/config/pru/pru.c +++ b/gcc/config/pru/pru.c @@ -559,8 +559,8 @@ pru_hard_regno_scratch_ok (unsigned int regno) /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. */ static bool -pru_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, - unsigned regno, machine_mode mode) +pru_hard_regno_call_part_clobbered (unsigned, unsigned regno, + machine_mode mode) { HARD_REG_SET caller_saved_set; HARD_REG_SET callee_saved_set; diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index d6e1fea..330e249 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1946,8 +1946,8 @@ rs6000_modes_tieable_p (machine_mode mode1, machine_mode mode2) /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. */ static bool -rs6000_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, - unsigned int regno, machine_mode mode) +rs6000_hard_regno_call_part_clobbered (unsigned int, unsigned int regno, + machine_mode mode) { if (TARGET_32BIT && TARGET_POWERPC64 diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index cfdfa4e..1764c34 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -10297,8 +10297,8 @@ s390_hard_regno_scratch_ok (unsigned int regno) bytes are saved across calls, however. */ static bool -s390_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED, - unsigned int regno, machine_mode mode) +s390_hard_regno_call_part_clobbered (unsigned int, unsigned int regno, + machine_mode mode) { if (!TARGET_64BIT && TARGET_ZARCH diff --git a/gcc/cselib.c b/gcc/cselib.c index 109cc27..5de14a0 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "cselib.h" #include "params.h" +#include "function-abi.h" /* A list of cselib_val structures. */ struct elt_list @@ -2765,11 +2766,13 @@ cselib_process_insn (rtx_insn *insn) memory. */ if (CALL_P (insn)) { + function_abi callee_abi = insn_callee_abi (insn); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (call_used_or_fixed_reg_p (i) || (REG_VALUES (i) && REG_VALUES (i)->elt && (targetm.hard_regno_call_part_clobbered - (insn, i, GET_MODE (REG_VALUES (i)->elt->val_rtx))))) + (callee_abi.id (), i, + GET_MODE (REG_VALUES (i)->elt->val_rtx))))) cselib_invalidate_regno (i, reg_raw_mode[i]); /* Since it is not clear how cselib is going to be used, be diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 33997a5..419c706 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1919,14 +1919,23 @@ interoperability between several ABIs in the same translation unit. @cindex call-used register @cindex call-clobbered register @cindex call-saved register -@deftypefn {Target Hook} bool TARGET_HARD_REGNO_CALL_PART_CLOBBERED (rtx_insn *@var{insn}, unsigned int @var{regno}, machine_mode @var{mode}) -This hook should return true if @var{regno} is partly call-saved and -partly call-clobbered, and if a value of mode @var{mode} would be partly -clobbered by call instruction @var{insn}. If @var{insn} is NULL then it -should return true if any call could partly clobber the register. -For example, if the low 32 bits of @var{regno} are preserved across a call -but higher bits are clobbered, this hook should return true for a 64-bit -mode but false for a 32-bit mode. +@deftypefn {Target Hook} bool TARGET_HARD_REGNO_CALL_PART_CLOBBERED (unsigned int @var{abi_id}, unsigned int @var{regno}, machine_mode @var{mode}) +ABIs usually specify that calls must preserve the full contents +of a particular register, or that calls can alter any part of a +particular register. This information is captured by the target macro +@code{CALL_REALLY_USED_REGISTERS}. However, some ABIs specify that calls +must preserve certain bits of a particular register but can alter others. +This hook should return true if this applies to at least one of the +registers in @samp{(reg:@var{mode} @var{regno})}, and if as a result the +call would alter part of the @var{mode} value. For example, if a call +preserves the low 32 bits of a 64-bit hard register @var{regno} but can +clobber the upper 32 bits, this hook should return true for a 64-bit mode +but false for a 32-bit mode. + +The value of @var{abi_id} comes from the @code{predefined_function_abi} +structure that describes the ABI of the call; see the definition of the +structure for more details. If (as is usual) the target uses the same ABI +for all functions in a translation unit, @var{abi_id} is always 0. The default implementation returns false, which is correct for targets that don't have partly call-clobbered registers. diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index e2c35b6..1d1ac9a 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -50,7 +50,7 @@ predefined_function_abi::initialize (unsigned int id, If the ABI specifies that part of a hard register R is call-clobbered, we should be able to find a single-register mode M for which - targetm.hard_regno_call_part_clobbered (NULL, R, M) is true. + targetm.hard_regno_call_part_clobbered (m_id, R, M) is true. In other words, it shouldn't be the case that R can hold all single-register modes across a call, but can't hold part of a multi-register mode. @@ -66,7 +66,7 @@ predefined_function_abi::initialize (unsigned int id, for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) if (targetm.hard_regno_mode_ok (regno, mode) && hard_regno_nregs (regno, mode) == 1 - && targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + && targetm.hard_regno_call_part_clobbered (m_id, regno, mode)) SET_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno); } @@ -89,7 +89,7 @@ predefined_function_abi::initialize (unsigned int id, for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) if (targetm.hard_regno_mode_ok (regno, mode) && !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno) - && !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + && !targetm.hard_regno_call_part_clobbered (m_id, regno, mode)) remove_from_hard_reg_set (&m_mode_clobbers[i], mode, regno); } @@ -104,7 +104,7 @@ predefined_function_abi::initialize (unsigned int id, for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) if (targetm.hard_regno_mode_ok (regno, mode) && !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno) - && targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + && targetm.hard_regno_call_part_clobbered (m_id, regno, mode)) gcc_assert (overlaps_hard_reg_set_p (all_clobbers, mode, regno) && overlaps_hard_reg_set_p (m_mode_clobbers[i], mode, regno)); diff --git a/gcc/hooks.c b/gcc/hooks.c index ca731c4..a9a87de 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -140,9 +140,8 @@ hook_bool_puint64_puint64_true (poly_uint64, poly_uint64) return true; } -/* Generic hook that takes (unsigned int, machine_mode) and returns false. */ bool -hook_bool_insn_uint_mode_false (rtx_insn *, unsigned int, machine_mode) +hook_bool_uint_uint_mode_false (unsigned int, unsigned int, machine_mode) { return false; } diff --git a/gcc/hooks.h b/gcc/hooks.h index 040eff0..7cfe91d 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -40,7 +40,7 @@ extern bool hook_bool_const_rtx_insn_const_rtx_insn_true (const rtx_insn *, extern bool hook_bool_mode_uhwi_false (machine_mode, unsigned HOST_WIDE_INT); extern bool hook_bool_puint64_puint64_true (poly_uint64, poly_uint64); -extern bool hook_bool_insn_uint_mode_false (rtx_insn *, unsigned int, +extern bool hook_bool_uint_uint_mode_false (unsigned int, unsigned int, machine_mode); extern bool hook_bool_uint_mode_true (unsigned int, machine_mode); extern bool hook_bool_tree_false (tree); diff --git a/gcc/ira-conflicts.c b/gcc/ira-conflicts.c index c199309..6ceed53 100644 --- a/gcc/ira-conflicts.c +++ b/gcc/ira-conflicts.c @@ -838,7 +838,7 @@ ira_build_conflicts (void) regs must conflict with them. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (!TEST_HARD_REG_BIT (call_used_or_fixed_regs, regno) - && targetm.hard_regno_call_part_clobbered (NULL, regno, + && targetm.hard_regno_call_part_clobbered (0, regno, obj_mode)) { SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno); diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c index aefec08..2e7e10a 100644 --- a/gcc/ira-costs.c +++ b/gcc/ira-costs.c @@ -2381,7 +2381,7 @@ ira_tune_allocno_costs (void) *crossed_calls_clobber_regs) && (ira_hard_reg_set_intersection_p (regno, mode, call_used_or_fixed_regs) - || targetm.hard_regno_call_part_clobbered (NULL, regno, + || targetm.hard_regno_call_part_clobbered (0, regno, mode))) cost += (ALLOCNO_CALL_FREQ (a) * (ira_memory_move_cost[mode][rclass][0] diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index a60bc6c..43fe107 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -131,6 +131,7 @@ #include "lra.h" #include "lra-int.h" #include "print-rtl.h" +#include "function-abi.h" /* Value of LRA_CURR_RELOAD_NUM at the beginning of BB of the current insn. Remember that LRA_CURR_RELOAD_NUM is the number of emitted @@ -5442,7 +5443,8 @@ need_for_call_save_p (int regno) : call_used_or_fixed_regs, PSEUDO_REGNO_MODE (regno), reg_renumber[regno]) || (targetm.hard_regno_call_part_clobbered - (lra_reg_info[regno].call_insn, + (lra_reg_info[regno].call_insn + ? insn_callee_abi (lra_reg_info[regno].call_insn).id () : 0, reg_renumber[regno], PSEUDO_REGNO_MODE (regno))))); } diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index b84d646..40e9f66 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -594,7 +594,7 @@ check_pseudos_live_through_calls (int regno, if (! sparseset_bit_p (pseudos_live_through_calls, regno)) return; - gcc_assert (call_insn && CALL_P (call_insn)); + function_abi callee_abi = insn_callee_abi (call_insn); old_call_insn = lra_reg_info[regno].call_insn; if (!old_call_insn || (targetm.return_call_with_max_clobbers @@ -606,7 +606,7 @@ check_pseudos_live_through_calls (int regno, lra_reg_info[regno].conflict_hard_regs |= last_call_used_reg_set; for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++) - if (targetm.hard_regno_call_part_clobbered (call_insn, hr, + if (targetm.hard_regno_call_part_clobbered (callee_abi.id (), hr, PSEUDO_REGNO_MODE (regno))) add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs, PSEUDO_REGNO_MODE (regno), hr); diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 4879063..0bdd6b9 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -1057,7 +1057,7 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if ((callee_abi.clobbers_full_reg_p (regno) || (targetm.hard_regno_call_part_clobbered - (insn, regno, vd->e[regno].mode))) + (callee_abi.id (), regno, vd->e[regno].mode))) && (regno < set_regno || regno >= set_regno + set_nregs)) kill_value_regno (regno, 1, vd); diff --git a/gcc/reginfo.c b/gcc/reginfo.c index a3fbbe6..f084c0e 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -568,7 +568,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) && (!call_saved - || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; @@ -576,7 +576,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) && (!call_saved - || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; @@ -584,7 +584,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) && (!call_saved - || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; @@ -592,7 +592,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) && (!call_saved - || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; @@ -606,7 +606,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) && (!call_saved - || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))) + || !targetm.hard_regno_call_part_clobbered (0, regno, mode))) return mode; } diff --git a/gcc/regrename.c b/gcc/regrename.c index 14ce954..6a2442bd 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -339,9 +339,9 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg, && ! DEBUG_INSN_P (tmp->insn)) || (this_head->need_caller_save_reg && ! (targetm.hard_regno_call_part_clobbered - (NULL, reg, GET_MODE (*tmp->loc))) + (0, reg, GET_MODE (*tmp->loc))) && (targetm.hard_regno_call_part_clobbered - (NULL, new_reg, GET_MODE (*tmp->loc))))) + (0, new_reg, GET_MODE (*tmp->loc))))) return false; return true; diff --git a/gcc/reload.c b/gcc/reload.c index 7731e0f..b760130 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -6912,14 +6912,14 @@ find_equiv_reg (rtx goal, rtx_insn *insn, enum reg_class rclass, int other, if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER) for (i = 0; i < nregs; ++i) if (call_used_or_fixed_reg_p (regno + i) - || targetm.hard_regno_call_part_clobbered (NULL, regno + i, + || targetm.hard_regno_call_part_clobbered (0, regno + i, mode)) return 0; if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER) for (i = 0; i < valuenregs; ++i) if (call_used_or_fixed_reg_p (valueno + i) - || targetm.hard_regno_call_part_clobbered (NULL, valueno + i, + || targetm.hard_regno_call_part_clobbered (0, valueno + i, mode)) return 0; } diff --git a/gcc/reload1.c b/gcc/reload1.c index c619c54..39dff6a 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -8193,8 +8193,7 @@ emit_reload_insns (class insn_chain *chain) : out_regno + k); reg_reloaded_insn[regno + k] = insn; SET_HARD_REG_BIT (reg_reloaded_valid, regno + k); - if (targetm.hard_regno_call_part_clobbered (NULL, - regno + k, + if (targetm.hard_regno_call_part_clobbered (0, regno + k, mode)) SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + k); @@ -8274,8 +8273,7 @@ emit_reload_insns (class insn_chain *chain) : in_regno + k); reg_reloaded_insn[regno + k] = insn; SET_HARD_REG_BIT (reg_reloaded_valid, regno + k); - if (targetm.hard_regno_call_part_clobbered (NULL, - regno + k, + if (targetm.hard_regno_call_part_clobbered (0, regno + k, mode)) SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + k); @@ -8391,7 +8389,7 @@ emit_reload_insns (class insn_chain *chain) CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + k); SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k); if (targetm.hard_regno_call_part_clobbered - (NULL, src_regno + k, mode)) + (0, src_regno + k, mode)) SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, src_regno + k); else diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c index 52db3cc..87d0791 100644 --- a/gcc/sched-deps.c +++ b/gcc/sched-deps.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "sched-int.h" #include "params.h" #include "cselib.h" +#include "function-abi.h" #ifdef INSN_SCHEDULING @@ -3723,6 +3724,7 @@ deps_analyze_insn (class deps_desc *deps, rtx_insn *insn) } else { + function_abi callee_abi = insn_callee_abi (insn); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) /* A call may read and modify global register variables. */ if (global_regs[i]) @@ -3734,8 +3736,8 @@ deps_analyze_insn (class deps_desc *deps, rtx_insn *insn) Since we only have a choice between 'might be clobbered' and 'definitely not clobbered', we must include all partly call-clobbered registers here. */ - else if (targetm.hard_regno_call_part_clobbered (insn, i, - reg_raw_mode[i]) + else if (targetm.hard_regno_call_part_clobbered + (callee_abi.id (), i, reg_raw_mode[i]) || TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) SET_REGNO_REG_SET (reg_pending_clobbers, i); /* We don't know what set of fixed registers might be used diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c index 077845e..bf370b5 100644 --- a/gcc/sel-sched.c +++ b/gcc/sel-sched.c @@ -1102,7 +1102,7 @@ init_regs_for_mode (machine_mode mode) if (i >= 0) continue; - if (targetm.hard_regno_call_part_clobbered (NULL, cur_reg, mode)) + if (targetm.hard_regno_call_part_clobbered (0, cur_reg, mode)) SET_HARD_REG_BIT (sel_hrd.regs_for_call_clobbered[mode], cur_reg); @@ -1247,7 +1247,7 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, /* Exclude registers that are partially call clobbered. */ if (def->crosses_call - && !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)) + && !targetm.hard_regno_call_part_clobbered (0, regno, mode)) reg_rename_p->available_for_renaming &= ~sel_hrd.regs_for_call_clobbered[mode]; diff --git a/gcc/target.def b/gcc/target.def index adf7a96..3bdbb8d 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5814,18 +5814,27 @@ The default version of this hook always returns @code{true}.", DEFHOOK (hard_regno_call_part_clobbered, - "This hook should return true if @var{regno} is partly call-saved and\n\ -partly call-clobbered, and if a value of mode @var{mode} would be partly\n\ -clobbered by call instruction @var{insn}. If @var{insn} is NULL then it\n\ -should return true if any call could partly clobber the register.\n\ -For example, if the low 32 bits of @var{regno} are preserved across a call\n\ -but higher bits are clobbered, this hook should return true for a 64-bit\n\ -mode but false for a 32-bit mode.\n\ + "ABIs usually specify that calls must preserve the full contents\n\ +of a particular register, or that calls can alter any part of a\n\ +particular register. This information is captured by the target macro\n\ +@code{CALL_REALLY_USED_REGISTERS}. However, some ABIs specify that calls\n\ +must preserve certain bits of a particular register but can alter others.\n\ +This hook should return true if this applies to at least one of the\n\ +registers in @samp{(reg:@var{mode} @var{regno})}, and if as a result the\n\ +call would alter part of the @var{mode} value. For example, if a call\n\ +preserves the low 32 bits of a 64-bit hard register @var{regno} but can\n\ +clobber the upper 32 bits, this hook should return true for a 64-bit mode\n\ +but false for a 32-bit mode.\n\ +\n\ +The value of @var{abi_id} comes from the @code{predefined_function_abi}\n\ +structure that describes the ABI of the call; see the definition of the\n\ +structure for more details. If (as is usual) the target uses the same ABI\n\ +for all functions in a translation unit, @var{abi_id} is always 0.\n\ \n\ The default implementation returns false, which is correct\n\ for targets that don't have partly call-clobbered registers.", - bool, (rtx_insn *insn, unsigned int regno, machine_mode mode), - hook_bool_insn_uint_mode_false) + bool, (unsigned int abi_id, unsigned int regno, machine_mode mode), + hook_bool_uint_uint_mode_false) DEFHOOK (return_call_with_max_clobbers, diff --git a/gcc/targhooks.c b/gcc/targhooks.c index d2e3ff6..6105137 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1928,7 +1928,7 @@ default_dwarf_frame_reg_mode (int regno) { machine_mode save_mode = reg_raw_mode[regno]; - if (targetm.hard_regno_call_part_clobbered (NULL, regno, save_mode)) + if (targetm.hard_regno_call_part_clobbered (0, regno, save_mode)) save_mode = choose_hard_reg_mode (regno, 1, true); return save_mode; } -- cgit v1.1 From 737d6a1a1745bdd4041e73800a842a1086967d5d Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:04 +0000 Subject: Pass an ABI to choose_hard_reg_mode choose_hard_reg_mode previously took a boolean saying whether the mode needed to be call-preserved. This patch replaces it with an optional ABI pointer instead, so that the function can use that to test whether a value is call-saved. default_dwarf_frame_reg_mode uses eh_edge_abi because that's the ABI that matters for unwinding. Targets need to override the hook if they want something different. 2019-09-30 Richard Sandiford gcc/ * rtl.h (predefined_function_abi): Declare. (choose_hard_reg_mode): Take a pointer to a predefined_function_abi instead of a boolean call_save flag. * config/gcn/gcn.c (gcn_hard_regno_caller_save_mode): Update call accordingly. * config/i386/i386.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. * config/ia64/ia64.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. * config/mips/mips.c (mips_hard_regno_caller_save_mode): Likewise. * config/msp430/msp430.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. * config/rs6000/rs6000.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. * config/sh/sh.c (sh_hard_regno_caller_save_mode): Likewise. * reginfo.c (init_reg_modes_target): Likewise. (choose_hard_reg_mode): Take a pointer to a predefined_function_abi instead of a boolean call_save flag. * targhooks.c: Include function-abi.h. (default_dwarf_frame_reg_mode): Update call to choose_hard_reg_mode, using eh_edge_abi to choose the mode. From-SVN: r276312 --- gcc/ChangeLog | 20 ++++++++++++++++++++ gcc/config/gcn/gcn.c | 2 +- gcc/config/i386/i386.h | 2 +- gcc/config/ia64/ia64.h | 2 +- gcc/config/mips/mips.c | 2 +- gcc/config/msp430/msp430.h | 2 +- gcc/config/rs6000/rs6000.h | 2 +- gcc/config/sh/sh.c | 2 +- gcc/reginfo.c | 22 +++++++++------------- gcc/rtl.h | 5 ++++- gcc/targhooks.c | 6 ++++-- 11 files changed, 44 insertions(+), 23 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 59bfeb2..86caf6e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,25 @@ 2019-09-30 Richard Sandiford + * rtl.h (predefined_function_abi): Declare. + (choose_hard_reg_mode): Take a pointer to a predefined_function_abi + instead of a boolean call_save flag. + * config/gcn/gcn.c (gcn_hard_regno_caller_save_mode): Update call + accordingly. + * config/i386/i386.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. + * config/ia64/ia64.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. + * config/mips/mips.c (mips_hard_regno_caller_save_mode): Likewise. + * config/msp430/msp430.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. + * config/rs6000/rs6000.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. + * config/sh/sh.c (sh_hard_regno_caller_save_mode): Likewise. + * reginfo.c (init_reg_modes_target): Likewise. + (choose_hard_reg_mode): Take a pointer to a predefined_function_abi + instead of a boolean call_save flag. + * targhooks.c: Include function-abi.h. + (default_dwarf_frame_reg_mode): Update call to choose_hard_reg_mode, + using eh_edge_abi to choose the mode. + +2019-09-30 Richard Sandiford + * target.def (hard_regno_call_part_clobbered): Take an ABI identifier instead of an rtx_insn. * doc/tm.texi: Regenerate. diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c index 50ae8e1..b5f09da 100644 --- a/gcc/config/gcn/gcn.c +++ b/gcc/config/gcn/gcn.c @@ -3017,7 +3017,7 @@ machine_mode gcn_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs, machine_mode regmode) { - machine_mode result = choose_hard_reg_mode (regno, nregs, false); + machine_mode result = choose_hard_reg_mode (regno, nregs, NULL); if (VECTOR_MODE_P (result) && !VECTOR_MODE_P (regmode)) result = (nregs == 1 ? SImode : DImode); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 885846e..9fe1f45 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1258,7 +1258,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ (CC_REGNO_P (REGNO) ? VOIDmode \ : (MODE) == VOIDmode && (NREGS) != 1 ? VOIDmode \ - : (MODE) == VOIDmode ? choose_hard_reg_mode ((REGNO), (NREGS), false) \ + : (MODE) == VOIDmode ? choose_hard_reg_mode ((REGNO), (NREGS), NULL) \ : (MODE) == HImode && !((GENERAL_REGNO_P (REGNO) \ && TARGET_PARTIAL_REG_STALL) \ || MASK_REGNO_P (REGNO)) ? SImode \ diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index d9d78fd..fc985b4 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -562,7 +562,7 @@ while (0) #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ ((FR_REGNO_P (REGNO) && (NREGS) == 1) ? RFmode \ - : choose_hard_reg_mode ((REGNO), (NREGS), false)) + : choose_hard_reg_mode ((REGNO), (NREGS), NULL)) /* Handling Leaf Functions */ diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 91dd94b..648d95f 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -22174,7 +22174,7 @@ mips_hard_regno_caller_save_mode (unsigned int regno, /* For performance, avoid saving/restoring upper parts of a register by returning MODE as save mode when the mode is known. */ if (mode == VOIDmode) - return choose_hard_reg_mode (regno, nregs, false); + return choose_hard_reg_mode (regno, nregs, NULL); else return mode; } diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index 36b715d..3449bd4 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -467,7 +467,7 @@ typedef struct when spilling hard registers when they may contain PSImode values. */ #define HARD_REGNO_CALLER_SAVE_MODE(REGNO,NREGS,MODE) \ ((TARGET_LARGE && ((NREGS) <= 2)) ? PSImode \ - : choose_hard_reg_mode ((REGNO), (NREGS), false)) + : choose_hard_reg_mode ((REGNO), (NREGS), NULL)) #define ACCUMULATE_OUTGOING_ARGS 1 diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 0156448..27373c5 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1038,7 +1038,7 @@ enum data_align { align_abi, align_opt, align_both }; ? DFmode \ : (MODE) == TDmode && FP_REGNO_P (REGNO) \ ? DImode \ - : choose_hard_reg_mode ((REGNO), (NREGS), false)) + : choose_hard_reg_mode ((REGNO), (NREGS), NULL)) #define VSX_VECTOR_MODE(MODE) \ ((MODE) == V4SFmode \ diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 34c4c8f..9917f2b 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -10637,7 +10637,7 @@ sh_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs, && ((regno - FIRST_FP_REG) & 1) == 0))) return mode; - return choose_hard_reg_mode (regno, nregs, false); + return choose_hard_reg_mode (regno, nregs, NULL); } /* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ diff --git a/gcc/reginfo.c b/gcc/reginfo.c index f084c0e..265157f 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -442,7 +442,7 @@ init_reg_modes_target (void) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { - reg_raw_mode[i] = choose_hard_reg_mode (i, 1, false); + reg_raw_mode[i] = choose_hard_reg_mode (i, 1, NULL); /* If we couldn't find a valid mode, just use the previous mode if it is suitable, otherwise fall back on word_mode. */ @@ -550,10 +550,11 @@ memory_move_secondary_cost (machine_mode mode, reg_class_t rclass, /* Return a machine mode that is legitimate for hard reg REGNO and large enough to save nregs. If we can't find one, return VOIDmode. - If CALL_SAVED is true, only consider modes that are call saved. */ + If ABI is nonnull, only consider modes that are preserved across + calls that use ABI. */ machine_mode choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, - unsigned int nregs, bool call_saved) + unsigned int nregs, const predefined_function_abi *abi) { unsigned int /* machine_mode */ m; machine_mode found_mode = VOIDmode, mode; @@ -567,32 +568,28 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, FOR_EACH_MODE_IN_CLASS (mode, MODE_INT) if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) - && (!call_saved - || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) + && (!abi || !abi->clobbers_reg_p (mode, regno)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; FOR_EACH_MODE_IN_CLASS (mode, MODE_FLOAT) if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) - && (!call_saved - || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) + && (!abi || !abi->clobbers_reg_p (mode, regno)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT) if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) - && (!call_saved - || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) + && (!abi || !abi->clobbers_reg_p (mode, regno)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT) if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) - && (!call_saved - || !targetm.hard_regno_call_part_clobbered (0, regno, mode)) + && (!abi || !abi->clobbers_reg_p (mode, regno)) && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode))) found_mode = mode; @@ -605,8 +602,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, mode = (machine_mode) m; if (hard_regno_nregs (regno, mode) == nregs && targetm.hard_regno_mode_ok (regno, mode) - && (!call_saved - || !targetm.hard_regno_call_part_clobbered (0, regno, mode))) + && (!abi || !abi->clobbers_reg_p (mode, regno))) return mode; } diff --git a/gcc/rtl.h b/gcc/rtl.h index d798562..554608c 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -36,6 +36,8 @@ along with GCC; see the file COPYING3. If not see #include "hard-reg-set.h" +class predefined_function_abi; + /* Value used by some passes to "recognize" noop moves as valid instructions. */ #define NOOP_MOVE_INSN_CODE INT_MAX @@ -3410,7 +3412,8 @@ extern bool val_signbit_known_clear_p (machine_mode, unsigned HOST_WIDE_INT); /* In reginfo.c */ -extern machine_mode choose_hard_reg_mode (unsigned int, unsigned int, bool); +extern machine_mode choose_hard_reg_mode (unsigned int, unsigned int, + const predefined_function_abi *); extern const HARD_REG_SET &simplifiable_subregs (const subreg_shape &); /* In emit-rtl.c */ diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 6105137..5445038 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see #include "real.h" #include "langhooks.h" #include "sbitmap.h" +#include "function-abi.h" bool default_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, @@ -1928,8 +1929,9 @@ default_dwarf_frame_reg_mode (int regno) { machine_mode save_mode = reg_raw_mode[regno]; - if (targetm.hard_regno_call_part_clobbered (0, regno, save_mode)) - save_mode = choose_hard_reg_mode (regno, 1, true); + if (targetm.hard_regno_call_part_clobbered (eh_edge_abi.id (), + regno, save_mode)) + save_mode = choose_hard_reg_mode (regno, 1, &eh_edge_abi); return save_mode; } -- cgit v1.1 From 7392e5d8888462610b5536c2894d2923b826faed Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:08 +0000 Subject: Remove global call sets: caller-save.c All caller-save.c uses of "|= fixed_reg_set" added in a previous patch were redundant, since the sets are later ANDed with ~fixed_reg_set. 2019-09-30 Richard Sandiford gcc/ * caller-save.c (setup_save_areas): Remove redundant |s of fixed_reg_set. (save_call_clobbered_regs): Likewise. Use the call ABI rather than call_used_or_fixed_regs to decide whether a REG_RETURNED value is useful. From-SVN: r276313 --- gcc/ChangeLog | 8 ++++++++ gcc/caller-save.c | 17 ++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 86caf6e..d912a87 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2019-09-30 Richard Sandiford + * caller-save.c (setup_save_areas): Remove redundant |s of + fixed_reg_set. + (save_call_clobbered_regs): Likewise. Use the call ABI rather + than call_used_or_fixed_regs to decide whether a REG_RETURNED + value is useful. + +2019-09-30 Richard Sandiford + * rtl.h (predefined_function_abi): Declare. (choose_hard_reg_mode): Take a pointer to a predefined_function_abi instead of a boolean call_save flag. diff --git a/gcc/caller-save.c b/gcc/caller-save.c index 10b6737..6945387 100644 --- a/gcc/caller-save.c +++ b/gcc/caller-save.c @@ -428,8 +428,6 @@ setup_save_areas (void) REG_SET_TO_HARD_REG_SET (hard_regs_to_save, &chain->live_throughout); used_regs = insn_callee_abi (insn).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not be needed. */ - used_regs |= fixed_reg_set; /* Record all registers set in this call insn. These don't need to be saved. N.B. the call insn might set a subreg @@ -513,9 +511,6 @@ setup_save_areas (void) REG_SET_TO_HARD_REG_SET (hard_regs_to_save, &chain->live_throughout); used_regs = insn_callee_abi (insn).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not - be needed. */ - used_regs |= fixed_reg_set; /* Record all registers set in this call insn. These don't need to be saved. N.B. the call insn might set a subreg @@ -793,7 +788,6 @@ save_call_clobbered_regs (void) { unsigned regno; HARD_REG_SET hard_regs_to_save; - HARD_REG_SET call_def_reg_set; reg_set_iterator rsi; rtx cheap; @@ -840,15 +834,12 @@ save_call_clobbered_regs (void) note_stores (insn, mark_set_regs, &this_insn_sets); /* Compute which hard regs must be saved before this call. */ + function_abi callee_abi = insn_callee_abi (insn); hard_regs_to_save &= ~(fixed_reg_set | this_insn_sets | hard_regs_saved); hard_regs_to_save &= savable_regs; - call_def_reg_set = insn_callee_abi (insn).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not - be needed. */ - call_def_reg_set |= fixed_reg_set; - hard_regs_to_save &= call_def_reg_set; + hard_regs_to_save &= callee_abi.full_reg_clobbers (); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) @@ -863,8 +854,8 @@ save_call_clobbered_regs (void) if (cheap && HARD_REGISTER_P (cheap) - && TEST_HARD_REG_BIT (call_used_or_fixed_regs, - REGNO (cheap))) + && callee_abi.clobbers_reg_p (GET_MODE (cheap), + REGNO (cheap))) { rtx dest, newpat; rtx pat = PATTERN (insn); -- cgit v1.1 From 016996861c7333f42772c84a5a2a4e52e0bd07c5 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:12 +0000 Subject: Remove global call sets: cfgcleanup.c old_insns_match_p just tests whether two instructions are similar enough to merge. With insn_callee_abi it makes more sense to compare the ABIs directly. 2019-09-30 Richard Sandiford gcc/ * cfgcleanup.c (old_insns_match_p): Compare the ABIs of calls instead of the call-clobbered sets. From-SVN: r276314 --- gcc/ChangeLog | 5 +++++ gcc/cfgcleanup.c | 8 +------- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d912a87..a3e4ff2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-09-30 Richard Sandiford + * cfgcleanup.c (old_insns_match_p): Compare the ABIs of calls + instead of the call-clobbered sets. + +2019-09-30 Richard Sandiford + * caller-save.c (setup_save_areas): Remove redundant |s of fixed_reg_set. (save_call_clobbered_regs): Likewise. Use the call ABI rather diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 329fa0c..ced7e0a 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -1227,13 +1227,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx_insn *i1, rtx_insn *i2) } } - HARD_REG_SET i1_used = insn_callee_abi (i1).full_reg_clobbers (); - HARD_REG_SET i2_used = insn_callee_abi (i2).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not be needed. */ - i1_used |= fixed_reg_set; - i2_used |= fixed_reg_set; - - if (i1_used != i2_used) + if (insn_callee_abi (i1) != insn_callee_abi (i2)) return dir_none; } -- cgit v1.1 From 43b484fbf281553353c6ef55ff0871b222579004 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:15 +0000 Subject: Remove global call sets: cfgloopanal.c ...or rather, make the use of the default ABI explicit. That seems OK if not ideal for this heuristic. In practical terms, the code patched here is counting GENERAL_REGS, which are treated in the same way by all concurrent ABI variants on AArch64. It might give bad results if used for interrupt handlers though. 2019-09-30 Richard Sandiford gcc/ * cfgloopanal.c: Include regs.h and function-abi.h. (init_set_costs): Use default_function_abi to test whether a general register is call-clobbered. From-SVN: r276315 --- gcc/ChangeLog | 6 ++++++ gcc/cfgloopanal.c | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a3e4ff2..6b08d70 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * cfgloopanal.c: Include regs.h and function-abi.h. + (init_set_costs): Use default_function_abi to test whether + a general register is call-clobbered. + +2019-09-30 Richard Sandiford + * cfgcleanup.c (old_insns_match_p): Compare the ABIs of calls instead of the call-clobbered sets. diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c index 0ebecc3..95ec929 100644 --- a/gcc/cfgloopanal.c +++ b/gcc/cfgloopanal.c @@ -32,6 +32,8 @@ along with GCC; see the file COPYING3. If not see #include "graphds.h" #include "params.h" #include "sreal.h" +#include "regs.h" +#include "function-abi.h" struct target_cfgloop default_target_cfgloop; #if SWITCHABLE_TARGET @@ -353,7 +355,10 @@ init_set_costs (void) && !fixed_regs[i]) { target_avail_regs++; - if (call_used_or_fixed_reg_p (i)) + /* ??? This is only a rough heuristic. It doesn't cope well + with alternative ABIs, but that's an optimization rather than + correctness issue. */ + if (default_function_abi.clobbers_full_reg_p (i)) target_clobbered_regs++; } -- cgit v1.1 From 212b7076eec027d212e1badb9cb5a9db4b62ab50 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:19 +0000 Subject: Remove global call sets: combine.c There shouldn't be many cases in which a useful hard register is live across a call before RA, so we might as well keep things simple and invalidate partially-clobbered registers here, in case the values they hold leak into the call-clobbered part. In principle this is a bug fix for TARGET_HARD_REGNO_CALL_PART_CLOBBERED targets, but in practice it probably doesn't make a difference. 2019-09-30 Richard Sandiford gcc/ * combine.c: Include function-abi.h. (record_dead_and_set_regs): Use insn_callee_abi to get the ABI of the target of call insns. Invalidate partially-clobbered registers as well as fully-clobbered ones. From-SVN: r276316 --- gcc/ChangeLog | 7 +++++++ gcc/combine.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6b08d70..ed08c19 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-30 Richard Sandiford + * combine.c: Include function-abi.h. + (record_dead_and_set_regs): Use insn_callee_abi to get the ABI + of the target of call insns. Invalidate partially-clobbered + registers as well as fully-clobbered ones. + +2019-09-30 Richard Sandiford + * cfgloopanal.c: Include regs.h and function-abi.h. (init_set_costs): Use default_function_abi to test whether a general register is call-clobbered. diff --git a/gcc/combine.c b/gcc/combine.c index 981e7b0..d200c5a 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -105,6 +105,7 @@ along with GCC; see the file COPYING3. If not see #include "valtrack.h" #include "rtl-iter.h" #include "print-rtl.h" +#include "function-abi.h" /* Number of attempts to combine instructions in this function. */ @@ -13464,11 +13465,21 @@ record_dead_and_set_regs (rtx_insn *insn) if (CALL_P (insn)) { + HARD_REG_SET callee_clobbers + = insn_callee_abi (insn).full_and_partial_reg_clobbers (); hard_reg_set_iterator hrsi; - EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, i, hrsi) + EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, i, hrsi) { reg_stat_type *rsp; + /* ??? We could try to preserve some information from the last + set of register I if the call doesn't actually clobber + (reg:last_set_mode I), which might be true for ABIs with + partial clobbers. However, it would be difficult to + update last_set_nonzero_bits and last_sign_bit_copies + to account for the part of I that actually was clobbered. + It wouldn't help much anyway, since we rarely see this + situation before RA. */ rsp = ®_stat[i]; rsp->last_set_invalid = 1; rsp->last_set = insn; -- cgit v1.1 From 311b62ce0310876fbffeeaab0b50707242b3e663 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:23 +0000 Subject: Remove global call sets: cse.c Like with the combine.c patch, this one keeps things simple by invalidating values in partially-clobbered registers, rather than trying to tell whether the value in a partially-clobbered register is actually clobbered or not. Again, this is in principle a bug fix, but probably never matters in practice. 2019-09-30 Richard Sandiford gcc/ * cse.c: Include regs.h and function-abi.h. (invalidate_for_call): Take the call insn as an argument. Use insn_callee_abi to get the ABI of the call and invalidate partially clobbered registers as well as fully clobbered ones. (cse_insn): Update call accordingly. From-SVN: r276317 --- gcc/ChangeLog | 8 ++++++++ gcc/cse.c | 43 ++++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 19 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ed08c19..181fd80 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2019-09-30 Richard Sandiford + * cse.c: Include regs.h and function-abi.h. + (invalidate_for_call): Take the call insn as an argument. + Use insn_callee_abi to get the ABI of the call and invalidate + partially clobbered registers as well as fully clobbered ones. + (cse_insn): Update call accordingly. + +2019-09-30 Richard Sandiford + * combine.c: Include function-abi.h. (record_dead_and_set_regs): Use insn_callee_abi to get the ABI of the target of call insns. Invalidate partially-clobbered diff --git a/gcc/cse.c b/gcc/cse.c index 32b6790..be3277b 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -42,6 +42,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "dbgcnt.h" #include "rtl-iter.h" +#include "regs.h" +#include "function-abi.h" /* The basic idea of common subexpression elimination is to go through the code, keeping a record of expressions that would @@ -566,7 +568,6 @@ static void remove_invalid_subreg_refs (unsigned int, poly_uint64, machine_mode); static void rehash_using_reg (rtx); static void invalidate_memory (void); -static void invalidate_for_call (void); static rtx use_related_value (rtx, struct table_elt *); static inline unsigned canon_hash (rtx, machine_mode); @@ -2091,23 +2092,31 @@ rehash_using_reg (rtx x) } /* Remove from the hash table any expression that is a call-clobbered - register. Also update their TICK values. */ + register in INSN. Also update their TICK values. */ static void -invalidate_for_call (void) +invalidate_for_call (rtx_insn *insn) { - unsigned int regno, endregno; - unsigned int i; + unsigned int regno; unsigned hash; struct table_elt *p, *next; int in_table = 0; hard_reg_set_iterator hrsi; - /* Go through all the hard registers. For each that is clobbered in - a CALL_INSN, remove the register from quantity chains and update + /* Go through all the hard registers. For each that might be clobbered + in call insn INSN, remove the register from quantity chains and update reg_tick if defined. Also see if any of these registers is currently - in the table. */ - EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi) + in the table. + + ??? We could be more precise for partially-clobbered registers, + and only invalidate values that actually occupy the clobbered part + of the registers. It doesn't seem worth the effort though, since + we shouldn't see this situation much before RA. Whatever choice + we make here has to be consistent with the table walk below, + so any change to this test will require a change there too. */ + HARD_REG_SET callee_clobbers + = insn_callee_abi (insn).full_and_partial_reg_clobbers (); + EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi) { delete_reg_equiv (regno); if (REG_TICK (regno) >= 0) @@ -2132,15 +2141,11 @@ invalidate_for_call (void) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER) continue; - regno = REGNO (p->exp); - endregno = END_REGNO (p->exp); - - for (i = regno; i < endregno; i++) - if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) - { - remove_from_table (p, hash); - break; - } + /* This must use the same test as above rather than the + more accurate clobbers_reg_p. */ + if (overlaps_hard_reg_set_p (callee_clobbers, GET_MODE (p->exp), + REGNO (p->exp))) + remove_from_table (p, hash); } } @@ -5823,7 +5828,7 @@ cse_insn (rtx_insn *insn) if (GET_CODE (XEXP (tem, 0)) == USE && MEM_P (XEXP (XEXP (tem, 0), 0))) invalidate (XEXP (XEXP (tem, 0), 0), VOIDmode); - invalidate_for_call (); + invalidate_for_call (insn); } /* Now invalidate everything set by this instruction. -- cgit v1.1 From 3bd2918594dae34ae84f802747471445a976af09 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:26 +0000 Subject: Remove global call sets: cselib.c cselib_invalidate_regno is a no-op if REG_VALUES (i) is null, so we can check that first. Then, if we know what mode the register currently has, we can check whether it's clobbered in that mode. Using GET_MODE (values->elt->val_rtx) to get the mode of the last set is taken from cselib_reg_set_mode. 2019-09-30 Richard Sandiford gcc/ * cselib.c (cselib_process_insn): If we know what mode a register was set in, check whether it is clobbered in that mode by a call. Only fall back to reg_raw_mode if that fails. From-SVN: r276318 --- gcc/ChangeLog | 6 ++++++ gcc/cselib.c | 24 ++++++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 181fd80..5440a33 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * cselib.c (cselib_process_insn): If we know what mode a + register was set in, check whether it is clobbered in that + mode by a call. Only fall back to reg_raw_mode if that fails. + +2019-09-30 Richard Sandiford + * cse.c: Include regs.h and function-abi.h. (invalidate_for_call): Take the call insn as an argument. Use insn_callee_abi to get the ABI of the call and invalidate diff --git a/gcc/cselib.c b/gcc/cselib.c index 5de14a0..36f649d 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -2768,12 +2768,24 @@ cselib_process_insn (rtx_insn *insn) { function_abi callee_abi = insn_callee_abi (insn); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (call_used_or_fixed_reg_p (i) - || (REG_VALUES (i) && REG_VALUES (i)->elt - && (targetm.hard_regno_call_part_clobbered - (callee_abi.id (), i, - GET_MODE (REG_VALUES (i)->elt->val_rtx))))) - cselib_invalidate_regno (i, reg_raw_mode[i]); + if (elt_list *values = REG_VALUES (i)) + { + /* If we know what mode the value was set in, check whether + it is still available after the call in that mode. If we + don't know the mode, we have to check for the worst-case + scenario instead. */ + if (values->elt) + { + machine_mode mode = GET_MODE (values->elt->val_rtx); + if (callee_abi.clobbers_reg_p (mode, i)) + cselib_invalidate_regno (i, mode); + } + else + { + if (callee_abi.clobbers_at_least_part_of_reg_p (i)) + cselib_invalidate_regno (i, reg_raw_mode[i]); + } + } /* Since it is not clear how cselib is going to be used, be conservative here and treat looping pure or const functions -- cgit v1.1 From c92503717bd0c3a0706f8c9626c47d49d901063b Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:30 +0000 Subject: Remove global call sets: DF (EH edges) The DF dense_invalidated_by_call and sparse_invalidated_by_call sets are actually only used on EH edges, and so are more the set of registers that are invalidated by a taken EH edge. Under the new order, that means that they describe eh_edge_abi. 2019-09-30 Richard Sandiford gcc/ * df-problems.c: Include regs.h and function-abi.h. (df_rd_problem_data): Rename sparse_invalidated_by_call to sparse_invalidated_by_eh and dense_invalidated_by_call to dense_invalidated_by_eh. (df_print_bb_index): Update accordingly. (df_rd_alloc, df_rd_start_dump, df_rd_confluence_n): Likewise. (df_lr_confluence_n): Use eh_edge_abi to get the set of registers that are clobbered by an EH edge. Clobber partially-clobbered registers as well as fully-clobbered ones. (df_md_confluence_n): Likewise. (df_rd_local_compute): Likewise. Update for changes to df_rd_problem_data. * df-scan.c (df_scan_start_dump): Use eh_edge_abi to get the set of registers that are clobbered by an EH edge. Includde partially- clobbered registers as well as fully-clobbered ones. From-SVN: r276319 --- gcc/ChangeLog | 18 ++++++++++++++++++ gcc/df-problems.c | 52 +++++++++++++++++++++++++++++++--------------------- gcc/df-scan.c | 5 +++-- 3 files changed, 52 insertions(+), 23 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5440a33..13caa91 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,23 @@ 2019-09-30 Richard Sandiford + * df-problems.c: Include regs.h and function-abi.h. + (df_rd_problem_data): Rename sparse_invalidated_by_call to + sparse_invalidated_by_eh and dense_invalidated_by_call to + dense_invalidated_by_eh. + (df_print_bb_index): Update accordingly. + (df_rd_alloc, df_rd_start_dump, df_rd_confluence_n): Likewise. + (df_lr_confluence_n): Use eh_edge_abi to get the set of registers + that are clobbered by an EH edge. Clobber partially-clobbered + registers as well as fully-clobbered ones. + (df_md_confluence_n): Likewise. + (df_rd_local_compute): Likewise. Update for changes to + df_rd_problem_data. + * df-scan.c (df_scan_start_dump): Use eh_edge_abi to get the set + of registers that are clobbered by an EH edge. Includde partially- + clobbered registers as well as fully-clobbered ones. + +2019-09-30 Richard Sandiford + * cselib.c (cselib_process_insn): If we know what mode a register was set in, check whether it is clobbered in that mode by a call. Only fall back to reg_raw_mode if that fails. diff --git a/gcc/df-problems.c b/gcc/df-problems.c index 89a9293..f1fd0af 100644 --- a/gcc/df-problems.c +++ b/gcc/df-problems.c @@ -36,6 +36,8 @@ along with GCC; see the file COPYING3. If not see #include "valtrack.h" #include "dumpfile.h" #include "rtl-iter.h" +#include "regs.h" +#include "function-abi.h" /* Note that turning REG_DEAD_DEBUGGING on will cause gcc.c-torture/unsorted/dump-noaddr.c to fail because it prints @@ -139,18 +141,17 @@ df_print_bb_index (basic_block bb, FILE *file) these along with the bitmap_clear_range call to remove ranges of bits without actually generating a knockout vector. - The kill and sparse_kill and the dense_invalidated_by_call and - sparse_invalidated_by_call both play this game. */ + The kill and sparse_kill and the dense_invalidated_by_eh and + sparse_invalidated_by_eh both play this game. */ /* Private data used to compute the solution for this problem. These data structures are not accessible outside of this module. */ class df_rd_problem_data { public: - /* The set of defs to regs invalidated by call. */ - bitmap_head sparse_invalidated_by_call; - /* The set of defs to regs invalidate by call for rd. */ - bitmap_head dense_invalidated_by_call; + /* The set of defs to regs invalidated by EH edges. */ + bitmap_head sparse_invalidated_by_eh; + bitmap_head dense_invalidated_by_eh; /* An obstack for the bitmaps we need for this problem. */ bitmap_obstack rd_bitmaps; }; @@ -187,8 +188,8 @@ df_rd_alloc (bitmap all_blocks) if (df_rd->problem_data) { problem_data = (class df_rd_problem_data *) df_rd->problem_data; - bitmap_clear (&problem_data->sparse_invalidated_by_call); - bitmap_clear (&problem_data->dense_invalidated_by_call); + bitmap_clear (&problem_data->sparse_invalidated_by_eh); + bitmap_clear (&problem_data->dense_invalidated_by_eh); } else { @@ -196,9 +197,9 @@ df_rd_alloc (bitmap all_blocks) df_rd->problem_data = problem_data; bitmap_obstack_initialize (&problem_data->rd_bitmaps); - bitmap_initialize (&problem_data->sparse_invalidated_by_call, + bitmap_initialize (&problem_data->sparse_invalidated_by_eh, &problem_data->rd_bitmaps); - bitmap_initialize (&problem_data->dense_invalidated_by_call, + bitmap_initialize (&problem_data->dense_invalidated_by_eh, &problem_data->rd_bitmaps); } @@ -391,8 +392,8 @@ df_rd_local_compute (bitmap all_blocks) bitmap_iterator bi; class df_rd_problem_data *problem_data = (class df_rd_problem_data *) df_rd->problem_data; - bitmap sparse_invalidated = &problem_data->sparse_invalidated_by_call; - bitmap dense_invalidated = &problem_data->dense_invalidated_by_call; + bitmap sparse_invalidated = &problem_data->sparse_invalidated_by_eh; + bitmap dense_invalidated = &problem_data->dense_invalidated_by_eh; bitmap_initialize (&seen_in_block, &df_bitmap_obstack); bitmap_initialize (&seen_in_insn, &df_bitmap_obstack); @@ -404,10 +405,13 @@ df_rd_local_compute (bitmap all_blocks) df_rd_bb_local_compute (bb_index); } - /* Set up the knockout bit vectors to be applied across EH_EDGES. */ + /* Set up the knockout bit vectors to be applied across EH_EDGES. + Conservatively treat partially-clobbered registers as surviving + across the EH edge, i.e. assume that definitions before the edge + is taken *might* reach uses after it has been taken. */ if (!(df->changeable_flags & DF_NO_HARD_REGS)) for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) - if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)) + if (eh_edge_abi.clobbers_full_reg_p (regno)) { if (DF_DEFS_COUNT (regno) > DF_SPARSE_THRESHOLD) bitmap_set_bit (sparse_invalidated, regno); @@ -455,8 +459,8 @@ df_rd_confluence_n (edge e) { class df_rd_problem_data *problem_data = (class df_rd_problem_data *) df_rd->problem_data; - bitmap sparse_invalidated = &problem_data->sparse_invalidated_by_call; - bitmap dense_invalidated = &problem_data->dense_invalidated_by_call; + bitmap sparse_invalidated = &problem_data->sparse_invalidated_by_eh; + bitmap dense_invalidated = &problem_data->dense_invalidated_by_eh; bitmap_iterator bi; unsigned int regno; @@ -579,9 +583,9 @@ df_rd_start_dump (FILE *file) fprintf (file, ";; Reaching defs:\n"); fprintf (file, ";; sparse invalidated \t"); - dump_bitmap (file, &problem_data->sparse_invalidated_by_call); + dump_bitmap (file, &problem_data->sparse_invalidated_by_eh); fprintf (file, ";; dense invalidated \t"); - dump_bitmap (file, &problem_data->dense_invalidated_by_call); + dump_bitmap (file, &problem_data->dense_invalidated_by_eh); fprintf (file, ";; reg->defs[] map:\t"); for (regno = 0; regno < m; regno++) @@ -976,12 +980,15 @@ df_lr_confluence_n (edge e) bitmap op2 = &df_lr_get_bb_info (e->dest->index)->in; bool changed = false; - /* Call-clobbered registers die across exception and call edges. */ + /* Call-clobbered registers die across exception and call edges. + Conservatively treat partially-clobbered registers as surviving + across the edges; they might or might not, depending on what + mode they have. */ /* ??? Abnormal call edges ignored for the moment, as this gets confused by sibling call edges, which crashes reg-stack. */ if (e->flags & EDGE_EH) { - bitmap_view eh_kills (regs_invalidated_by_call); + bitmap_view eh_kills (eh_edge_abi.full_reg_clobbers ()); changed = bitmap_ior_and_compl_into (op1, op2, eh_kills); } else @@ -4636,7 +4643,10 @@ df_md_confluence_n (edge e) if (e->flags & EDGE_EH) { - bitmap_view eh_kills (regs_invalidated_by_call); + /* Conservatively treat partially-clobbered registers as surviving + across the edge; they might or might not, depending on what mode + they have. */ + bitmap_view eh_kills (eh_edge_abi.full_reg_clobbers ()); return bitmap_ior_and_compl_into (op1, op2, eh_kills); } else diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 7ca1050..7dda4ca 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -312,8 +312,9 @@ df_scan_start_dump (FILE *file ATTRIBUTE_UNUSED) basic_block bb; rtx_insn *insn; - fprintf (file, ";; invalidated by call \t"); - df_print_regset (file, bitmap_view (regs_invalidated_by_call)); + fprintf (file, ";; fully invalidated by EH \t"); + df_print_regset + (file, bitmap_view (eh_edge_abi.full_reg_clobbers ())); fprintf (file, ";; hardware regs used \t"); df_print_regset (file, &df->hardware_regs_used); fprintf (file, ";; regular block artificial uses \t"); -- cgit v1.1 From 559c1ae100489da76a0283750361ace146fdeb77 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:34 +0000 Subject: Remove global call sets: DF (entry/exit defs) The code patched here is seeing whether the current function needs to save at least part of a register before using it. 2019-09-30 Richard Sandiford gcc/ * df-scan.c (df_get_entry_block_def_set): Use crtl->abi to test whether the current function needs to save at least part of a register before using it. (df_get_exit_block_use_set): Likewise for epilogue restores. From-SVN: r276320 --- gcc/ChangeLog | 7 +++++++ gcc/df-scan.c | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 13caa91..3617216 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-30 Richard Sandiford + * df-scan.c (df_get_entry_block_def_set): Use crtl->abi to test + whether the current function needs to save at least part of a + register before using it. + (df_get_exit_block_use_set): Likewise for epilogue restores. + +2019-09-30 Richard Sandiford + * df-problems.c: Include regs.h and function-abi.h. (df_rd_problem_data): Rename sparse_invalidated_by_call to sparse_invalidated_by_eh and dense_invalidated_by_call to diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 7dda4ca..36012b7 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -3499,7 +3499,9 @@ df_get_entry_block_def_set (bitmap entry_block_defs) /* Defs for the callee saved registers are inserted so that the pushes have some defining location. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if ((call_used_or_fixed_reg_p (i) == 0) && (df_regs_ever_live_p (i))) + if (!crtl->abi->clobbers_full_reg_p (i) + && !fixed_regs[i] + && df_regs_ever_live_p (i)) bitmap_set_bit (entry_block_defs, i); } @@ -3672,8 +3674,9 @@ df_get_exit_block_use_set (bitmap exit_block_uses) { /* Mark all call-saved registers that we actually used. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (df_regs_ever_live_p (i) && !LOCAL_REGNO (i) - && !TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) + if (df_regs_ever_live_p (i) + && !LOCAL_REGNO (i) + && !crtl->abi->clobbers_full_reg_p (i)) bitmap_set_bit (exit_block_uses, i); } -- cgit v1.1 From 1849569621d13c9c070c555f9463ad289afb8416 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:37 +0000 Subject: Remove global call sets: early-remat.c This pass previously excluded rematerialisation candidates if they clobbered a call-preserved register, on the basis that it then wouldn't be safe to add new instances of the candidate instruction after a call. This patch instead makes the decision on a call-by-call basis. The second emit_remat_insns_for_block hunk probably isn't needed, but it seems safer and more consistent to have it, so that every call to emit_remat_insns is preceded by a check for invalid clobbers. 2019-09-30 Richard Sandiford gcc/ * early-remat.c: Include regs.h and function-abi.h. (early_remat::maybe_add_candidate): Don't check for call-clobbered registers here. (early_remat::restrict_remat_for_unavail_regs): New function. (early_remat::restrict_remat_for_call): Likewise. (early_remat::process_block): Before calling emit_remat_insns for a previous call in the block, invalidate any candidates that would clobber call-preserved registers. (early_remat::emit_remat_insns_for_block): Likewise for the final call in a block. Do the same thing for live-in registers when calling emit_remat_insns at the head of a block. From-SVN: r276321 --- gcc/ChangeLog | 14 +++++++++++ gcc/early-remat.c | 74 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 22 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3617216..138f3f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,19 @@ 2019-09-30 Richard Sandiford + * early-remat.c: Include regs.h and function-abi.h. + (early_remat::maybe_add_candidate): Don't check for call-clobbered + registers here. + (early_remat::restrict_remat_for_unavail_regs): New function. + (early_remat::restrict_remat_for_call): Likewise. + (early_remat::process_block): Before calling emit_remat_insns + for a previous call in the block, invalidate any candidates + that would clobber call-preserved registers. + (early_remat::emit_remat_insns_for_block): Likewise for the + final call in a block. Do the same thing for live-in registers + when calling emit_remat_insns at the head of a block. + +2019-09-30 Richard Sandiford + * df-scan.c (df_get_entry_block_def_set): Use crtl->abi to test whether the current function needs to save at least part of a register before using it. diff --git a/gcc/early-remat.c b/gcc/early-remat.c index 0396f16..bb2d433 100644 --- a/gcc/early-remat.c +++ b/gcc/early-remat.c @@ -36,6 +36,8 @@ along with GCC; see the file COPYING3. If not see #include "rtlhash.h" #include "print-rtl.h" #include "rtl-iter.h" +#include "regs.h" +#include "function-abi.h" /* This pass runs before register allocation and implements an aggressive form of rematerialization. It looks for pseudo registers R of mode M @@ -435,6 +437,8 @@ private: void compute_clobbers (unsigned int); void assign_value_number (unsigned int); void decide_candidate_validity (void); + void restrict_remat_for_unavail_regs (bitmap, const_bitmap); + void restrict_remat_for_call (bitmap, rtx_insn *); bool stable_use_p (unsigned int); void emit_copy_before (unsigned int, rtx, rtx); void stabilize_pattern (unsigned int); @@ -889,8 +893,8 @@ early_remat::maybe_add_candidate (rtx_insn *insn, unsigned int regno) else { /* The instruction can set additional registers, provided that - they're call-clobbered hard registers. This is useful for - instructions that alter the condition codes. */ + they're hard registers. This is useful for instructions + that alter the condition codes. */ if (!HARD_REGISTER_NUM_P (def_regno)) { if (dump_file) @@ -898,20 +902,6 @@ early_remat::maybe_add_candidate (rtx_insn *insn, unsigned int regno) " pseudo reg %d\n", FAILURE_ARGS, def_regno); return false; } - if (global_regs[def_regno]) - { - if (dump_file) - fprintf (dump_file, FAILURE_FORMAT "insn also sets" - " global reg %d\n", FAILURE_ARGS, def_regno); - return false; - } - if (!TEST_HARD_REG_BIT (regs_invalidated_by_call, def_regno)) - { - if (dump_file) - fprintf (dump_file, FAILURE_FORMAT "insn also sets" - " call-preserved reg %d\n", FAILURE_ARGS, def_regno); - return false; - } } } @@ -1532,6 +1522,39 @@ early_remat::decide_candidate_validity (void) } } +/* Remove any candidates in CANDIDATES that would clobber a register in + UNAVAIL_REGS. */ + +void +early_remat::restrict_remat_for_unavail_regs (bitmap candidates, + const_bitmap unavail_regs) +{ + bitmap_clear (&m_tmp_bitmap); + unsigned int cand_index; + bitmap_iterator bi; + EXECUTE_IF_SET_IN_BITMAP (candidates, 0, cand_index, bi) + { + remat_candidate *cand = &m_candidates[cand_index]; + if (cand->clobbers + && bitmap_intersect_p (cand->clobbers, unavail_regs)) + bitmap_set_bit (&m_tmp_bitmap, cand_index); + } + bitmap_and_compl_into (candidates, &m_tmp_bitmap); +} + +/* Remove any candidates in CANDIDATES that would clobber a register + that is potentially live across CALL. */ + +void +early_remat::restrict_remat_for_call (bitmap candidates, rtx_insn *call) +{ + /* We don't know whether partially-clobbered registers are live + across the call or not, so assume that they are. */ + bitmap_view call_preserved_regs + (~insn_callee_abi (call).full_reg_clobbers ()); + restrict_remat_for_unavail_regs (candidates, call_preserved_regs); +} + /* Assuming that every path reaching a point P contains a copy of a use U of REGNO, return true if another copy of U at P would have access to the same value of REGNO. */ @@ -1984,10 +2007,13 @@ early_remat::process_block (basic_block bb) init_temp_bitmap (&m_required); } else - /* The fully-local case: candidates that need to be - rematerialized after a previous call in the block. */ - emit_remat_insns (m_required, NULL, info->rd_after_call, - last_call); + { + /* The fully-local case: candidates that need to be + rematerialized after a previous call in the block. */ + restrict_remat_for_call (m_required, last_call); + emit_remat_insns (m_required, NULL, info->rd_after_call, + last_call); + } last_call = insn; bitmap_clear (m_available); gcc_checking_assert (empty_p (m_required)); @@ -2480,8 +2506,11 @@ early_remat::emit_remat_insns_for_block (basic_block bb) remat_block_info *info = &m_block_info[bb->index]; if (info->last_call && !empty_p (info->required_after_call)) - emit_remat_insns (info->required_after_call, NULL, - info->rd_after_call, info->last_call); + { + restrict_remat_for_call (info->required_after_call, info->last_call); + emit_remat_insns (info->required_after_call, NULL, + info->rd_after_call, info->last_call); + } if (!empty_p (info->required_in)) { @@ -2489,6 +2518,7 @@ early_remat::emit_remat_insns_for_block (basic_block bb) while (insn != BB_END (bb) && !INSN_P (NEXT_INSN (insn))) insn = NEXT_INSN (insn); + restrict_remat_for_unavail_regs (info->required_in, DF_LR_IN (bb)); emit_remat_insns (info->required_in, info->available_in, info->rd_in, insn); } -- cgit v1.1 From c1b582720a39c3cb944aaff0298f721cdd034e3f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:41 +0000 Subject: Remove global call sets: function.c Whatever the rights and wrongs of the way aggregate_value_p handles call-preserved registers, it's a de facto part of the ABI, so we shouldn't change it. The patch simply extends the current approach to whatever call-preserved set the function happens to be using. 2019-09-30 Richard Sandiford gcc/ * function.c (aggregate_value_p): Work out which ABI the function is using before testing which registers are at least partly preserved by a call. From-SVN: r276322 --- gcc/ChangeLog | 6 ++++++ gcc/function.c | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 138f3f0..9d8b083 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * function.c (aggregate_value_p): Work out which ABI the + function is using before testing which registers are at least + partly preserved by a call. + +2019-09-30 Richard Sandiford + * early-remat.c: Include regs.h and function-abi.h. (early_remat::maybe_add_candidate): Don't check for call-clobbered registers here. diff --git a/gcc/function.c b/gcc/function.c index c3aa6a5..a1c76a4 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -2120,10 +2120,17 @@ aggregate_value_p (const_tree exp, const_tree fntype) if (!REG_P (reg)) return 0; + /* Use the default ABI if the type of the function isn't known. + The scheme for handling interoperability between different ABIs + requires us to be able to tell when we're calling a function with + a nondefault ABI. */ + const predefined_function_abi &abi = (fntype + ? fntype_abi (fntype) + : default_function_abi); regno = REGNO (reg); nregs = hard_regno_nregs (regno, TYPE_MODE (type)); for (i = 0; i < nregs; i++) - if (! call_used_or_fixed_reg_p (regno + i)) + if (!fixed_regs[regno + i] && !abi.clobbers_full_reg_p (regno + i)) return 1; return 0; -- cgit v1.1 From a4dfaad2e5594d871fe00a1116005e28f95d644e Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:44 +0000 Subject: Remove global call sets: gcse.c This is another case in which we can conservatively treat partial kills as full kills. Again this is in principle a bug fix for TARGET_HARD_REGNO_CALL_PART_CLOBBERED targets, but in practice it probably doesn't make a difference. 2019-09-30 Richard Sandiford gcc/ * gcse.c: Include function-abi.h. (compute_hash_table_work): Use insn_callee_abi to get the ABI of the call insn target. Invalidate partially call-clobbered registers as well as fully call-clobbered ones. From-SVN: r276323 --- gcc/ChangeLog | 7 +++++++ gcc/gcse.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9d8b083..1b1c31c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-30 Richard Sandiford + * gcse.c: Include function-abi.h. + (compute_hash_table_work): Use insn_callee_abi to get the ABI of + the call insn target. Invalidate partially call-clobbered + registers as well as fully call-clobbered ones. + +2019-09-30 Richard Sandiford + * function.c (aggregate_value_p): Work out which ABI the function is using before testing which registers are at least partly preserved by a call. diff --git a/gcc/gcse.c b/gcc/gcse.c index 9bde861..aeb59c6 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -160,6 +160,7 @@ along with GCC; see the file COPYING3. If not see #include "dbgcnt.h" #include "gcse.h" #include "gcse-common.h" +#include "function-abi.h" /* We support GCSE via Partial Redundancy Elimination. PRE optimizations are a superset of those done by classic GCSE. @@ -1528,8 +1529,13 @@ compute_hash_table_work (struct gcse_hash_table_d *table) if (CALL_P (insn)) { hard_reg_set_iterator hrsi; - EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, - 0, regno, hrsi) + + /* We don't track modes of hard registers, so we need + to be conservative and assume that partial kills + are full kills. */ + HARD_REG_SET callee_clobbers + = insn_callee_abi (insn).full_and_partial_reg_clobbers (); + EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi) record_last_reg_set_info (insn, regno); if (! RTL_CONST_OR_PURE_CALL_P (insn) -- cgit v1.1 From 7450506b5d48642a71459cfc24efcea6ca58e97e Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:48 +0000 Subject: Remove global call sets: haifa-sched.c The code patched here is counting how many registers the current function would need to save in the prologue before it uses them. The code is called per function, so using crtl is OK. 2019-09-30 Richard Sandiford gcc/ * haifa-sched.c: Include function-abi.h. (alloc_global_sched_pressure_data): Use crtl->abi to check whether the function would need to save a register before using it. From-SVN: r276324 --- gcc/ChangeLog | 6 ++++++ gcc/haifa-sched.c | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1b1c31c..12129b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * haifa-sched.c: Include function-abi.h. + (alloc_global_sched_pressure_data): Use crtl->abi to check whether + the function would need to save a register before using it. + +2019-09-30 Richard Sandiford + * gcse.c: Include function-abi.h. (compute_hash_table_work): Use insn_callee_abi to get the ABI of the call insn target. Invalidate partially call-clobbered diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index dba3acf..7338050 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -146,6 +146,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "dumpfile.h" #include "print-rtl.h" +#include "function-abi.h" #ifdef INSN_SCHEDULING @@ -939,7 +940,8 @@ static bitmap tmp_bitmap; /* Effective number of available registers of a given class (see comment in sched_pressure_start_bb). */ static int sched_class_regs_num[N_REG_CLASSES]; -/* Number of call_saved_regs and fixed_regs. Helpers for calculating of +/* The number of registers that the function would need to save before it + uses them, and the number of fixed_regs. Helpers for calculating of sched_class_regs_num. */ static int call_saved_regs_num[N_REG_CLASSES]; static int fixed_regs_num[N_REG_CLASSES]; @@ -7207,10 +7209,13 @@ alloc_global_sched_pressure_data (void) fixed_regs_num[cl] = 0; for (int i = 0; i < ira_class_hard_regs_num[cl]; ++i) - if (!call_used_or_fixed_reg_p (ira_class_hard_regs[cl][i])) - ++call_saved_regs_num[cl]; - else if (fixed_regs[ira_class_hard_regs[cl][i]]) - ++fixed_regs_num[cl]; + { + unsigned int regno = ira_class_hard_regs[cl][i]; + if (fixed_regs[regno]) + ++fixed_regs_num[cl]; + else if (!crtl->abi->clobbers_full_reg_p (regno)) + ++call_saved_regs_num[cl]; + } } } } -- cgit v1.1 From 6c47622219d6386807b26890dcdc84f192499d33 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:52 +0000 Subject: Remove global call sets: IRA For -fipa-ra, IRA already keeps track of which specific registers are call-clobbered in a region, rather than using global information. The patch generalises this so that it tracks which ABIs are used by calls in the region. We can then use the new ABI descriptors to handle partially-clobbered registers in the same way as fully-clobbered registers, without having special code for targetm.hard_regno_call_part_clobbered. This in turn makes -fipa-ra work for partially-clobbered registers too. A side-effect of allowing multiple ABIs is that we no longer have an obvious set of conflicting registers for the self-described "fragile hack" in ira-constraints.c. This code kicks in for user-defined registers that aren't live across a call at -O0, and it tries to avoid allocating a call-clobbered register to them. Here I've used the set of call-clobbered registers in the current function's ABI, applying on top of any registers that are clobbered by called functions. This is enough to keep gcc.dg/debug/dwarf2/pr5948.c happy. The handling of GENERIC_STACK_CHECK in do_reload seemed to have a reversed condition: for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (df_regs_ever_live_p (i) && !fixed_regs[i] && call_used_or_fixed_reg_p (i)) size += UNITS_PER_WORD; The final part of the condition counts registers that don't need to be saved in the prologue, but I think the opposite was intended. 2019-09-30 Richard Sandiford gcc/ * function-abi.h (call_clobbers_in_region): Declare. (call_clobbered_in_region_p): New function. * function-abi.cc (call_clobbers_in_region): Likewise. * ira-int.h: Include function-abi.h. (ira_allocno::crossed_calls_abis): New field. (ALLOCNO_CROSSED_CALLS_ABIS): New macro. (ira_need_caller_save_regs): New function. (ira_need_caller_save_p): Likewise. * ira.c (setup_reg_renumber): Use ira_need_caller_save_p instead of call_used_or_fixed_regs. (do_reload): Use crtl->abi to test whether the current function needs to save a register in the prologue. Count registers that need to be saved rather than registers that don't. * ira-build.c (create_cap_allocno): Copy ALLOCNO_CROSSED_CALLS_ABIS. Remove unnecessary | from ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS. (propagate_allocno_info): Merge ALLOCNO_CROSSED_CALLS_ABIS too. (propagate_some_info_from_allocno): Likewise. (copy_info_to_removed_store_destinations): Likewise. (ira_flattening): Say that ALLOCNO_CROSSED_CALLS_ABIS and ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS are handled conservatively. (ira_build): Use ira_need_caller_save_regs instead of call_used_or_fixed_regs. * ira-color.c (calculate_saved_nregs): Use crtl->abi to test whether the current function would need to save a register before using it. (calculate_spill_cost): Likewise. (allocno_reload_assign): Use ira_need_caller_save_regs and ira_need_caller_save_p instead of call_used_or_fixed_regs. * ira-conflicts.c (ira_build_conflicts): Use ira_need_caller_save_regs rather than call_used_or_fixed_regs as the set of call-clobbered registers. Remove the call_used_or_fixed_regs mask from the calculation of temp_hard_reg_set and mask its use instead. Remove special handling of partially-clobbered registers. * ira-costs.c (ira_tune_allocno_costs): Use ira_need_caller_save_p. * ira-lives.c (process_bb_node_lives): Use mode_clobbers to calculate the set of conflicting registers for calls that can throw. Record the ABIs of calls in ALLOCNO_CROSSED_CALLS_ABIS. Use full_and_partial_reg_clobbers rather than full_reg_clobbers for the calculation of ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS. Use eh_edge_abi to calculate the set of registers that could be clobbered by an EH edge. Include partially-clobbered as well as fully-clobbered registers. From-SVN: r276325 --- gcc/ChangeLog | 46 +++++++++++++++++++++++++++++++++++++++++++ gcc/function-abi.cc | 25 ++++++++++++++++++++++++ gcc/function-abi.h | 26 +++++++++++++++++++++++++ gcc/ira-build.c | 13 +++++++++++-- gcc/ira-color.c | 23 +++++++++------------- gcc/ira-conflicts.c | 56 +++++++++++++++++------------------------------------ gcc/ira-costs.c | 10 +--------- gcc/ira-int.h | 29 +++++++++++++++++++++++++++ gcc/ira-lives.c | 24 +++++++++++------------ gcc/ira.c | 6 ++---- 10 files changed, 178 insertions(+), 80 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 12129b6..c0454ce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,51 @@ 2019-09-30 Richard Sandiford + * function-abi.h (call_clobbers_in_region): Declare. + (call_clobbered_in_region_p): New function. + * function-abi.cc (call_clobbers_in_region): Likewise. + * ira-int.h: Include function-abi.h. + (ira_allocno::crossed_calls_abis): New field. + (ALLOCNO_CROSSED_CALLS_ABIS): New macro. + (ira_need_caller_save_regs): New function. + (ira_need_caller_save_p): Likewise. + * ira.c (setup_reg_renumber): Use ira_need_caller_save_p instead + of call_used_or_fixed_regs. + (do_reload): Use crtl->abi to test whether the current function + needs to save a register in the prologue. Count registers that + need to be saved rather than registers that don't. + * ira-build.c (create_cap_allocno): Copy ALLOCNO_CROSSED_CALLS_ABIS. + Remove unnecessary | from ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS. + (propagate_allocno_info): Merge ALLOCNO_CROSSED_CALLS_ABIS too. + (propagate_some_info_from_allocno): Likewise. + (copy_info_to_removed_store_destinations): Likewise. + (ira_flattening): Say that ALLOCNO_CROSSED_CALLS_ABIS and + ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS are handled conservatively. + (ira_build): Use ira_need_caller_save_regs instead of + call_used_or_fixed_regs. + * ira-color.c (calculate_saved_nregs): Use crtl->abi to test + whether the current function would need to save a register + before using it. + (calculate_spill_cost): Likewise. + (allocno_reload_assign): Use ira_need_caller_save_regs and + ira_need_caller_save_p instead of call_used_or_fixed_regs. + * ira-conflicts.c (ira_build_conflicts): Use + ira_need_caller_save_regs rather than call_used_or_fixed_regs + as the set of call-clobbered registers. Remove the + call_used_or_fixed_regs mask from the calculation of + temp_hard_reg_set and mask its use instead. Remove special + handling of partially-clobbered registers. + * ira-costs.c (ira_tune_allocno_costs): Use ira_need_caller_save_p. + * ira-lives.c (process_bb_node_lives): Use mode_clobbers to + calculate the set of conflicting registers for calls that + can throw. Record the ABIs of calls in ALLOCNO_CROSSED_CALLS_ABIS. + Use full_and_partial_reg_clobbers rather than full_reg_clobbers + for the calculation of ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS. + Use eh_edge_abi to calculate the set of registers that could + be clobbered by an EH edge. Include partially-clobbered as + well as fully-clobbered registers. + +2019-09-30 Richard Sandiford + * haifa-sched.c: Include function-abi.h. (alloc_global_sched_pressure_data): Use crtl->abi to check whether the function would need to save a register before using it. diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index 1d1ac9a..4bace9e 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -126,6 +126,31 @@ predefined_function_abi::add_full_reg_clobber (unsigned int regno) SET_HARD_REG_BIT (m_mode_clobbers[i], regno); } +/* Return the set of registers that cannot be used to hold a value of + mode MODE across the calls in a region described by ABIS and MASK, where: + + * Bit ID of ABIS is set if the region contains a call with + function_abi identifier ID. + + * MASK contains all the registers that are fully or partially + clobbered by calls in the region. + + This is not quite as accurate as testing each individual call, + but it's a close and conservatively-correct approximation. + It's much better for some targets than just using MASK. */ + +HARD_REG_SET +call_clobbers_in_region (unsigned int abis, const_hard_reg_set mask, + machine_mode mode) +{ + HARD_REG_SET result; + CLEAR_HARD_REG_SET (result); + for (unsigned int id = 0; abis; abis >>= 1, ++id) + if (abis & 1) + result |= function_abis[id].mode_clobbers (mode); + return result & mask; +} + /* Return the predefined ABI used by functions with type TYPE. */ const predefined_function_abi & diff --git a/gcc/function-abi.h b/gcc/function-abi.h index c8f3f29..8dd139e 100644 --- a/gcc/function-abi.h +++ b/gcc/function-abi.h @@ -265,6 +265,32 @@ extern target_function_abi_info *this_target_function_abi_info; (this_target_function_abi_info->x_function_abis[0]) #define eh_edge_abi default_function_abi +extern HARD_REG_SET call_clobbers_in_region (unsigned int, const_hard_reg_set, + machine_mode mode); + +/* Return true if (reg:MODE REGNO) might be clobbered by one of the + calls in a region described by ABIS and MASK, where: + + * Bit ID of ABIS is set if the region contains a call with + function_abi identifier ID. + + * MASK contains all the registers that are fully or partially + clobbered by calls in the region. + + This is not quite as accurate as testing each individual call, + but it's a close and conservatively-correct approximation. + It's much better for some targets than: + + overlaps_hard_reg_set_p (MASK, MODE, REGNO). */ + +inline bool +call_clobbered_in_region_p (unsigned int abis, const_hard_reg_set mask, + machine_mode mode, unsigned int regno) +{ + HARD_REG_SET clobbers = call_clobbers_in_region (abis, mask, mode); + return overlaps_hard_reg_set_p (clobbers, mode, regno); +} + extern const predefined_function_abi &fntype_abi (const_tree); extern function_abi fndecl_abi (const_tree); extern function_abi insn_callee_abi (const rtx_insn *); diff --git a/gcc/ira-build.c b/gcc/ira-build.c index b5e6933..ad1eaa4 100644 --- a/gcc/ira-build.c +++ b/gcc/ira-build.c @@ -903,8 +903,9 @@ create_cap_allocno (ira_allocno_t a) ALLOCNO_CALLS_CROSSED_NUM (cap) = ALLOCNO_CALLS_CROSSED_NUM (a); ALLOCNO_CHEAP_CALLS_CROSSED_NUM (cap) = ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a); + ALLOCNO_CROSSED_CALLS_ABIS (cap) = ALLOCNO_CROSSED_CALLS_ABIS (a); ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (cap) - |= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a); + = ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a); if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) { fprintf (ira_dump_file, " Creating cap "); @@ -2032,6 +2033,8 @@ propagate_allocno_info (void) += ALLOCNO_CALLS_CROSSED_NUM (a); ALLOCNO_CHEAP_CALLS_CROSSED_NUM (parent_a) += ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a); + ALLOCNO_CROSSED_CALLS_ABIS (parent_a) + |= ALLOCNO_CROSSED_CALLS_ABIS (a); ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (parent_a) |= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a); ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a) @@ -2415,6 +2418,7 @@ propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a) ALLOCNO_CALLS_CROSSED_NUM (a) += ALLOCNO_CALLS_CROSSED_NUM (from_a); ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a) += ALLOCNO_CHEAP_CALLS_CROSSED_NUM (from_a); + ALLOCNO_CROSSED_CALLS_ABIS (a) |= ALLOCNO_CROSSED_CALLS_ABIS (from_a); ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a) |= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (from_a); @@ -3056,6 +3060,8 @@ copy_info_to_removed_store_destinations (int regno) += ALLOCNO_CALLS_CROSSED_NUM (a); ALLOCNO_CHEAP_CALLS_CROSSED_NUM (parent_a) += ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a); + ALLOCNO_CROSSED_CALLS_ABIS (parent_a) + |= ALLOCNO_CROSSED_CALLS_ABIS (a); ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (parent_a) |= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a); ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a) @@ -3155,6 +3161,9 @@ ira_flattening (int max_regno_before_emit, int ira_max_point_before_emit) -= ALLOCNO_CALLS_CROSSED_NUM (a); ALLOCNO_CHEAP_CALLS_CROSSED_NUM (parent_a) -= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a); + /* Assume that ALLOCNO_CROSSED_CALLS_ABIS and + ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS stay the same. + We'd need to rebuild the IR to do better. */ ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a) -= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a); ira_assert (ALLOCNO_CALLS_CROSSED_NUM (parent_a) >= 0 @@ -3462,7 +3471,7 @@ ira_build (void) allocno crossing calls. */ FOR_EACH_ALLOCNO (a, ai) if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) - ior_hard_reg_conflicts (a, call_used_or_fixed_regs); + ior_hard_reg_conflicts (a, ira_need_caller_save_regs (a)); } if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) print_copies (ira_dump_file); diff --git a/gcc/ira-color.c b/gcc/ira-color.c index 505d5c8..9197db9 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -1650,7 +1650,7 @@ calculate_saved_nregs (int hard_regno, machine_mode mode) ira_assert (hard_regno >= 0); for (i = hard_regno_nregs (hard_regno, mode) - 1; i >= 0; i--) if (!allocated_hardreg_p[hard_regno + i] - && !TEST_HARD_REG_BIT (call_used_or_fixed_regs, hard_regno + i) + && !crtl->abi->clobbers_full_reg_p (hard_regno + i) && !LOCAL_REGNO (hard_regno + i)) nregs++; return nregs; @@ -4379,7 +4379,7 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs) saved[i] = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj); OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= forbidden_regs; if (! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0) - OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= call_used_or_fixed_regs; + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= ira_need_caller_save_regs (a); } ALLOCNO_ASSIGNED_P (a) = false; aclass = ALLOCNO_CLASS (a); @@ -4398,9 +4398,7 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs) ? ALLOCNO_CLASS_COST (a) : ALLOCNO_HARD_REG_COSTS (a)[ira_class_hard_reg_index [aclass][hard_regno]])); - if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0 - && ira_hard_reg_set_intersection_p (hard_regno, ALLOCNO_MODE (a), - call_used_or_fixed_regs)) + if (ira_need_caller_save_p (a, regno)) { ira_assert (flag_caller_saves); caller_save_needed = 1; @@ -4687,16 +4685,16 @@ ira_mark_new_stack_slot (rtx x, int regno, poly_uint64 total_size) given IN and OUT for INSN. Return also number points (through EXCESS_PRESSURE_LIVE_LENGTH) where the pseudo-register lives and the register pressure is high, number of references of the - pseudo-registers (through NREFS), number of callee-clobbered - hard-registers occupied by the pseudo-registers (through - CALL_USED_COUNT), and the first hard regno occupied by the + pseudo-registers (through NREFS), the number of psuedo registers + whose allocated register wouldn't need saving in the prologue + (through CALL_USED_COUNT), and the first hard regno occupied by the pseudo-registers (through FIRST_HARD_REGNO). */ static int calculate_spill_cost (int *regnos, rtx in, rtx out, rtx_insn *insn, int *excess_pressure_live_length, int *nrefs, int *call_used_count, int *first_hard_regno) { - int i, cost, regno, hard_regno, j, count, saved_cost, nregs; + int i, cost, regno, hard_regno, count, saved_cost; bool in_p, out_p; int length; ira_allocno_t a; @@ -4713,11 +4711,8 @@ calculate_spill_cost (int *regnos, rtx in, rtx out, rtx_insn *insn, a = ira_regno_allocno_map[regno]; length += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) / ALLOCNO_NUM_OBJECTS (a); cost += ALLOCNO_MEMORY_COST (a) - ALLOCNO_CLASS_COST (a); - nregs = hard_regno_nregs (hard_regno, ALLOCNO_MODE (a)); - for (j = 0; j < nregs; j++) - if (! TEST_HARD_REG_BIT (call_used_or_fixed_regs, hard_regno + j)) - break; - if (j == nregs) + if (in_hard_reg_set_p (crtl->abi->full_reg_clobbers (), + ALLOCNO_MODE (a), hard_regno)) count++; in_p = in && REG_P (in) && (int) REGNO (in) == hard_regno; out_p = out && REG_P (out) && (int) REGNO (out) == hard_regno; diff --git a/gcc/ira-conflicts.c b/gcc/ira-conflicts.c index 6ceed53..a0aefaa 100644 --- a/gcc/ira-conflicts.c +++ b/gcc/ira-conflicts.c @@ -770,9 +770,7 @@ ira_build_conflicts (void) if (! targetm.class_likely_spilled_p (base)) CLEAR_HARD_REG_SET (temp_hard_reg_set); else - temp_hard_reg_set = (reg_class_contents[base] - & ~ira_no_alloc_regs - & call_used_or_fixed_regs); + temp_hard_reg_set = reg_class_contents[base] & ~ira_no_alloc_regs; FOR_EACH_ALLOCNO (a, ai) { int i, n = ALLOCNO_NUM_OBJECTS (a); @@ -780,29 +778,28 @@ ira_build_conflicts (void) for (i = 0; i < n; i++) { ira_object_t obj = ALLOCNO_OBJECT (a, i); - machine_mode obj_mode = obj->allocno->mode; rtx allocno_reg = regno_reg_rtx [ALLOCNO_REGNO (a)]; - if ((! flag_caller_saves && ALLOCNO_CALLS_CROSSED_NUM (a) != 0) - /* For debugging purposes don't put user defined variables in - callee-clobbered registers. However, do allow parameters - in callee-clobbered registers to improve debugging. This - is a bit of a fragile hack. */ - || (optimize == 0 - && REG_USERVAR_P (allocno_reg) - && ! reg_is_parm_p (allocno_reg))) + /* For debugging purposes don't put user defined variables in + callee-clobbered registers. However, do allow parameters + in callee-clobbered registers to improve debugging. This + is a bit of a fragile hack. */ + if (optimize == 0 + && REG_USERVAR_P (allocno_reg) + && ! reg_is_parm_p (allocno_reg)) { - OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= call_used_or_fixed_regs; - OBJECT_CONFLICT_HARD_REGS (obj) |= call_used_or_fixed_regs; + HARD_REG_SET new_conflict_regs = crtl->abi->full_reg_clobbers (); + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= new_conflict_regs; + OBJECT_CONFLICT_HARD_REGS (obj) |= new_conflict_regs; } - else if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) + + if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) { - HARD_REG_SET no_caller_save_reg_set - = (call_used_or_fixed_regs & ~savable_regs); - OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= no_caller_save_reg_set; - OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= temp_hard_reg_set; - OBJECT_CONFLICT_HARD_REGS (obj) |= no_caller_save_reg_set; - OBJECT_CONFLICT_HARD_REGS (obj) |= temp_hard_reg_set; + HARD_REG_SET new_conflict_regs = ira_need_caller_save_regs (a); + if (flag_caller_saves) + new_conflict_regs &= (~savable_regs | temp_hard_reg_set); + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= new_conflict_regs; + OBJECT_CONFLICT_HARD_REGS (obj) |= new_conflict_regs; } /* Now we deal with paradoxical subreg cases where certain registers @@ -829,23 +826,6 @@ ira_build_conflicts (void) } } } - - if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) - { - int regno; - - /* Allocnos bigger than the saved part of call saved - regs must conflict with them. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (!TEST_HARD_REG_BIT (call_used_or_fixed_regs, regno) - && targetm.hard_regno_call_part_clobbered (0, regno, - obj_mode)) - { - SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno); - SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), - regno); - } - } } } if (optimize && ira_conflicts_p diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c index 2e7e10a..65511a3 100644 --- a/gcc/ira-costs.c +++ b/gcc/ira-costs.c @@ -2340,7 +2340,6 @@ ira_tune_allocno_costs (void) ira_allocno_object_iterator oi; ira_object_t obj; bool skip_p; - HARD_REG_SET *crossed_calls_clobber_regs; FOR_EACH_ALLOCNO (a, ai) { @@ -2375,14 +2374,7 @@ ira_tune_allocno_costs (void) continue; rclass = REGNO_REG_CLASS (regno); cost = 0; - crossed_calls_clobber_regs - = &(ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a)); - if (ira_hard_reg_set_intersection_p (regno, mode, - *crossed_calls_clobber_regs) - && (ira_hard_reg_set_intersection_p (regno, mode, - call_used_or_fixed_regs) - || targetm.hard_regno_call_part_clobbered (0, regno, - mode))) + if (ira_need_caller_save_p (a, regno)) cost += (ALLOCNO_CALL_FREQ (a) * (ira_memory_move_cost[mode][rclass][0] + ira_memory_move_cost[mode][rclass][1])); diff --git a/gcc/ira-int.h b/gcc/ira-int.h index 95e22aa..6da37f8 100644 --- a/gcc/ira-int.h +++ b/gcc/ira-int.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_IRA_INT_H #include "recog.h" +#include "function-abi.h" /* To provide consistency in naming, all IRA external variables, functions, common typedefs start with prefix ira_. */ @@ -287,6 +288,9 @@ struct ira_allocno /* Register class which should be used for allocation for given allocno. NO_REGS means that we should use memory. */ ENUM_BITFIELD (reg_class) aclass : 16; + /* A bitmask of the ABIs used by calls that occur while the allocno + is live. */ + unsigned int crossed_calls_abis : NUM_ABI_IDS; /* During the reload, value TRUE means that we should not reassign a hard register to the allocno got memory earlier. It is set up when we removed memory-memory move insn before each iteration of @@ -423,6 +427,7 @@ struct ira_allocno #define ALLOCNO_CALL_FREQ(A) ((A)->call_freq) #define ALLOCNO_CALLS_CROSSED_NUM(A) ((A)->calls_crossed_num) #define ALLOCNO_CHEAP_CALLS_CROSSED_NUM(A) ((A)->cheap_calls_crossed_num) +#define ALLOCNO_CROSSED_CALLS_ABIS(A) ((A)->crossed_calls_abis) #define ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS(A) \ ((A)->crossed_calls_clobbered_regs) #define ALLOCNO_MEM_OPTIMIZED_DEST(A) ((A)->mem_optimized_dest) @@ -1510,4 +1515,28 @@ ira_allocate_and_set_or_copy_costs (int **vec, enum reg_class aclass, extern rtx ira_create_new_reg (rtx); extern int first_moveable_pseudo, last_moveable_pseudo; +/* Return the set of registers that would need a caller save if allocno A + overlapped them. */ + +inline HARD_REG_SET +ira_need_caller_save_regs (ira_allocno_t a) +{ + return call_clobbers_in_region (ALLOCNO_CROSSED_CALLS_ABIS (a), + ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a), + ALLOCNO_MODE (a)); +} + +/* Return true if we would need to save allocno A around a call if we + assigned hard register REGNO. */ + +inline bool +ira_need_caller_save_p (ira_allocno_t a, unsigned int regno) +{ + if (ALLOCNO_CALLS_CROSSED_NUM (a) == 0) + return false; + return call_clobbered_in_region_p (ALLOCNO_CROSSED_CALLS_ABIS (a), + ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a), + ALLOCNO_MODE (a), regno); +} + #endif /* GCC_IRA_INT_H */ diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c index e24831a..cce73a1 100644 --- a/gcc/ira-lives.c +++ b/gcc/ira-lives.c @@ -1255,11 +1255,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) ira_object_t obj = ira_object_id_map[i]; a = OBJECT_ALLOCNO (obj); int num = ALLOCNO_NUM (a); - HARD_REG_SET this_call_used_reg_set - = insn_callee_abi (insn).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not be - needed. */ - this_call_used_reg_set |= fixed_reg_set; + function_abi callee_abi = insn_callee_abi (insn); /* Don't allocate allocnos that cross setjmps or any call, if this function receives a nonlocal @@ -1275,9 +1271,9 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) if (can_throw_internal (insn)) { OBJECT_CONFLICT_HARD_REGS (obj) - |= this_call_used_reg_set; + |= callee_abi.mode_clobbers (ALLOCNO_MODE (a)); OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) - |= this_call_used_reg_set; + |= callee_abi.mode_clobbers (ALLOCNO_MODE (a)); } if (sparseset_bit_p (allocnos_processed, num)) @@ -1294,8 +1290,9 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) /* Mark it as saved at the next call. */ allocno_saved_at_call[num] = last_call_num + 1; ALLOCNO_CALLS_CROSSED_NUM (a)++; + ALLOCNO_CROSSED_CALLS_ABIS (a) |= 1 << callee_abi.id (); ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a) - |= this_call_used_reg_set; + |= callee_abi.full_and_partial_reg_clobbers (); if (cheap_reg != NULL_RTX && ALLOCNO_REGNO (a) == (int) REGNO (cheap_reg)) ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a)++; @@ -1359,10 +1356,11 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) } /* Allocnos can't go in stack regs at the start of a basic block - that is reached by an abnormal edge. Likewise for call - clobbered regs, because caller-save, fixup_abnormal_edges and - possibly the table driven EH machinery are not quite ready to - handle such allocnos live across such edges. */ + that is reached by an abnormal edge. Likewise for registers + that are at least partly call clobbered, because caller-save, + fixup_abnormal_edges and possibly the table driven EH machinery + are not quite ready to handle such allocnos live across such + edges. */ if (bb_has_abnormal_pred (bb)) { #ifdef STACK_REGS @@ -1382,7 +1380,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) if (!cfun->has_nonlocal_label && has_abnormal_call_or_eh_pred_edge_p (bb)) for (px = 0; px < FIRST_PSEUDO_REGISTER; px++) - if (call_used_or_fixed_reg_p (px) + if (eh_edge_abi.clobbers_at_least_part_of_reg_p (px) #ifdef REAL_PIC_OFFSET_TABLE_REGNUM /* We should create a conflict of PIC pseudo with PIC hard reg as PIC hard reg can have a wrong diff --git a/gcc/ira.c b/gcc/ira.c index a4321d3..925ea26 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -2368,9 +2368,7 @@ setup_reg_renumber (void) OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= ~reg_class_contents[pclass]; } - if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0 - && ira_hard_reg_set_intersection_p (hard_regno, ALLOCNO_MODE (a), - call_used_or_fixed_regs)) + if (ira_need_caller_save_p (a, hard_regno)) { ira_assert (!optimize || flag_caller_saves || (ALLOCNO_CALLS_CROSSED_NUM (a) @@ -5591,7 +5589,7 @@ do_reload (void) for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (df_regs_ever_live_p (i) && !fixed_regs[i] - && call_used_or_fixed_reg_p (i)) + && !crtl->abi->clobbers_full_reg_p (i)) size += UNITS_PER_WORD; if (constant_lower_bound (size) > STACK_CHECK_MAX_FRAME_SIZE) -- cgit v1.1 From 5c64181d62bb816b8c2c91e251cee7e2b597f244 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:20:56 +0000 Subject: Remove global call sets: loop-iv.c Similar idea to the combine.c and gcse.c patches. 2019-09-30 Richard Sandiford gcc/ * loop-iv.c: Include regs.h and function-abi.h. (simplify_using_initial_values): Use insn_callee_abi to get the ABI of the call insn target. Conservatively assume that partially-clobbered registers are altered. From-SVN: r276326 --- gcc/ChangeLog | 7 +++++++ gcc/loop-iv.c | 12 ++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c0454ce..1129ec5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-30 Richard Sandiford + * loop-iv.c: Include regs.h and function-abi.h. + (simplify_using_initial_values): Use insn_callee_abi to get the + ABI of the call insn target. Conservatively assume that + partially-clobbered registers are altered. + +2019-09-30 Richard Sandiford + * function-abi.h (call_clobbers_in_region): Declare. (call_clobbered_in_region_p): New function. * function-abi.cc (call_clobbers_in_region): Likewise. diff --git a/gcc/loop-iv.c b/gcc/loop-iv.c index 33be75a..d0e6994 100644 --- a/gcc/loop-iv.c +++ b/gcc/loop-iv.c @@ -62,6 +62,8 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "rtl-iter.h" #include "tree-ssa-loop-niter.h" +#include "regs.h" +#include "function-abi.h" /* Possible return values of iv_get_reaching_def. */ @@ -1972,8 +1974,14 @@ simplify_using_initial_values (class loop *loop, enum rtx_code op, rtx *expr) CLEAR_REG_SET (this_altered); note_stores (insn, mark_altered, this_altered); if (CALL_P (insn)) - /* Kill all call clobbered registers. */ - IOR_REG_SET_HRS (this_altered, regs_invalidated_by_call); + { + /* Kill all registers that might be clobbered by the call. + We don't track modes of hard registers, so we need to be + conservative and assume that partial kills are full kills. */ + function_abi callee_abi = insn_callee_abi (insn); + IOR_REG_SET_HRS (this_altered, + callee_abi.full_and_partial_reg_clobbers ()); + } if (suitable_set_for_replacement (insn, &dest, &src)) { -- cgit v1.1 From a1e6ee38e708ef2bdef4dfbb99473344bd56fa2f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:00 +0000 Subject: Remove global call sets: LRA lra_reg has an actual_call_used_reg_set field that is only used during inheritance. This in turn required a special lra_create_live_ranges pass for flag_ipa_ra to set up this field. This patch instead makes the inheritance code do its own live register tracking, using the same ABI-mask-and-clobber-set pair as for IRA. Tracking ABIs simplifies (and cheapens) the logic in lra-lives.c and means we no longer need a separate path for -fipa-ra. It also means we can remove TARGET_RETURN_CALL_WITH_MAX_CLOBBERS. The patch also strengthens the sanity check in lra_assigns so that we check that reg_renumber is consistent with the whole conflict set, not just the call-clobbered registers. 2019-09-30 Richard Sandiford gcc/ * target.def (return_call_with_max_clobbers): Delete. * doc/tm.texi.in (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): Delete. * doc/tm.texi: Regenerate. * config/aarch64/aarch64.c (aarch64_return_call_with_max_clobbers) (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): Delete. * lra-int.h (lra_reg::actual_call_used_reg_set): Delete. (lra_reg::call_insn): Delete. * lra.c: Include function-abi.h. (initialize_lra_reg_info_element): Don't initialize the fields above. (lra): Use crtl->abi to test whether the current function needs to save a register in the prologue. Remove special pre-inheritance lra_create_live_ranges pass for flag_ipa_ra. * lra-assigns.c: Include function-abi.h (find_hard_regno_for_1): Use crtl->abi to test whether the current function needs to save a register in the prologue. (lra_assign): Assert that registers aren't allocated to a conflicting register, rather than checking only for overlaps with call_used_or_fixed_regs. Do this even for flag_ipa_ra, and for registers that are not live across a call. * lra-constraints.c (last_call_for_abi): New variable. (full_and_partial_call_clobbers): Likewise. (setup_next_usage_insn): Remove the register from full_and_partial_call_clobbers. (need_for_call_save_p): Use call_clobbered_in_region_p to test whether the register needs a caller save. (need_for_split_p): Use full_and_partial_reg_clobbers instead of call_used_or_fixed_regs. (inherit_in_ebb): Initialize and maintain last_call_for_abi and full_and_partial_call_clobbers. * lra-lives.c (check_pseudos_live_through_calls): Replace last_call_used_reg_set and call_insn arguments with an abi argument. Remove handling of lra_reg::call_insn. Use function_abi::mode_clobbers as the set of conflicting registers. (calls_have_same_clobbers_p): Delete. (process_bb_lives): Track the ABI of the last call instead of an insn/HARD_REG_SET pair. Update calls to check_pseudos_live_through_calls. Use eh_edge_abi to calculate the set of registers that could be clobbered by an EH edge. Include partially-clobbered as well as fully-clobbered registers. (lra_create_live_ranges_1): Don't initialize lra_reg::call_insn. * lra-remat.c: Include function-abi.h. (call_used_regs_arr_len, call_used_regs_arr): Delete. (set_bb_regs): Use insn_callee_abi to get the set of call-clobbered registers and bitmap_view to combine them into dead_regs. (call_used_input_regno_present_p): Take a function_abi argument and use it to test whether a register is call-clobbered. (calculate_gen_cands): Use insn_callee_abi to get the ABI of the call insn target. Update tje call to call_used_input_regno_present_p. (do_remat): Likewise. (lra_remat): Remove the initialization of call_used_regs_arr_len and call_used_regs_arr. From-SVN: r276327 --- gcc/ChangeLog | 54 +++++++++++++++++++++ gcc/config/aarch64/aarch64.c | 17 ------- gcc/doc/tm.texi | 12 ----- gcc/doc/tm.texi.in | 2 - gcc/lra-assigns.c | 11 +++-- gcc/lra-constraints.c | 51 ++++++++++++++------ gcc/lra-int.h | 6 --- gcc/lra-lives.c | 110 ++++++++++--------------------------------- gcc/lra-remat.c | 67 +++++++++++++------------- gcc/lra.c | 21 ++------- gcc/target.def | 14 ------ 11 files changed, 160 insertions(+), 205 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1129ec5..df3a2f6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,59 @@ 2019-09-30 Richard Sandiford + * target.def (return_call_with_max_clobbers): Delete. + * doc/tm.texi.in (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): Delete. + * doc/tm.texi: Regenerate. + * config/aarch64/aarch64.c (aarch64_return_call_with_max_clobbers) + (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): Delete. + * lra-int.h (lra_reg::actual_call_used_reg_set): Delete. + (lra_reg::call_insn): Delete. + * lra.c: Include function-abi.h. + (initialize_lra_reg_info_element): Don't initialize the fields above. + (lra): Use crtl->abi to test whether the current function needs to + save a register in the prologue. Remove special pre-inheritance + lra_create_live_ranges pass for flag_ipa_ra. + * lra-assigns.c: Include function-abi.h + (find_hard_regno_for_1): Use crtl->abi to test whether the current + function needs to save a register in the prologue. + (lra_assign): Assert that registers aren't allocated to a + conflicting register, rather than checking only for overlaps + with call_used_or_fixed_regs. Do this even for flag_ipa_ra, + and for registers that are not live across a call. + * lra-constraints.c (last_call_for_abi): New variable. + (full_and_partial_call_clobbers): Likewise. + (setup_next_usage_insn): Remove the register from + full_and_partial_call_clobbers. + (need_for_call_save_p): Use call_clobbered_in_region_p to test + whether the register needs a caller save. + (need_for_split_p): Use full_and_partial_reg_clobbers instead + of call_used_or_fixed_regs. + (inherit_in_ebb): Initialize and maintain last_call_for_abi and + full_and_partial_call_clobbers. + * lra-lives.c (check_pseudos_live_through_calls): Replace + last_call_used_reg_set and call_insn arguments with an abi argument. + Remove handling of lra_reg::call_insn. Use function_abi::mode_clobbers + as the set of conflicting registers. + (calls_have_same_clobbers_p): Delete. + (process_bb_lives): Track the ABI of the last call instead of an + insn/HARD_REG_SET pair. Update calls to + check_pseudos_live_through_calls. Use eh_edge_abi to calculate + the set of registers that could be clobbered by an EH edge. + Include partially-clobbered as well as fully-clobbered registers. + (lra_create_live_ranges_1): Don't initialize lra_reg::call_insn. + * lra-remat.c: Include function-abi.h. + (call_used_regs_arr_len, call_used_regs_arr): Delete. + (set_bb_regs): Use insn_callee_abi to get the set of call-clobbered + registers and bitmap_view to combine them into dead_regs. + (call_used_input_regno_present_p): Take a function_abi argument + and use it to test whether a register is call-clobbered. + (calculate_gen_cands): Use insn_callee_abi to get the ABI of the + call insn target. Update tje call to call_used_input_regno_present_p. + (do_remat): Likewise. + (lra_remat): Remove the initialization of call_used_regs_arr_len + and call_used_regs_arr. + +2019-09-30 Richard Sandiford + * loop-iv.c: Include regs.h and function-abi.h. (simplify_using_initial_values): Use insn_callee_abi to get the ABI of the call insn target. Conservatively assume that diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index ca4c183..2d4cd37 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1926,19 +1926,6 @@ aarch64_hard_regno_call_part_clobbered (unsigned int abi_id, return false; } -/* Implement TARGET_RETURN_CALL_WITH_MAX_CLOBBERS. */ - -rtx_insn * -aarch64_return_call_with_max_clobbers (rtx_insn *call_1, rtx_insn *call_2) -{ - gcc_assert (CALL_P (call_1) && CALL_P (call_2)); - - if (!aarch64_simd_call_p (call_1) || aarch64_simd_call_p (call_2)) - return call_1; - else - return call_2; -} - /* Implement REGMODE_NATURAL_SIZE. */ poly_uint64 aarch64_regmode_natural_size (machine_mode mode) @@ -21002,10 +20989,6 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_INSN_CALLEE_ABI #define TARGET_INSN_CALLEE_ABI aarch64_insn_callee_abi -#undef TARGET_RETURN_CALL_WITH_MAX_CLOBBERS -#define TARGET_RETURN_CALL_WITH_MAX_CLOBBERS \ - aarch64_return_call_with_max_clobbers - #undef TARGET_CONSTANT_ALIGNMENT #define TARGET_CONSTANT_ALIGNMENT aarch64_constant_alignment diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 419c706..915e961 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1941,18 +1941,6 @@ The default implementation returns false, which is correct for targets that don't have partly call-clobbered registers. @end deftypefn -@deftypefn {Target Hook} {rtx_insn *} TARGET_RETURN_CALL_WITH_MAX_CLOBBERS (rtx_insn *@var{call_1}, rtx_insn *@var{call_2}) -This hook returns a pointer to the call that partially clobbers the -most registers. If a platform supports multiple ABIs where the registers -that are partially clobbered may vary, this function compares two -calls and returns a pointer to the one that clobbers the most registers. -If both calls clobber the same registers, @var{call_1} must be returned. - -The registers clobbered in different ABIs must be a proper subset or -superset of all other ABIs. @var{call_1} must always be a call insn, -call_2 may be NULL or a call insn. -@end deftypefn - @deftypefn {Target Hook} {const char *} TARGET_GET_MULTILIB_ABI_NAME (void) This hook returns name of multilib ABI name. @end deftypefn diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 55fb5d4..ac0f049 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -1718,8 +1718,6 @@ must be defined. Modern ports should define @code{CALL_REALLY_USED_REGISTERS}. @cindex call-saved register @hook TARGET_HARD_REGNO_CALL_PART_CLOBBERED -@hook TARGET_RETURN_CALL_WITH_MAX_CLOBBERS - @hook TARGET_GET_MULTILIB_ABI_NAME @findex fixed_regs diff --git a/gcc/lra-assigns.c b/gcc/lra-assigns.c index 014fb496..e14a246 100644 --- a/gcc/lra-assigns.c +++ b/gcc/lra-assigns.c @@ -94,6 +94,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "lra.h" #include "lra-int.h" +#include "function-abi.h" /* Current iteration number of the pass and current iteration number of the pass after the latest spill pass when any former reload @@ -654,7 +655,7 @@ find_hard_regno_for_1 (int regno, int *cost, int try_only_hard_regno, for (j = 0; j < hard_regno_nregs (hard_regno, PSEUDO_REGNO_MODE (regno)); j++) - if (! TEST_HARD_REG_BIT (call_used_or_fixed_regs, hard_regno + j) + if (! crtl->abi->clobbers_full_reg_p (hard_regno + j) && ! df_regs_ever_live_p (hard_regno + j)) /* It needs save restore. */ hard_regno_costs[hard_regno] @@ -1634,14 +1635,14 @@ lra_assign (bool &fails_p) bitmap_initialize (&all_spilled_pseudos, ®_obstack); create_live_range_start_chains (); setup_live_pseudos_and_spill_after_risky_transforms (&all_spilled_pseudos); - if (! lra_asm_error_p && flag_checking && !flag_ipa_ra) + if (! lra_asm_error_p && flag_checking) /* Check correctness of allocation for call-crossed pseudos but only when there are no asm errors as in the case of errors the asm is removed and it can result in incorrect allocation. */ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0 - && lra_reg_info[i].call_insn - && overlaps_hard_reg_set_p (call_used_or_fixed_regs, + if (lra_reg_info[i].nrefs != 0 + && reg_renumber[i] >= 0 + && overlaps_hard_reg_set_p (lra_reg_info[i].conflict_hard_regs, PSEUDO_REGNO_MODE (i), reg_renumber[i])) gcc_unreachable (); /* Setup insns to process on the next constraint pass. */ diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 43fe107..0db6d31 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -5147,6 +5147,14 @@ static int reloads_num; /* Number of calls passed so far in current EBB. */ static int calls_num; +/* Index ID is the CALLS_NUM associated the last call we saw with + ABI identifier ID. */ +static int last_call_for_abi[NUM_ABI_IDS]; + +/* Which registers have been fully or partially clobbered by a call + since they were last used. */ +static HARD_REG_SET full_and_partial_call_clobbers; + /* Current reload pseudo check for validity of elements in USAGE_INSNS. */ static int curr_usage_insns_check; @@ -5190,6 +5198,10 @@ setup_next_usage_insn (int regno, rtx insn, int reloads_num, bool after_p) usage_insns[regno].reloads_num = reloads_num; usage_insns[regno].calls_num = calls_num; usage_insns[regno].after_p = after_p; + if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0) + remove_from_hard_reg_set (&full_and_partial_call_clobbers, + PSEUDO_REGNO_MODE (regno), + reg_renumber[regno]); } /* The function is used to form list REGNO usages which consists of @@ -5435,17 +5447,19 @@ static inline bool need_for_call_save_p (int regno) { lra_assert (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0); - return (usage_insns[regno].calls_num < calls_num - && (overlaps_hard_reg_set_p - ((flag_ipa_ra && - ! hard_reg_set_empty_p (lra_reg_info[regno].actual_call_used_reg_set)) - ? lra_reg_info[regno].actual_call_used_reg_set - : call_used_or_fixed_regs, - PSEUDO_REGNO_MODE (regno), reg_renumber[regno]) - || (targetm.hard_regno_call_part_clobbered - (lra_reg_info[regno].call_insn - ? insn_callee_abi (lra_reg_info[regno].call_insn).id () : 0, - reg_renumber[regno], PSEUDO_REGNO_MODE (regno))))); + if (usage_insns[regno].calls_num < calls_num) + { + unsigned int abis = 0; + for (unsigned int i = 0; i < NUM_ABI_IDS; ++i) + if (last_call_for_abi[i] > usage_insns[regno].calls_num) + abis |= 1 << i; + gcc_assert (abis); + if (call_clobbered_in_region_p (abis, full_and_partial_call_clobbers, + PSEUDO_REGNO_MODE (regno), + reg_renumber[regno])) + return true; + } + return false; } /* Global registers occurring in the current EBB. */ @@ -5485,8 +5499,7 @@ need_for_split_p (HARD_REG_SET potential_reload_hard_regs, int regno) true) the assign pass assumes that all pseudos living through calls are assigned to call saved hard regs. */ && (regno >= FIRST_PSEUDO_REGISTER - || ! TEST_HARD_REG_BIT (call_used_or_fixed_regs, regno) - || usage_insns[regno].calls_num == calls_num) + || !TEST_HARD_REG_BIT (full_and_partial_call_clobbers, regno)) /* We need at least 2 reloads to make pseudo splitting profitable. We should provide hard regno splitting in any case to solve 1st insn scheduling problem when @@ -6238,6 +6251,9 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail) curr_usage_insns_check++; clear_invariants (); reloads_num = calls_num = 0; + for (unsigned int i = 0; i < NUM_ABI_IDS; ++i) + last_call_for_abi[i] = 0; + CLEAR_HARD_REG_SET (full_and_partial_call_clobbers); bitmap_clear (&check_only_regs); bitmap_clear (&invalid_invariant_regs); last_processed_bb = NULL; @@ -6451,6 +6467,10 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail) int regno, hard_regno; calls_num++; + function_abi callee_abi = insn_callee_abi (curr_insn); + last_call_for_abi[callee_abi.id ()] = calls_num; + full_and_partial_call_clobbers + |= callee_abi.full_and_partial_reg_clobbers (); if ((cheap = find_reg_note (curr_insn, REG_RETURNED, NULL_RTX)) != NULL_RTX && ((cheap = XEXP (cheap, 0)), true) @@ -6460,7 +6480,7 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail) /* If there are pending saves/restores, the optimization is not worth. */ && usage_insns[regno].calls_num == calls_num - 1 - && TEST_HARD_REG_BIT (call_used_or_fixed_regs, hard_regno)) + && callee_abi.clobbers_reg_p (GET_MODE (cheap), hard_regno)) { /* Restore the pseudo from the call result as REG_RETURNED note says that the pseudo value is @@ -6483,6 +6503,9 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail) /* We don't need to save/restore of the pseudo from this call. */ usage_insns[regno].calls_num = calls_num; + remove_from_hard_reg_set + (&full_and_partial_call_clobbers, + GET_MODE (cheap), hard_regno); bitmap_set_bit (&check_only_regs, regno); } } diff --git a/gcc/lra-int.h b/gcc/lra-int.h index 77abb7b..7f2bbbe 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -73,10 +73,6 @@ public: /* The following fields are defined only for pseudos. */ /* Hard registers with which the pseudo conflicts. */ HARD_REG_SET conflict_hard_regs; - /* Call used registers with which the pseudo conflicts, taking into account - the registers used by functions called from calls which cross the - pseudo. */ - HARD_REG_SET actual_call_used_reg_set; /* We assign hard registers to reload pseudos which can occur in few places. So two hard register preferences are enough for them. The following fields define the preferred hard registers. If @@ -104,8 +100,6 @@ public: int val; /* Offset from relative eliminate register to pesudo reg. */ poly_int64 offset; - /* Call instruction, if any, that may affect this psuedo reg. */ - rtx_insn *call_insn; /* These members are set up in lra-lives.c and updated in lra-coalesce.c. */ /* The biggest size mode in which each pseudo reg is referred in diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index 40e9f66..a6cd7bb 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -576,40 +576,21 @@ lra_setup_reload_pseudo_preferenced_hard_reg (int regno, } } -/* Check that REGNO living through calls and setjumps, set up conflict - regs using LAST_CALL_USED_REG_SET, and clear corresponding bits in - PSEUDOS_LIVE_THROUGH_CALLS and PSEUDOS_LIVE_THROUGH_SETJUMPS. - CALL_INSN is a call that is representative of all calls in the region - described by the PSEUDOS_LIVE_THROUGH_* sets, in terms of the registers - that it preserves and clobbers. */ +/* Check whether REGNO lives through calls and setjmps and clear + the corresponding bits in PSEUDOS_LIVE_THROUGH_CALLS and + PSEUDOS_LIVE_THROUGH_SETJUMPS. All calls in the region described + by PSEUDOS_LIVE_THROUGH_CALLS have the given ABI. */ static inline void -check_pseudos_live_through_calls (int regno, - HARD_REG_SET last_call_used_reg_set, - rtx_insn *call_insn) +check_pseudos_live_through_calls (int regno, const function_abi &abi) { - int hr; - rtx_insn *old_call_insn; - if (! sparseset_bit_p (pseudos_live_through_calls, regno)) return; - function_abi callee_abi = insn_callee_abi (call_insn); - old_call_insn = lra_reg_info[regno].call_insn; - if (!old_call_insn - || (targetm.return_call_with_max_clobbers - && targetm.return_call_with_max_clobbers (old_call_insn, call_insn) - == call_insn)) - lra_reg_info[regno].call_insn = call_insn; + machine_mode mode = PSEUDO_REGNO_MODE (regno); sparseset_clear_bit (pseudos_live_through_calls, regno); - lra_reg_info[regno].conflict_hard_regs |= last_call_used_reg_set; - - for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++) - if (targetm.hard_regno_call_part_clobbered (callee_abi.id (), hr, - PSEUDO_REGNO_MODE (regno))) - add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs, - PSEUDO_REGNO_MODE (regno), hr); + lra_reg_info[regno].conflict_hard_regs |= abi.mode_clobbers (mode); if (! sparseset_bit_p (pseudos_live_through_setjumps, regno)) return; sparseset_clear_bit (pseudos_live_through_setjumps, regno); @@ -630,19 +611,6 @@ reg_early_clobber_p (const struct lra_insn_reg *reg, int n_alt) && TEST_BIT (reg->early_clobber_alts, n_alt))); } -/* Return true if call instructions CALL1 and CALL2 use ABIs that - preserve the same set of registers. */ - -static bool -calls_have_same_clobbers_p (rtx_insn *call1, rtx_insn *call2) -{ - if (!targetm.return_call_with_max_clobbers) - return false; - - return (targetm.return_call_with_max_clobbers (call1, call2) == call1 - && targetm.return_call_with_max_clobbers (call2, call1) == call2); -} - /* Process insns of the basic block BB to update pseudo live ranges, pseudo hard register conflicts, and insn notes. We do it on backward scan of BB insns. CURR_POINT is the program point where @@ -662,15 +630,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) rtx_insn *next; rtx link, *link_loc; bool need_curr_point_incr; - HARD_REG_SET last_call_used_reg_set; - rtx_insn *call_insn = NULL; - rtx_insn *last_call_insn = NULL; + /* Only has a meaningful value once we've seen a call. */ + function_abi last_call_abi = default_function_abi; reg_live_out = df_get_live_out (bb); sparseset_clear (pseudos_live); sparseset_clear (pseudos_live_through_calls); sparseset_clear (pseudos_live_through_setjumps); - CLEAR_HARD_REG_SET (last_call_used_reg_set); REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out); hard_regs_live &= ~eliminable_regset; EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi) @@ -876,9 +842,8 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) { update_pseudo_point (reg->regno, curr_point, USE_POINT); mark_regno_live (reg->regno, reg->biggest_mode); - check_pseudos_live_through_calls (reg->regno, - last_call_used_reg_set, - call_insn); + /* ??? Should be a no-op for unused registers. */ + check_pseudos_live_through_calls (reg->regno, last_call_abi); } if (!HARD_REGISTER_NUM_P (reg->regno)) @@ -927,37 +892,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) if (call_p) { - call_insn = curr_insn; - if (! flag_ipa_ra && ! targetm.return_call_with_max_clobbers) - last_call_used_reg_set = call_used_or_fixed_regs; - else - { - HARD_REG_SET this_call_used_reg_set - = insn_callee_abi (curr_insn).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not - be needed. */ - this_call_used_reg_set |= fixed_reg_set; - - bool flush = (! hard_reg_set_empty_p (last_call_used_reg_set) - && (last_call_used_reg_set - != this_call_used_reg_set)) - || (last_call_insn && ! calls_have_same_clobbers_p - (call_insn, - last_call_insn)); - - EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j) - { - lra_reg_info[j].actual_call_used_reg_set - |= this_call_used_reg_set; + function_abi call_abi = insn_callee_abi (curr_insn); - if (flush) - check_pseudos_live_through_calls (j, - last_call_used_reg_set, - last_call_insn); - } - last_call_used_reg_set = this_call_used_reg_set; - last_call_insn = call_insn; - } + if (last_call_abi != call_abi) + EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j) + check_pseudos_live_through_calls (j, last_call_abi); + + last_call_abi = call_abi; sparseset_ior (pseudos_live_through_calls, pseudos_live_through_calls, pseudos_live); @@ -995,9 +936,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) if (reg->type == OP_IN) update_pseudo_point (reg->regno, curr_point, USE_POINT); mark_regno_live (reg->regno, reg->biggest_mode); - check_pseudos_live_through_calls (reg->regno, - last_call_used_reg_set, - call_insn); + check_pseudos_live_through_calls (reg->regno, last_call_abi); } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) @@ -1091,10 +1030,10 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) } /* Pseudos can't go in stack regs at the start of a basic block that - is reached by an abnormal edge. Likewise for call clobbered regs, - because caller-save, fixup_abnormal_edges and possibly the table - driven EH machinery are not quite ready to handle such pseudos - live across such edges. */ + is reached by an abnormal edge. Likewise for registers that are at + least partly call clobbered, because caller-save, fixup_abnormal_edges + and possibly the table driven EH machinery are not quite ready to + handle such pseudos live across such edges. */ if (bb_has_abnormal_pred (bb)) { #ifdef STACK_REGS @@ -1109,7 +1048,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) if (!cfun->has_nonlocal_label && has_abnormal_call_or_eh_pred_edge_p (bb)) for (px = 0; HARD_REGISTER_NUM_P (px); px++) - if (call_used_or_fixed_reg_p (px) + if (eh_edge_abi.clobbers_at_least_part_of_reg_p (px) #ifdef REAL_PIC_OFFSET_TABLE_REGNUM /* We should create a conflict of PIC pseudo with PIC hard reg as PIC hard reg can have a wrong value after @@ -1166,7 +1105,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) if (sparseset_cardinality (pseudos_live_through_calls) == 0) break; if (sparseset_bit_p (pseudos_live_through_calls, j)) - check_pseudos_live_through_calls (j, last_call_used_reg_set, call_insn); + check_pseudos_live_through_calls (j, last_call_abi); } for (i = 0; HARD_REGISTER_NUM_P (i); ++i) @@ -1400,7 +1339,6 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p) lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]); else lra_reg_info[i].biggest_mode = VOIDmode; - lra_reg_info[i].call_insn = NULL; if (!HARD_REGISTER_NUM_P (i) && lra_reg_info[i].nrefs != 0) { diff --git a/gcc/lra-remat.c b/gcc/lra-remat.c index ea6e817..ee7ebf6 100644 --- a/gcc/lra-remat.c +++ b/gcc/lra-remat.c @@ -65,16 +65,11 @@ along with GCC; see the file COPYING3. If not see #include "recog.h" #include "lra.h" #include "lra-int.h" +#include "function-abi.h" /* Number of candidates for rematerialization. */ static unsigned int cands_num; -/* The following is used for representation of call_used_or_fixed_regs in - form array whose elements are hard register numbers with nonzero bit - in CALL_USED_OR_FIXED_REGS. */ -static int call_used_regs_arr_len; -static int call_used_regs_arr[FIRST_PSEUDO_REGISTER]; - /* Bitmap used for different calculations. */ static bitmap_head temp_bitmap; @@ -633,9 +628,12 @@ set_bb_regs (basic_block bb, rtx_insn *insn) bitmap_set_bit (&subreg_regs, regno); } if (CALL_P (insn)) - for (int i = 0; i < call_used_regs_arr_len; i++) - bitmap_set_bit (&get_remat_bb_data (bb)->dead_regs, - call_used_regs_arr[i]); + { + /* Partially-clobbered registers might still be live. */ + HARD_REG_SET clobbers = insn_callee_abi (insn).full_reg_clobbers (); + bitmap_ior_into (&get_remat_bb_data (bb)->dead_regs, + bitmap_view (clobbers)); + } } /* Calculate changed_regs and dead_regs for each BB. */ @@ -698,7 +696,7 @@ reg_overlap_for_remat_p (lra_insn_reg *reg, rtx_insn *insn) /* Return true if a call used register is an input operand of INSN. */ static bool -call_used_input_regno_present_p (rtx_insn *insn) +call_used_input_regno_present_p (const function_abi &abi, rtx_insn *insn) { int iter; lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); @@ -709,8 +707,9 @@ call_used_input_regno_present_p (rtx_insn *insn) for (reg = (iter == 0 ? id->regs : static_id->hard_regs); reg != NULL; reg = reg->next) - if (reg->type == OP_IN && reg->regno < FIRST_PSEUDO_REGISTER - && TEST_HARD_REG_BIT (call_used_or_fixed_regs, reg->regno)) + if (reg->type == OP_IN + && reg->regno < FIRST_PSEUDO_REGISTER + && abi.clobbers_reg_p (reg->biggest_mode, reg->regno)) return true; return false; } @@ -799,18 +798,21 @@ calculate_gen_cands (void) } if (CALL_P (insn)) - EXECUTE_IF_SET_IN_BITMAP (gen_insns, 0, uid, bi) - { - rtx_insn *insn2 = lra_insn_recog_data[uid]->insn; + { + function_abi callee_abi = insn_callee_abi (insn); + EXECUTE_IF_SET_IN_BITMAP (gen_insns, 0, uid, bi) + { + rtx_insn *insn2 = lra_insn_recog_data[uid]->insn; - cand = insn_to_cand[INSN_UID (insn2)]; - gcc_assert (cand != NULL); - if (call_used_input_regno_present_p (insn2)) - { - bitmap_clear_bit (gen_cands, cand->index); - bitmap_set_bit (&temp_bitmap, uid); - } - } + cand = insn_to_cand[INSN_UID (insn2)]; + gcc_assert (cand != NULL); + if (call_used_input_regno_present_p (callee_abi, insn2)) + { + bitmap_clear_bit (gen_cands, cand->index); + bitmap_set_bit (&temp_bitmap, uid); + } + } + } bitmap_and_compl_into (gen_insns, &temp_bitmap); cand = insn_to_cand[INSN_UID (insn)]; @@ -1205,13 +1207,16 @@ do_remat (void) } if (CALL_P (insn)) - EXECUTE_IF_SET_IN_BITMAP (avail_cands, 0, cid, bi) - { - cand = all_cands[cid]; + { + function_abi callee_abi = insn_callee_abi (insn); + EXECUTE_IF_SET_IN_BITMAP (avail_cands, 0, cid, bi) + { + cand = all_cands[cid]; - if (call_used_input_regno_present_p (cand->insn)) - bitmap_set_bit (&temp_bitmap, cand->index); - } + if (call_used_input_regno_present_p (callee_abi, cand->insn)) + bitmap_set_bit (&temp_bitmap, cand->index); + } + } bitmap_and_compl_into (avail_cands, &temp_bitmap); @@ -1307,10 +1312,6 @@ lra_remat (void) insn_to_cand_activation = XCNEWVEC (cand_t, get_max_uid ()); regno_cands = XCNEWVEC (cand_t, max_regno); all_cands.create (8000); - call_used_regs_arr_len = 0; - for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (call_used_or_fixed_reg_p (i)) - call_used_regs_arr[call_used_regs_arr_len++] = i; initiate_cand_table (); create_remat_bb_data (); bitmap_initialize (&temp_bitmap, ®_obstack); diff --git a/gcc/lra.c b/gcc/lra.c index 65c0877..a6e6a8d 100644 --- a/gcc/lra.c +++ b/gcc/lra.c @@ -121,6 +121,7 @@ along with GCC; see the file COPYING3. If not see #include "lra.h" #include "lra-int.h" #include "print-rtl.h" +#include "function-abi.h" /* Dump bitmap SET with TITLE and BB INDEX. */ void @@ -1323,7 +1324,6 @@ initialize_lra_reg_info_element (int i) lra_reg_info[i].no_stack_p = false; #endif CLEAR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs); - CLEAR_HARD_REG_SET (lra_reg_info[i].actual_call_used_reg_set); lra_reg_info[i].preferred_hard_regno1 = -1; lra_reg_info[i].preferred_hard_regno2 = -1; lra_reg_info[i].preferred_hard_regno_profit1 = 0; @@ -1336,7 +1336,6 @@ initialize_lra_reg_info_element (int i) lra_reg_info[i].val = get_new_reg_value (); lra_reg_info[i].offset = 0; lra_reg_info[i].copies = NULL; - lra_reg_info[i].call_insn = NULL; } /* Initialize common reg info and copies. */ @@ -2420,7 +2419,9 @@ lra (FILE *f) if (crtl->saves_all_registers) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (!call_used_or_fixed_reg_p (i) && !fixed_regs[i] && !LOCAL_REGNO (i)) + if (!crtl->abi->clobbers_full_reg_p (i) + && !fixed_regs[i] + && !LOCAL_REGNO (i)) df_set_regs_ever_live (i, true); /* We don't DF from now and avoid its using because it is to @@ -2478,19 +2479,7 @@ lra (FILE *f) } /* Do inheritance only for regular algorithms. */ if (! lra_simple_p) - { - if (flag_ipa_ra) - { - if (live_p) - lra_clear_live_ranges (); - /* As a side-effect of lra_create_live_ranges, we calculate - actual_call_used_reg_set, which is needed during - lra_inheritance. */ - lra_create_live_ranges (true, true); - live_p = true; - } - lra_inheritance (); - } + lra_inheritance (); if (live_p) lra_clear_live_ranges (); bool fails_p; diff --git a/gcc/target.def b/gcc/target.def index 3bdbb8d..1f011ed 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5837,20 +5837,6 @@ for targets that don't have partly call-clobbered registers.", hook_bool_uint_uint_mode_false) DEFHOOK -(return_call_with_max_clobbers, - "This hook returns a pointer to the call that partially clobbers the\n\ -most registers. If a platform supports multiple ABIs where the registers\n\ -that are partially clobbered may vary, this function compares two\n\ -calls and returns a pointer to the one that clobbers the most registers.\n\ -If both calls clobber the same registers, @var{call_1} must be returned.\n\ -\n\ -The registers clobbered in different ABIs must be a proper subset or\n\ -superset of all other ABIs. @var{call_1} must always be a call insn,\n\ -call_2 may be NULL or a call insn.", - rtx_insn *, (rtx_insn *call_1, rtx_insn *call_2), - NULL) - -DEFHOOK (get_multilib_abi_name, "This hook returns name of multilib ABI name.", const char *, (void), -- cgit v1.1 From 3df28f006a7ceaf958a9ce9d100dd1e266e18f26 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:03 +0000 Subject: Remove global call sets: postreload.c The "|= fixed_regs" in reload_combine isn't necessary, since the set is only used to determine which values have changed (rather than, for example, which registers are available for use). In reload_cse_move2add we can be accurate about which registers are still available. BLKmode indicates a continuation of the previous register, and since clobbers_reg_p handles multi-register values, it's enough to skip over BLKmode entries and just test the start register. 2019-09-30 Richard Sandiford gcc/ * postreload.c (reload_combine_recognize_pattern): Use crtl->abi when deciding whether a register is free for use after RA. (reload_combine): Remove unnecessary use of fixed_reg_set. (reload_cse_move2add): Use insn_callee_abi to get the ABI of the call insn target. Use reg_mode when testing whether a register is no longer available. From-SVN: r276328 --- gcc/ChangeLog | 9 +++++++++ gcc/postreload.c | 17 ++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index df3a2f6..208d32f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,14 @@ 2019-09-30 Richard Sandiford + * postreload.c (reload_combine_recognize_pattern): Use crtl->abi + when deciding whether a register is free for use after RA. + (reload_combine): Remove unnecessary use of fixed_reg_set. + (reload_cse_move2add): Use insn_callee_abi to get the ABI of the + call insn target. Use reg_mode when testing whether a register + is no longer available. + +2019-09-30 Richard Sandiford + * target.def (return_call_with_max_clobbers): Delete. * doc/tm.texi.in (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): Delete. * doc/tm.texi: Regenerate. diff --git a/gcc/postreload.c b/gcc/postreload.c index 467df7b..e66377e 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -1136,7 +1136,8 @@ reload_combine_recognize_pattern (rtx_insn *insn) if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i) && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES && reg_state[i].store_ruid <= reg_state[regno].use_ruid - && (call_used_or_fixed_reg_p (i) || df_regs_ever_live_p (i)) + && (crtl->abi->clobbers_full_reg_p (i) + || df_regs_ever_live_p (i)) && (!frame_pointer_needed || i != HARD_FRAME_POINTER_REGNUM) && !fixed_regs[i] && !global_regs[i] && hard_regno_nregs (i, GET_MODE (reg)) == 1 @@ -1332,9 +1333,6 @@ reload_combine (void) { rtx link; HARD_REG_SET used_regs = insn_callee_abi (insn).full_reg_clobbers (); - /* ??? This preserves traditional behavior; it might not be - needed. */ - used_regs |= fixed_reg_set; for (r = 0; r < FIRST_PSEUDO_REGISTER; r++) if (TEST_HARD_REG_BIT (used_regs, r)) @@ -2126,12 +2124,13 @@ reload_cse_move2add (rtx_insn *first) unknown values. */ if (CALL_P (insn)) { + function_abi callee_abi = insn_callee_abi (insn); for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) - { - if (call_used_or_fixed_reg_p (i)) - /* Reset the information about this register. */ - reg_mode[i] = VOIDmode; - } + if (reg_mode[i] != VOIDmode + && reg_mode[i] != BLKmode + && callee_abi.clobbers_reg_p (reg_mode[i], i)) + /* Reset the information about this register. */ + reg_mode[i] = VOIDmode; } } return changed; -- cgit v1.1 From 7187286ef3381ebde6377015fe776d6d11329a32 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:07 +0000 Subject: Remove global call sets: postreload-gcse.c This is another case in which we should conservatively treat partial kills as full kills. 2019-09-30 Richard Sandiford gcc/ * postreload-gcse.c: Include regs.h and function-abi.h. (record_opr_changes): Use insn_callee_abi to get the ABI of the call insn target. Conservatively assume that partially-clobbered registers are altered. From-SVN: r276329 --- gcc/ChangeLog | 7 +++++++ gcc/postreload-gcse.c | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 208d32f..a30c38d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2019-09-30 Richard Sandiford + * postreload-gcse.c: Include regs.h and function-abi.h. + (record_opr_changes): Use insn_callee_abi to get the ABI of the + call insn target. Conservatively assume that partially-clobbered + registers are altered. + +2019-09-30 Richard Sandiford + * postreload.c (reload_combine_recognize_pattern): Use crtl->abi when deciding whether a register is free for use after RA. (reload_combine): Remove unnecessary use of fixed_reg_set. diff --git a/gcc/postreload-gcse.c b/gcc/postreload-gcse.c index a709838..0c12b38 100644 --- a/gcc/postreload-gcse.c +++ b/gcc/postreload-gcse.c @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "gcse-common.h" #include "gcse.h" +#include "regs.h" +#include "function-abi.h" /* The following code implements gcse after reload, the purpose of this pass is to cleanup redundant loads generated by reload and other @@ -772,7 +774,11 @@ record_opr_changes (rtx_insn *insn) { unsigned int regno; hard_reg_set_iterator hrsi; - EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi) + /* We don't track modes of hard registers, so we need to be + conservative and assume that partial kills are full kills. */ + HARD_REG_SET callee_clobbers + = insn_callee_abi (insn).full_and_partial_reg_clobbers (); + EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi) record_last_reg_set_info_regno (insn, regno); if (! RTL_CONST_OR_PURE_CALL_P (insn)) -- cgit v1.1 From 35b81ea3f7412360d6f108c5b9b7a8a1b9f3b138 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:10 +0000 Subject: Remove global call sets: recog.c 2019-09-30 Richard Sandiford gcc/ * recog.c: Include function-abi.h. (peep2_find_free_register): Use crtl->abi when deciding whether a register is free for use after RA. From-SVN: r276330 --- gcc/ChangeLog | 6 ++++++ gcc/recog.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a30c38d..24f73f8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * recog.c: Include function-abi.h. + (peep2_find_free_register): Use crtl->abi when deciding whether + a register is free for use after RA. + +2019-09-30 Richard Sandiford + * postreload-gcse.c: Include regs.h and function-abi.h. (record_opr_changes): Use insn_callee_abi to get the ABI of the call insn target. Conservatively assume that partially-clobbered diff --git a/gcc/recog.c b/gcc/recog.c index f3e8a4c..aa31ffa 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgcleanup.h" #include "reload.h" #include "tree-pass.h" +#include "function-abi.h" #ifndef STACK_POP_CODE #if STACK_GROWS_DOWNWARD @@ -3227,7 +3228,7 @@ peep2_find_free_register (int from, int to, const char *class_str, break; } /* And that we don't create an extra save/restore. */ - if (! call_used_or_fixed_reg_p (regno + j) + if (! crtl->abi->clobbers_full_reg_p (regno + j) && ! df_regs_ever_live_p (regno + j)) { success = 0; -- cgit v1.1 From 30503f4ea491b9d6b9da00889155ecaa5d15cfb9 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:14 +0000 Subject: Remove global call sets: regcprop.c This is a direct replacement of an existing test for fully and partially clobbered registers. 2019-09-30 Richard Sandiford gcc/ * regcprop.c (copyprop_hardreg_forward_1): Use the recorded mode of the register when deciding whether it is no longer available after a call. From-SVN: r276331 --- gcc/ChangeLog | 6 ++++++ gcc/regcprop.c | 11 +++++------ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 24f73f8..d1534e4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * regcprop.c (copyprop_hardreg_forward_1): Use the recorded + mode of the register when deciding whether it is no longer + available after a call. + +2019-09-30 Richard Sandiford + * recog.c: Include function-abi.h. (peep2_find_free_register): Use crtl->abi when deciding whether a register is free for use after RA. diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 0bdd6b9..87cc394 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -1055,16 +1055,15 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) function_abi callee_abi = insn_callee_abi (insn); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((callee_abi.clobbers_full_reg_p (regno) - || (targetm.hard_regno_call_part_clobbered - (callee_abi.id (), regno, vd->e[regno].mode))) + if (vd->e[regno].mode != VOIDmode + && callee_abi.clobbers_reg_p (vd->e[regno].mode, regno) && (regno < set_regno || regno >= set_regno + set_nregs)) kill_value_regno (regno, 1, vd); /* If SET was seen in CALL_INSN_FUNCTION_USAGE, and SET_SRC - of the SET isn't in regs_invalidated_by_call hard reg set, - but instead among CLOBBERs on the CALL_INSN, we could wrongly - assume the value in it is still live. */ + of the SET isn't clobbered by CALLEE_ABI, but instead among + CLOBBERs on the CALL_INSN, we could wrongly assume the + value in it is still live. */ if (ksvd.ignore_set_reg) kill_clobbered_values (insn, vd); } -- cgit v1.1 From 0ce77f463d1d150e70a91807502d628492ca7ae5 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:19 +0000 Subject: Remove global call sets: regrename.c This patch makes regrename use a similar mask-and-clobber-set pair to IRA when tracking whether registers are clobbered by calls in a region. Testing for a nonzero ABI mask is equivalent to testing for a register that crosses a call. Since AArch64 and c6x use regrename.h, they need to be updated to include function-abi.h first. AIUI this is preferred over including function-abi.h in regrename.h. 2019-09-30 Richard Sandiford gcc/ * regrename.h (du_head::call_clobber_mask): New field. (du_head::need_caller_save_reg): Replace with... (du_head::call_abis): ...this new field. * regrename.c: Include function-abi.h. (call_clobbered_in_chain_p): New function. (check_new_reg_p): Use crtl->abi when deciding whether a register is free for use after RA. Use call_clobbered_in_chain_p to test whether a candidate register would be clobbered by a call. (find_rename_reg): Don't add call-clobber conflicts here. (rename_chains): Check call_abis instead of need_caller_save_reg. (merge_chains): Update for changes to du_head. (build_def_use): Use insn_callee_abi to get the ABI of the call insn target. Record the ABI identifier in call_abis and the set of fully or partially clobbered registers in call_clobber_mask. Add fully-clobbered registers to hard_conflicts here rather than in find_rename_reg. * config/aarch64/cortex-a57-fma-steering.c: Include function-abi.h. (rename_single_chain): Check call_abis instead of need_caller_save_reg. * config/aarch64/falkor-tag-collision-avoidance.c: Include function-abi.h. * config/c6x/c6x.c: Likewise. From-SVN: r276332 --- gcc/ChangeLog | 24 +++++++++++++ gcc/config/aarch64/cortex-a57-fma-steering.c | 3 +- .../aarch64/falkor-tag-collision-avoidance.c | 1 + gcc/config/c6x/c6x.c | 1 + gcc/regrename.c | 41 ++++++++++++++-------- gcc/regrename.h | 7 ++-- 6 files changed, 59 insertions(+), 18 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d1534e4..6458d2b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,29 @@ 2019-09-30 Richard Sandiford + * regrename.h (du_head::call_clobber_mask): New field. + (du_head::need_caller_save_reg): Replace with... + (du_head::call_abis): ...this new field. + * regrename.c: Include function-abi.h. + (call_clobbered_in_chain_p): New function. + (check_new_reg_p): Use crtl->abi when deciding whether a register + is free for use after RA. Use call_clobbered_in_chain_p to test + whether a candidate register would be clobbered by a call. + (find_rename_reg): Don't add call-clobber conflicts here. + (rename_chains): Check call_abis instead of need_caller_save_reg. + (merge_chains): Update for changes to du_head. + (build_def_use): Use insn_callee_abi to get the ABI of the call insn + target. Record the ABI identifier in call_abis and the set of + fully or partially clobbered registers in call_clobber_mask. + Add fully-clobbered registers to hard_conflicts here rather + than in find_rename_reg. + * config/aarch64/cortex-a57-fma-steering.c: Include function-abi.h. + (rename_single_chain): Check call_abis instead of need_caller_save_reg. + * config/aarch64/falkor-tag-collision-avoidance.c: Include + function-abi.h. + * config/c6x/c6x.c: Likewise. + +2019-09-30 Richard Sandiford + * regcprop.c (copyprop_hardreg_forward_1): Use the recorded mode of the register when deciding whether it is no longer available after a call. diff --git a/gcc/config/aarch64/cortex-a57-fma-steering.c b/gcc/config/aarch64/cortex-a57-fma-steering.c index 3e890ad..d8e6038 100644 --- a/gcc/config/aarch64/cortex-a57-fma-steering.c +++ b/gcc/config/aarch64/cortex-a57-fma-steering.c @@ -37,6 +37,7 @@ #include "insn-attr.h" #include "context.h" #include "tree-pass.h" +#include "function-abi.h" #include "regrename.h" #include "aarch64-protos.h" @@ -281,7 +282,7 @@ rename_single_chain (du_head_p head, HARD_REG_SET *unavailable) { fprintf (dump_file, "Register %s in insn %d", reg_names[reg], INSN_UID (head->first->insn)); - if (head->need_caller_save_reg) + if (head->call_abis) fprintf (dump_file, " crosses a call"); } diff --git a/gcc/config/aarch64/falkor-tag-collision-avoidance.c b/gcc/config/aarch64/falkor-tag-collision-avoidance.c index 9faed40..35ca792 100644 --- a/gcc/config/aarch64/falkor-tag-collision-avoidance.c +++ b/gcc/config/aarch64/falkor-tag-collision-avoidance.c @@ -38,6 +38,7 @@ #include "optabs.h" #include "regs.h" #include "recog.h" +#include "function-abi.h" #include "regrename.h" #include "print-rtl.h" diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c index e593273..f8e8295 100644 --- a/gcc/config/c6x/c6x.c +++ b/gcc/config/c6x/c6x.c @@ -55,6 +55,7 @@ #include "sel-sched.h" #include "debug.h" #include "hw-doloop.h" +#include "function-abi.h" #include "regrename.h" #include "dumpfile.h" #include "builtins.h" diff --git a/gcc/regrename.c b/gcc/regrename.c index 6a2442bd..8c3bae8 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -33,6 +33,7 @@ #include "addresses.h" #include "cfganal.h" #include "tree-pass.h" +#include "function-abi.h" #include "regrename.h" /* This file implements the RTL register renaming pass of the compiler. It is @@ -303,6 +304,18 @@ merge_overlapping_regs (HARD_REG_SET *pset, class du_head *head) } } +/* Return true if (reg:MODE REGNO) would be clobbered by a call covered + by THIS_HEAD. */ + +static bool +call_clobbered_in_chain_p (du_head *this_head, machine_mode mode, + unsigned int regno) +{ + return call_clobbered_in_region_p (this_head->call_abis, + this_head->call_clobber_mask, + mode, regno); +} + /* Check if NEW_REG can be the candidate register to rename for REG in THIS_HEAD chain. THIS_UNAVAILABLE is a set of unavailable hard registers. */ @@ -322,7 +335,7 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg, || global_regs[new_reg + i] /* Can't use regs which aren't saved by the prologue. */ || (! df_regs_ever_live_p (new_reg + i) - && ! call_used_or_fixed_reg_p (new_reg + i)) + && ! crtl->abi->clobbers_full_reg_p (new_reg + i)) #ifdef LEAF_REGISTERS /* We can't use a non-leaf register if we're in a leaf function. */ @@ -337,11 +350,8 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg, for (tmp = this_head->first; tmp; tmp = tmp->next_use) if ((!targetm.hard_regno_mode_ok (new_reg, GET_MODE (*tmp->loc)) && ! DEBUG_INSN_P (tmp->insn)) - || (this_head->need_caller_save_reg - && ! (targetm.hard_regno_call_part_clobbered - (0, reg, GET_MODE (*tmp->loc))) - && (targetm.hard_regno_call_part_clobbered - (0, new_reg, GET_MODE (*tmp->loc))))) + || call_clobbered_in_chain_p (this_head, GET_MODE (*tmp->loc), + new_reg)) return false; return true; @@ -363,12 +373,6 @@ find_rename_reg (du_head_p this_head, enum reg_class super_class, int pass; int best_new_reg = old_reg; - /* Further narrow the set of registers we can use for renaming. - If the chain needs a call-saved register, mark the call-used - registers as unavailable. */ - if (this_head->need_caller_save_reg) - *unavailable |= call_used_or_fixed_regs; - /* Mark registers that overlap this chain's lifetime as unavailable. */ merge_overlapping_regs (unavailable, this_head); @@ -499,7 +503,7 @@ rename_chains (void) { fprintf (dump_file, "Register %s in insn %d", reg_names[reg], INSN_UID (this_head->first->insn)); - if (this_head->need_caller_save_reg) + if (this_head->call_abis) fprintf (dump_file, " crosses a call"); } @@ -680,7 +684,8 @@ merge_chains (du_head_p c1, du_head_p c2) c1->hard_conflicts |= c2->hard_conflicts; bitmap_ior_into (&c1->conflicts, &c2->conflicts); - c1->need_caller_save_reg |= c2->need_caller_save_reg; + c1->call_clobber_mask |= c2->call_clobber_mask; + c1->call_abis |= c2->call_abis; c1->cannot_rename |= c2->cannot_rename; } @@ -1834,9 +1839,15 @@ build_def_use (basic_block bb) requires a caller-saved reg. */ if (CALL_P (insn)) { + function_abi callee_abi = insn_callee_abi (insn); class du_head *p; for (p = open_chains; p; p = p->next_chain) - p->need_caller_save_reg = 1; + { + p->call_abis |= (1 << callee_abi.id ()); + p->call_clobber_mask + |= callee_abi.full_and_partial_reg_clobbers (); + p->hard_conflicts |= callee_abi.full_reg_clobbers (); + } } /* Step 5: Close open chains that overlap writes. Similar to diff --git a/gcc/regrename.h b/gcc/regrename.h index 2fe12d5..a678963 100644 --- a/gcc/regrename.h +++ b/gcc/regrename.h @@ -41,9 +41,12 @@ public: bitmap_head conflicts; /* Conflicts with untracked hard registers. */ HARD_REG_SET hard_conflicts; + /* Which registers are fully or partially clobbered by the calls that + the chain crosses. */ + HARD_REG_SET call_clobber_mask; - /* Nonzero if the chain crosses a call. */ - unsigned int need_caller_save_reg:1; + /* A bitmask of ABIs used by the calls that the chain crosses. */ + unsigned int call_abis : NUM_ABI_IDS; /* Nonzero if the register is used in a way that prevents renaming, such as the SET_DEST of a CALL_INSN or an asm operand that used to be a hard register. */ -- cgit v1.1 From 12e20dde63c77eb696118e2624aacf8f11feb1f9 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:23 +0000 Subject: Remove global call sets: reload.c The inheritance code in find_equiv_reg can use clobbers_reg_p to test whether a call clobbers either of the equivalent registers. reload and find_reg use crtl->abi to test whether a register needs to be saved in the prologue before use. reload_as_needed can use full_and_partial_reg_clobbers and thus avoid needing to keep its own record of which registers are part call-clobbered. 2019-09-30 Richard Sandiford gcc/ * reload.c: Include function-abi.h. (find_equiv_reg): Use clobbers_reg_p to test whether either of the equivalent registers is clobbered by a call. * reload1.c: Include function-abi.h. (reg_reloaded_call_part_clobbered): Delete. (reload): Use crtl->abi to test which registers would need saving in the prologue before use. (find_reg): Likewise. (emit_reload_insns): Remove code for reg_reloaded_call_part_clobbered. (reload_as_needed): Likewise. Use full_and_partial_reg_clobbers instead of call_used_or_fixed_regs | reg_reloaded_call_part_clobbered. From-SVN: r276333 --- gcc/ChangeLog | 14 ++++++++++++++ gcc/reload.c | 24 ++++++++++-------------- gcc/reload1.c | 38 ++++++-------------------------------- 3 files changed, 30 insertions(+), 46 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6458d2b..3887c43 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,19 @@ 2019-09-30 Richard Sandiford + * reload.c: Include function-abi.h. + (find_equiv_reg): Use clobbers_reg_p to test whether either + of the equivalent registers is clobbered by a call. + * reload1.c: Include function-abi.h. + (reg_reloaded_call_part_clobbered): Delete. + (reload): Use crtl->abi to test which registers would need + saving in the prologue before use. + (find_reg): Likewise. + (emit_reload_insns): Remove code for reg_reloaded_call_part_clobbered. + (reload_as_needed): Likewise. Use full_and_partial_reg_clobbers + instead of call_used_or_fixed_regs | reg_reloaded_call_part_clobbered. + +2019-09-30 Richard Sandiford + * regrename.h (du_head::call_clobber_mask): New field. (du_head::need_caller_save_reg): Replace with... (du_head::call_abis): ...this new field. diff --git a/gcc/reload.c b/gcc/reload.c index b760130..8582b48 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -106,6 +106,7 @@ a register with any other reload. */ #include "reload.h" #include "addresses.h" #include "params.h" +#include "function-abi.h" /* True if X is a constant that can be forced into the constant pool. MODE is the mode of the operand, or VOIDmode if not known. */ @@ -6904,24 +6905,19 @@ find_equiv_reg (rtx goal, rtx_insn *insn, enum reg_class rclass, int other, if either of the two is in a call-clobbered register, or memory. */ if (CALL_P (p)) { - int i; - if (goal_mem || need_stable_sp) return 0; - if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER) - for (i = 0; i < nregs; ++i) - if (call_used_or_fixed_reg_p (regno + i) - || targetm.hard_regno_call_part_clobbered (0, regno + i, - mode)) - return 0; + function_abi callee_abi = insn_callee_abi (p); + if (regno >= 0 + && regno < FIRST_PSEUDO_REGISTER + && callee_abi.clobbers_reg_p (mode, regno)) + return 0; - if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER) - for (i = 0; i < valuenregs; ++i) - if (call_used_or_fixed_reg_p (valueno + i) - || targetm.hard_regno_call_part_clobbered (0, valueno + i, - mode)) - return 0; + if (valueno >= 0 + && valueno < FIRST_PSEUDO_REGISTER + && callee_abi.clobbers_reg_p (mode, valueno)) + return 0; } if (INSN_P (p)) diff --git a/gcc/reload1.c b/gcc/reload1.c index 39dff6a..79a7ff6 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "except.h" #include "dumpfile.h" #include "rtl-iter.h" +#include "function-abi.h" /* This file contains the reload pass of the compiler, which is run after register allocation has been done. It checks that @@ -120,11 +121,6 @@ static HARD_REG_SET reg_reloaded_valid; This is only valid if reg_reloaded_contents is set and valid. */ static HARD_REG_SET reg_reloaded_dead; -/* Indicate whether the register's current value is one that is not - safe to retain across a call, even for registers that are normally - call-saved. This is only meaningful for members of reg_reloaded_valid. */ -static HARD_REG_SET reg_reloaded_call_part_clobbered; - /* Number of spill-regs so far; number of valid elements of spill_regs. */ static int n_spills; @@ -795,7 +791,7 @@ reload (rtx_insn *first, int global) if (crtl->saves_all_registers) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! call_used_or_fixed_reg_p (i) + if (! crtl->abi->clobbers_full_reg_p (i) && ! fixed_regs[i] && ! LOCAL_REGNO (i)) df_set_regs_ever_live (i, true); @@ -1908,8 +1904,8 @@ find_reg (class insn_chain *chain, int order) && (inv_reg_alloc_order[regno] < inv_reg_alloc_order[best_reg]) #else - && call_used_or_fixed_reg_p (regno) - && ! call_used_or_fixed_reg_p (best_reg) + && crtl->abi->clobbers_full_reg_p (regno) + && !crtl->abi->clobbers_full_reg_p (best_reg) #endif )) { @@ -4464,7 +4460,6 @@ reload_as_needed (int live_known) reg_last_reload_reg = XCNEWVEC (rtx, max_regno); INIT_REG_SET (®_has_output_reload); CLEAR_HARD_REG_SET (reg_reloaded_valid); - CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered); set_initial_elim_offsets (); @@ -4786,8 +4781,8 @@ reload_as_needed (int live_known) be partially clobbered by the call. */ else if (CALL_P (insn)) { - reg_reloaded_valid &= ~(call_used_or_fixed_regs - | reg_reloaded_call_part_clobbered); + reg_reloaded_valid + &= ~insn_callee_abi (insn).full_and_partial_reg_clobbers (); /* If this is a call to a setjmp-type function, we must not reuse any reload reg contents across the call; that will @@ -8193,13 +8188,6 @@ emit_reload_insns (class insn_chain *chain) : out_regno + k); reg_reloaded_insn[regno + k] = insn; SET_HARD_REG_BIT (reg_reloaded_valid, regno + k); - if (targetm.hard_regno_call_part_clobbered (0, regno + k, - mode)) - SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, - regno + k); - else - CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, - regno + k); } } } @@ -8273,13 +8261,6 @@ emit_reload_insns (class insn_chain *chain) : in_regno + k); reg_reloaded_insn[regno + k] = insn; SET_HARD_REG_BIT (reg_reloaded_valid, regno + k); - if (targetm.hard_regno_call_part_clobbered (0, regno + k, - mode)) - SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, - regno + k); - else - CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, - regno + k); } } } @@ -8388,13 +8369,6 @@ emit_reload_insns (class insn_chain *chain) reg_reloaded_insn[src_regno + k] = store_insn; CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + k); SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k); - if (targetm.hard_regno_call_part_clobbered - (0, src_regno + k, mode)) - SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, - src_regno + k); - else - CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, - src_regno + k); SET_HARD_REG_BIT (reg_is_output_reload, src_regno + k); if (note) SET_HARD_REG_BIT (reg_reloaded_died, src_regno); -- cgit v1.1 From 52053c3b536353510cac1c8370541b24847f8022 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:28 +0000 Subject: Remove global call sets: rtlanal.c The reg_set_p part is simple, since the caller is asking about a specific REG rtx, with a known register number and mode. The find_all_hard_reg_sets part emphasises that the "implicit" behaviour was always a bit suspect, since it includes fully-clobbered registers but not partially-clobbered registers. The only current user of this path is the c6x-specific scheduler predication code, and c6x doesn't have partly call-clobbered registers, so in practice it's fine. I've added a comment to try to disuade future users. (The !implicit path is OK and useful though.) 2019-09-30 Richard Sandiford gcc/ * rtlanal.c: Include function-abi.h. (reg_set_p): Use insn_callee_abi to get the ABI of the called function and clobbers_reg_p to test whether the register is call-clobbered. (find_all_hard_reg_sets): When implicit is true, use insn_callee_abi to get the ABI of the called function and full_reg_clobbers to get the set of fully call-clobbered registers. Warn about the pitfalls of using this mode. From-SVN: r276334 --- gcc/ChangeLog | 11 +++++++++++ gcc/rtlanal.c | 13 +++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3887c43..046fbfc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2019-09-30 Richard Sandiford + * rtlanal.c: Include function-abi.h. + (reg_set_p): Use insn_callee_abi to get the ABI of the called + function and clobbers_reg_p to test whether the register + is call-clobbered. + (find_all_hard_reg_sets): When implicit is true, use insn_callee_abi + to get the ABI of the called function and full_reg_clobbers to + get the set of fully call-clobbered registers. Warn about the + pitfalls of using this mode. + +2019-09-30 Richard Sandiford + * reload.c: Include function-abi.h. (find_equiv_reg): Use clobbers_reg_p to test whether either of the equivalent registers is clobbered by a call. diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 9c70eee..6adef47 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "addresses.h" #include "rtl-iter.h" #include "hard-reg-set.h" +#include "function-abi.h" /* Forward declarations */ static void set_of_1 (rtx, const_rtx, void *); @@ -1270,8 +1271,8 @@ reg_set_p (const_rtx reg, const_rtx insn) || (CALL_P (insn) && ((REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER - && overlaps_hard_reg_set_p (regs_invalidated_by_call, - GET_MODE (reg), REGNO (reg))) + && (insn_callee_abi (as_a (insn)) + .clobbers_reg_p (GET_MODE (reg), REGNO (reg)))) || MEM_P (reg) || find_reg_fusage (insn, CLOBBER, reg))))) return true; @@ -1486,7 +1487,11 @@ record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data) } /* Examine INSN, and compute the set of hard registers written by it. - Store it in *PSET. Should only be called after reload. */ + Store it in *PSET. Should only be called after reload. + + IMPLICIT is true if we should include registers that are fully-clobbered + by calls. This should be used with caution, since it doesn't include + partially-clobbered registers. */ void find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit) { @@ -1495,7 +1500,7 @@ find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit) CLEAR_HARD_REG_SET (*pset); note_stores (insn, record_hard_reg_sets, pset); if (CALL_P (insn) && implicit) - *pset |= call_used_or_fixed_regs; + *pset |= insn_callee_abi (insn).full_reg_clobbers (); for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC) record_hard_reg_sets (XEXP (link, 0), NULL, pset); -- cgit v1.1 From 2e2c6df346ab70eda7378a750cb96a1792de5b3b Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:34 +0000 Subject: Remove global call sets: sched-deps.c This is a straight replacement of an existing "full or partial" call-clobber check. 2019-09-30 Richard Sandiford gcc/ * sched-deps.c (deps_analyze_insn): Use the ABI of the target function to test whether a register is fully or partly clobbered. From-SVN: r276335 --- gcc/ChangeLog | 5 +++++ gcc/sched-deps.c | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 046fbfc..4c29a6c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-09-30 Richard Sandiford + * sched-deps.c (deps_analyze_insn): Use the ABI of the target + function to test whether a register is fully or partly clobbered. + +2019-09-30 Richard Sandiford + * rtlanal.c: Include function-abi.h. (reg_set_p): Use insn_callee_abi to get the ABI of the called function and clobbers_reg_p to test whether the register diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c index 87d0791..2571f04 100644 --- a/gcc/sched-deps.c +++ b/gcc/sched-deps.c @@ -3736,9 +3736,7 @@ deps_analyze_insn (class deps_desc *deps, rtx_insn *insn) Since we only have a choice between 'might be clobbered' and 'definitely not clobbered', we must include all partly call-clobbered registers here. */ - else if (targetm.hard_regno_call_part_clobbered - (callee_abi.id (), i, reg_raw_mode[i]) - || TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) + else if (callee_abi.clobbers_at_least_part_of_reg_p (i)) SET_REGNO_REG_SET (reg_pending_clobbers, i); /* We don't know what set of fixed registers might be used by the function, but it is certain that the stack pointer -- cgit v1.1 From 497b699b93759c7f84527f49a9644c3ea692405d Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:39 +0000 Subject: Remove global call sets: sel-sched.c The main change here is to replace a crosses_call boolean with a bitmask of the ABIs used by the crossed calls. For space reasons, I didn't also add a HARD_REG_SET that tracks the set of registers that are actually clobbered, which means that this is the one part of the series that doesn't benefit from -fipa-ra. The existing FIXME suggests that the current structures aren't the preferred way of representing this anyhow, and the pass already makes conservative assumptions about call-crossing registers. 2019-09-30 Richard Sandiford gcc/ * sel-sched-ir.h (_def::crosses_call): Replace with... (_def::crossed_call_abis): ..this new field. (def_list_add): Take a mask of ABIs instead of a crosses_call boolean. * sel-sched-ir.c (def_list_add): Likewise. Update initialization of _def accordingly. * sel-sched.c: Include function-abi.h. (hard_regs_data::regs_for_call_clobbered): Delete. (reg_rename::crosses_call): Replace with... (reg_rename::crossed_call_abis): ...this new field. (fur_static_params::crosses_call): Replace with... (fur_static_params::crossed_call_abis): ...this new field. (init_regs_for_mode): Don't initialize sel_hrd.regs_for_call_clobbered. (init_hard_regs_data): Use crtl->abi to test which registers the current function would need to save before it uses them. (mark_unavailable_hard_regs): Update handling of call-clobbered registers, using call_clobbers_in_region to find out which registers might be call-clobbered (but without taking -fipa-ra into account for now). Remove separate handling of partially call-clobbered registers. (verify_target_availability): Use crossed_call_abis instead of crosses_call. (get_spec_check_type_for_insn, find_used_regs): Likewise. (fur_orig_expr_found, fur_on_enter, fur_orig_expr_not_found): Likewise. From-SVN: r276336 --- gcc/ChangeLog | 27 +++++++++++++++++++ gcc/sel-sched-ir.c | 7 ++--- gcc/sel-sched-ir.h | 10 +++---- gcc/sel-sched.c | 78 +++++++++++++++++++++++++----------------------------- 4 files changed, 72 insertions(+), 50 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4c29a6c..6d2d20f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,32 @@ 2019-09-30 Richard Sandiford + * sel-sched-ir.h (_def::crosses_call): Replace with... + (_def::crossed_call_abis): ..this new field. + (def_list_add): Take a mask of ABIs instead of a crosses_call + boolean. + * sel-sched-ir.c (def_list_add): Likewise. Update initialization + of _def accordingly. + * sel-sched.c: Include function-abi.h. + (hard_regs_data::regs_for_call_clobbered): Delete. + (reg_rename::crosses_call): Replace with... + (reg_rename::crossed_call_abis): ...this new field. + (fur_static_params::crosses_call): Replace with... + (fur_static_params::crossed_call_abis): ...this new field. + (init_regs_for_mode): Don't initialize sel_hrd.regs_for_call_clobbered. + (init_hard_regs_data): Use crtl->abi to test which registers the + current function would need to save before it uses them. + (mark_unavailable_hard_regs): Update handling of call-clobbered + registers, using call_clobbers_in_region to find out which registers + might be call-clobbered (but without taking -fipa-ra into account + for now). Remove separate handling of partially call-clobbered + registers. + (verify_target_availability): Use crossed_call_abis instead of + crosses_call. + (get_spec_check_type_for_insn, find_used_regs): Likewise. + (fur_orig_expr_found, fur_on_enter, fur_orig_expr_not_found): Likewise. + +2019-09-30 Richard Sandiford + * sched-deps.c (deps_analyze_insn): Use the ABI of the target function to test whether a register is fully or partly clobbered. diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c index e4f5a45..8a1d414 100644 --- a/gcc/sel-sched-ir.c +++ b/gcc/sel-sched-ir.c @@ -311,9 +311,10 @@ flist_clear (flist_t *lp) flist_remove (lp); } -/* Add ORIGINAL_INSN the def list DL honoring CROSSES_CALL. */ +/* Add ORIGINAL_INSN the def list DL honoring CROSSED_CALL_ABIS. */ void -def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call) +def_list_add (def_list_t *dl, insn_t original_insn, + unsigned int crossed_call_abis) { def_t d; @@ -321,7 +322,7 @@ def_list_add (def_list_t *dl, insn_t original_insn, bool crosses_call) d = DEF_LIST_DEF (*dl); d->orig_insn = original_insn; - d->crosses_call = crosses_call; + d->crossed_call_abis = crossed_call_abis; } diff --git a/gcc/sel-sched-ir.h b/gcc/sel-sched-ir.h index b5824ae..ddc76a7 100644 --- a/gcc/sel-sched-ir.h +++ b/gcc/sel-sched-ir.h @@ -188,12 +188,12 @@ struct _def { insn_t orig_insn; - /* FIXME: Get rid of CROSSES_CALL in each def, since if we're moving up + /* FIXME: Get rid of CROSSED_CALL_ABIS in each def, since if we're moving up rhs from two different places, but only one of the code motion paths crosses a call, we can't use any of the call_used_regs, no matter which - path or whether all paths crosses a call. Thus we should move CROSSES_CALL - to static params. */ - bool crosses_call; + path or whether all paths crosses a call. Thus we should move + CROSSED_CALL_ABIS to static params. */ + unsigned int crossed_call_abis; }; typedef struct _def *def_t; @@ -1510,7 +1510,7 @@ extern void flist_tail_init (flist_tail_t); extern fence_t flist_lookup (flist_t, insn_t); extern void flist_clear (flist_t *); -extern void def_list_add (def_list_t *, insn_t, bool); +extern void def_list_add (def_list_t *, insn_t, unsigned int); /* Target context functions. */ extern tc_t create_target_context (bool); diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c index bf370b5..652784e 100644 --- a/gcc/sel-sched.c +++ b/gcc/sel-sched.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "sel-sched-dump.h" #include "sel-sched.h" #include "dbgcnt.h" +#include "function-abi.h" /* Implementation of selective scheduling approach. The below implementation follows the original approach with the following @@ -302,10 +303,6 @@ struct hard_regs_data that the whole set is not computed yet. */ HARD_REG_SET regs_for_rename[FIRST_PSEUDO_REGISTER]; - /* For every mode, this stores registers not available due to - call clobbering. */ - HARD_REG_SET regs_for_call_clobbered[NUM_MACHINE_MODES]; - /* All registers that are used or call used. */ HARD_REG_SET regs_ever_used; @@ -325,8 +322,8 @@ struct reg_rename /* These are *available* for renaming. */ HARD_REG_SET available_for_renaming; - /* Whether this code motion path crosses a call. */ - bool crosses_call; + /* The set of ABIs used by calls that the code motion path crosses. */ + unsigned int crossed_call_abis : NUM_ABI_IDS; }; /* A global structure that contains the needed information about harg @@ -390,8 +387,8 @@ struct fur_static_params /* Pointer to the list of original insns definitions. */ def_list_t *original_insns; - /* True if a code motion path contains a CALL insn. */ - bool crosses_call; + /* The set of ABIs used by calls that the code motion path crosses. */ + unsigned int crossed_call_abis : NUM_ABI_IDS; }; typedef struct fur_static_params *fur_static_params_p; @@ -1067,7 +1064,6 @@ init_regs_for_mode (machine_mode mode) int cur_reg; CLEAR_HARD_REG_SET (sel_hrd.regs_for_mode[mode]); - CLEAR_HARD_REG_SET (sel_hrd.regs_for_call_clobbered[mode]); for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++) { @@ -1102,10 +1098,6 @@ init_regs_for_mode (machine_mode mode) if (i >= 0) continue; - if (targetm.hard_regno_call_part_clobbered (0, cur_reg, mode)) - SET_HARD_REG_BIT (sel_hrd.regs_for_call_clobbered[mode], - cur_reg); - /* If the CUR_REG passed all the checks above, then it's ok. */ SET_HARD_REG_BIT (sel_hrd.regs_for_mode[mode], cur_reg); @@ -1123,7 +1115,8 @@ init_hard_regs_data (void) CLEAR_HARD_REG_SET (sel_hrd.regs_ever_used); for (cur_reg = 0; cur_reg < FIRST_PSEUDO_REGISTER; cur_reg++) - if (df_regs_ever_live_p (cur_reg) || call_used_or_fixed_reg_p (cur_reg)) + if (df_regs_ever_live_p (cur_reg) + || crtl->abi->clobbers_full_reg_p (cur_reg)) SET_HARD_REG_BIT (sel_hrd.regs_ever_used, cur_reg); /* Initialize registers that are valid based on mode when this is @@ -1193,7 +1186,7 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, SET_HARD_REG_SET (reg_rename_p->unavailable_hard_regs); /* Give a chance for original register, if it isn't in used_regs. */ - if (!def->crosses_call) + if (!def->crossed_call_abis) CLEAR_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs, regno); return; @@ -1224,13 +1217,20 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, reg_rename_p->unavailable_hard_regs |= sel_hrd.stack_regs; #endif - /* If there's a call on this path, make regs from call_used_or_fixed_regs - unavailable. */ - if (def->crosses_call) - reg_rename_p->unavailable_hard_regs |= call_used_or_fixed_regs; + mode = GET_MODE (orig_dest); + + /* If there's a call on this path, make regs from full_reg_clobbers + unavailable. - /* Stop here before reload: we need FRAME_REGS, STACK_REGS, and crosses_call, - but not register classes. */ + ??? It would be better to track the set of clobbered registers + directly, but that would be quite expensive in a def_t. */ + if (def->crossed_call_abis) + reg_rename_p->unavailable_hard_regs + |= call_clobbers_in_region (def->crossed_call_abis, + reg_class_contents[ALL_REGS], mode); + + /* Stop here before reload: we need FRAME_REGS, STACK_REGS, and + crossed_call_abis, but not register classes. */ if (!reload_completed) return; @@ -1238,19 +1238,11 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p, register class. */ reg_rename_p->available_for_renaming = reg_class_contents[cl]; - mode = GET_MODE (orig_dest); - /* Leave only registers available for this mode. */ if (!sel_hrd.regs_for_mode_ok[mode]) init_regs_for_mode (mode); reg_rename_p->available_for_renaming &= sel_hrd.regs_for_mode[mode]; - /* Exclude registers that are partially call clobbered. */ - if (def->crosses_call - && !targetm.hard_regno_call_part_clobbered (0, regno, mode)) - reg_rename_p->available_for_renaming - &= ~sel_hrd.regs_for_call_clobbered[mode]; - /* Leave only those that are ok to rename. */ EXECUTE_IF_SET_IN_HARD_REG_SET (reg_rename_p->available_for_renaming, 0, cur_reg, hrsi) @@ -1481,7 +1473,7 @@ choose_best_pseudo_reg (regset used_regs, /* Don't let register cross a call if it doesn't already cross one. This condition is written in accordance with that in sched-deps.c sched_analyze_reg(). */ - if (!reg_rename_p->crosses_call + if (!reg_rename_p->crossed_call_abis || REG_N_CALLS_CROSSED (orig_regno) > 0) return gen_rtx_REG (mode, orig_regno); } @@ -1508,7 +1500,8 @@ choose_best_pseudo_reg (regset used_regs, max_regno = max_reg_num (); maybe_extend_reg_info_p (); - REG_N_CALLS_CROSSED (REGNO (new_reg)) = reg_rename_p->crosses_call ? 1 : 0; + REG_N_CALLS_CROSSED (REGNO (new_reg)) + = reg_rename_p->crossed_call_abis ? 1 : 0; return new_reg; } @@ -1560,7 +1553,8 @@ verify_target_availability (expr_t expr, regset used_regs, as well. */ gcc_assert (scheduled_something_on_previous_fence || !live_available || !hard_available - || (!reload_completed && reg_rename_p->crosses_call + || (!reload_completed + && reg_rename_p->crossed_call_abis && REG_N_CALLS_CROSSED (regno) == 0)); } @@ -3248,7 +3242,7 @@ get_spec_check_type_for_insn (insn_t insn, expr_t expr) All the original operations found during the traversal are saved in the ORIGINAL_INSNS list. - REG_RENAME_P->CROSSES_CALL is true, if there is a call insn on the path + REG_RENAME_P->CROSSED_CALL_ABIS is true, if there is a call insn on the path from INSN to original insn. In this case CALL_USED_REG_SET will be added to unavailable hard regs at the point original operation is found. */ @@ -3269,7 +3263,7 @@ find_used_regs (insn_t insn, av_set_t orig_ops, regset used_regs, bitmap_clear (code_motion_visited_blocks); /* Init parameters for code_motion_path_driver. */ - sparams.crosses_call = false; + sparams.crossed_call_abis = 0; sparams.original_insns = original_insns; sparams.used_regs = used_regs; @@ -3278,7 +3272,7 @@ find_used_regs (insn_t insn, av_set_t orig_ops, regset used_regs, res = code_motion_path_driver (insn, orig_ops, NULL, &lparams, &sparams); - reg_rename_p->crosses_call |= sparams.crosses_call; + reg_rename_p->crossed_call_abis |= sparams.crossed_call_abis; gcc_assert (res == 1); gcc_assert (original_insns && *original_insns); @@ -6006,7 +6000,7 @@ move_op_orig_expr_found (insn_t insn, expr_t expr, /* The function is called when original expr is found. INSN - current insn traversed, EXPR - the corresponding expr found, - crosses_call and original_insns in STATIC_PARAMS are updated. */ + crossed_call_abis and original_insns in STATIC_PARAMS are updated. */ static void fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED, cmpd_local_params_p lparams ATTRIBUTE_UNUSED, @@ -6016,9 +6010,9 @@ fur_orig_expr_found (insn_t insn, expr_t expr ATTRIBUTE_UNUSED, regset tmp; if (CALL_P (insn)) - params->crosses_call = true; + params->crossed_call_abis |= 1 << insn_callee_abi (insn).id (); - def_list_add (params->original_insns, insn, params->crosses_call); + def_list_add (params->original_insns, insn, params->crossed_call_abis); /* Mark the registers that do not meet the following condition: (2) not among the live registers of the point @@ -6176,10 +6170,10 @@ fur_on_enter (insn_t insn ATTRIBUTE_UNUSED, cmpd_local_params_p local_params, least one insn in ORIGINAL_INSNS. */ gcc_assert (*sparams->original_insns); - /* Adjust CROSSES_CALL, since we may have come to this block along + /* Adjust CROSSED_CALL_ABIS, since we may have come to this block along different path. */ - DEF_LIST_DEF (*sparams->original_insns)->crosses_call - |= sparams->crosses_call; + DEF_LIST_DEF (*sparams->original_insns)->crossed_call_abis + |= sparams->crossed_call_abis; } else local_params->old_original_insns = *sparams->original_insns; @@ -6233,7 +6227,7 @@ fur_orig_expr_not_found (insn_t insn, av_set_t orig_ops, void *static_params) fur_static_params_p sparams = (fur_static_params_p) static_params; if (CALL_P (insn)) - sparams->crosses_call = true; + sparams->crossed_call_abis |= 1 << insn_callee_abi (insn).id (); else if (DEBUG_INSN_P (insn)) return true; -- cgit v1.1 From b21a62b6246d3344cf74c79965523e4f59db7459 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:44 +0000 Subject: Remove global call sets: shrink-wrap.c This is a straight replacement of "calls we can clobber without saving them first". 2019-09-30 Richard Sandiford gcc/ * shrink-wrap.c: Include function-abi.h. (requires_stack_frame_p): Use crtl->abi to test whether the current function can use a register without saving it first. From-SVN: r276337 --- gcc/ChangeLog | 6 ++++++ gcc/shrink-wrap.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6d2d20f..c47da4c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-09-30 Richard Sandiford + * shrink-wrap.c: Include function-abi.h. + (requires_stack_frame_p): Use crtl->abi to test whether the + current function can use a register without saving it first. + +2019-09-30 Richard Sandiford + * sel-sched-ir.h (_def::crosses_call): Replace with... (_def::crossed_call_abis): ..this new field. (def_list_add): Take a mask of ABIs instead of a crosses_call diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c index 0186966..2dc92c3 100644 --- a/gcc/shrink-wrap.c +++ b/gcc/shrink-wrap.c @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "regcprop.h" #include "rtl-iter.h" #include "valtrack.h" - +#include "function-abi.h" /* Return true if INSN requires the stack frame to be set up. PROLOGUE_USED contains the hard registers used in the function @@ -76,7 +76,7 @@ requires_stack_frame_p (rtx_insn *insn, HARD_REG_SET prologue_used, } if (hard_reg_set_intersect_p (hardregs, prologue_used)) return true; - hardregs &= ~call_used_or_fixed_regs; + hardregs &= ~crtl->abi->full_reg_clobbers (); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (TEST_HARD_REG_BIT (hardregs, regno) && df_regs_ever_live_p (regno)) -- cgit v1.1 From 7c3958812bd5e2e139c7f0adf8f03b505fda67f2 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:21:49 +0000 Subject: Hide regs_invalidated_by_call etc. The previous patches removed all target-independent uses of regs_invalidated_by_call, call_used_or_fixed_regs and call_used_or_fixed_reg_p. This patch therefore restricts them to target-specific code (and reginfo.c, which sets them up). 2019-09-30 Richard Sandiford gcc/ * hard-reg-set.h (regs_invalidated_by_call): Only define if IN_TARGET_CODE. (call_used_or_fixed_regs): Likewise. (call_used_or_fixed_reg_p): Likewise. * reginfo.c (regs_invalidated_by_call): New macro. From-SVN: r276338 --- gcc/ChangeLog | 8 ++++++++ gcc/hard-reg-set.h | 4 ++++ gcc/reginfo.c | 2 ++ 3 files changed, 14 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c47da4c..00a1731 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2019-09-30 Richard Sandiford + * hard-reg-set.h (regs_invalidated_by_call): Only define if + IN_TARGET_CODE. + (call_used_or_fixed_regs): Likewise. + (call_used_or_fixed_reg_p): Likewise. + * reginfo.c (regs_invalidated_by_call): New macro. + +2019-09-30 Richard Sandiford + * shrink-wrap.c: Include function-abi.h. (requires_stack_frame_p): Use crtl->abi to test whether the current function can use a register without saving it first. diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h index a54c167..6e7ceab 100644 --- a/gcc/hard-reg-set.h +++ b/gcc/hard-reg-set.h @@ -477,10 +477,12 @@ extern struct target_hard_regs *this_target_hard_regs; #endif #define savable_regs \ (this_target_hard_regs->x_savable_regs) +#ifdef IN_TARGET_CODE #define regs_invalidated_by_call \ (this_target_hard_regs->x_regs_invalidated_by_call) #define call_used_or_fixed_regs \ (regs_invalidated_by_call | fixed_reg_set) +#endif #define reg_alloc_order \ (this_target_hard_regs->x_reg_alloc_order) #define inv_reg_alloc_order \ @@ -509,6 +511,7 @@ extern const char * reg_class_names[]; #define REG_CAN_CHANGE_MODE_P(REGN, FROM, TO) \ (targetm.can_change_mode_class (FROM, TO, REGNO_REG_CLASS (REGN))) +#ifdef IN_TARGET_CODE /* Return true if register REGNO is either fixed or call-used (aka call-clobbered). */ @@ -517,5 +520,6 @@ call_used_or_fixed_reg_p (unsigned int regno) { return fixed_regs[regno] || this_target_hard_regs->x_call_used_regs[regno]; } +#endif #endif /* ! GCC_HARD_REG_SET_H */ diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 265157f..791c7a0 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -69,6 +69,8 @@ struct target_regs *this_target_regs = &default_target_regs; #define call_used_regs \ (this_target_hard_regs->x_call_used_regs) +#define regs_invalidated_by_call \ + (this_target_hard_regs->x_regs_invalidated_by_call) /* Data for initializing fixed_regs. */ static const char initial_fixed_regs[] = FIXED_REGISTERS; -- cgit v1.1 From 6d1e98dfd2bfce30640d71df355bedf114229744 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:39:38 +0000 Subject: Make ira call df_set_regs_ever_live for extra call-clobbered regs If we support multiple ABIs in the same translation unit, it can sometimes be the case that a callee clobbers more registers than its caller is allowed to. We need to call df_set_regs_ever_live on these extra registers so that the prologue and epilogue code can handle them appropriately. This patch does that in IRA. I wanted to avoid another full instruction walk just for this, so I combined it with the existing set_paradoxical_subreg walk. This happens before the first calculation of elimination offsets. 2019-09-30 Richard Sandiford gcc/ * function-abi.h (function_abi_aggregator): New class. * function-abi.cc (function_abi_aggregator::caller_save_regs): New function. * ira.c (update_equiv_regs_prescan): New function. Call set_paradoxical_subreg here rather than... (update_equiv_regs): ...here. (ira): Call update_equiv_regs_prescan. From-SVN: r276339 --- gcc/ChangeLog | 10 ++++++++++ gcc/function-abi.cc | 36 ++++++++++++++++++++++++++++++++++++ gcc/function-abi.h | 21 +++++++++++++++++++++ gcc/ira.c | 41 ++++++++++++++++++++++++++++++++--------- 4 files changed, 99 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 00a1731..28e411c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2019-09-30 Richard Sandiford + * function-abi.h (function_abi_aggregator): New class. + * function-abi.cc (function_abi_aggregator::caller_save_regs): New + function. + * ira.c (update_equiv_regs_prescan): New function. Call + set_paradoxical_subreg here rather than... + (update_equiv_regs): ...here. + (ira): Call update_equiv_regs_prescan. + +2019-09-30 Richard Sandiford + * hard-reg-set.h (regs_invalidated_by_call): Only define if IN_TARGET_CODE. (call_used_or_fixed_regs): Likewise. diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc index 4bace9e..eee789a 100644 --- a/gcc/function-abi.cc +++ b/gcc/function-abi.cc @@ -126,6 +126,42 @@ predefined_function_abi::add_full_reg_clobber (unsigned int regno) SET_HARD_REG_BIT (m_mode_clobbers[i], regno); } +/* Return the set of registers that the caller of the recorded functions must + save in order to honor the requirements of CALLER_ABI. */ + +HARD_REG_SET +function_abi_aggregator:: +caller_save_regs (const function_abi &caller_abi) const +{ + HARD_REG_SET result; + CLEAR_HARD_REG_SET (result); + for (unsigned int abi_id = 0; abi_id < NUM_ABI_IDS; ++abi_id) + { + const predefined_function_abi &callee_abi = function_abis[abi_id]; + + /* Skip cases that clearly aren't problematic. */ + if (abi_id == caller_abi.id () + || hard_reg_set_empty_p (m_abi_clobbers[abi_id])) + continue; + + /* Collect the set of registers that can be "more clobbered" by + CALLEE_ABI than by CALLER_ABI. */ + HARD_REG_SET extra_clobbers; + CLEAR_HARD_REG_SET (extra_clobbers); + for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i) + { + machine_mode mode = (machine_mode) i; + extra_clobbers |= (callee_abi.mode_clobbers (mode) + & ~caller_abi.mode_clobbers (mode)); + } + + /* Restrict it to the set of registers that we actually saw + clobbers for (e.g. taking -fipa-ra into account). */ + result |= (extra_clobbers & m_abi_clobbers[abi_id]); + } + return result; +} + /* Return the set of registers that cannot be used to hold a value of mode MODE across the calls in a region described by ABIS and MASK, where: diff --git a/gcc/function-abi.h b/gcc/function-abi.h index 8dd139e..9bb4d17 100644 --- a/gcc/function-abi.h +++ b/gcc/function-abi.h @@ -208,6 +208,27 @@ protected: HARD_REG_SET m_mask; }; +/* This class collects information about the ABIs of functions that are + called in a particular region of code. It is mostly intended to be + used as a local variable during an IR walk. */ +class function_abi_aggregator +{ +public: + function_abi_aggregator () : m_abi_clobbers () {} + + /* Record that the code region calls a function with the given ABI. */ + void + note_callee_abi (const function_abi &abi) + { + m_abi_clobbers[abi.id ()] |= abi.full_and_partial_reg_clobbers (); + } + + HARD_REG_SET caller_save_regs (const function_abi &) const; + +private: + HARD_REG_SET m_abi_clobbers[NUM_ABI_IDS]; +}; + struct target_function_abi_info { /* An array of all the target ABIs that are available in this diff --git a/gcc/ira.c b/gcc/ira.c index 925ea26..3b4f9a8 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -3362,6 +3362,37 @@ def_dominates_uses (int regno) return true; } +/* Scan the instructions before update_equiv_regs. Record which registers + are referenced as paradoxical subregs. Also check for cases in which + the current function needs to save a register that one of its call + instructions clobbers. + + These things are logically unrelated, but it's more efficient to do + them together. */ + +static void +update_equiv_regs_prescan (void) +{ + basic_block bb; + rtx_insn *insn; + function_abi_aggregator callee_abis; + + FOR_EACH_BB_FN (bb, cfun) + FOR_BB_INSNS (bb, insn) + if (NONDEBUG_INSN_P (insn)) + { + set_paradoxical_subreg (insn); + if (CALL_P (insn)) + callee_abis.note_callee_abi (insn_callee_abi (insn)); + } + + HARD_REG_SET extra_caller_saves = callee_abis.caller_save_regs (*crtl->abi); + if (!hard_reg_set_empty_p (extra_caller_saves)) + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (TEST_HARD_REG_BIT (extra_caller_saves, regno)) + df_set_regs_ever_live (regno, true); +} + /* Find registers that are equivalent to a single value throughout the compilation (either because they can be referenced in memory or are set once from a single constant). Lower their priority for a @@ -3378,15 +3409,6 @@ update_equiv_regs (void) rtx_insn *insn; basic_block bb; - /* Scan insns and set pdx_subregs if the reg is used in a - paradoxical subreg. Don't set such reg equivalent to a mem, - because lra will not substitute such equiv memory in order to - prevent access beyond allocated memory for paradoxical memory subreg. */ - FOR_EACH_BB_FN (bb, cfun) - FOR_BB_INSNS (bb, insn) - if (NONDEBUG_INSN_P (insn)) - set_paradoxical_subreg (insn); - /* Scan the insns and find which registers have equivalences. Do this in a separate scan of the insns because (due to -fcse-follow-jumps) a register can be set below its use. */ @@ -5276,6 +5298,7 @@ ira (FILE *f) init_alias_analysis (); loop_optimizer_init (AVOID_CFG_MODIFICATIONS); reg_equiv = XCNEWVEC (struct equivalence, max_reg_num ()); + update_equiv_regs_prescan (); update_equiv_regs (); /* Don't move insns if live range shrinkage or register -- cgit v1.1 From ce9d2a37f2db20328286f5d3d5a13a4e765c59f7 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:47:21 +0000 Subject: [AArch64] Allow shrink-wrapping of non-leaf vector PCS functions With the function ABI stuff, we can now support shrink-wrapping of non-leaf vector PCS functions. This is particularly useful if the vector PCS function calls an ordinary function on an error path, since we can then keep the extra saves and restores specific to that path too. 2019-09-30 Richard Sandiford gcc/ * config/aarch64/aarch64-protos.h (aarch64_use_simple_return_insn_p): Delete. * config/aarch64/aarch64.c (aarch64_components_for_bb): Check whether the block calls a function that clobbers more registers than the current function is allowed to. (aarch64_use_simple_return_insn_p): Delete. * config/aarch64/aarch64.md (simple_return): Remove condition. gcc/testsuite/ * gcc.target/aarch64/torture/simd-abi-9.c: New test. From-SVN: r276340 --- gcc/ChangeLog | 10 +++++ gcc/config/aarch64/aarch64-protos.h | 1 - gcc/config/aarch64/aarch64.c | 36 ++++++++-------- gcc/config/aarch64/aarch64.md | 2 +- gcc/testsuite/ChangeLog | 4 ++ .../gcc.target/aarch64/torture/simd-abi-9.c | 48 ++++++++++++++++++++++ 6 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 28e411c..7b0bcef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2019-09-30 Richard Sandiford + * config/aarch64/aarch64-protos.h (aarch64_use_simple_return_insn_p): + Delete. + * config/aarch64/aarch64.c (aarch64_components_for_bb): Check + whether the block calls a function that clobbers more registers + than the current function is allowed to. + (aarch64_use_simple_return_insn_p): Delete. + * config/aarch64/aarch64.md (simple_return): Remove condition. + +2019-09-30 Richard Sandiford + * function-abi.h (function_abi_aggregator): New class. * function-abi.cc (function_abi_aggregator::caller_save_regs): New function. diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index a870eb7..c9a3423 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -531,7 +531,6 @@ bool aarch64_split_dimode_const_store (rtx, rtx); bool aarch64_symbolic_address_p (rtx); bool aarch64_uimm12_shift (HOST_WIDE_INT); bool aarch64_use_return_insn_p (void); -bool aarch64_use_simple_return_insn_p (void); const char *aarch64_output_casesi (rtx *); enum aarch64_symbol_type aarch64_classify_symbol (rtx, HOST_WIDE_INT); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 2d4cd37..3da92a2 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -5976,13 +5976,30 @@ aarch64_components_for_bb (basic_block bb) sbitmap components = sbitmap_alloc (LAST_SAVED_REGNUM + 1); bitmap_clear (components); + /* Clobbered registers don't generate values in any meaningful sense, + since nothing after the clobber can rely on their value. And we can't + say that partially-clobbered registers are unconditionally killed, + because whether they're killed or not depends on the mode of the + value they're holding. Thus partially call-clobbered registers + appear in neither the kill set nor the gen set. + + Check manually for any calls that clobber more of a register than the + current function can. */ + function_abi_aggregator callee_abis; + rtx_insn *insn; + FOR_BB_INSNS (bb, insn) + if (CALL_P (insn)) + callee_abis.note_callee_abi (insn_callee_abi (insn)); + HARD_REG_SET extra_caller_saves = callee_abis.caller_save_regs (*crtl->abi); + /* GPRs are used in a bb if they are in the IN, GEN, or KILL sets. */ for (unsigned regno = 0; regno <= LAST_SAVED_REGNUM; regno++) if ((!call_used_or_fixed_reg_p (regno) || (simd_function && FP_SIMD_SAVED_REGNUM_P (regno))) - && (bitmap_bit_p (in, regno) - || bitmap_bit_p (gen, regno) - || bitmap_bit_p (kill, regno))) + && (TEST_HARD_REG_BIT (extra_caller_saves, regno) + || bitmap_bit_p (in, regno) + || bitmap_bit_p (gen, regno) + || bitmap_bit_p (kill, regno))) { unsigned regno2, offset, offset2; bitmap_set_bit (components, regno); @@ -6648,19 +6665,6 @@ aarch64_use_return_insn_p (void) return known_eq (cfun->machine->frame.frame_size, 0); } -/* Return false for non-leaf SIMD functions in order to avoid - shrink-wrapping them. Doing this will lose the necessary - save/restore of FP registers. */ - -bool -aarch64_use_simple_return_insn_p (void) -{ - if (aarch64_simd_decl_p (cfun->decl) && !crtl->is_leaf) - return false; - - return true; -} - /* Generate the epilogue instructions for returning from a function. This is almost exactly the reverse of the prolog sequence, except that we need to insert barriers to avoid scheduling loads that read diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index edeaa6f..fcba5ac 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -799,7 +799,7 @@ (define_insn "simple_return" [(simple_return)] - "aarch64_use_simple_return_insn_p ()" + "" "ret" [(set_attr "type" "branch")] ) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2ac61ff..ce3a967 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2019-09-30 Richard Sandiford + * gcc.target/aarch64/torture/simd-abi-9.c: New test. + +2019-09-30 Richard Sandiford + * gcc.target/aarch64/torture/simd-abi-8.c: New test. 2019-09-30 Richard Sandiford diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c new file mode 100644 index 0000000..aaa0316 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-9.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-fshrink-wrap -ffat-lto-objects" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +int callee (void); + +/* +** caller: +** ldr (w[0-9]+), \[x0\] +** cbn?z \1, [^\n]* +** ... +** ret +*/ +int __attribute__ ((aarch64_vector_pcs)) +caller (int *x) +{ + if (*x) + return callee () + 1; + else + return 0; +} + +/* { dg-final { scan-assembler {\sstp\tq8, q9} } } */ +/* { dg-final { scan-assembler {\sstp\tq10, q11} } } */ +/* { dg-final { scan-assembler {\sstp\tq12, q13} } } */ +/* { dg-final { scan-assembler {\sstp\tq14, q15} } } */ +/* { dg-final { scan-assembler {\sstp\tq16, q17} } } */ +/* { dg-final { scan-assembler {\sstp\tq18, q19} } } */ +/* { dg-final { scan-assembler {\sstp\tq20, q21} } } */ +/* { dg-final { scan-assembler {\sstp\tq22, q23} } } */ +/* { dg-final { scan-assembler {\sldp\tq8, q9} } } */ +/* { dg-final { scan-assembler {\sldp\tq10, q11} } } */ +/* { dg-final { scan-assembler {\sldp\tq12, q13} } } */ +/* { dg-final { scan-assembler {\sldp\tq14, q15} } } */ +/* { dg-final { scan-assembler {\sldp\tq16, q17} } } */ +/* { dg-final { scan-assembler {\sldp\tq18, q19} } } */ +/* { dg-final { scan-assembler {\sldp\tq20, q21} } } */ +/* { dg-final { scan-assembler {\sldp\tq22, q23} } } */ + +/* { dg-final { scan-assembler-not {\tstp\tq[0-7],} } } */ +/* { dg-final { scan-assembler-not {\tldp\tq[0-7],} } } */ +/* { dg-final { scan-assembler-not {\tstp\tq2[4-9],} } } */ +/* { dg-final { scan-assembler-not {\tldp\tq2[4-9],} } } */ +/* { dg-final { scan-assembler-not {\tstp\td} } } */ +/* { dg-final { scan-assembler-not {\tldp\td} } } */ +/* { dg-final { scan-assembler-not {\tstr\tq} } } */ +/* { dg-final { scan-assembler-not {\tldr\tq} } } */ -- cgit v1.1 From dcdd0f055731a8c960a15e5de8715d041d9a7876 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 16:47:39 +0000 Subject: [AArch64] Make more use of function_abi This patch makes more use of the function_abi infrastructure. We can then avoid checking specifically for the vector PCS in a few places, and can test it more directly otherwise. Specifically: we no longer need to call df_set_regs_ever_live for the extra call-saved registers, since IRA now does that for us. We also don't need to handle the vector PCS specially in aarch64_epilogue_uses, because DF now marks the registers as live on exit. 2019-09-30 Richard Sandiford gcc/ * config/aarch64/aarch64.c (aarch64_layout_frame): Use crtl->abi to test whether we're compiling a vector PCS function and to test whether the function needs to save a particular register. Remove the vector PCS handling of df_set_regs_ever_live. (aarch64_components_for_bb): Use crtl->abi to test whether the function needs to save a particular register. (aarch64_process_components): Use crtl->abi to test whether we're compiling a vector PCS function. (aarch64_expand_prologue, aarch64_expand_epilogue): Likewise. (aarch64_epilogue_uses): Remove handling of vector PCS functions. From-SVN: r276341 --- gcc/ChangeLog | 13 +++++++++++++ gcc/config/aarch64/aarch64.c | 33 ++++++++++----------------------- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7b0bcef..c3f7727 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2019-09-30 Richard Sandiford + * config/aarch64/aarch64.c (aarch64_layout_frame): Use crtl->abi + to test whether we're compiling a vector PCS function and to test + whether the function needs to save a particular register. + Remove the vector PCS handling of df_set_regs_ever_live. + (aarch64_components_for_bb): Use crtl->abi to test whether + the function needs to save a particular register. + (aarch64_process_components): Use crtl->abi to test whether + we're compiling a vector PCS function. + (aarch64_expand_prologue, aarch64_expand_epilogue): Likewise. + (aarch64_epilogue_uses): Remove handling of vector PCS functions. + +2019-09-30 Richard Sandiford + * config/aarch64/aarch64-protos.h (aarch64_use_simple_return_insn_p): Delete. * config/aarch64/aarch64.c (aarch64_components_for_bb): Check diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 3da92a2..ec180c8 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -5334,7 +5334,7 @@ aarch64_layout_frame (void) { HOST_WIDE_INT offset = 0; int regno, last_fp_reg = INVALID_REGNUM; - bool simd_function = aarch64_simd_decl_p (cfun->decl); + bool simd_function = (crtl->abi->id () == ARM_PCS_SIMD); cfun->machine->frame.emit_frame_chain = aarch64_needs_frame_chain (); @@ -5348,17 +5348,6 @@ aarch64_layout_frame (void) cfun->machine->frame.wb_candidate1 = INVALID_REGNUM; cfun->machine->frame.wb_candidate2 = INVALID_REGNUM; - /* If this is a non-leaf simd function with calls we assume that - at least one of those calls is to a non-simd function and thus - we must save V8 to V23 in the prologue. */ - - if (simd_function && !crtl->is_leaf) - { - for (regno = V0_REGNUM; regno <= V31_REGNUM; regno++) - if (FP_SIMD_SAVED_REGNUM_P (regno)) - df_set_regs_ever_live (regno, true); - } - /* First mark all the registers that really need to be saved... */ for (regno = R0_REGNUM; regno <= R30_REGNUM; regno++) cfun->machine->frame.reg_offset[regno] = SLOT_NOT_REQUIRED; @@ -5375,14 +5364,15 @@ aarch64_layout_frame (void) /* ... and any callee saved register that dataflow says is live. */ for (regno = R0_REGNUM; regno <= R30_REGNUM; regno++) if (df_regs_ever_live_p (regno) + && !fixed_regs[regno] && (regno == R30_REGNUM - || !call_used_or_fixed_reg_p (regno))) + || !crtl->abi->clobbers_full_reg_p (regno))) cfun->machine->frame.reg_offset[regno] = SLOT_REQUIRED; for (regno = V0_REGNUM; regno <= V31_REGNUM; regno++) if (df_regs_ever_live_p (regno) - && (!call_used_or_fixed_reg_p (regno) - || (simd_function && FP_SIMD_SAVED_REGNUM_P (regno)))) + && !fixed_regs[regno] + && !crtl->abi->clobbers_full_reg_p (regno)) { cfun->machine->frame.reg_offset[regno] = SLOT_REQUIRED; last_fp_reg = regno; @@ -5971,7 +5961,6 @@ aarch64_components_for_bb (basic_block bb) bitmap in = DF_LIVE_IN (bb); bitmap gen = &DF_LIVE_BB_INFO (bb)->gen; bitmap kill = &DF_LIVE_BB_INFO (bb)->kill; - bool simd_function = aarch64_simd_decl_p (cfun->decl); sbitmap components = sbitmap_alloc (LAST_SAVED_REGNUM + 1); bitmap_clear (components); @@ -5994,8 +5983,8 @@ aarch64_components_for_bb (basic_block bb) /* GPRs are used in a bb if they are in the IN, GEN, or KILL sets. */ for (unsigned regno = 0; regno <= LAST_SAVED_REGNUM; regno++) - if ((!call_used_or_fixed_reg_p (regno) - || (simd_function && FP_SIMD_SAVED_REGNUM_P (regno))) + if (!fixed_regs[regno] + && !crtl->abi->clobbers_full_reg_p (regno) && (TEST_HARD_REG_BIT (extra_caller_saves, regno) || bitmap_bit_p (in, regno) || bitmap_bit_p (gen, regno) @@ -6100,7 +6089,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) mergeable with the current one into a pair. */ if (!satisfies_constraint_Ump (mem) || GP_REGNUM_P (regno) != GP_REGNUM_P (regno2) - || (aarch64_simd_decl_p (cfun->decl) && FP_REGNUM_P (regno)) + || (crtl->abi->id () == ARM_PCS_SIMD && FP_REGNUM_P (regno)) || maybe_ne ((offset2 - cfun->machine->frame.reg_offset[regno]), GET_MODE_SIZE (mode))) { @@ -6432,8 +6421,6 @@ aarch64_epilogue_uses (int regno) { if (regno == LR_REGNUM) return 1; - if (aarch64_simd_decl_p (cfun->decl) && FP_SIMD_SAVED_REGNUM_P (regno)) - return 1; } return 0; } @@ -6634,7 +6621,7 @@ aarch64_expand_prologue (void) aarch64_save_callee_saves (DImode, callee_offset, R0_REGNUM, R30_REGNUM, callee_adjust != 0 || emit_frame_chain); - if (aarch64_simd_decl_p (cfun->decl)) + if (crtl->abi->id () == ARM_PCS_SIMD) aarch64_save_callee_saves (TFmode, callee_offset, V0_REGNUM, V31_REGNUM, callee_adjust != 0 || emit_frame_chain); else @@ -6733,7 +6720,7 @@ aarch64_expand_epilogue (bool for_sibcall) aarch64_restore_callee_saves (DImode, callee_offset, R0_REGNUM, R30_REGNUM, callee_adjust != 0, &cfi_ops); - if (aarch64_simd_decl_p (cfun->decl)) + if (crtl->abi->id () == ARM_PCS_SIMD) aarch64_restore_callee_saves (TFmode, callee_offset, V0_REGNUM, V31_REGNUM, callee_adjust != 0, &cfi_ops); else -- cgit v1.1 From c0c2f013906a695b8a02226f119649a370d9e083 Mon Sep 17 00:00:00 2001 From: Yuliang Wang Date: Mon, 30 Sep 2019 16:55:45 +0000 Subject: [AArch64][SVE] Utilize ASRD instruction for division and remainder 2019-09-30 Yuliang Wang gcc/ * config/aarch64/aarch64-sve.md (sdiv_pow23): New pattern for ASRD. * config/aarch64/iterators.md (UNSPEC_ASRD): New unspec. * internal-fn.def (IFN_DIV_POW2): New internal function. * optabs.def (sdiv_pow2_optab): New optab. * tree-vect-patterns.c (vect_recog_divmod_pattern): Modify pattern to support new operation. * doc/md.texi (sdiv_pow2$var{m3}): Documentation for the above. * doc/sourcebuild.texi (vect_sdiv_pow2_si): Document new target selector. gcc/testsuite/ * gcc.dg/vect/vect-sdiv-pow2-1.c: New test. * gcc.target/aarch64/sve/asrdiv_1.c: As above. * lib/target-supports.exp (check_effective_target_vect_sdiv_pow2_si): Return true for AArch64 with SVE. From-SVN: r276343 --- gcc/ChangeLog | 13 ++++ gcc/config/aarch64/aarch64-sve.md | 41 +++++++++++++ gcc/config/aarch64/iterators.md | 1 + gcc/doc/md.texi | 11 ++++ gcc/doc/sourcebuild.texi | 4 ++ gcc/internal-fn.def | 2 + gcc/optabs.def | 1 + gcc/testsuite/ChangeLog | 7 +++ gcc/testsuite/gcc.dg/vect/vect-sdiv-pow2-1.c | 79 +++++++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/sve/asrdiv_1.c | 51 ++++++++++++++++ gcc/testsuite/lib/target-supports.exp | 8 +++ gcc/tree-vect-patterns.c | 32 +++++++++- 12 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-sdiv-pow2-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/asrdiv_1.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c3f7727..78d296d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-09-30 Yuliang Wang + + * config/aarch64/aarch64-sve.md (sdiv_pow23): + New pattern for ASRD. + * config/aarch64/iterators.md (UNSPEC_ASRD): New unspec. + * internal-fn.def (IFN_DIV_POW2): New internal function. + * optabs.def (sdiv_pow2_optab): New optab. + * tree-vect-patterns.c (vect_recog_divmod_pattern): + Modify pattern to support new operation. + * doc/md.texi (sdiv_pow2$var{m3}): Documentation for the above. + * doc/sourcebuild.texi (vect_sdiv_pow2_si): + Document new target selector. + 2019-09-30 Richard Sandiford * config/aarch64/aarch64.c (aarch64_layout_frame): Use crtl->abi diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index f58353e..41c8689 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -71,6 +71,7 @@ ;; ---- [INT] Binary logical operations ;; ---- [INT] Binary logical operations (inverted second input) ;; ---- [INT] Shifts +;; ---- [INT] Shifts (rounding towards 0) ;; ---- [FP] General binary arithmetic corresponding to rtx codes ;; ---- [FP] General binary arithmetic corresponding to unspecs ;; ---- [FP] Addition @@ -2564,6 +2565,46 @@ ) ;; ------------------------------------------------------------------------- +;; ---- [INT] Shifts (rounding towards 0) +;; ------------------------------------------------------------------------- +;; Includes: +;; - ASRD +;; ------------------------------------------------------------------------- + +;; Unpredicated arithmetic right shift for division by power-of-2. +(define_expand "sdiv_pow23" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_dup 3) + (unspec:SVE_I + [(match_operand:SVE_I 1 "register_operand") + (match_operand 2 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD)] + UNSPEC_PRED_X))] + "TARGET_SVE" + { + operands[3] = aarch64_ptrue_reg (mode); + } +) + +;; Predicated ASRD with PTRUE. +(define_insn "*sdiv_pow23" + [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") + (unspec:SVE_I + [(match_operand: 1 "register_operand" "Upl, Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "0, w") + (match_operand 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD)] + UNSPEC_PRED_X))] + "TARGET_SVE" + "@ + asrd\t%0., %1/m, %0., #%3 + movprfx\t%0, %2\;asrd\t%0., %1/m, %0., #%3" + [(set_attr "movprfx" "*,yes")] +) + +;; ------------------------------------------------------------------------- ;; ---- [FP] General binary arithmetic corresponding to rtx codes ;; ------------------------------------------------------------------------- ;; Includes post-RA forms of: diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 03b3ce3..1e321af 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -538,6 +538,7 @@ UNSPEC_SMULHRS ; Used in aarch64-sve2.md. UNSPEC_UMULHS ; Used in aarch64-sve2.md. UNSPEC_UMULHRS ; Used in aarch64-sve2.md. + UNSPEC_ASRD ; Used in aarch64-sve.md. ]) ;; ------------------------------------------------------------------ diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index f35fd2b..868016a 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5414,6 +5414,17 @@ op0 = (narrow) (((((wide) op1 * (wide) op2) >> (N / 2 - 2)) + 1) >> 1); where the sign of @samp{narrow} determines whether this is a signed or unsigned operation, and @var{N} is the size of @samp{wide} in bits. +@cindex @code{sdiv_pow2@var{m3}} instruction pattern +@item @samp{sdiv_pow2@var{m3}} +@cindex @code{sdiv_pow2@var{m3}} instruction pattern +@itemx @samp{sdiv_pow2@var{m3}} +Signed division by power-of-2 immediate. Equivalent to: +@smallexample +signed op0, op1; +@dots{} +op0 = op1 / (1 << imm); +@end smallexample + @cindex @code{vec_shl_insert_@var{m}} instruction pattern @item @samp{vec_shl_insert_@var{m}} Shift the elements in vector input operand 1 left one element (i.e.@: diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 9b98f01..5696792 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -1446,6 +1446,10 @@ of bytes. Target supports both signed and unsigned multiply-high-with-round-and-scale operations on vectors of half-words. +@item vect_sdiv_pow2_si +Target supports signed division by constant power-of-2 operations +on vectors of 4-byte integers. + @item vect_condition Target supports vector conditional operations. diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 49f5797..a945944 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -140,6 +140,8 @@ DEF_INTERNAL_OPTAB_FN (WHILE_ULT, ECF_CONST | ECF_NOTHROW, while_ult, while) DEF_INTERNAL_OPTAB_FN (VEC_SHL_INSERT, ECF_CONST | ECF_NOTHROW, vec_shl_insert, binary) +DEF_INTERNAL_OPTAB_FN (DIV_POW2, ECF_CONST | ECF_NOTHROW, sdiv_pow2, binary) + DEF_INTERNAL_OPTAB_FN (FMS, ECF_CONST, fms, ternary) DEF_INTERNAL_OPTAB_FN (FNMA, ECF_CONST, fnma, ternary) DEF_INTERNAL_OPTAB_FN (FNMS, ECF_CONST, fnms, ternary) diff --git a/gcc/optabs.def b/gcc/optabs.def index 3086968..e937315 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -347,6 +347,7 @@ OPTAB_D (smulhs_optab, "smulhs$a3") OPTAB_D (smulhrs_optab, "smulhrs$a3") OPTAB_D (umulhs_optab, "umulhs$a3") OPTAB_D (umulhrs_optab, "umulhrs$a3") +OPTAB_D (sdiv_pow2_optab, "sdiv_pow2$a3") OPTAB_D (vec_pack_sfix_trunc_optab, "vec_pack_sfix_trunc_$a") OPTAB_D (vec_pack_ssat_optab, "vec_pack_ssat_$a") OPTAB_D (vec_pack_trunc_optab, "vec_pack_trunc_$a") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce3a967..cc31ac8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-09-30 Yuliang Wang + + * gcc.dg/vect/vect-sdiv-pow2-1.c: New test. + * gcc.target/aarch64/sve/asrdiv_1.c: As above. + * lib/target-supports.exp (check_effective_target_vect_sdiv_pow2_si): + Return true for AArch64 with SVE. + 2019-09-30 Richard Sandiford * gcc.target/aarch64/torture/simd-abi-9.c: New test. diff --git a/gcc/testsuite/gcc.dg/vect/vect-sdiv-pow2-1.c b/gcc/testsuite/gcc.dg/vect/vect-sdiv-pow2-1.c new file mode 100644 index 0000000..be70bc6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-sdiv-pow2-1.c @@ -0,0 +1,79 @@ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +#define DIV(x,y) ((x)/(y)) +#define MOD(x,y) ((x)%(y)) + +#define TEMPLATE(PO2,OP) \ +void __attribute__ ((noipa)) \ +f_##PO2##_##OP (int *restrict a, int *restrict b, __INTPTR_TYPE__ n) \ +{ \ + for (__INTPTR_TYPE__ i = 0; i < n; ++i) \ + a[i] = OP (b[i], (1 << PO2)); \ +} +#define TEMPLATES(PO2) \ +TEMPLATE (PO2,DIV); \ +TEMPLATE (PO2,MOD); + +TEMPLATES (1); +TEMPLATES (2); +TEMPLATES (3); +TEMPLATES (7); +TEMPLATES (8); +TEMPLATES (10); +TEMPLATES (15); +TEMPLATES (16); +TEMPLATES (20); + +typedef void (*func_t) (int *, int *, __INTPTR_TYPE__); +typedef struct { + int po2; + func_t div; + func_t mod; +} fn_t; +const fn_t fns[] = { +#define FN_PAIR(PO2) { PO2, f_##PO2##_DIV, f_##PO2##_MOD } + FN_PAIR (1), + FN_PAIR (2), + FN_PAIR (3), + FN_PAIR (7), + FN_PAIR (8), + FN_PAIR (10), + FN_PAIR (15), + FN_PAIR (16), + FN_PAIR (20), +}; + +int __attribute__ ((noipa, noinline)) +power2 (int x) +{ + return 1 << x; +} + +#define N 50 + +int +main (void) +{ + int a[N], b[N], c[N]; + + for (int i = 0; i < (sizeof(fns)/sizeof(fns[0])); i++) + { + int p = power2 (fns[i].po2); + for (int j = 0; j < N; j++) + a[j] = ((p << 4) * j) / (N - 1) - (p << 5); + + fns[i].div (b, a, N); + fns[i].mod (c, a, N); + + for (int j = 0; j < N; j++) + if (a[j] != (b[j] * p + c[j])) + __builtin_abort (); + } + + return 0; +} + +/* { dg-final { scan-tree-dump {\.DIV_POW2} "vect" { target vect_sdiv_pow2_si } } } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loop" 18 "vect" { target vect_sdiv_pow2_si } } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/asrdiv_1.c b/gcc/testsuite/gcc.target/aarch64/sve/asrdiv_1.c new file mode 100644 index 0000000..615d8b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/asrdiv_1.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-details --save-temps" } */ + +#include + +#define SIGNED(S) int##S##_t + +#define DIV(x,y) ((x)/(y)) +#define MOD(x,y) ((x)%(y)) + +#define TEMPLATE(OP,SIZE) \ +void __attribute__ ((noinline, noclone)) \ +f_##OP##_##SIZE (SIGNED(SIZE) *restrict a, SIGNED(SIZE) *restrict b, \ + __INTPTR_TYPE__ n) \ +{ \ + for (__INTPTR_TYPE__ i = 0; i < n; ++i) \ + a[i] = OP (b[i], ((SIGNED(SIZE))1 << ((SIZE)/2+1))); \ +} +#define DIVMOD(SIZE) \ +TEMPLATE (DIV,SIZE); \ +TEMPLATE (MOD,SIZE); + +DIVMOD (8); +DIVMOD (16); +DIVMOD (32); +DIVMOD (64); + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 8 "vect" } } */ + +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+, z[0-9]+\n} 4 } } */ + +/* { dg-final { scan-assembler-times {\tasrd\tz[0-9]+\.b, p[0-9]+/m, z[0-9]+\.b, #5\n} 2 } } */ +/* { dg-final { scan-assembler-times {\tlsl\tz[0-9]+\.b, z[0-9]+\.b, #5\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tsub\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tasrd\tz[0-9]+\.h, p[0-9]+/m, z[0-9]+\.h, #9\n} 2 } } */ +/* { dg-final { scan-assembler-times {\tlsl\tz[0-9]+\.h, z[0-9]+\.h, #9\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tsub\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tasrd\tz[0-9]+\.s, p[0-9]+/m, z[0-9]+\.s, #17\n} 2 } } */ +/* { dg-final { scan-assembler-times {\tlsl\tz[0-9]+\.s, z[0-9]+\.s, #17\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tsub\tz[0-9]+\.s, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tasrd\tz[0-9]+\.d, p[0-9]+/m, z[0-9]+\.d, #33\n} 2 } } */ +/* { dg-final { scan-assembler-times {\tlsl\tz[0-9]+\.d, z[0-9]+\.d, #33\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tsub\tz[0-9]+\.d, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-not {\tasr\t%} } } */ +/* { dg-final { scan-assembler-not {\tlsr\t%} } } */ +/* { dg-final { scan-assembler-not {\tcmplt\t%} } } */ +/* { dg-final { scan-assembler-not {\tand\t%} } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 0268acd..a7b76b6 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6256,6 +6256,14 @@ proc check_effective_target_vect_mulhrs_hi {} { && [check_effective_target_aarch64_sve2] }] } +# Return 1 if the target plus current options supports signed division +# by power-of-2 operations on vectors of 4-byte integers. + +proc check_effective_target_vect_sdiv_pow2_si {} { + return [expr { [istarget aarch64*-*-*] + && [check_effective_target_aarch64_sve] }] +} + # Return 1 if the target plus current options supports a vector # demotion (packing) of shorts (to chars) and ints (to shorts) # using modulo arithmetic, 0 otherwise. diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index baa9a4c..4dfebbe 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -2927,6 +2927,37 @@ vect_recog_divmod_pattern (stmt_vec_info stmt_vinfo, tree *type_out) /* Pattern detected. */ vect_pattern_detected ("vect_recog_divmod_pattern", last_stmt); + *type_out = vectype; + + /* Check if the target supports this internal function. */ + internal_fn ifn = IFN_DIV_POW2; + if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED)) + { + tree shift = build_int_cst (itype, tree_log2 (oprnd1)); + + tree var_div = vect_recog_temp_ssa_var (itype, NULL); + gimple *div_stmt = gimple_build_call_internal (ifn, 2, oprnd0, shift); + gimple_call_set_lhs (div_stmt, var_div); + + if (rhs_code == TRUNC_MOD_EXPR) + { + append_pattern_def_seq (stmt_vinfo, div_stmt); + def_stmt + = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL), + LSHIFT_EXPR, var_div, shift); + append_pattern_def_seq (stmt_vinfo, def_stmt); + pattern_stmt + = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL), + MINUS_EXPR, oprnd0, + gimple_assign_lhs (def_stmt)); + } + else + pattern_stmt = div_stmt; + gimple_set_location (pattern_stmt, gimple_location (last_stmt)); + + return pattern_stmt; + } + cond = build2 (LT_EXPR, boolean_type_node, oprnd0, build_int_cst (itype, 0)); if (rhs_code == TRUNC_DIV_EXPR @@ -3003,7 +3034,6 @@ vect_recog_divmod_pattern (stmt_vec_info stmt_vinfo, tree *type_out) signmask); } - *type_out = vectype; return pattern_stmt; } -- cgit v1.1 From 6b34d5ff5563916c52582a4c7473689bb0086c19 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Mon, 30 Sep 2019 17:22:14 +0000 Subject: Fix typo in my last commit's ChangeLog entry From-SVN: r276359 --- gcc/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 78d296d..0d90ef4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -586,7 +586,7 @@ unused. * config/rs6000/rs6000-protos.h (enum insn_form): New enumeration. - (enum non_prefixed): New enumeration. + (enum non_prefixed_form): New enumeration. (address_to_insn_form): New declaration. (prefixed_load_p): New declaration. (prefixed_store_p): New declaration. -- cgit v1.1 From 021f65807164b2770e8f113b0f85b1bb193020ef Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 30 Sep 2019 17:40:02 +0000 Subject: S/390: Remove code duplication in vec_unordered vec_unordered is vec_ordered plus a negation at the end. Reuse vec_unordered logic. gcc/ChangeLog: 2019-09-30 Ilya Leoshkevich PR target/77918 * config/s390/vector.md (vec_unordered): Call gen_vec_ordered. From-SVN: r276360 --- gcc/ChangeLog | 6 ++++++ gcc/config/s390/vector.md | 14 +++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0d90ef4..28296d5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-09-30 Ilya Leoshkevich + + PR target/77918 + * config/s390/vector.md (vec_unordered): Call + gen_vec_ordered. + 2019-09-30 Yuliang Wang * config/aarch64/aarch64-sve.md (sdiv_pow23): diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 0702e1d..961d2c6 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -1546,15 +1546,15 @@ ; UNORDERED (a, b): !ORDERED (a, b) (define_expand "vec_unordered" - [(set (match_operand: 0 "register_operand" "=v") - (ge: (match_operand:VFT 1 "register_operand" "v") - (match_operand:VFT 2 "register_operand" "v"))) - (set (match_dup 3) (gt: (match_dup 2) (match_dup 1))) - (set (match_dup 0) (ior: (match_dup 0) (match_dup 3))) - (set (match_dup 0) (not: (match_dup 0)))] + [(match_operand: 0 "register_operand" "=v") + (match_operand:VFT 1 "register_operand" "v") + (match_operand:VFT 2 "register_operand" "v")] "TARGET_VX" { - operands[3] = gen_reg_rtx (mode); + emit_insn (gen_vec_ordered (operands[0], operands[1], operands[2])); + emit_insn (gen_rtx_SET (operands[0], + gen_rtx_NOT (mode, operands[0]))); + DONE; }) (define_expand "vec_unordered" -- cgit v1.1 From 2f00786128f190a4ad7a0819a84026cd8be19ad4 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 30 Sep 2019 18:36:11 +0000 Subject: [x86] Cache result of expensive_function_p between frame layouts ix86_compute_frame_layout sets use_fast_prologue_epilogue if the function isn't more expensive than a certain threshold, where the threshold depends on the number of saved registers. However, the RA is allowed to insert and delete instructions as it goes along, which can change whether this threshold is crossed or not. I hit this with an RA change I'm working on. Rematerialisation was able to remove an instruction and avoid a spill, which happened to bring the size of the function below the threshold. But since nothing legitimately frame-related had changed, there was no need for the RA to lay out the frame again. We then failed the final sanity check in lra_eliminate. 2019-09-30 Richard Sandiford gcc/ * config/i386/i386.h (ix86_frame::expensive_p): New field. (ix86_frame::expensive_count): Likewise. * config/i386/i386.c (ix86_compute_frame_layout): Make the choice of use_fast_prologue_epilogue robust against incidental changes in function size. From-SVN: r276361 --- gcc/ChangeLog | 8 ++++++++ gcc/config/i386/i386.c | 19 ++++++++++++++++--- gcc/config/i386/i386.h | 5 +++++ 3 files changed, 29 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 28296d5..f665a5c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-30 Richard Sandiford + + * config/i386/i386.h (ix86_frame::expensive_p): New field. + (ix86_frame::expensive_count): Likewise. + * config/i386/i386.c (ix86_compute_frame_layout): Make the choice + of use_fast_prologue_epilogue robust against incidental changes + in function size. + 2019-09-30 Ilya Leoshkevich PR target/77918 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 8af4bc5..083e228 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5877,7 +5877,14 @@ ix86_compute_frame_layout (void) case function is known to be outside hot spot (this is known with feedback only). Weight the size of function by number of registers to save as it is cheap to use one or two push instructions but very - slow to use many of them. */ + slow to use many of them. + + Calling this hook multiple times with the same frame requirements + must produce the same layout, since the RA might otherwise be + unable to reach a fixed point or might fail its final sanity checks. + This means that once we've assumed that a function does or doesn't + have a particular size, we have to stick to that assumption + regardless of how the function has changed since. */ if (count) count = (count - 1) * FAST_PROLOGUE_INSN_COUNT; if (node->frequency < NODE_FREQUENCY_NORMAL @@ -5885,8 +5892,14 @@ ix86_compute_frame_layout (void) && node->frequency < NODE_FREQUENCY_HOT)) m->use_fast_prologue_epilogue = false; else - m->use_fast_prologue_epilogue - = !expensive_function_p (count); + { + if (count != frame->expensive_count) + { + frame->expensive_count = count; + frame->expensive_p = expensive_function_p (count); + } + m->use_fast_prologue_epilogue = !frame->expensive_p; + } } frame->save_regs_using_mov diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 9fe1f45..4e37336 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2643,6 +2643,11 @@ struct GTY(()) ix86_frame /* When save_regs_using_mov is set, emit prologue using move instead of push instructions. */ bool save_regs_using_mov; + + /* Assume without checking that: + EXPENSIVE_P = expensive_function_p (EXPENSIVE_COUNT). */ + bool expensive_p; + int expensive_count; }; /* Machine specific frame tracking during prologue/epilogue generation. All -- cgit v1.1 From 5a05b737e1b626f92ee968f6e32715bf955dae54 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 30 Sep 2019 20:03:55 +0000 Subject: diagnostic-show-locus.c: rework handling of multiple labels This patch improves the handling of large numbers of labels within a rich_location: previously, overlapping labels could lead to an assertion failure within layout::print_any_labels. Also, the labels were printed in reverse order of insertion into the rich_location. This patch moves the determination of whether a vertical bar should be printed for a line_label into the 'Figure out how many "label lines" we need, and which one each label is printed in.' step of layout::print_any_labels, rather than doing it as the lines are printed. It also flips the sort order, so that labels at the same line/column are printed in order of insertion into the rich_location. I haven't run into these issues with our existing diagnostics, but it affects a patch kit I'm working on that makes more extensive use of labels. gcc/ChangeLog: * diagnostic-show-locus.c (line_label::line_label): Initialize m_has_vbar. (line_label::comparator): Reverse the sort order by m_state_idx, so that when the list is walked backwards the labels appear in order of insertion into the rich_location. (line_label::m_has_vbar): New field. (layout::print_any_labels): When dealing with multiple labels at the same line and column, only print vertical bars for the one with the highest label_line. (selftest::test_one_liner_labels): Update test for multiple labels to expect the labels to be in the order of insertion into the rich_location. Add a test for many such labels, where the column numbers are out-of-order relative to the insertion order. From-SVN: r276371 --- gcc/ChangeLog | 16 ++++++++++ gcc/diagnostic-show-locus.c | 75 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f665a5c..5c3e3e1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2019-09-30 David Malcolm + + * diagnostic-show-locus.c (line_label::line_label): Initialize + m_has_vbar. + (line_label::comparator): Reverse the sort order by m_state_idx, + so that when the list is walked backwards the labels appear in + order of insertion into the rich_location. + (line_label::m_has_vbar): New field. + (layout::print_any_labels): When dealing with multiple labels at + the same line and column, only print vertical bars for the one + with the highest label_line. + (selftest::test_one_liner_labels): Update test for multiple labels + to expect the labels to be in the order of insertion into the + rich_location. Add a test for many such labels, where the column + numbers are out-of-order relative to the insertion order. + 2019-09-30 Richard Sandiford * config/i386/i386.h (ix86_frame::expensive_p): New field. diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c index 4d563dd..6612cbb6 100644 --- a/gcc/diagnostic-show-locus.c +++ b/gcc/diagnostic-show-locus.c @@ -1416,7 +1416,7 @@ public: line_label (int state_idx, int column, label_text text) : m_state_idx (state_idx), m_column (column), m_text (text), m_length (strlen (text.m_buffer)), - m_label_line (0) + m_label_line (0), m_has_vbar (true) {} /* Sorting is primarily by column, then by state index. */ @@ -1427,7 +1427,10 @@ public: int column_cmp = compare (ll1->m_column, ll2->m_column); if (column_cmp) return column_cmp; - return compare (ll1->m_state_idx, ll2->m_state_idx); + /* Order by reverse state index, so that labels are printed + in order of insertion into the rich_location when the + sorted list is walked backwards. */ + return -compare (ll1->m_state_idx, ll2->m_state_idx); } int m_state_idx; @@ -1435,6 +1438,7 @@ public: label_text m_text; size_t m_length; int m_label_line; + bool m_has_vbar; }; /* Print any labels in this row. */ @@ -1511,8 +1515,8 @@ layout::print_any_labels (linenum_type row) foo + bar ^ : label line 0 | : label line 1 - label 1 : label line 2 - label 0 : label line 3. */ + label 0 : label line 2 + label 1 : label line 3. */ int max_label_line = 1; { @@ -1522,7 +1526,15 @@ layout::print_any_labels (linenum_type row) { /* Would this label "touch" or overlap the next label? */ if (label->m_column + label->m_length >= (size_t)next_column) - max_label_line++; + { + max_label_line++; + + /* If we've already seen labels with the same column, suppress the + vertical bar for subsequent ones in this backwards iteration; + hence only the one with the highest label_line has m_has_vbar set. */ + if (label->m_column == next_column) + label->m_has_vbar = false; + } label->m_label_line = max_label_line; next_column = label->m_column; @@ -1533,10 +1545,6 @@ layout::print_any_labels (linenum_type row) either a vertical bar ('|') for the labels that are lower down, or the labels themselves once we've reached their line. */ { - /* Keep track of in which column we last printed a vertical bar. - This allows us to suppress duplicate vertical bars for the case - where multiple labels are on one column. */ - int last_vbar = 0; for (int label_line = 0; label_line <= max_label_line; label_line++) { start_annotation_line (); @@ -1558,14 +1566,13 @@ layout::print_any_labels (linenum_type row) m_colorizer.set_normal_text (); column += label->m_length; } - else if (label->m_column != last_vbar) + else if (label->m_has_vbar) { gcc_assert (column <= label->m_column); move_to_column (&column, label->m_column, true); m_colorizer.set_range (label->m_state_idx); pp_character (m_pp, '|'); m_colorizer.set_normal_text (); - last_vbar = column; column++; } } @@ -2783,9 +2790,51 @@ test_one_liner_labels () " foo = bar.field;\n" " ^~~\n" " |\n" - " label 2\n" + " label 0\n" " label 1\n" - " label 0\n", + " label 2\n", + pp_formatted_text (dc.printer)); + } + + /* Example of out-of-order ranges (thus requiring a sort), where + they overlap, and there are multiple ranges on the same point. */ + { + text_range_label label_0a ("label 0a"); + text_range_label label_1a ("label 1a"); + text_range_label label_2a ("label 2a"); + text_range_label label_0b ("label 0b"); + text_range_label label_1b ("label 1b"); + text_range_label label_2b ("label 2b"); + text_range_label label_0c ("label 0c"); + text_range_label label_1c ("label 1c"); + text_range_label label_2c ("label 2c"); + gcc_rich_location richloc (field, &label_0a); + richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1a); + richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2a); + + richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label_0b); + richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1b); + richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2b); + + richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label_0c); + richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1c); + richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2c); + + test_diagnostic_context dc; + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ~~~ ~~~ ^~~~~\n" + " | | |\n" + " | | label 0a\n" + " | | label 0b\n" + " | | label 0c\n" + " | label 1a\n" + " | label 1b\n" + " | label 1c\n" + " label 2a\n" + " label 2b\n" + " label 2c\n", pp_formatted_text (dc.printer)); } -- cgit v1.1 From 6ba3c0f71767c2c98d21cda5add80ef03ecd3e37 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 30 Sep 2019 22:53:42 +0100 Subject: * es.po: Update. From-SVN: r276380 --- gcc/po/ChangeLog | 4 +++ gcc/po/es.po | 84 ++++++++++++++++++++++---------------------------------- 2 files changed, 37 insertions(+), 51 deletions(-) (limited to 'gcc') diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index 52a20a0..b597c8d 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,7 @@ +2019-09-30 Joseph Myers + + * es.po: Update. + 2019-08-31 Joseph Myers * es.po: Update. diff --git a/gcc/po/es.po b/gcc/po/es.po index 5d62016..c6eed01 100644 --- a/gcc/po/es.po +++ b/gcc/po/es.po @@ -43,7 +43,7 @@ msgstr "" "Project-Id-Version: gcc 9.1.0\n" "Report-Msgid-Bugs-To: https://gcc.gnu.org/bugs/\n" "POT-Creation-Date: 2019-05-02 20:28+0000\n" -"PO-Revision-Date: 2019-08-31 18:04+0200\n" +"PO-Revision-Date: 2019-09-30 17:16+0200\n" "Last-Translator: Antonio Ceballos Roa \n" "Language-Team: Spanish \n" "Language: es\n" @@ -6795,7 +6795,7 @@ msgstr "Advierte de conversiones de entero a puntero y viceversa incompatibles." #: c-family/c.opt:677 msgid "Warn for suspicious integer expressions in boolean context." -msgstr "" +msgstr "Advierte de expresiones enteras sospechosas en contexto booleano." #: c-family/c.opt:681 msgid "Warn when there is a cast to a pointer from an integer of a different size." @@ -6859,7 +6859,7 @@ msgstr "Avisa sobre campos faltantes en los inicializadores de struct." #: c-family/c.opt:745 msgid "Warn about unsafe macros expanding to multiple statements used as a body of a clause such as if, else, while, switch, or for." -msgstr "" +msgstr "Advierte de expansiones de macros no seguras a sentencias múltiples utilizadas como cuerpo de una cláusula como if, while, switch o for." #: c-family/c.opt:749 msgid "Warn on direct multiple inheritance." @@ -6871,7 +6871,7 @@ msgstr "Advierta de la definición de espacios de nombres." #: c-family/c.opt:757 msgid "Warn when fields in a struct with the packed attribute are misaligned." -msgstr "" +msgstr "Avisa cuando un struct con el atributo «packed» tiene campos desalineados." #: c-family/c.opt:761 msgid "Warn about missing sized deallocation functions." @@ -6879,7 +6879,7 @@ msgstr "Advierte de funciones de desasignación con tamaño ausentes." #: c-family/c.opt:765 msgid "Warn about suspicious divisions of two sizeof expressions that don't work correctly with pointers." -msgstr "" +msgstr "Advierte de divisiones sospechosas de dos expresiones sizeof que no funcionan correctamente con punteros." #: c-family/c.opt:769 msgid "Warn about suspicious length parameters to certain string functions if the argument uses sizeof." @@ -6891,7 +6891,7 @@ msgstr "Avisa cuando se aplica sizeof a parámetros declarados como array." #: c-family/c.opt:777 msgid "Warn about buffer overflow in string manipulation functions like memcpy and strcpy." -msgstr "" +msgstr "Advierte de desbordamiento de búfer en funciones que manipulan cadenas, como memcpy y strcpy." #: c-family/c.opt:782 msgid "Under the control of Object Size type, warn about buffer overflow in string manipulation functions like memcpy and strcpy." @@ -7059,7 +7059,7 @@ msgstr "Avisa sobre malos usos de pragmas." #: c-family/c.opt:991 msgid "Warn if constructor or destructors with priorities from 0 to 100 are used." -msgstr "" +msgstr "Avisa si se usan constructores o destructores con prioridades entre 0 y 100." #: c-family/c.opt:995 msgid "Warn if a property for an Objective-C object has no assign semantics specified." @@ -7079,7 +7079,7 @@ msgstr "Avisa sobre declaraciones múltiples del mismo objeto." #: c-family/c.opt:1015 msgid "Warn about redundant calls to std::move." -msgstr "" +msgstr "Advierte de llamadas redundantes a std::move." #: c-family/c.opt:1019 msgid "Warn about uses of register storage specifier." @@ -7283,11 +7283,11 @@ msgstr "-fada-spec-parent=unidad Vuelca specs de Ada como unidades hijas del pa #: c-family/c.opt:1267 msgid "Support C++17 allocation of over-aligned types." -msgstr "" +msgstr "Admite alojamiento C++17 de tipos sobrealineados." #: c-family/c.opt:1271 msgid "-faligned-new= Use C++17 over-aligned type allocation for alignments greater than N." -msgstr "" +msgstr "-faligned-new= Usa alojamiento de tipo sobrealineado de C++17 para alineamientos mayores que N." #: c-family/c.opt:1278 msgid "Allow variadic functions without named parameter." @@ -7312,7 +7312,7 @@ msgstr "Donde acorte, usar rutas canonicalizadas para cabeceras de sistemas." #: c-family/c.opt:1305 msgid "Enable the char8_t fundamental type and use it as the type for UTF-8 string and character literals." -msgstr "" +msgstr "Habilita el tipo fundamental char8_t y lo usa como el tipo para los literales de cadenas UTF-8 y de caracteres." #: c-family/c.opt:1393 msgid "Deprecated in GCC 8. This switch has no effect." @@ -7356,7 +7356,7 @@ msgstr "Factoriza constructores y destructores complejos para favorecer el espac #: c-family/c.opt:1441 msgid "Print hierarchical comparisons when template types are mismatched." -msgstr "" +msgstr "Imprime comparaciones jerárquicas cuando los tipos de plantilla no coinciden." #: c-family/c.opt:1445 msgid "Preprocess directives only." @@ -7368,7 +7368,7 @@ msgstr "Permite '$' como un identificador de carácter." #: c-family/c.opt:1453 msgid "-fmacro-prefix-map== Map one directory name to another in __FILE__, __BASE_FILE__, and __builtin_FILE()." -msgstr "" +msgstr "-fmacro-prefix-map== Asocia un nombre de directorio a otro en __FILE__, __BASE_FILE__, y __builtin_FILE()." #: c-family/c.opt:1457 msgid "Write all declarations as Ada code transitively." @@ -7909,13 +7909,11 @@ msgstr "No considerada." #: d/lang.opt:51 msgid "-Hd \tWrite D interface files to directory ." -msgstr "" +msgstr "-Hd \tEscribe los ficheros de interfaz de D en el directorio ." #: d/lang.opt:55 -#, fuzzy -#| msgid "-o \tPlace output into ." msgid "-Hf \tWrite D interface to ." -msgstr "-o \tColoca la salida en el ." +msgstr "-Hf \tEscribe el interfaz de D en el ." #: d/lang.opt:123 msgid "Warn about casts that will produce a null result." @@ -7950,10 +7948,8 @@ msgid "Generate code for all template instantiations." msgstr "Genera código para todas las instanciaciones de plantillas." #: d/lang.opt:178 -#, fuzzy -#| msgid "Generate code for GNU assembler (gas)." msgid "Generate code for assert contracts." -msgstr "Genera código para el ensamblador de GNU (gas)." +msgstr "Genera código para contratos de assert." #: d/lang.opt:186 msgid "-fbounds-check=[on|safeonly|off]\tTurn array bounds checks on, in @safe code only, or off." @@ -8019,19 +8015,15 @@ msgstr "Genera código para el modo de usuario." #: d/lang.opt:262 msgid "Process all modules specified on the command line, but only generate code for the module specified by the argument." -msgstr "" +msgstr "Procesa todos los módulos especificados en la línea de órdenes, pero solo genera código para el módulo especificado por el argumento." #: d/lang.opt:266 -#, fuzzy -#| msgid "Generate code for built-in atomic operations." msgid "Generate code for postcondition contracts." -msgstr "Genera código para operaciones atómicas internas." +msgstr "Genera código para contratos de postcondiciones." #: d/lang.opt:270 -#, fuzzy -#| msgid "Generate code for built-in atomic operations." msgid "Generate code for precondition contracts." -msgstr "Genera código para operaciones atómicas internas." +msgstr "Genera código para contratos de precondiciones." #: d/lang.opt:274 #, fuzzy @@ -8040,14 +8032,12 @@ msgid "Compile release version." msgstr "Muestra la versión del compilador." #: d/lang.opt:282 -#, fuzzy -#| msgid "Generate code for the supervisor mode (default)." msgid "Generate code for switches without a default case." -msgstr "Genera código para el modo supervisor (predeterminado)." +msgstr "Genera código para las opciones sin caso predefinido." #: d/lang.opt:286 msgid "List information on all language changes." -msgstr "" +msgstr "Muestra información sobre todos los cambios del lenguaje." #: d/lang.opt:290 msgid "Give deprecation messages about -ftransition=import anomalies." @@ -8055,7 +8045,7 @@ msgstr "" #: d/lang.opt:294 msgid "List all usages of complex or imaginary types." -msgstr "" +msgstr "Enumera todos los usos de los tipos complejo o imaginario." #: d/lang.opt:298 msgid "Implement DIP1000: Scoped pointers (experimental)." @@ -8067,21 +8057,19 @@ msgstr "" #: d/lang.opt:306 msgid "List all non-mutable fields which occupy an object instance." -msgstr "" +msgstr "Enumera todos los campos no mutables que ocupan la instancia de un objeto." #: d/lang.opt:310 msgid "Revert to single phase name lookup." -msgstr "" +msgstr "Revierta a búsqueda de nombres de una sola fase." #: d/lang.opt:314 msgid "List all hidden GC allocations." msgstr "" #: d/lang.opt:318 -#, fuzzy -#| msgid "Use given thread-local storage dialect." msgid "List all variables going into thread local storage." -msgstr "Usa el dialecto de almacenamiento thread-local dado." +msgstr "Enumera todas las variables que van al almacenamiento local del hilo." #: d/lang.opt:322 #, fuzzy @@ -8094,18 +8082,16 @@ msgid "-fversion=\tCompile in version code >= or identified msgstr "" #: d/lang.opt:350 -#, fuzzy -#| msgid "Do not assume that standard C libraries and \"main\" exist." msgid "Do not link the standard D library in the compilation." -msgstr "No asume que existen las bibliotecas C estándar y \"main\"." +msgstr "No enlaza la biblioteca D estándar en la compilación." #: d/lang.opt:358 msgid "Link the standard D library statically in the compilation." -msgstr "" +msgstr "Enlaza la biblioteca D estándar estáticamente en la compilación." #: d/lang.opt:362 msgid "Link the standard D library dynamically in the compilation." -msgstr "" +msgstr "Enlaza la biblioteca D estándar dinámicamente en la compilación." #: go/lang.opt:42 msgid "-fgo-c-header=\tWrite Go struct definitions to file as C code." @@ -8172,16 +8158,12 @@ msgid "-mpointer-size=[no,32,short,64,long]\tSet the default pointer size." msgstr "-mpointer-size=[no,32,short,64,long]\tEstablece el tamaña predeterminado de los punteros." #: config/mcore/mcore.opt:23 -#, fuzzy -#| msgid "Generate code for the M*Core M210" msgid "Generate code for the M*Core M210." -msgstr "Genera código para el M*Core M210" +msgstr "Genera código para el M*Core M210." #: config/mcore/mcore.opt:27 -#, fuzzy -#| msgid "Generate code for the M*Core M340" msgid "Generate code for the M*Core M340." -msgstr "Genera código para el M*Core M340" +msgstr "Genera código para el M*Core M340." #: config/mcore/mcore.opt:31 msgid "Force functions to be aligned to a 4 byte boundary." @@ -8551,7 +8533,7 @@ msgstr "Activa la biblioteca compartida basada en ID." #: config/m68k/m68k.opt:147 msgid "Use 32-bit offsets in jump tables rather than 16-bit offsets." -msgstr "" +msgstr "Usa desplazamientos de 32 bits en las tablas de saltos en lugar de desplazamientos de 16 bits." #: config/m68k/m68k.opt:151 msgid "Do not use the bit-field instructions." @@ -8662,11 +8644,11 @@ msgstr "Utiliza operadores %reloc() en vez de macros de ensamblador para cargar #: config/riscv/riscv.opt:114 msgid "Take advantage of linker relaxations to reduce the number of instructions required to materialize symbol addresses." -msgstr "" +msgstr "Aprovecha los descansos del enlazador para reducir el número de instrucciones requeridas para materializar direcciones de símbolos." #: config/riscv/riscv.opt:133 msgid "Emit RISC-V ELF attribute." -msgstr "" +msgstr "Emite el atributo ELF de RISC-V." #: config/m32c/m32c.opt:23 msgid "-msim\tUse simulator runtime." -- cgit v1.1 From d79e9c5e969cffb8ddf55db4d63df1782069e98f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 30 Sep 2019 22:27:44 +0000 Subject: compiler: change escape maps to hash tables Also use just one table lookup, not two. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/197759 From-SVN: r276382 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/escape.cc | 54 ++++++++++++++++++++++----------------------- gcc/go/gofrontend/escape.h | 6 ++--- 3 files changed, 31 insertions(+), 31 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 3f2c3dc..f7c45ee 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -10a1671d94ddc0c39f2f4b039e5ea33358f414c0 +07faafda5fbd66a710153814f30d93c91461e7cb The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index 91f43a6..bfd1a39 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -579,9 +579,9 @@ Node::is_sink() const return false; } -std::map Node::objects; -std::map Node::expressions; -std::map Node::statements; +Unordered_map(Named_object*, Node*) Node::objects; +Unordered_map(Expression*, Node*) Node::expressions; +Unordered_map(Statement*, Node*) Node::statements; std::vector Node::indirects; // Make a object node or return a cached node for this object. @@ -589,13 +589,12 @@ std::vector Node::indirects; Node* Node::make_node(Named_object* no) { - if (Node::objects.find(no) != Node::objects.end()) - return Node::objects[no]; - - Node* n = new Node(no); - std::pair val(no, n); - Node::objects.insert(val); - return n; + std::pair val(no, NULL); + std::pair ins = + Node::objects.insert(val); + if (ins.second) + ins.first->second = new Node(no); + return ins.first->second; } // Make an expression node or return a cached node for this expression. @@ -603,13 +602,12 @@ Node::make_node(Named_object* no) Node* Node::make_node(Expression* e) { - if (Node::expressions.find(e) != Node::expressions.end()) - return Node::expressions[e]; - - Node* n = new Node(e); - std::pair val(e, n); - Node::expressions.insert(val); - return n; + std::pair val(e, NULL); + std::pair ins = + Node::expressions.insert(val); + if (ins.second) + ins.first->second = new Node(e); + return ins.first->second; } // Make a statement node or return a cached node for this statement. @@ -617,13 +615,12 @@ Node::make_node(Expression* e) Node* Node::make_node(Statement* s) { - if (Node::statements.find(s) != Node::statements.end()) - return Node::statements[s]; - - Node* n = new Node(s); - std::pair val(s, n); - Node::statements.insert(val); - return n; + std::pair val(s, NULL); + std::pair ins = + Node::statements.insert(val); + if (ins.second) + ins.first->second = new Node(s); + return ins.first->second; } // Make an indirect node with given child. @@ -3447,19 +3444,22 @@ Gogo::reclaim_escape_nodes() void Node::reclaim_nodes() { - for (std::map::iterator p = Node::objects.begin(); + for (Unordered_map(Named_object*, Node*)::iterator p = + Node::objects.begin(); p != Node::objects.end(); ++p) delete p->second; Node::objects.clear(); - for (std::map::iterator p = Node::expressions.begin(); + for (Unordered_map(Expression*, Node*)::iterator p = + Node::expressions.begin(); p != Node::expressions.end(); ++p) delete p->second; Node::expressions.clear(); - for (std::map::iterator p = Node::statements.begin(); + for (Unordered_map(Statement*, Node*)::iterator p = + Node::statements.begin(); p != Node::statements.end(); ++p) delete p->second; diff --git a/gcc/go/gofrontend/escape.h b/gcc/go/gofrontend/escape.h index 88e23ce..e97b529 100644 --- a/gcc/go/gofrontend/escape.h +++ b/gcc/go/gofrontend/escape.h @@ -329,9 +329,9 @@ class Node Node* child_; // Cache all the Nodes created via Node::make_node to make the API simpler. - static std::map objects; - static std::map expressions; - static std::map statements; + static Unordered_map(Named_object*, Node*) objects; + static Unordered_map(Expression*, Node*) expressions; + static Unordered_map(Statement*, Node*) statements; // Collection of all NODE_INDIRECT Nodes, used for reclaiming memory. This // is not a cache -- each make_indirect_node will make a fresh Node. -- cgit v1.1 From c6db6feebee097fadf1c1ec9e1fa3e05a304d535 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 1 Oct 2019 00:16:16 +0000 Subject: Daily bump. From-SVN: r276386 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index afc3f20..05ec96c 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20190930 +20191001 -- cgit v1.1 From bd2d1b3d44353c0f4e3a628fc338810dca68dafc Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 1 Oct 2019 08:50:31 +0200 Subject: doc/md.texi: Fix some typos It says "size N/2" in a few places where "size S/2" is meant. * doc/md.texi (vec_pack_trunc_@var{m}): Fix typo. (vec_pack_sfix_trunc_@var{m}, vec_pack_ufix_trunc_@var{m}): Ditto. (vec_packs_float_@var{m}, vec_packu_float_@var{m}): Ditto. From-SVN: r276387 --- gcc/ChangeLog | 6 ++++++ gcc/doc/md.texi | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5c3e3e1..d1fa196 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Segher Boessenkool + + * doc/md.texi (vec_pack_trunc_@var{m}): Fix typo. + (vec_pack_sfix_trunc_@var{m}, vec_pack_ufix_trunc_@var{m}): Ditto. + (vec_packs_float_@var{m}, vec_packu_float_@var{m}): Ditto. + 2019-09-30 David Malcolm * diagnostic-show-locus.c (line_label::line_label): Initialize diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 868016a..859ebed 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5454,7 +5454,7 @@ The output and input vectors should have the same modes. Narrow (demote) and merge the elements of two vectors. Operands 1 and 2 are vectors of the same mode having N integral or floating point elements of size S@. Operand 0 is the resulting vector in which 2*N elements of -size N/2 are concatenated after narrowing them down using truncation. +size S/2 are concatenated after narrowing them down using truncation. @cindex @code{vec_pack_sbool_trunc_@var{m}} instruction pattern @item @samp{vec_pack_sbool_trunc_@var{m}} @@ -5481,7 +5481,7 @@ saturating arithmetic. Narrow, convert to signed/unsigned integral type and merge the elements of two vectors. Operands 1 and 2 are vectors of the same mode having N floating point elements of size S@. Operand 0 is the resulting vector -in which 2*N elements of size N/2 are concatenated. +in which 2*N elements of size S/2 are concatenated. @cindex @code{vec_packs_float_@var{m}} instruction pattern @cindex @code{vec_packu_float_@var{m}} instruction pattern @@ -5489,7 +5489,7 @@ in which 2*N elements of size N/2 are concatenated. Narrow, convert to floating point type and merge the elements of two vectors. Operands 1 and 2 are vectors of the same mode having N signed/unsigned integral elements of size S@. Operand 0 is the resulting vector -in which 2*N elements of size N/2 are concatenated. +in which 2*N elements of size S/2 are concatenated. @cindex @code{vec_unpacks_hi_@var{m}} instruction pattern @cindex @code{vec_unpacks_lo_@var{m}} instruction pattern -- cgit v1.1 From ba8fa8daf52c560fce0e4d35556137ca5b8217d0 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 07:46:45 +0000 Subject: Update remaining calls to choose_hard_reg_mode 2019-10-01 Richard Sandiford gcc/ * regs.h (HARD_REGNO_CALLER_SAVE_MODE): Update call to choose_hard_reg_mode. * config/sparc/sparc.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. From-SVN: r276388 --- gcc/ChangeLog | 6 ++++++ gcc/config/sparc/sparc.h | 2 +- gcc/regs.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d1fa196..aa44ccd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Richard Sandiford + + * regs.h (HARD_REGNO_CALLER_SAVE_MODE): Update call to + choose_hard_reg_mode. + * config/sparc/sparc.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. + 2019-10-01 Segher Boessenkool * doc/md.texi (vec_pack_trunc_@var{m}): Fix typo. diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index d147418..2b730f7 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -716,7 +716,7 @@ along with GCC; see the file COPYING3. If not see mode but the largest suitable mode for the given (REGNO, NREGS) pair and it quickly creates paradoxical subregs that can be problematic. */ #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ - ((MODE) == VOIDmode ? choose_hard_reg_mode (REGNO, NREGS, false) : (MODE)) + ((MODE) == VOIDmode ? choose_hard_reg_mode (REGNO, NREGS, NULL) : (MODE)) /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ diff --git a/gcc/regs.h b/gcc/regs.h index 821979e..ea775df 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -192,7 +192,7 @@ extern int caller_save_needed; /* Select a register mode required for caller save of hard regno REGNO. */ #ifndef HARD_REGNO_CALLER_SAVE_MODE #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ - choose_hard_reg_mode (REGNO, NREGS, false) + choose_hard_reg_mode (REGNO, NREGS, NULL) #endif /* Target-dependent globals. */ -- cgit v1.1 From 08cc4d925f640c3cd0336bae4dc6004244a5c80a Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 08:53:54 +0000 Subject: [AArch64] Make call insns record the callee's arm_pcs At the moment we rely on SYMBOL_REF_DECL to get the ABI of the callee of a call insn, falling back to the default ABI if the decl isn't available. I think it'd be cleaner to attach the ABI directly to the call instruction instead, which would also have the very minor benefit of handling indirect calls more efficiently. 2019-10-01 Richard Sandiford gcc/ * config/aarch64/aarch64-protos.h (aarch64_expand_call): Take an extra callee_abi argument. * config/aarch64/aarch64.c (aarch64_expand_call): Likewise. Insert a CALLEE_ABI unspec into the call pattern as the second element in the PARALLEL. (aarch64_simd_call_p): Delete. (aarch64_insn_callee_abi): Get the arm_pcs of the callee from the new CALLEE_ABI element of the PARALLEL. (aarch64_init_cumulative_args): Get the arm_pcs of the callee from the function type, if given. (aarch64_function_arg_advance): Handle ARM_PCS_SIMD. (aarch64_function_arg): Likewise. Return the arm_pcs of the callee when passed the function_arg_info end marker. (aarch64_output_mi_thunk): Pass the arm_pcs of the callee as the final argument of gen_sibcall. * config/aarch64/aarch64.md (UNSPEC_CALLEE_ABI): New unspec. (call): Make operand 2 a const_int_operand and pass it to expand_call. Wrap it in an UNSPEC_CALLEE_ABI unspec for the dummy define_expand pattern. (call_value): Likewise operand 3. (sibcall): Likewise operand 2. Place the unspec before rather than after the return. (sibcall_value): Likewise operand 3. (*call_insn, *call_value_insn): Include an UNSPEC_CALLEE_ABI. (tlsgd_small_, *tlsgd_small_): Likewise. (*sibcall_insn, *sibcall_value_insn): Likewise. Remove empty constraint strings. (untyped_call): Pass const0_rtx as the callee ABI to gen_call. gcc/testsuite/ * gcc.target/aarch64/torture/simd-abi-10.c: New test. * gcc.target/aarch64/torture/simd-abi-11.c: Likewise. From-SVN: r276391 --- gcc/ChangeLog | 31 +++++++++++ gcc/config/aarch64/aarch64-protos.h | 2 +- gcc/config/aarch64/aarch64.c | 65 ++++++++++------------ gcc/config/aarch64/aarch64.md | 65 +++++++++++++--------- gcc/testsuite/ChangeLog | 5 ++ .../gcc.target/aarch64/torture/simd-abi-10.c | 14 +++++ .../gcc.target/aarch64/torture/simd-abi-11.c | 26 +++++++++ 7 files changed, 144 insertions(+), 64 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/torture/simd-abi-10.c create mode 100644 gcc/testsuite/gcc.target/aarch64/torture/simd-abi-11.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index aa44ccd..cfe5f84 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,36 @@ 2019-10-01 Richard Sandiford + * config/aarch64/aarch64-protos.h (aarch64_expand_call): Take an + extra callee_abi argument. + * config/aarch64/aarch64.c (aarch64_expand_call): Likewise. + Insert a CALLEE_ABI unspec into the call pattern as the second + element in the PARALLEL. + (aarch64_simd_call_p): Delete. + (aarch64_insn_callee_abi): Get the arm_pcs of the callee from + the new CALLEE_ABI element of the PARALLEL. + (aarch64_init_cumulative_args): Get the arm_pcs of the callee + from the function type, if given. + (aarch64_function_arg_advance): Handle ARM_PCS_SIMD. + (aarch64_function_arg): Likewise. Return the arm_pcs of the callee + when passed the function_arg_info end marker. + (aarch64_output_mi_thunk): Pass the arm_pcs of the callee as the + final argument of gen_sibcall. + * config/aarch64/aarch64.md (UNSPEC_CALLEE_ABI): New unspec. + (call): Make operand 2 a const_int_operand and pass it to expand_call. + Wrap it in an UNSPEC_CALLEE_ABI unspec for the dummy define_expand + pattern. + (call_value): Likewise operand 3. + (sibcall): Likewise operand 2. Place the unspec before rather than + after the return. + (sibcall_value): Likewise operand 3. + (*call_insn, *call_value_insn): Include an UNSPEC_CALLEE_ABI. + (tlsgd_small_, *tlsgd_small_): Likewise. + (*sibcall_insn, *sibcall_value_insn): Likewise. Remove empty + constraint strings. + (untyped_call): Pass const0_rtx as the callee ABI to gen_call. + +2019-10-01 Richard Sandiford + * regs.h (HARD_REGNO_CALLER_SAVE_MODE): Update call to choose_hard_reg_mode. * config/sparc/sparc.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise. diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index c9a3423..919f2b1 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -468,7 +468,7 @@ bool aarch64_const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, bool aarch64_constant_address_p (rtx); bool aarch64_emit_approx_div (rtx, rtx, rtx); bool aarch64_emit_approx_sqrt (rtx, rtx, bool); -void aarch64_expand_call (rtx, rtx, bool); +void aarch64_expand_call (rtx, rtx, rtx, bool); bool aarch64_expand_cpymem (rtx *); bool aarch64_float_const_zero_rtx_p (rtx); bool aarch64_float_const_rtx_p (rtx); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index ec180c8..85c87bb 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1872,37 +1872,17 @@ aarch64_reg_save_mode (tree fndecl, unsigned regno) : (aarch64_simd_decl_p (fndecl) ? E_TFmode : E_DFmode); } -/* Return true if the instruction is a call to a SIMD function, false - if it is not a SIMD function or if we do not know anything about - the function. */ - -static bool -aarch64_simd_call_p (const rtx_insn *insn) -{ - rtx symbol; - rtx call; - tree fndecl; - - gcc_assert (CALL_P (insn)); - call = get_call_rtx_from (insn); - symbol = XEXP (XEXP (call, 0), 0); - if (GET_CODE (symbol) != SYMBOL_REF) - return false; - fndecl = SYMBOL_REF_DECL (symbol); - if (!fndecl) - return false; - - return aarch64_simd_decl_p (fndecl); -} - /* Implement TARGET_INSN_CALLEE_ABI. */ const predefined_function_abi & aarch64_insn_callee_abi (const rtx_insn *insn) { - if (aarch64_simd_call_p (insn)) - return aarch64_simd_abi (); - return default_function_abi; + rtx pat = PATTERN (insn); + gcc_assert (GET_CODE (pat) == PARALLEL); + rtx unspec = XVECEXP (pat, 0, 1); + gcc_assert (GET_CODE (unspec) == UNSPEC + && XINT (unspec, 1) == UNSPEC_CALLEE_ABI); + return function_abis[INTVAL (XVECEXP (unspec, 0, 0))]; } /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. The callee only saves @@ -4847,10 +4827,11 @@ static rtx aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg) { CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); - gcc_assert (pcum->pcs_variant == ARM_PCS_AAPCS64); + gcc_assert (pcum->pcs_variant == ARM_PCS_AAPCS64 + || pcum->pcs_variant == ARM_PCS_SIMD); if (arg.end_marker_p ()) - return NULL_RTX; + return gen_int_mode (pcum->pcs_variant, DImode); aarch64_layout_arg (pcum_v, arg.mode, arg.type, arg.named); return pcum->aapcs_reg; @@ -4858,16 +4839,19 @@ aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg) void aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum, - const_tree fntype ATTRIBUTE_UNUSED, - rtx libname ATTRIBUTE_UNUSED, - const_tree fndecl ATTRIBUTE_UNUSED, - unsigned n_named ATTRIBUTE_UNUSED) + const_tree fntype, + rtx libname ATTRIBUTE_UNUSED, + const_tree fndecl ATTRIBUTE_UNUSED, + unsigned n_named ATTRIBUTE_UNUSED) { pcum->aapcs_ncrn = 0; pcum->aapcs_nvrn = 0; pcum->aapcs_nextncrn = 0; pcum->aapcs_nextnvrn = 0; - pcum->pcs_variant = ARM_PCS_AAPCS64; + if (fntype) + pcum->pcs_variant = (arm_pcs) fntype_abi (fntype).id (); + else + pcum->pcs_variant = ARM_PCS_AAPCS64; pcum->aapcs_reg = NULL_RTX; pcum->aapcs_arg_processed = false; pcum->aapcs_stack_words = 0; @@ -4892,7 +4876,8 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, const function_arg_info &arg) { CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); - if (pcum->pcs_variant == ARM_PCS_AAPCS64) + if (pcum->pcs_variant == ARM_PCS_AAPCS64 + || pcum->pcs_variant == ARM_PCS_SIMD) { aarch64_layout_arg (pcum_v, arg.mode, arg.type, arg.named); gcc_assert ((pcum->aapcs_reg != NULL_RTX) @@ -6921,7 +6906,8 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, } funexp = XEXP (DECL_RTL (function), 0); funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); - insn = emit_call_insn (gen_sibcall (funexp, const0_rtx, NULL_RTX)); + rtx callee_abi = gen_int_mode (fndecl_abi (function).id (), DImode); + insn = emit_call_insn (gen_sibcall (funexp, const0_rtx, callee_abi)); SIBLING_CALL_P (insn) = 1; insn = get_insns (); @@ -7999,11 +7985,12 @@ aarch64_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) RESULT is the register in which the result is returned. It's NULL for "call" and "sibcall". MEM is the location of the function call. + CALLEE_ABI is a const_int that gives the arm_pcs of the callee. SIBCALL indicates whether this function call is normal call or sibling call. It will generate different pattern accordingly. */ void -aarch64_expand_call (rtx result, rtx mem, bool sibcall) +aarch64_expand_call (rtx result, rtx mem, rtx callee_abi, bool sibcall) { rtx call, callee, tmp; rtvec vec; @@ -8033,7 +8020,11 @@ aarch64_expand_call (rtx result, rtx mem, bool sibcall) else tmp = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNUM)); - vec = gen_rtvec (2, call, tmp); + gcc_assert (CONST_INT_P (callee_abi)); + callee_abi = gen_rtx_UNSPEC (DImode, gen_rtvec (1, callee_abi), + UNSPEC_CALLEE_ABI); + + vec = gen_rtvec (3, call, callee_abi, tmp); call = gen_rtx_PARALLEL (VOIDmode, vec); aarch64_emit_call_insn (call); diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index fcba5ac..e483572 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -130,6 +130,7 @@ UNSPEC_AUTIB1716 UNSPEC_AUTIASP UNSPEC_AUTIBSP + UNSPEC_CALLEE_ABI UNSPEC_CASESI UNSPEC_CRC32B UNSPEC_CRC32CB @@ -913,14 +914,15 @@ ;; ------------------------------------------------------------------- (define_expand "call" - [(parallel [(call (match_operand 0 "memory_operand") - (match_operand 1 "general_operand")) - (use (match_operand 2 "" "")) - (clobber (reg:DI LR_REGNUM))])] + [(parallel + [(call (match_operand 0 "memory_operand") + (match_operand 1 "general_operand")) + (unspec:DI [(match_operand 2 "const_int_operand")] UNSPEC_CALLEE_ABI) + (clobber (reg:DI LR_REGNUM))])] "" " { - aarch64_expand_call (NULL_RTX, operands[0], false); + aarch64_expand_call (NULL_RTX, operands[0], operands[2], false); DONE; }" ) @@ -928,6 +930,7 @@ (define_insn "*call_insn" [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "r, Usf")) (match_operand 1 "" "")) + (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI) (clobber (reg:DI LR_REGNUM))] "" "@ @@ -937,15 +940,16 @@ ) (define_expand "call_value" - [(parallel [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand") - (match_operand 2 "general_operand"))) - (use (match_operand 3 "" "")) - (clobber (reg:DI LR_REGNUM))])] + [(parallel + [(set (match_operand 0 "") + (call (match_operand 1 "memory_operand") + (match_operand 2 "general_operand"))) + (unspec:DI [(match_operand 3 "const_int_operand")] UNSPEC_CALLEE_ABI) + (clobber (reg:DI LR_REGNUM))])] "" " { - aarch64_expand_call (operands[0], operands[1], false); + aarch64_expand_call (operands[0], operands[1], operands[3], false); DONE; }" ) @@ -954,6 +958,7 @@ [(set (match_operand 0 "" "") (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "r, Usf")) (match_operand 2 "" ""))) + (unspec:DI [(match_operand:DI 3 "const_int_operand")] UNSPEC_CALLEE_ABI) (clobber (reg:DI LR_REGNUM))] "" "@ @@ -963,33 +968,36 @@ ) (define_expand "sibcall" - [(parallel [(call (match_operand 0 "memory_operand") - (match_operand 1 "general_operand")) - (return) - (use (match_operand 2 "" ""))])] + [(parallel + [(call (match_operand 0 "memory_operand") + (match_operand 1 "general_operand")) + (unspec:DI [(match_operand 2 "const_int_operand")] UNSPEC_CALLEE_ABI) + (return)])] "" { - aarch64_expand_call (NULL_RTX, operands[0], true); + aarch64_expand_call (NULL_RTX, operands[0], operands[2], true); DONE; } ) (define_expand "sibcall_value" - [(parallel [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand") - (match_operand 2 "general_operand"))) - (return) - (use (match_operand 3 "" ""))])] + [(parallel + [(set (match_operand 0 "") + (call (match_operand 1 "memory_operand") + (match_operand 2 "general_operand"))) + (unspec:DI [(match_operand 3 "const_int_operand")] UNSPEC_CALLEE_ABI) + (return)])] "" { - aarch64_expand_call (operands[0], operands[1], true); + aarch64_expand_call (operands[0], operands[1], operands[3], true); DONE; } ) (define_insn "*sibcall_insn" [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf")) - (match_operand 1 "" "")) + (match_operand 1 "")) + (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI) (return)] "SIBLING_CALL_P (insn)" "@ @@ -999,10 +1007,11 @@ ) (define_insn "*sibcall_value_insn" - [(set (match_operand 0 "" "") + [(set (match_operand 0 "") (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "Ucs, Usf")) - (match_operand 2 "" ""))) + (match_operand 2 ""))) + (unspec:DI [(match_operand:DI 3 "const_int_operand")] UNSPEC_CALLEE_ABI) (return)] "SIBLING_CALL_P (insn)" "@ @@ -1022,7 +1031,9 @@ { int i; - emit_call_insn (gen_call (operands[0], const0_rtx, NULL)); + /* Untyped calls always use the default ABI. It's only possible to use + ABI variants if we know the type of the target function. */ + emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx)); for (i = 0; i < XVECLEN (operands[2], 0); i++) { @@ -6682,6 +6693,7 @@ (define_expand "tlsgd_small_" [(parallel [(set (match_operand 0 "register_operand") (call (mem:DI (match_dup 2)) (const_int 1))) + (unspec:DI [(const_int 0)] UNSPEC_CALLEE_ABI) (unspec:DI [(match_operand:PTR 1 "aarch64_valid_symref")] UNSPEC_GOTSMALLTLS) (clobber (reg:DI LR_REGNUM))])] "" @@ -6692,6 +6704,7 @@ (define_insn "*tlsgd_small_" [(set (match_operand 0 "register_operand" "") (call (mem:DI (match_operand:DI 2 "" "")) (const_int 1))) + (unspec:DI [(const_int 0)] UNSPEC_CALLEE_ABI) (unspec:DI [(match_operand:PTR 1 "aarch64_valid_symref" "S")] UNSPEC_GOTSMALLTLS) (clobber (reg:DI LR_REGNUM)) ] diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cc31ac8..2bf37cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Richard Sandiford + + * gcc.target/aarch64/torture/simd-abi-10.c: New test. + * gcc.target/aarch64/torture/simd-abi-11.c: Likewise. + 2019-09-30 Yuliang Wang * gcc.dg/vect/vect-sdiv-pow2-1.c: New test. diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-10.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-10.c new file mode 100644 index 0000000..3d6893e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-10.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +int __attribute__((aarch64_vector_pcs)) (*callee) (void); + +int __attribute__ ((aarch64_vector_pcs)) +caller (int *x) +{ + return callee () + 1; +} + +/* { dg-final { scan-assembler-not {\tstp\tq} } } */ +/* { dg-final { scan-assembler-not {\tldp\tq} } } */ +/* { dg-final { scan-assembler-not {\tstr\tq} } } */ +/* { dg-final { scan-assembler-not {\tldr\tq} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-11.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-11.c new file mode 100644 index 0000000..de99bd7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-11.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +int (*callee) (void); + +int __attribute__ ((aarch64_vector_pcs)) +caller (int *x) +{ + return callee () + 1; +} + +/* { dg-final { scan-assembler {\sstp\tq8, q9} } } */ +/* { dg-final { scan-assembler {\sstp\tq10, q11} } } */ +/* { dg-final { scan-assembler {\sstp\tq12, q13} } } */ +/* { dg-final { scan-assembler {\sstp\tq14, q15} } } */ +/* { dg-final { scan-assembler {\sstp\tq16, q17} } } */ +/* { dg-final { scan-assembler {\sstp\tq18, q19} } } */ +/* { dg-final { scan-assembler {\sstp\tq20, q21} } } */ +/* { dg-final { scan-assembler {\sstp\tq22, q23} } } */ +/* { dg-final { scan-assembler {\sldp\tq8, q9} } } */ +/* { dg-final { scan-assembler {\sldp\tq10, q11} } } */ +/* { dg-final { scan-assembler {\sldp\tq12, q13} } } */ +/* { dg-final { scan-assembler {\sldp\tq14, q15} } } */ +/* { dg-final { scan-assembler {\sldp\tq16, q17} } } */ +/* { dg-final { scan-assembler {\sldp\tq18, q19} } } */ +/* { dg-final { scan-assembler {\sldp\tq20, q21} } } */ +/* { dg-final { scan-assembler {\sldp\tq22, q23} } } */ -- cgit v1.1 From bb6ce448fc194cca8e51aea274a1b2408c7746c3 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 08:55:28 +0000 Subject: [AArch64] Use calls for SVE TLSDESC One (unintended) side effect of the patches to support multiple ABIs is that we can now represent tlsdesc calls as normal calls on SVE targets. This is likely to be handled more efficiently than clobber_high, and for example fixes the long-standing failure in gcc.target/aarch64/sve/tls_preserve_1.c. 2019-10-01 Richard Sandiford gcc/ PR target/91452 * config/aarch64/aarch64.h (ARM_PCS_TLSDESC): New arm_pcs. * config/aarch64/aarch64-protos.h (aarch64_tlsdesc_abi_id): Declare. * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): Handle ARM_PCS_TLSDESC. (aarch64_tlsdesc_abi_id): New function. * config/aarch64/aarch64.md (tlsdesc_small_sve_): Use a call rtx instead of a list of clobbers and clobber_highs. (tlsdesc_small_): Update accordingly. From-SVN: r276392 --- gcc/ChangeLog | 12 ++++++ gcc/config/aarch64/aarch64-protos.h | 1 + gcc/config/aarch64/aarch64.c | 25 ++++++++++++- gcc/config/aarch64/aarch64.h | 1 + gcc/config/aarch64/aarch64.md | 74 ++++++++----------------------------- 5 files changed, 53 insertions(+), 60 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cfe5f84..e0aa3ac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,17 @@ 2019-10-01 Richard Sandiford + PR target/91452 + * config/aarch64/aarch64.h (ARM_PCS_TLSDESC): New arm_pcs. + * config/aarch64/aarch64-protos.h (aarch64_tlsdesc_abi_id): Declare. + * config/aarch64/aarch64.c (aarch64_hard_regno_call_part_clobbered): + Handle ARM_PCS_TLSDESC. + (aarch64_tlsdesc_abi_id): New function. + * config/aarch64/aarch64.md (tlsdesc_small_sve_): Use a call + rtx instead of a list of clobbers and clobber_highs. + (tlsdesc_small_): Update accordingly. + +2019-10-01 Richard Sandiford + * config/aarch64/aarch64-protos.h (aarch64_expand_call): Take an extra callee_abi argument. * config/aarch64/aarch64.c (aarch64_expand_call): Likewise. diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 919f2b1..ab27a12 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -533,6 +533,7 @@ bool aarch64_uimm12_shift (HOST_WIDE_INT); bool aarch64_use_return_insn_p (void); const char *aarch64_output_casesi (rtx *); +unsigned int aarch64_tlsdesc_abi_id (); enum aarch64_symbol_type aarch64_classify_symbol (rtx, HOST_WIDE_INT); enum aarch64_symbol_type aarch64_classify_tls_symbol (rtx); enum reg_class aarch64_regno_regclass (unsigned); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 85c87bb..7ee31a6 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1896,12 +1896,13 @@ aarch64_hard_regno_call_part_clobbered (unsigned int abi_id, { if (FP_REGNUM_P (regno)) { - bool simd_p = (abi_id == ARM_PCS_SIMD); poly_int64 per_register_size = GET_MODE_SIZE (mode); unsigned int nregs = hard_regno_nregs (regno, mode); if (nregs > 1) per_register_size = exact_div (per_register_size, nregs); - return maybe_gt (per_register_size, simd_p ? 16 : 8); + if (abi_id == ARM_PCS_SIMD || abi_id == ARM_PCS_TLSDESC) + return maybe_gt (per_register_size, 16); + return maybe_gt (per_register_size, 8); } return false; } @@ -13953,6 +13954,26 @@ aarch64_can_inline_p (tree caller, tree callee) return true; } +/* Return the ID of the TLDESC ABI, initializing the descriptor if hasn't + been already. */ + +unsigned int +aarch64_tlsdesc_abi_id () +{ + predefined_function_abi &tlsdesc_abi = function_abis[ARM_PCS_TLSDESC]; + if (!tlsdesc_abi.initialized_p ()) + { + HARD_REG_SET full_reg_clobbers; + CLEAR_HARD_REG_SET (full_reg_clobbers); + SET_HARD_REG_BIT (full_reg_clobbers, R0_REGNUM); + SET_HARD_REG_BIT (full_reg_clobbers, CC_REGNUM); + for (int regno = P0_REGNUM; regno <= P15_REGNUM; ++regno) + SET_HARD_REG_BIT (full_reg_clobbers, regno); + tlsdesc_abi.initialize (ARM_PCS_TLSDESC, full_reg_clobbers); + } + return tlsdesc_abi.id (); +} + /* Return true if SYMBOL_REF X binds locally. */ static bool diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 5aff106..abd14a2 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -784,6 +784,7 @@ enum arm_pcs { ARM_PCS_AAPCS64, /* Base standard AAPCS for 64 bit. */ ARM_PCS_SIMD, /* For aarch64_vector_pcs functions. */ + ARM_PCS_TLSDESC, /* For targets of tlsdesc calls. */ ARM_PCS_UNKNOWN }; diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index e483572..e7a6930 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -6805,7 +6805,12 @@ "TARGET_TLS_DESC" { if (TARGET_SVE) - emit_insn (gen_tlsdesc_small_sve_ (operands[0])); + { + rtx abi = gen_int_mode (aarch64_tlsdesc_abi_id (), DImode); + rtx_insn *call + = emit_call_insn (gen_tlsdesc_small_sve_ (operands[0], abi)); + RTL_CONST_CALL_P (call) = 1; + } else emit_insn (gen_tlsdesc_small_advsimd_ (operands[0])); DONE; @@ -6827,67 +6832,20 @@ [(set_attr "type" "call") (set_attr "length" "16")]) -;; For SVE, model tlsdesc calls as clobbering the lower 128 bits of -;; all vector registers, and clobber all predicate registers, on -;; top of the usual R0 and LR. +;; For SVE, model tlsdesc calls as normal calls, with the callee ABI +;; describing the extra call-preserved guarantees. This would work +;; for non-SVE too, but avoiding a call is probably better if we can. (define_insn "tlsdesc_small_sve_" [(set (reg:PTR R0_REGNUM) - (unspec:PTR [(match_operand 0 "aarch64_valid_symref" "S")] - UNSPEC_TLSDESC)) + (call (mem:DI (unspec:PTR + [(match_operand 0 "aarch64_valid_symref")] + UNSPEC_TLSDESC)) + (const_int 0))) + (unspec:DI [(match_operand:DI 1 "const_int_operand")] UNSPEC_CALLEE_ABI) (clobber (reg:DI LR_REGNUM)) - (clobber (reg:CC CC_REGNUM)) - (clobber_high (reg:TI V0_REGNUM)) - (clobber_high (reg:TI V1_REGNUM)) - (clobber_high (reg:TI V2_REGNUM)) - (clobber_high (reg:TI V3_REGNUM)) - (clobber_high (reg:TI V4_REGNUM)) - (clobber_high (reg:TI V5_REGNUM)) - (clobber_high (reg:TI V6_REGNUM)) - (clobber_high (reg:TI V7_REGNUM)) - (clobber_high (reg:TI V8_REGNUM)) - (clobber_high (reg:TI V9_REGNUM)) - (clobber_high (reg:TI V10_REGNUM)) - (clobber_high (reg:TI V11_REGNUM)) - (clobber_high (reg:TI V12_REGNUM)) - (clobber_high (reg:TI V13_REGNUM)) - (clobber_high (reg:TI V14_REGNUM)) - (clobber_high (reg:TI V15_REGNUM)) - (clobber_high (reg:TI V16_REGNUM)) - (clobber_high (reg:TI V17_REGNUM)) - (clobber_high (reg:TI V18_REGNUM)) - (clobber_high (reg:TI V19_REGNUM)) - (clobber_high (reg:TI V20_REGNUM)) - (clobber_high (reg:TI V21_REGNUM)) - (clobber_high (reg:TI V22_REGNUM)) - (clobber_high (reg:TI V23_REGNUM)) - (clobber_high (reg:TI V24_REGNUM)) - (clobber_high (reg:TI V25_REGNUM)) - (clobber_high (reg:TI V26_REGNUM)) - (clobber_high (reg:TI V27_REGNUM)) - (clobber_high (reg:TI V28_REGNUM)) - (clobber_high (reg:TI V29_REGNUM)) - (clobber_high (reg:TI V30_REGNUM)) - (clobber_high (reg:TI V31_REGNUM)) - (clobber (reg:VNx2BI P0_REGNUM)) - (clobber (reg:VNx2BI P1_REGNUM)) - (clobber (reg:VNx2BI P2_REGNUM)) - (clobber (reg:VNx2BI P3_REGNUM)) - (clobber (reg:VNx2BI P4_REGNUM)) - (clobber (reg:VNx2BI P5_REGNUM)) - (clobber (reg:VNx2BI P6_REGNUM)) - (clobber (reg:VNx2BI P7_REGNUM)) - (clobber (reg:VNx2BI P8_REGNUM)) - (clobber (reg:VNx2BI P9_REGNUM)) - (clobber (reg:VNx2BI P10_REGNUM)) - (clobber (reg:VNx2BI P11_REGNUM)) - (clobber (reg:VNx2BI P12_REGNUM)) - (clobber (reg:VNx2BI P13_REGNUM)) - (clobber (reg:VNx2BI P14_REGNUM)) - (clobber (reg:VNx2BI P15_REGNUM)) - (clobber (match_scratch:DI 1 "=r")) - (use (reg:DI FP_REGNUM))] + (clobber (match_scratch:DI 2 "=r"))] "TARGET_TLS_DESC && TARGET_SVE" - "adrp\\tx0, %A0\;ldr\\t%1, [x0, #%L0]\;add\\t0, 0, %L0\;.tlsdesccall\\t%0\;blr\\t%1" + "adrp\\tx0, %A0\;ldr\\t%2, [x0, #%L0]\;add\\t0, 0, %L0\;.tlsdesccall\\t%0\;blr\\t%2" [(set_attr "type" "call") (set_attr "length" "16")]) -- cgit v1.1 From 17d184e5c4896264c27c27d125a6c1f8462d9d37 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 08:55:50 +0000 Subject: Remove clobber_high The AArch64 SVE tlsdesc patterns were the main motivating reason for clobber_high. It's no longer needed now that the patterns use calls instead. At the time, one of the possible future uses for clobber_high was for asm statements. However, the current code wouldn't handle that case without modification, so I think we might as well remove it for now. We can always reapply it in future if it turns out to be useful again. 2019-10-01 Richard Sandiford gcc/ * rtl.def (CLOBBER_HIGH): Delete. * doc/rtl.texi (clobber_high): Remove documentation. * rtl.h (SET_DEST): Remove CLOBBER_HIGH from the list of codes. (reg_is_clobbered_by_clobber_high): Delete. (gen_hard_reg_clobber_high): Likewise. * alias.c (record_set): Remove CLOBBER_HIGH handling. * cfgexpand.c (expand_gimple_stmt): Likewise. * combine-stack-adj.c (single_set_for_csa): Likewise. * combine.c (find_single_use_1, set_nonzero_bits_and_sign_copies) (can_combine_p, is_parallel_of_n_reg_sets, try_combine) (record_dead_and_set_regs_1, reg_dead_at_p_1): Likewise. * cse.c (invalidate_reg): Remove clobber_high parameter. (invalidate): Update call accordingly. (canonicalize_insn): Remove CLOBBER_HIGH handling. (invalidate_from_clobbers, invalidate_from_sets_and_clobbers) (count_reg_usage, insn_live_p): Likewise. * cselib.h (cselib_invalidate_rtx): Remove sett argument. * cselib.c (cselib_invalidate_regno, cselib_invalidate_rtx): Likewise. (cselib_invalidate_rtx_note_stores): Update call accordingly. (cselib_expand_value_rtx_1): Remove CLOBBER_HIGH handling. (cselib_invalidate_regno, cselib_process_insn): Likewise. * dce.c (deletable_insn_p, mark_nonreg_stores_1): Likewise. (mark_nonreg_stores_2): Likewise. * df-scan.c (df_find_hard_reg_defs, df_uses_record): Likewise. (df_get_call_refs): Likewise. * dwarf2out.c (mem_loc_descriptor): Likewise. * emit-rtl.c (verify_rtx_sharing): Likewise. (copy_insn_1, copy_rtx_if_shared_1): Likewise. (hard_reg_clobbers_high, gen_hard_reg_clobber_high): Delete. * genconfig.c (walk_insn_part): Remove CLOBBER_HIGH handling. * genemit.c (gen_exp, gen_insn): Likewise. * genrecog.c (validate_pattern, remove_clobbers): Likewise. * haifa-sched.c (haifa_classify_rtx): Likewise. * ira-build.c (create_insn_allocnos): Likewise. * ira-costs.c (scan_one_insn): Likewise. * ira.c (equiv_init_movable_p, memref_referenced_p): Likewise. (rtx_moveable_p, interesting_dest_for_shprep): Likewise. * jump.c (mark_jump_label_1): Likewise. * lra-int.h (lra_insn_reg::clobber_high): Delete. * lra-eliminations.c (lra_eliminate_regs_1): Remove CLOBBER_HIGH handling. (mark_not_eliminable): Likewise. * lra-lives.c (process_bb_lives): Likewise. * lra.c (new_insn_reg): Remove clobber_high parameter. (collect_non_operand_hard_regs): Likewise. Update call to new insn_reg. Remove CLOBBER_HIGH handling. (lra_set_insn_recog_data): Remove CLOBBER_HIGH handling. Update call to collect_non_operand_hard_regs. (add_regs_to_insn_regno_info): Remove CLOBBER_HIGH handling. Update call to new_insn_reg. (lra_update_insn_regno_info): Remove CLOBBER_HIGH handling. * postreload.c (reload_cse_simplify, reload_combine_note_use) (move2add_note_store): Likewise. * print-rtl.c (print_pattern): Likewise. * recog.c (store_data_bypass_p_1, store_data_bypass_p): Likewise. (if_test_bypass_p): Likewise. * regcprop.c (kill_clobbered_value, kill_set_value): Likewise. * reginfo.c (reg_scan_mark_refs): Likewise. * reload1.c (maybe_fix_stack_asms, eliminate_regs_1): Likewise. (elimination_effects, mark_not_eliminable, scan_paradoxical_subregs) (forget_old_reloads_1): Likewise. * reorg.c (find_end_label, try_merge_delay_insns, redundant_insn) (own_thread_p, fill_simple_delay_slots, fill_slots_from_thread) (dbr_schedule): Likewise. * resource.c (update_live_status, mark_referenced_resources) (mark_set_resources): Likewise. * rtl.c (copy_rtx): Likewise. * rtlanal.c (reg_referenced_p, set_of_1, single_set_2, noop_move_p) (note_pattern_stores): Likewise. (reg_is_clobbered_by_clobber_high): Delete. * sched-deps.c (sched_analyze_reg, sched_analyze_insn): Remove CLOBBER_HIGH handling. From-SVN: r276393 --- gcc/ChangeLog | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/alias.c | 10 ------- gcc/cfgexpand.c | 1 - gcc/combine-stack-adj.c | 1 - gcc/combine.c | 23 +-------------- gcc/cse.c | 69 +++++++-------------------------------------- gcc/cselib.c | 41 +++++++-------------------- gcc/cselib.h | 2 +- gcc/dce.c | 11 ++------ gcc/df-scan.c | 6 ---- gcc/doc/rtl.texi | 15 +--------- gcc/dwarf2out.c | 1 - gcc/emit-rtl.c | 18 ------------ gcc/genconfig.c | 1 - gcc/genemit.c | 12 +------- gcc/genrecog.c | 3 +- gcc/haifa-sched.c | 3 -- gcc/ira-build.c | 5 ---- gcc/ira-costs.c | 7 ----- gcc/ira.c | 7 +---- gcc/jump.c | 1 - gcc/lra-eliminations.c | 11 -------- gcc/lra-int.h | 2 -- gcc/lra-lives.c | 28 ++++++------------ gcc/lra.c | 53 +++++++++++----------------------- gcc/postreload.c | 17 +---------- gcc/print-rtl.c | 1 - gcc/recog.c | 8 ++---- gcc/regcprop.c | 8 ++---- gcc/reginfo.c | 4 --- gcc/reload1.c | 17 +---------- gcc/reorg.c | 27 ++++++------------ gcc/resource.c | 24 ++-------------- gcc/rtl.c | 4 --- gcc/rtl.def | 10 ------- gcc/rtl.h | 13 +-------- gcc/rtlanal.c | 48 ++----------------------------- gcc/sched-deps.c | 15 +--------- 38 files changed, 152 insertions(+), 450 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e0aa3ac..2c515e1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,80 @@ 2019-10-01 Richard Sandiford + * rtl.def (CLOBBER_HIGH): Delete. + * doc/rtl.texi (clobber_high): Remove documentation. + * rtl.h (SET_DEST): Remove CLOBBER_HIGH from the list of codes. + (reg_is_clobbered_by_clobber_high): Delete. + (gen_hard_reg_clobber_high): Likewise. + * alias.c (record_set): Remove CLOBBER_HIGH handling. + * cfgexpand.c (expand_gimple_stmt): Likewise. + * combine-stack-adj.c (single_set_for_csa): Likewise. + * combine.c (find_single_use_1, set_nonzero_bits_and_sign_copies) + (can_combine_p, is_parallel_of_n_reg_sets, try_combine) + (record_dead_and_set_regs_1, reg_dead_at_p_1): Likewise. + * cse.c (invalidate_reg): Remove clobber_high parameter. + (invalidate): Update call accordingly. + (canonicalize_insn): Remove CLOBBER_HIGH handling. + (invalidate_from_clobbers, invalidate_from_sets_and_clobbers) + (count_reg_usage, insn_live_p): Likewise. + * cselib.h (cselib_invalidate_rtx): Remove sett argument. + * cselib.c (cselib_invalidate_regno, cselib_invalidate_rtx): Likewise. + (cselib_invalidate_rtx_note_stores): Update call accordingly. + (cselib_expand_value_rtx_1): Remove CLOBBER_HIGH handling. + (cselib_invalidate_regno, cselib_process_insn): Likewise. + * dce.c (deletable_insn_p, mark_nonreg_stores_1): Likewise. + (mark_nonreg_stores_2): Likewise. + * df-scan.c (df_find_hard_reg_defs, df_uses_record): Likewise. + (df_get_call_refs): Likewise. + * dwarf2out.c (mem_loc_descriptor): Likewise. + * emit-rtl.c (verify_rtx_sharing): Likewise. + (copy_insn_1, copy_rtx_if_shared_1): Likewise. + (hard_reg_clobbers_high, gen_hard_reg_clobber_high): Delete. + * genconfig.c (walk_insn_part): Remove CLOBBER_HIGH handling. + * genemit.c (gen_exp, gen_insn): Likewise. + * genrecog.c (validate_pattern, remove_clobbers): Likewise. + * haifa-sched.c (haifa_classify_rtx): Likewise. + * ira-build.c (create_insn_allocnos): Likewise. + * ira-costs.c (scan_one_insn): Likewise. + * ira.c (equiv_init_movable_p, memref_referenced_p): Likewise. + (rtx_moveable_p, interesting_dest_for_shprep): Likewise. + * jump.c (mark_jump_label_1): Likewise. + * lra-int.h (lra_insn_reg::clobber_high): Delete. + * lra-eliminations.c (lra_eliminate_regs_1): Remove CLOBBER_HIGH + handling. + (mark_not_eliminable): Likewise. + * lra-lives.c (process_bb_lives): Likewise. + * lra.c (new_insn_reg): Remove clobber_high parameter. + (collect_non_operand_hard_regs): Likewise. Update call to new + insn_reg. Remove CLOBBER_HIGH handling. + (lra_set_insn_recog_data): Remove CLOBBER_HIGH handling. Update call + to collect_non_operand_hard_regs. + (add_regs_to_insn_regno_info): Remove CLOBBER_HIGH handling. + Update call to new_insn_reg. + (lra_update_insn_regno_info): Remove CLOBBER_HIGH handling. + * postreload.c (reload_cse_simplify, reload_combine_note_use) + (move2add_note_store): Likewise. + * print-rtl.c (print_pattern): Likewise. + * recog.c (store_data_bypass_p_1, store_data_bypass_p): Likewise. + (if_test_bypass_p): Likewise. + * regcprop.c (kill_clobbered_value, kill_set_value): Likewise. + * reginfo.c (reg_scan_mark_refs): Likewise. + * reload1.c (maybe_fix_stack_asms, eliminate_regs_1): Likewise. + (elimination_effects, mark_not_eliminable, scan_paradoxical_subregs) + (forget_old_reloads_1): Likewise. + * reorg.c (find_end_label, try_merge_delay_insns, redundant_insn) + (own_thread_p, fill_simple_delay_slots, fill_slots_from_thread) + (dbr_schedule): Likewise. + * resource.c (update_live_status, mark_referenced_resources) + (mark_set_resources): Likewise. + * rtl.c (copy_rtx): Likewise. + * rtlanal.c (reg_referenced_p, set_of_1, single_set_2, noop_move_p) + (note_pattern_stores): Likewise. + (reg_is_clobbered_by_clobber_high): Delete. + * sched-deps.c (sched_analyze_reg, sched_analyze_insn): Remove + CLOBBER_HIGH handling. + +2019-10-01 Richard Sandiford + PR target/91452 * config/aarch64/aarch64.h (ARM_PCS_TLSDESC): New arm_pcs. * config/aarch64/aarch64-protos.h (aarch64_tlsdesc_abi_id): Declare. diff --git a/gcc/alias.c b/gcc/alias.c index 0ed1cbe..34e19fe 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -1556,16 +1556,6 @@ record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED) new_reg_base_value[regno] = 0; return; } - /* A CLOBBER_HIGH only wipes out the old value if the mode of the old - value is greater than that of the clobber. */ - else if (GET_CODE (set) == CLOBBER_HIGH) - { - if (new_reg_base_value[regno] != 0 - && reg_is_clobbered_by_clobber_high ( - regno, GET_MODE (new_reg_base_value[regno]), XEXP (set, 0))) - new_reg_base_value[regno] = 0; - return; - } src = SET_SRC (set); } diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index a2f9623..c34a53b 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3891,7 +3891,6 @@ expand_gimple_stmt (gimple *stmt) /* If we want exceptions for non-call insns, any may_trap_p instruction may throw. */ && GET_CODE (PATTERN (insn)) != CLOBBER - && GET_CODE (PATTERN (insn)) != CLOBBER_HIGH && GET_CODE (PATTERN (insn)) != USE && insn_could_throw_p (insn)) make_reg_eh_region_note (insn, 0, lp_nr); diff --git a/gcc/combine-stack-adj.c b/gcc/combine-stack-adj.c index 3638a1b..d14d59a 100644 --- a/gcc/combine-stack-adj.c +++ b/gcc/combine-stack-adj.c @@ -133,7 +133,6 @@ single_set_for_csa (rtx_insn *insn) && SET_SRC (this_rtx) == SET_DEST (this_rtx)) ; else if (GET_CODE (this_rtx) != CLOBBER - && GET_CODE (this_rtx) != CLOBBER_HIGH && GET_CODE (this_rtx) != USE) return NULL_RTX; } diff --git a/gcc/combine.c b/gcc/combine.c index d200c5a..d295a81 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -572,7 +572,6 @@ find_single_use_1 (rtx dest, rtx *loc) case SYMBOL_REF: CASE_CONST_ANY: case CLOBBER: - case CLOBBER_HIGH: return 0; case SET: @@ -1763,9 +1762,6 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data) return; } - /* Should not happen as we only using pseduo registers. */ - gcc_assert (GET_CODE (set) != CLOBBER_HIGH); - /* If this register is being initialized using itself, and the register is uninitialized in this basic block, and there are no LOG_LINKS which set the register, then part of the @@ -1924,7 +1920,6 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED, /* We can ignore CLOBBERs. */ case CLOBBER: - case CLOBBER_HIGH: break; case SET: @@ -2595,8 +2590,6 @@ is_parallel_of_n_reg_sets (rtx pat, int n) if (XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx) return false; break; - case CLOBBER_HIGH: - break; default: return false; } @@ -2897,8 +2890,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, for (i = 0; ok && i < XVECLEN (p2, 0); i++) { if ((GET_CODE (XVECEXP (p2, 0, i)) == SET - || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER - || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER_HIGH) + || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER) && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)), SET_DEST (XVECEXP (p2, 0, i)))) ok = false; @@ -13409,15 +13401,6 @@ record_dead_and_set_regs_1 (rtx dest, const_rtx setter, void *data) ? SET_SRC (setter) : gen_lowpart (GET_MODE (dest), SET_SRC (setter))); - else if (GET_CODE (setter) == CLOBBER_HIGH) - { - reg_stat_type *rsp = ®_stat[REGNO (dest)]; - if (rsp->last_set_value - && reg_is_clobbered_by_clobber_high - (REGNO (dest), GET_MODE (rsp->last_set_value), - XEXP (setter, 0))) - record_value_for_reg (dest, NULL, NULL_RTX); - } else record_value_for_reg (dest, record_dead_insn, NULL_RTX); } @@ -13863,10 +13846,6 @@ reg_dead_at_p_1 (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED) if (!REG_P (dest)) return; - if (GET_CODE (x) == CLOBBER_HIGH - && !reg_is_clobbered_by_clobber_high (reg_dead_reg, XEXP (x, 0))) - return; - regno = REGNO (dest); endregno = END_REGNO (dest); if (reg_dead_endregno > regno && reg_dead_regno < endregno) diff --git a/gcc/cse.c b/gcc/cse.c index be3277b..097fb94 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -561,7 +561,6 @@ static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned, static struct table_elt *insert (rtx, struct table_elt *, unsigned, machine_mode); static void merge_equiv_classes (struct table_elt *, struct table_elt *); -static void invalidate_reg (rtx, bool); static void invalidate (rtx, machine_mode); static void remove_invalid_refs (unsigned int); static void remove_invalid_subreg_refs (unsigned int, poly_uint64, @@ -1822,12 +1821,10 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr) } /* Remove from the hash table, or mark as invalid, all expressions whose - values could be altered by storing in register X. - - CLOBBER_HIGH is set if X was part of a CLOBBER_HIGH expression. */ + values could be altered by storing in register X. */ static void -invalidate_reg (rtx x, bool clobber_high) +invalidate_reg (rtx x) { gcc_assert (GET_CODE (x) == REG); @@ -1852,10 +1849,7 @@ invalidate_reg (rtx x, bool clobber_high) SUBREG_TICKED (regno) = -1; if (regno >= FIRST_PSEUDO_REGISTER) - { - gcc_assert (!clobber_high); - remove_pseudo_from_table (x, hash); - } + remove_pseudo_from_table (x, hash); else { HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno); @@ -1883,18 +1877,10 @@ invalidate_reg (rtx x, bool clobber_high) if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER) continue; - if (clobber_high) - { - if (reg_is_clobbered_by_clobber_high (p->exp, x)) - remove_from_table (p, hash); - } - else - { - unsigned int tregno = REGNO (p->exp); - unsigned int tendregno = END_REGNO (p->exp); - if (tendregno > regno && tregno < endregno) - remove_from_table (p, hash); - } + unsigned int tregno = REGNO (p->exp); + unsigned int tendregno = END_REGNO (p->exp); + if (tendregno > regno && tregno < endregno) + remove_from_table (p, hash); } } } @@ -1921,7 +1907,7 @@ invalidate (rtx x, machine_mode full_mode) switch (GET_CODE (x)) { case REG: - invalidate_reg (x, false); + invalidate_reg (x); return; case SUBREG: @@ -4425,8 +4411,6 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets) if (MEM_P (XEXP (x, 0))) canon_reg (XEXP (x, 0), insn); } - else if (GET_CODE (x) == CLOBBER_HIGH) - gcc_assert (REG_P (XEXP (x, 0))); else if (GET_CODE (x) == USE && ! (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)) @@ -4458,8 +4442,6 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets) if (MEM_P (XEXP (y, 0))) canon_reg (XEXP (y, 0), insn); } - else if (GET_CODE (y) == CLOBBER_HIGH) - gcc_assert (REG_P (XEXP (y, 0))); else if (GET_CODE (y) == USE && ! (REG_P (XEXP (y, 0)) && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER)) @@ -6149,12 +6131,6 @@ invalidate_from_clobbers (rtx_insn *insn) invalidate (XEXP (ref, 0), GET_MODE (ref)); } } - if (GET_CODE (x) == CLOBBER_HIGH) - { - rtx ref = XEXP (x, 0); - gcc_assert (REG_P (ref)); - invalidate_reg (ref, true); - } else if (GET_CODE (x) == PARALLEL) { int i; @@ -6171,12 +6147,6 @@ invalidate_from_clobbers (rtx_insn *insn) || GET_CODE (ref) == ZERO_EXTRACT) invalidate (XEXP (ref, 0), GET_MODE (ref)); } - else if (GET_CODE (y) == CLOBBER_HIGH) - { - rtx ref = XEXP (y, 0); - gcc_assert (REG_P (ref)); - invalidate_reg (ref, true); - } } } } @@ -6198,12 +6168,6 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn) rtx temx = XEXP (tem, 0); if (GET_CODE (temx) == CLOBBER) invalidate (SET_DEST (temx), VOIDmode); - else if (GET_CODE (temx) == CLOBBER_HIGH) - { - rtx temref = XEXP (temx, 0); - gcc_assert (REG_P (temref)); - invalidate_reg (temref, true); - } } } @@ -6231,12 +6195,6 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn) || GET_CODE (clobbered) == ZERO_EXTRACT) invalidate (XEXP (clobbered, 0), GET_MODE (clobbered)); } - else if (GET_CODE (y) == CLOBBER_HIGH) - { - rtx ref = XEXP (y, 0); - gcc_assert (REG_P (ref)); - invalidate_reg (ref, true); - } else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL) invalidate (SET_DEST (y), VOIDmode); } @@ -6896,10 +6854,6 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr) count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr); return; - case CLOBBER_HIGH: - gcc_assert (REG_P ((XEXP (x, 0)))); - return; - case SET: /* Unless we are setting a REG, count everything in SET_DEST. */ if (!REG_P (SET_DEST (x))) @@ -6952,8 +6906,7 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr) || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE) /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)), involving registers in the address. */ - || GET_CODE (XEXP (x, 0)) == CLOBBER - || GET_CODE (XEXP (x, 0)) == CLOBBER_HIGH) + || GET_CODE (XEXP (x, 0)) == CLOBBER) count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr); count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr); @@ -7037,9 +6990,7 @@ insn_live_p (rtx_insn *insn, int *counts) if (set_live_p (elt, insn, counts)) return true; } - else if (GET_CODE (elt) != CLOBBER - && GET_CODE (elt) != CLOBBER_HIGH - && GET_CODE (elt) != USE) + else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE) return true; } return false; diff --git a/gcc/cselib.c b/gcc/cselib.c index 36f649d..500793b 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -55,8 +55,7 @@ static unsigned int cselib_hash_rtx (rtx, int, machine_mode); static cselib_val *new_cselib_val (unsigned int, machine_mode, rtx); static void add_mem_for_addr (cselib_val *, cselib_val *, rtx); static cselib_val *cselib_lookup_mem (rtx, int); -static void cselib_invalidate_regno (unsigned int, machine_mode, - const_rtx = NULL); +static void cselib_invalidate_regno (unsigned int, machine_mode); static void cselib_invalidate_mem (rtx); static void cselib_record_set (rtx, cselib_val *, cselib_val *); static void cselib_record_sets (rtx_insn *); @@ -1663,7 +1662,6 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, /* SCRATCH must be shared because they represent distinct values. */ return orig; case CLOBBER: - case CLOBBER_HIGH: if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0)))) return orig; break; @@ -2166,8 +2164,7 @@ cselib_lookup (rtx x, machine_mode mode, invalidating call clobbered registers across a call. */ static void -cselib_invalidate_regno (unsigned int regno, machine_mode mode, - const_rtx setter) +cselib_invalidate_regno (unsigned int regno, machine_mode mode) { unsigned int endregno; unsigned int i; @@ -2190,9 +2187,6 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode, i = regno - max_value_regs; endregno = end_hard_regno (mode, regno); - - if (setter && GET_CODE (setter) == CLOBBER_HIGH) - gcc_assert (endregno == regno + 1); } else { @@ -2225,19 +2219,6 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode, continue; } - /* Ignore if clobber high and the register isn't clobbered. */ - if (setter && GET_CODE (setter) == CLOBBER_HIGH) - { - gcc_assert (endregno == regno + 1); - const_rtx x = XEXP (setter, 0); - if (!reg_is_clobbered_by_clobber_high (i, GET_MODE (v->val_rtx), - x)) - { - l = &(*l)->next; - continue; - } - } - /* We have an overlap. */ if (*l == REG_VALUES (i)) { @@ -2372,10 +2353,10 @@ cselib_invalidate_mem (rtx mem_rtx) *vp = &dummy_val; } -/* Invalidate DEST, which is being assigned to or clobbered by SETTER. */ +/* Invalidate DEST. */ void -cselib_invalidate_rtx (rtx dest, const_rtx setter) +cselib_invalidate_rtx (rtx dest) { while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == ZERO_EXTRACT @@ -2383,7 +2364,7 @@ cselib_invalidate_rtx (rtx dest, const_rtx setter) dest = XEXP (dest, 0); if (REG_P (dest)) - cselib_invalidate_regno (REGNO (dest), GET_MODE (dest), setter); + cselib_invalidate_regno (REGNO (dest), GET_MODE (dest)); else if (MEM_P (dest)) cselib_invalidate_mem (dest); } @@ -2391,10 +2372,10 @@ cselib_invalidate_rtx (rtx dest, const_rtx setter) /* A wrapper for cselib_invalidate_rtx to be called via note_stores. */ static void -cselib_invalidate_rtx_note_stores (rtx dest, const_rtx setter, +cselib_invalidate_rtx_note_stores (rtx dest, const_rtx, void *data ATTRIBUTE_UNUSED) { - cselib_invalidate_rtx (dest, setter); + cselib_invalidate_rtx (dest); } /* Record the result of a SET instruction. DEST is being set; the source @@ -2809,11 +2790,9 @@ cselib_process_insn (rtx_insn *insn) if (CALL_P (insn)) { for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1)) - { - gcc_assert (GET_CODE (XEXP (x, 0)) != CLOBBER_HIGH); - if (GET_CODE (XEXP (x, 0)) == CLOBBER) - cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0)); - } + if (GET_CODE (XEXP (x, 0)) == CLOBBER) + cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0)); + /* Flush everything on setjmp. */ if (cselib_preserve_constants && find_reg_note (insn, REG_SETJMP, NULL)) diff --git a/gcc/cselib.h b/gcc/cselib.h index 8b8d3e8..b5854ae 100644 --- a/gcc/cselib.h +++ b/gcc/cselib.h @@ -92,7 +92,7 @@ extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int, cselib_expand_callback, void *); extern rtx cselib_subst_to_values (rtx, machine_mode); extern rtx cselib_subst_to_values_from_insn (rtx, machine_mode, rtx_insn *); -extern void cselib_invalidate_rtx (rtx, const_rtx = NULL); +extern void cselib_invalidate_rtx (rtx); extern void cselib_reset_table (unsigned int); extern unsigned int cselib_get_next_uid (void); diff --git a/gcc/dce.c b/gcc/dce.c index af22eb3..2894fa5 100644 --- a/gcc/dce.c +++ b/gcc/dce.c @@ -174,7 +174,6 @@ deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores) return false; case CLOBBER: - case CLOBBER_HIGH: if (fast) { /* A CLOBBER of a dead pseudo register serves no purpose. @@ -244,10 +243,7 @@ static void mark_nonreg_stores_1 (rtx dest, const_rtx pattern, void *data) { if (GET_CODE (pattern) != CLOBBER && !REG_P (dest)) - { - gcc_checking_assert (GET_CODE (pattern) != CLOBBER_HIGH); - mark_insn ((rtx_insn *) data, true); - } + mark_insn ((rtx_insn *) data, true); } @@ -258,10 +254,7 @@ static void mark_nonreg_stores_2 (rtx dest, const_rtx pattern, void *data) { if (GET_CODE (pattern) != CLOBBER && !REG_P (dest)) - { - gcc_checking_assert (GET_CODE (pattern) != CLOBBER_HIGH); - mark_insn ((rtx_insn *) data, false); - } + mark_insn ((rtx_insn *) data, false); } diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 36012b7..55c03c8 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -2775,7 +2775,6 @@ df_find_hard_reg_defs (rtx x, HARD_REG_SET *defs) break; case CLOBBER: - case CLOBBER_HIGH: df_find_hard_reg_defs_1 (XEXP (x, 0), defs); break; @@ -2835,10 +2834,6 @@ df_uses_record (class df_collection_rec *collection_rec, /* If we're clobbering a REG then we have a def so ignore. */ return; - case CLOBBER_HIGH: - gcc_assert (REG_P (XEXP (x, 0))); - return; - case MEM: df_uses_record (collection_rec, &XEXP (x, 0), DF_REF_REG_MEM_LOAD, @@ -3133,7 +3128,6 @@ df_get_call_refs (class df_collection_rec *collection_rec, for (note = CALL_INSN_FUNCTION_USAGE (insn_info->insn); note; note = XEXP (note, 1)) { - gcc_assert (GET_CODE (XEXP (note, 0)) != CLOBBER_HIGH); if (GET_CODE (XEXP (note, 0)) == USE) df_uses_record (collection_rec, &XEXP (XEXP (note, 0), 0), DF_REF_REG_USE, bb, insn_info, flags); diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 0814b66..3df7982 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -3295,18 +3295,6 @@ There is one other known use for clobbering a pseudo register in a clobbered by the insn. In this case, using the same pseudo register in the clobber and elsewhere in the insn produces the expected results. -@findex clobber_high -@item (clobber_high @var{x}) -Represents the storing or possible storing of an unpredictable, -undescribed value into the upper parts of @var{x}. The mode of the expression -represents the lower parts of the register which will not be overwritten. -@code{reg} must be a reg expression. - -One place this is used is when calling into functions where the registers are -preserved, but only up to a given number of bits. For example when using -Aarch64 SVE, calling a TLS descriptor will cause only the lower 128 bits of -each of the vector registers to be preserved. - @findex use @item (use @var{x}) Represents the use of the value of @var{x}. It indicates that the @@ -3360,8 +3348,7 @@ Represents several side effects performed in parallel. The square brackets stand for a vector; the operand of @code{parallel} is a vector of expressions. @var{x0}, @var{x1} and so on are individual side effect expressions---expressions of code @code{set}, @code{call}, -@code{return}, @code{simple_return}, @code{clobber} @code{use} or -@code{clobber_high}. +@code{return}, @code{simple_return}, @code{clobber} or @code{use}. ``In parallel'' means that first all the values used in the individual side-effects are computed, and second all the actual side-effects are diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index cec25fa..d33f19b 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -16430,7 +16430,6 @@ mem_loc_descriptor (rtx rtl, machine_mode mode, case CONST_FIXED: case CLRSB: case CLOBBER: - case CLOBBER_HIGH: break; case CONST_STRING: diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 783fdb9..feff49a 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -2898,7 +2898,6 @@ verify_rtx_sharing (rtx orig, rtx insn) /* SCRATCH must be shared because they represent distinct values. */ return; case CLOBBER: - case CLOBBER_HIGH: /* Share clobbers of hard registers (like cc0), but do not share pseudo reg clobbers or clobbers of hard registers that originated as pseudos. This is needed to allow safe register renaming. */ @@ -3152,7 +3151,6 @@ repeat: /* SCRATCH must be shared because they represent distinct values. */ return; case CLOBBER: - case CLOBBER_HIGH: /* Share clobbers of hard registers (like cc0), but do not share pseudo reg clobbers or clobbers of hard registers that originated as pseudos. This is needed to allow safe register renaming. */ @@ -5726,7 +5724,6 @@ copy_insn_1 (rtx orig) case SIMPLE_RETURN: return orig; case CLOBBER: - case CLOBBER_HIGH: /* Share clobbers of hard registers (like cc0), but do not share pseudo reg clobbers or clobbers of hard registers that originated as pseudos. This is needed to allow safe register renaming. */ @@ -6538,21 +6535,6 @@ gen_hard_reg_clobber (machine_mode mode, unsigned int regno) gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno))); } -static GTY((deletable)) rtx -hard_reg_clobbers_high[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER]; - -/* Return a CLOBBER_HIGH expression for register REGNO that clobbers MODE, - caching into HARD_REG_CLOBBERS_HIGH. */ -rtx -gen_hard_reg_clobber_high (machine_mode mode, unsigned int regno) -{ - if (hard_reg_clobbers_high[mode][regno]) - return hard_reg_clobbers_high[mode][regno]; - else - return (hard_reg_clobbers_high[mode][regno] - = gen_rtx_CLOBBER_HIGH (VOIDmode, gen_rtx_REG (mode, regno))); -} - location_t prologue_location; location_t epilogue_location; diff --git a/gcc/genconfig.c b/gcc/genconfig.c index 194fe95..6f914b1 100644 --- a/gcc/genconfig.c +++ b/gcc/genconfig.c @@ -72,7 +72,6 @@ walk_insn_part (rtx part, int recog_p, int non_pc_set_src) switch (code) { case CLOBBER: - case CLOBBER_HIGH: clobbers_seen_this_insn++; break; diff --git a/gcc/genemit.c b/gcc/genemit.c index 4d7011c..73ed323 100644 --- a/gcc/genemit.c +++ b/gcc/genemit.c @@ -169,15 +169,6 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info) return; } break; - case CLOBBER_HIGH: - if (!REG_P (XEXP (x, 0))) - error ("CLOBBER_HIGH argument is not a register expr, at %s:%d", - info->loc.filename, info->loc.lineno); - printf ("gen_hard_reg_clobber_high (%smode, %i)", - GET_MODE_NAME (GET_MODE (XEXP (x, 0))), - REGNO (XEXP (x, 0))); - return; - break; case CC0: printf ("cc0_rtx"); return; @@ -343,8 +334,7 @@ gen_insn (md_rtx_info *info) for (i = XVECLEN (insn, 1) - 1; i > 0; i--) { - if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER - && GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER_HIGH) + if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER) break; if (REG_P (XEXP (XVECEXP (insn, 1, i), 0))) diff --git a/gcc/genrecog.c b/gcc/genrecog.c index f20089e..d38a55f 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -718,7 +718,6 @@ validate_pattern (rtx pattern, md_rtx_info *info, rtx set, int set_code) } case CLOBBER: - case CLOBBER_HIGH: validate_pattern (SET_DEST (pattern), info, pattern, '='); return; @@ -5313,7 +5312,7 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr) for (i = XVECLEN (pattern, 0); i > 0; i--) { rtx x = XVECEXP (pattern, 0, i - 1); - if ((GET_CODE (x) != CLOBBER && GET_CODE (x) != CLOBBER_HIGH) + if (GET_CODE (x) != CLOBBER || (!REG_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 0)) != MATCH_SCRATCH)) break; diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 7338050..41cf1f3 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -530,9 +530,6 @@ haifa_classify_rtx (const_rtx x) /* Test if it is a 'store'. */ tmp_class = may_trap_exp (XEXP (x, 0), 1); break; - case CLOBBER_HIGH: - gcc_assert (REG_P (XEXP (x, 0))); - break; case SET: /* Test if it is a store. */ tmp_class = may_trap_exp (SET_DEST (x), 1); diff --git a/gcc/ira-build.c b/gcc/ira-build.c index ad1eaa4..222956e 100644 --- a/gcc/ira-build.c +++ b/gcc/ira-build.c @@ -1873,11 +1873,6 @@ create_insn_allocnos (rtx x, rtx outer, bool output_p) create_insn_allocnos (XEXP (x, 0), NULL, true); return; } - else if (code == CLOBBER_HIGH) - { - gcc_assert (REG_P (XEXP (x, 0)) && HARD_REGISTER_P (XEXP (x, 0))); - return; - } else if (code == MEM) { create_insn_allocnos (XEXP (x, 0), NULL, false); diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c index 65511a3..baf7261 100644 --- a/gcc/ira-costs.c +++ b/gcc/ira-costs.c @@ -1477,13 +1477,6 @@ scan_one_insn (rtx_insn *insn) return insn; } - if (pat_code == CLOBBER_HIGH) - { - gcc_assert (REG_P (XEXP (PATTERN (insn), 0)) - && HARD_REGISTER_P (XEXP (PATTERN (insn), 0))); - return insn; - } - counted_mem = false; set = single_set (insn); extract_insn (insn); diff --git a/gcc/ira.c b/gcc/ira.c index 3b4f9a8..9f8da67 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -3063,7 +3063,6 @@ equiv_init_movable_p (rtx x, int regno) case CC0: case CLOBBER: - case CLOBBER_HIGH: return 0; case PRE_INC: @@ -3170,7 +3169,6 @@ memref_referenced_p (rtx memref, rtx x, bool read_p) return memref_referenced_p (memref, SET_SRC (x), true); case CLOBBER: - case CLOBBER_HIGH: if (process_set_for_memref_referenced_p (memref, XEXP (x, 0))) return true; @@ -4451,7 +4449,6 @@ rtx_moveable_p (rtx *loc, enum op_type type) && rtx_moveable_p (&XEXP (x, 2), OP_IN)); case CLOBBER: - case CLOBBER_HIGH: return rtx_moveable_p (&SET_DEST (x), OP_OUT); case UNSPEC_VOLATILE: @@ -4904,9 +4901,7 @@ interesting_dest_for_shprep (rtx_insn *insn, basic_block call_dom) for (int i = 0; i < XVECLEN (pat, 0); i++) { rtx sub = XVECEXP (pat, 0, i); - if (GET_CODE (sub) == USE - || GET_CODE (sub) == CLOBBER - || GET_CODE (sub) == CLOBBER_HIGH) + if (GET_CODE (sub) == USE || GET_CODE (sub) == CLOBBER) continue; if (GET_CODE (sub) != SET || side_effects_p (sub)) diff --git a/gcc/jump.c b/gcc/jump.c index ce5cee5..17642a9 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -1094,7 +1094,6 @@ mark_jump_label_1 (rtx x, rtx_insn *insn, bool in_mem, bool is_target) case CC0: case REG: case CLOBBER: - case CLOBBER_HIGH: case CALL: return; diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c index 749834e..04dc6df 100644 --- a/gcc/lra-eliminations.c +++ b/gcc/lra-eliminations.c @@ -655,7 +655,6 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode, return x; case CLOBBER: - case CLOBBER_HIGH: case SET: gcc_unreachable (); @@ -808,16 +807,6 @@ mark_not_eliminable (rtx x, machine_mode mem_mode) setup_can_eliminate (ep, false); return; - case CLOBBER_HIGH: - gcc_assert (REG_P (XEXP (x, 0))); - gcc_assert (REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER); - for (ep = reg_eliminate; - ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (reg_is_clobbered_by_clobber_high (ep->to_rtx, XEXP (x, 0))) - setup_can_eliminate (ep, false); - return; - case SET: if (SET_DEST (x) == stack_pointer_rtx && GET_CODE (SET_SRC (x)) == PLUS diff --git a/gcc/lra-int.h b/gcc/lra-int.h index 7f2bbbe..707b5d4 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -154,8 +154,6 @@ struct lra_insn_reg /* True if the reg is accessed through a subreg and the subreg is just a part of the register. */ unsigned int subreg_p : 1; - /* True if the reg is clobber highed by the operand. */ - unsigned int clobber_high : 1; /* The corresponding regno of the register. */ int regno; /* Next reg info of the same insn. */ diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index a6cd7bb..389a79d 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -668,7 +668,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) bool call_p; int n_alt, dst_regno, src_regno; rtx set; - struct lra_insn_reg *reg, *hr; + struct lra_insn_reg *reg; if (!NONDEBUG_INSN_P (curr_insn)) continue; @@ -700,7 +700,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) break; } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN && !reg->clobber_high) + if (reg->type != OP_IN) { remove_p = false; break; @@ -837,23 +837,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) unused values because they still conflict with quantities that are live at the time of the definition. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - { - if (reg->type != OP_IN) - { - update_pseudo_point (reg->regno, curr_point, USE_POINT); - mark_regno_live (reg->regno, reg->biggest_mode); - /* ??? Should be a no-op for unused registers. */ - check_pseudos_live_through_calls (reg->regno, last_call_abi); - } - - if (!HARD_REGISTER_NUM_P (reg->regno)) - for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next) - if (hr->clobber_high - && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)), - GET_MODE_SIZE (hr->biggest_mode))) - SET_HARD_REG_BIT (lra_reg_info[reg->regno].conflict_hard_regs, - hr->regno); - } + if (reg->type != OP_IN) + { + update_pseudo_point (reg->regno, curr_point, USE_POINT); + mark_regno_live (reg->regno, reg->biggest_mode); + /* ??? Should be a no-op for unused registers. */ + check_pseudos_live_through_calls (reg->regno, last_call_abi); + } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) if (reg->type != OP_IN) diff --git a/gcc/lra.c b/gcc/lra.c index a6e6a8d..2c9a29a 100644 --- a/gcc/lra.c +++ b/gcc/lra.c @@ -540,13 +540,12 @@ object_allocator lra_insn_reg_pool ("insn regs"); is reference through subreg (SUBREG_P), and reference to the next insn reg info (NEXT). If REGNO can be early clobbered, alternatives in which it can be early clobbered are given by - EARLY_CLOBBER_ALTS. CLOBBER_HIGH marks if reference is a clobber - high. */ + EARLY_CLOBBER_ALTS. */ static struct lra_insn_reg * new_insn_reg (rtx_insn *insn, int regno, enum op_type type, machine_mode mode, bool subreg_p, alternative_mask early_clobber_alts, - struct lra_insn_reg *next, bool clobber_high) + struct lra_insn_reg *next) { lra_insn_reg *ir = lra_insn_reg_pool.allocate (); ir->type = type; @@ -556,7 +555,6 @@ new_insn_reg (rtx_insn *insn, int regno, enum op_type type, lra_reg_info[regno].biggest_mode = mode; ir->subreg_p = subreg_p; ir->early_clobber_alts = early_clobber_alts; - ir->clobber_high = clobber_high; ir->regno = regno; ir->next = next; return ir; @@ -824,13 +822,12 @@ setup_operand_alternative (lra_insn_recog_data_t data, not the insn operands, in X with TYPE (in/out/inout) and flag that it is early clobbered in the insn (EARLY_CLOBBER) and add the info to LIST. X is a part of insn given by DATA. Return the result - list. CLOBBER_HIGH marks if X is a clobber high. */ + list. */ static struct lra_insn_reg * collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, lra_insn_recog_data_t data, struct lra_insn_reg *list, - enum op_type type, bool early_clobber, - bool clobber_high) + enum op_type type, bool early_clobber) { int i, j, regno, last; bool subreg_p; @@ -890,8 +887,7 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, && regno <= LAST_STACK_REG)); #endif list = new_insn_reg (data->insn, regno, type, mode, subreg_p, - early_clobber ? ALL_ALTERNATIVES : 0, list, - clobber_high); + early_clobber ? ALL_ALTERNATIVES : 0, list); } } return list; @@ -900,31 +896,24 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, { case SET: list = collect_non_operand_hard_regs (insn, &SET_DEST (op), data, - list, OP_OUT, false, false); + list, OP_OUT, false); list = collect_non_operand_hard_regs (insn, &SET_SRC (op), data, - list, OP_IN, false, false); + list, OP_IN, false); break; case CLOBBER: /* We treat clobber of non-operand hard registers as early clobber. */ list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, - list, OP_OUT, true, false); - break; - case CLOBBER_HIGH: - /* Clobber high should always span exactly one register. */ - gcc_assert (REG_NREGS (XEXP (op, 0)) == 1); - /* We treat clobber of non-operand hard registers as early clobber. */ - list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, - list, OP_OUT, true, true); + list, OP_OUT, true); break; case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, - list, OP_INOUT, false, false); + list, OP_INOUT, false); break; case PRE_MODIFY: case POST_MODIFY: list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, - list, OP_INOUT, false, false); + list, OP_INOUT, false); list = collect_non_operand_hard_regs (insn, &XEXP (op, 1), data, - list, OP_IN, false, false); + list, OP_IN, false); break; default: fmt = GET_RTX_FORMAT (code); @@ -932,12 +921,11 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, { if (fmt[i] == 'e') list = collect_non_operand_hard_regs (insn, &XEXP (op, i), data, - list, OP_IN, false, false); + list, OP_IN, false); else if (fmt[i] == 'E') for (j = XVECLEN (op, i) - 1; j >= 0; j--) list = collect_non_operand_hard_regs (insn, &XVECEXP (op, i, j), - data, list, OP_IN, false, - false); + data, list, OP_IN, false); } } return list; @@ -1086,7 +1074,7 @@ lra_set_insn_recog_data (rtx_insn *insn) else insn_static_data->hard_regs = collect_non_operand_hard_regs (insn, &PATTERN (insn), data, - NULL, OP_IN, false, false); + NULL, OP_IN, false); data->arg_hard_regs = NULL; if (CALL_P (insn)) { @@ -1112,10 +1100,6 @@ lra_set_insn_recog_data (rtx_insn *insn) arg_hard_regs[n_hard_regs++] = regno + i + (use_p ? 0 : FIRST_PSEUDO_REGISTER); } - else if (GET_CODE (XEXP (link, 0)) == CLOBBER_HIGH) - /* We could support CLOBBER_HIGH and treat it in the same way as - HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet. */ - gcc_unreachable (); if (n_hard_regs != 0) { @@ -1475,7 +1459,7 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, INSN_UID (insn))) { data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p, - early_clobber_alts, data->regs, false); + early_clobber_alts, data->regs); return; } else @@ -1488,7 +1472,7 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, structure. */ data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p, early_clobber_alts, - data->regs, false); + data->regs); else { if (curr->type != type) @@ -1513,8 +1497,6 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_OUT, ALL_ALTERNATIVES); break; - case CLOBBER_HIGH: - gcc_unreachable (); case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, 0); break; @@ -1650,9 +1632,6 @@ lra_update_insn_regno_info (rtx_insn *insn) link = XEXP (link, 1)) { code = GET_CODE (XEXP (link, 0)); - /* We could support CLOBBER_HIGH and treat it in the same way as - HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet. */ - gcc_assert (code != CLOBBER_HIGH); if ((code == USE || code == CLOBBER) && MEM_P (XEXP (XEXP (link, 0), 0))) add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn, diff --git a/gcc/postreload.c b/gcc/postreload.c index e66377e..12d74fc 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -134,8 +134,6 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg) for (i = XVECLEN (body, 0) - 1; i >= 0; --i) { rtx part = XVECEXP (body, 0, i); - /* asms can only have full clobbers, not clobber_highs. */ - gcc_assert (GET_CODE (part) != CLOBBER_HIGH); if (GET_CODE (part) == CLOBBER && REG_P (XEXP (part, 0))) cselib_invalidate_rtx (XEXP (part, 0)); } @@ -158,9 +156,7 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg) value = SET_DEST (part); } } - else if (GET_CODE (part) != CLOBBER - && GET_CODE (part) != CLOBBER_HIGH - && GET_CODE (part) != USE) + else if (GET_CODE (part) != CLOBBER && GET_CODE (part) != USE) break; } @@ -1515,10 +1511,6 @@ reload_combine_note_use (rtx *xp, rtx_insn *insn, int ruid, rtx containing_mem) } break; - case CLOBBER_HIGH: - gcc_assert (REG_P (SET_DEST (x))); - return; - case PLUS: /* We are interested in (plus (reg) (const_int)) . */ if (!REG_P (XEXP (x, 0)) @@ -2284,13 +2276,6 @@ move2add_note_store (rtx dst, const_rtx set, void *data) move2add_record_mode (dst); } - else if (GET_CODE (set) == CLOBBER_HIGH) - { - /* Only invalidate if actually clobbered. */ - if (reg_mode[regno] == BLKmode - || reg_is_clobbered_by_clobber_high (regno, reg_mode[regno], dst)) - goto invalidate; - } else { invalidate: diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index b96ab5e..b0ee300 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -1763,7 +1763,6 @@ print_pattern (pretty_printer *pp, const_rtx x, int verbose) print_exp (pp, x, verbose); break; case CLOBBER: - case CLOBBER_HIGH: case USE: pp_printf (pp, "%s ", GET_RTX_NAME (GET_CODE (x))); print_value (pp, XEXP (x, 0), verbose); diff --git a/gcc/recog.c b/gcc/recog.c index aa31ffa..9e9cca7 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -3726,8 +3726,7 @@ store_data_bypass_p_1 (rtx_insn *out_insn, rtx in_set) { rtx out_exp = XVECEXP (out_pat, 0, i); - if (GET_CODE (out_exp) == CLOBBER || GET_CODE (out_exp) == USE - || GET_CODE (out_exp) == CLOBBER_HIGH) + if (GET_CODE (out_exp) == CLOBBER || GET_CODE (out_exp) == USE) continue; gcc_assert (GET_CODE (out_exp) == SET); @@ -3758,8 +3757,7 @@ store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn) { rtx in_exp = XVECEXP (in_pat, 0, i); - if (GET_CODE (in_exp) == CLOBBER || GET_CODE (in_exp) == USE - || GET_CODE (in_exp) == CLOBBER_HIGH) + if (GET_CODE (in_exp) == CLOBBER || GET_CODE (in_exp) == USE) continue; gcc_assert (GET_CODE (in_exp) == SET); @@ -3811,7 +3809,7 @@ if_test_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn) { rtx exp = XVECEXP (out_pat, 0, i); - if (GET_CODE (exp) == CLOBBER || GET_CODE (exp) == CLOBBER_HIGH) + if (GET_CODE (exp) == CLOBBER) continue; gcc_assert (GET_CODE (exp) == SET); diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 87cc394..4b0b53f 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -238,11 +238,8 @@ static void kill_clobbered_value (rtx x, const_rtx set, void *data) { struct value_data *const vd = (struct value_data *) data; - gcc_assert (GET_CODE (set) != CLOBBER_HIGH || REG_P (x)); - if (GET_CODE (set) == CLOBBER - || (GET_CODE (set) == CLOBBER_HIGH - && reg_is_clobbered_by_clobber_high (x, XEXP (set, 0)))) + if (GET_CODE (set) == CLOBBER) kill_value (x, vd); } @@ -263,8 +260,7 @@ kill_set_value (rtx x, const_rtx set, void *data) if (rtx_equal_p (x, ksvd->ignore_set_reg)) return; - gcc_assert (GET_CODE (set) != CLOBBER_HIGH || REG_P (x)); - if (GET_CODE (set) != CLOBBER && GET_CODE (set) != CLOBBER_HIGH) + if (GET_CODE (set) != CLOBBER) { kill_value (x, ksvd->vd); if (REG_P (x)) diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 791c7a0..6bed844 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -1025,10 +1025,6 @@ reg_scan_mark_refs (rtx x, rtx_insn *insn) reg_scan_mark_refs (XEXP (XEXP (x, 0), 0), insn); break; - case CLOBBER_HIGH: - gcc_assert (!(MEM_P (XEXP (x, 0)))); - break; - case SET: /* Count a set of the destination if it is a register. */ for (dest = SET_DEST (x); diff --git a/gcc/reload1.c b/gcc/reload1.c index 79a7ff6..2d96fe9 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1337,8 +1337,6 @@ maybe_fix_stack_asms (void) rtx t = XVECEXP (pat, 0, i); if (GET_CODE (t) == CLOBBER && STACK_REG_P (XEXP (t, 0))) SET_HARD_REG_BIT (clobbered, REGNO (XEXP (t, 0))); - /* CLOBBER_HIGH is only supported for LRA. */ - gcc_assert (GET_CODE (t) != CLOBBER_HIGH); } /* Get the operand values and constraints out of the insn. */ @@ -2879,7 +2877,6 @@ eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn, return x; case CLOBBER: - case CLOBBER_HIGH: case ASM_OPERANDS: gcc_assert (insn && DEBUG_INSN_P (insn)); break; @@ -3090,10 +3087,6 @@ elimination_effects (rtx x, machine_mode mem_mode) elimination_effects (XEXP (x, 0), mem_mode); return; - case CLOBBER_HIGH: - /* CLOBBER_HIGH is only supported for LRA. */ - return; - case SET: /* Check for setting a register that we know about. */ if (REG_P (SET_DEST (x))) @@ -3725,9 +3718,6 @@ mark_not_eliminable (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED) if (dest == hard_frame_pointer_rtx) return; - /* CLOBBER_HIGH is only supported for LRA. */ - gcc_assert (GET_CODE (x) != CLOBBER_HIGH); - for (i = 0; i < NUM_ELIMINABLE_REGS; i++) if (reg_eliminate[i].can_eliminate && dest == reg_eliminate[i].to_rtx && (GET_CODE (x) != SET @@ -4355,7 +4345,6 @@ scan_paradoxical_subregs (rtx x) case PC: case USE: case CLOBBER: - case CLOBBER_HIGH: return; case SUBREG: @@ -4809,8 +4798,7 @@ reload_as_needed (int live_known) to be forgotten later. */ static void -forget_old_reloads_1 (rtx x, const_rtx setter, - void *data) +forget_old_reloads_1 (rtx x, const_rtx, void *data) { unsigned int regno; unsigned int nr; @@ -4829,9 +4817,6 @@ forget_old_reloads_1 (rtx x, const_rtx setter, if (!REG_P (x)) return; - /* CLOBBER_HIGH is only supported for LRA. */ - gcc_assert (setter == NULL_RTX || GET_CODE (setter) != CLOBBER_HIGH); - regno = REGNO (x); if (regno >= FIRST_PSEUDO_REGISTER) diff --git a/gcc/reorg.c b/gcc/reorg.c index f542a10..cba183e 100644 --- a/gcc/reorg.c +++ b/gcc/reorg.c @@ -410,8 +410,7 @@ find_end_label (rtx kind) while (NOTE_P (insn) || (NONJUMP_INSN_P (insn) && (GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER - || GET_CODE (PATTERN (insn)) == CLOBBER_HIGH))) + || GET_CODE (PATTERN (insn)) == CLOBBER))) insn = PREV_INSN (insn); /* When a target threads its epilogue we might already have a @@ -1311,8 +1310,7 @@ try_merge_delay_insns (rtx_insn *insn, rtx_insn *thread) /* TRIAL must be a CALL_INSN or INSN. Skip USE and CLOBBER. */ if (NONJUMP_INSN_P (trial) - && (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == CLOBBER_HIGH)) + && (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)) continue; if (GET_CODE (next_to_match) == GET_CODE (trial) @@ -1506,8 +1504,7 @@ redundant_insn (rtx insn, rtx_insn *target, const vec &delay_list) --insns_to_search; pat = PATTERN (trial); - if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == CLOBBER_HIGH) + if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; if (GET_CODE (trial) == DEBUG_INSN) @@ -1605,8 +1602,7 @@ redundant_insn (rtx insn, rtx_insn *target, const vec &delay_list) --insns_to_search; pat = PATTERN (trial); - if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == CLOBBER_HIGH) + if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; if (GET_CODE (trial) == DEBUG_INSN) @@ -1718,8 +1714,7 @@ own_thread_p (rtx thread, rtx label, int allow_fallthrough) || LABEL_P (insn) || (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER - && GET_CODE (PATTERN (insn)) != CLOBBER_HIGH)) + && GET_CODE (PATTERN (insn)) != CLOBBER)) return 0; return 1; @@ -2042,8 +2037,7 @@ fill_simple_delay_slots (int non_jumps_p) pat = PATTERN (trial); /* Stand-alone USE and CLOBBER are just for flow. */ - if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == CLOBBER_HIGH) + if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; /* And DEBUG_INSNs never go into delay slots. */ @@ -2169,8 +2163,7 @@ fill_simple_delay_slots (int non_jumps_p) pat = PATTERN (trial); /* Stand-alone USE and CLOBBER are just for flow. */ - if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == CLOBBER_HIGH) + if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; /* And DEBUG_INSNs do not go in delay slots. */ @@ -2438,8 +2431,7 @@ fill_slots_from_thread (rtx_jump_insn *insn, rtx condition, } pat = PATTERN (trial); - if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER - || GET_CODE (pat) == CLOBBER_HIGH) + if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; if (GET_CODE (trial) == DEBUG_INSN) @@ -3833,8 +3825,7 @@ dbr_schedule (rtx_insn *first) if (! insn->deleted () && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER - && GET_CODE (PATTERN (insn)) != CLOBBER_HIGH) + && GET_CODE (PATTERN (insn)) != CLOBBER) { if (GET_CODE (PATTERN (insn)) == SEQUENCE) { diff --git a/gcc/resource.c b/gcc/resource.c index c66b6e3..bf2d6be 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -109,11 +109,6 @@ update_live_status (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED) if (GET_CODE (x) == CLOBBER) for (i = first_regno; i < last_regno; i++) CLEAR_HARD_REG_BIT (current_live_regs, i); - else if (GET_CODE (x) == CLOBBER_HIGH) - /* No current target supports both branch delay slots and CLOBBER_HIGH. - We'd need more elaborate liveness tracking to handle that - combination. */ - gcc_unreachable (); else for (i = first_regno; i < last_regno; i++) { @@ -299,7 +294,6 @@ mark_referenced_resources (rtx x, struct resources *res, return; case CLOBBER: - case CLOBBER_HIGH: return; case CALL_INSN: @@ -670,15 +664,9 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, for (link = CALL_INSN_FUNCTION_USAGE (call_insn); link; link = XEXP (link, 1)) - { - /* We could support CLOBBER_HIGH and treat it in the same way as - HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that - yet. */ - gcc_assert (GET_CODE (XEXP (link, 0)) != CLOBBER_HIGH); - if (GET_CODE (XEXP (link, 0)) == CLOBBER) - mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1, - MARK_SRC_DEST); - } + if (GET_CODE (XEXP (link, 0)) == CLOBBER) + mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1, + MARK_SRC_DEST); /* Check for a REG_SETJMP. If it exists, then we must assume that this call can clobber any register. */ @@ -721,12 +709,6 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, mark_set_resources (XEXP (x, 0), res, 1, MARK_SRC_DEST); return; - case CLOBBER_HIGH: - /* No current target supports both branch delay slots and CLOBBER_HIGH. - We'd need more elaborate liveness tracking to handle that - combination. */ - gcc_unreachable (); - case SEQUENCE: { rtx_sequence *seq = as_a (x); diff --git a/gcc/rtl.c b/gcc/rtl.c index 0be52d3..8822ff6 100644 --- a/gcc/rtl.c +++ b/gcc/rtl.c @@ -310,10 +310,6 @@ copy_rtx (rtx orig) return orig; break; - case CLOBBER_HIGH: - gcc_assert (REG_P (XEXP (orig, 0))); - return orig; - case CONST: if (shared_const_p (orig)) return orig; diff --git a/gcc/rtl.def b/gcc/rtl.def index c756af8..d8683a9 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -312,16 +312,6 @@ DEF_RTL_EXPR(USE, "use", "e", RTX_EXTRA) is considered undeletable before reload. */ DEF_RTL_EXPR(CLOBBER, "clobber", "e", RTX_EXTRA) -/* Indicate that the upper parts of something are clobbered in a way that we - don't want to explain. The MODE references the lower bits that will be - preserved. Anything above that size will be clobbered. - - CLOBBER_HIGH only occurs as the operand of a PARALLEL rtx. It cannot appear - in other contexts, and unlike CLOBBER, it cannot appear on its own. - CLOBBER_HIGH can only be used with fixed register rtxes. */ - -DEF_RTL_EXPR(CLOBBER_HIGH, "clobber_high", "e", RTX_EXTRA) - /* Call a subroutine. Operand 1 is the address to call. Operand 2 is the number of arguments. */ diff --git a/gcc/rtl.h b/gcc/rtl.h index 554608c..1369e66 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2679,7 +2679,7 @@ do { \ /* For a SET rtx, SET_DEST is the place that is set and SET_SRC is the value it is set to. */ -#define SET_DEST(RTX) XC3EXP (RTX, 0, SET, CLOBBER, CLOBBER_HIGH) +#define SET_DEST(RTX) XC2EXP (RTX, 0, SET, CLOBBER) #define SET_SRC(RTX) XCEXP (RTX, 1, SET) #define SET_IS_RETURN_P(RTX) \ (RTL_FLAG_CHECK1 ("SET_IS_RETURN_P", (RTX), SET)->jump) @@ -3524,16 +3524,6 @@ extern rtx tablejump_casesi_pattern (const rtx_insn *insn); extern int computed_jump_p (const rtx_insn *); extern bool tls_referenced_p (const_rtx); extern bool contains_mem_rtx_p (rtx x); -extern bool reg_is_clobbered_by_clobber_high (unsigned int, machine_mode, - const_rtx); - -/* Convenient wrapper for reg_is_clobbered_by_clobber_high. */ -inline bool -reg_is_clobbered_by_clobber_high (const_rtx x, const_rtx clobber_high_op) -{ - return reg_is_clobbered_by_clobber_high (REGNO (x), GET_MODE (x), - clobber_high_op); -} /* Overload for refers_to_regno_p for checking a single register. */ inline bool @@ -4330,7 +4320,6 @@ extern void vt_equate_reg_base_value (const_rtx, const_rtx); extern bool memory_modified_in_insn_p (const_rtx, const_rtx); extern bool may_be_sp_based_p (rtx); extern rtx gen_hard_reg_clobber (machine_mode, unsigned int); -extern rtx gen_hard_reg_clobber_high (machine_mode, unsigned int); extern rtx get_reg_known_value (unsigned int); extern bool get_reg_known_equiv_p (unsigned int); extern rtx get_reg_base_value (unsigned int); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 6adef47..720aa09 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -1216,10 +1216,6 @@ reg_referenced_p (const_rtx x, const_rtx body) return 1; return 0; - case CLOBBER_HIGH: - gcc_assert (REG_P (XEXP (body, 0))); - return 0; - case COND_EXEC: if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body))) return 1; @@ -1442,11 +1438,7 @@ set_of_1 (rtx x, const_rtx pat, void *data1) { struct set_of_data *const data = (struct set_of_data *) (data1); if (rtx_equal_p (x, data->pat) - || (GET_CODE (pat) == CLOBBER_HIGH - && REGNO(data->pat) == REGNO(XEXP (pat, 0)) - && reg_is_clobbered_by_clobber_high (data->pat, XEXP (pat, 0))) - || (GET_CODE (pat) != CLOBBER_HIGH && !MEM_P (x) - && reg_overlap_mentioned_p (data->pat, x))) + || (!MEM_P (x) && reg_overlap_mentioned_p (data->pat, x))) data->found = pat; } @@ -1533,7 +1525,6 @@ single_set_2 (const rtx_insn *insn, const_rtx pat) { case USE: case CLOBBER: - case CLOBBER_HIGH: break; case SET: @@ -1687,9 +1678,7 @@ noop_move_p (const rtx_insn *insn) { rtx tem = XVECEXP (pat, 0, i); - if (GET_CODE (tem) == USE - || GET_CODE (tem) == CLOBBER - || GET_CODE (tem) == CLOBBER_HIGH) + if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER) continue; if (GET_CODE (tem) != SET || ! set_noop_p (tem)) @@ -1923,9 +1912,7 @@ note_pattern_stores (const_rtx x, if (GET_CODE (x) == COND_EXEC) x = COND_EXEC_CODE (x); - if (GET_CODE (x) == SET - || GET_CODE (x) == CLOBBER - || GET_CODE (x) == CLOBBER_HIGH) + if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) { rtx dest = SET_DEST (x); @@ -6658,32 +6645,3 @@ tls_referenced_p (const_rtx x) return true; return false; } - -/* Return true if reg REGNO with mode REG_MODE would be clobbered by the - clobber_high operand in CLOBBER_HIGH_OP. */ - -bool -reg_is_clobbered_by_clobber_high (unsigned int regno, machine_mode reg_mode, - const_rtx clobber_high_op) -{ - unsigned int clobber_regno = REGNO (clobber_high_op); - machine_mode clobber_mode = GET_MODE (clobber_high_op); - unsigned char regno_nregs = hard_regno_nregs (regno, reg_mode); - - /* Clobber high should always span exactly one register. */ - gcc_assert (REG_NREGS (clobber_high_op) == 1); - - /* Clobber high needs to match with one of the registers in X. */ - if (clobber_regno < regno || clobber_regno >= regno + regno_nregs) - return false; - - gcc_assert (reg_mode != BLKmode && clobber_mode != BLKmode); - - if (reg_mode == VOIDmode) - return clobber_mode != VOIDmode; - - /* Clobber high will clobber if its size might be greater than the size of - register regno. */ - return maybe_gt (exact_div (GET_MODE_SIZE (reg_mode), regno_nregs), - GET_MODE_SIZE (clobber_mode)); -} diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c index 2571f04..308db4e 100644 --- a/gcc/sched-deps.c +++ b/gcc/sched-deps.c @@ -2320,13 +2320,6 @@ sched_analyze_reg (class deps_desc *deps, int regno, machine_mode mode, while (--i >= 0) note_reg_use (regno + i); } - else if (ref == CLOBBER_HIGH) - { - gcc_assert (i == 1); - /* We don't know the current state of the register, so have to treat - the clobber high as a full clobber. */ - note_reg_clobber (regno); - } else { while (--i >= 0) @@ -2350,8 +2343,6 @@ sched_analyze_reg (class deps_desc *deps, int regno, machine_mode mode, else if (ref == USE) note_reg_use (regno); else - /* For CLOBBER_HIGH, we don't know the current state of the register, - so have to treat it as a full clobber. */ note_reg_clobber (regno); /* Pseudos that are REG_EQUIV to something may be replaced @@ -2974,7 +2965,7 @@ sched_analyze_insn (class deps_desc *deps, rtx x, rtx_insn *insn) sub = COND_EXEC_CODE (sub); code = GET_CODE (sub); } - else if (code == SET || code == CLOBBER || code == CLOBBER_HIGH) + else if (code == SET || code == CLOBBER) sched_analyze_1 (deps, sub, insn); else sched_analyze_2 (deps, sub, insn); @@ -2990,10 +2981,6 @@ sched_analyze_insn (class deps_desc *deps, rtx x, rtx_insn *insn) { if (GET_CODE (XEXP (link, 0)) == CLOBBER) sched_analyze_1 (deps, XEXP (link, 0), insn); - else if (GET_CODE (XEXP (link, 0)) == CLOBBER_HIGH) - /* We could support CLOBBER_HIGH and treat it in the same way as - HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet. */ - gcc_unreachable (); else if (GET_CODE (XEXP (link, 0)) != SET) sched_analyze_2 (deps, XEXP (link, 0), insn); } -- cgit v1.1 From 8209db250f305cc79fd751c3ed056fb9ff551a83 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 08:56:12 +0000 Subject: [C] Improve diagnostics for vector types Given the following invalid arm_neon.h-based code: float x; int8x8_t y = x; the error message we emit is pretty good: incompatible types when initializing type 'int8x8_t' using type 'float' But convert the types to pointers: int8x8_t *ptr = &x; and the message becomes: initialization of '__vector(8) signed char *' from incompatible pointer type 'float *' Although it's reasonably obvious what '__vector(8) signed char *' means, it isn't valid C or C++ syntax and is quite far from what the user wrote, so using 'int8x8_t *' would be better. This patch therefore prints the type name of vectors that have one. It's still OK to print the __vector syntax as an "aka", although I have a follow-on patch to tweak this slightly for types defined in system header files. The follow-on patch also addresses the ??? in gcc.target/aarch64/diag_aka_1.c. The C++ test already passed, but it seemed worth including for consistency. 2019-10-01 Richard Sandiford gcc/c-family/ * c-pretty-print.c (pp_c_specifier_qualifier_list): If a vector type has a type name, use it in preference to the __vector syntax. gcc/testsuite/ * gcc.dg/diag-aka-3.c: New test. * gcc.target/aarch64/diag_aka_1.c: New test. * g++.dg/diagnostic/aka4.C: New test. From-SVN: r276394 --- gcc/c-family/ChangeLog | 5 +++++ gcc/c-family/c-pretty-print.c | 10 ++++++++++ gcc/testsuite/ChangeLog | 6 ++++++ gcc/testsuite/g++.dg/diagnostic/aka4.C | 9 +++++++++ gcc/testsuite/gcc.dg/diag-aka-3.c | 9 +++++++++ gcc/testsuite/gcc.target/aarch64/diag_aka_1.c | 14 ++++++++++++++ 6 files changed, 53 insertions(+) create mode 100644 gcc/testsuite/g++.dg/diagnostic/aka4.C create mode 100644 gcc/testsuite/gcc.dg/diag-aka-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/diag_aka_1.c (limited to 'gcc') diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d0973dd..eaea04b 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Richard Sandiford + + * c-pretty-print.c (pp_c_specifier_qualifier_list): If a vector type + has a type name, use it in preference to the __vector syntax. + 2019-09-30 Richard Sandiford * c-pretty-print.c (pp_c_parameter_type_list): Avoid printing diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c index e5cad67..1b06cc2 100644 --- a/gcc/c-family/c-pretty-print.c +++ b/gcc/c-family/c-pretty-print.c @@ -470,6 +470,16 @@ pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t) ? "_Complex" : "__complex__")); else if (code == VECTOR_TYPE) { + /* The syntax we print for vector types isn't real C or C++ syntax, + so it's better to print the type name if we have one. */ + tree name = TYPE_NAME (t); + if (!(pp->flags & pp_c_flag_gnu_v3) + && name + && TREE_CODE (name) == TYPE_DECL) + { + pp->id_expression (name); + break; + } pp_c_ws_string (pp, "__vector"); pp_c_left_paren (pp); pp_wide_integer (pp, TYPE_VECTOR_SUBPARTS (t)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2bf37cb..af7f6a2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2019-10-01 Richard Sandiford + * gcc.dg/diag-aka-3.c: New test. + * gcc.target/aarch64/diag_aka_1.c: New test. + * g++.dg/diagnostic/aka4.C: New test. + +2019-10-01 Richard Sandiford + * gcc.target/aarch64/torture/simd-abi-10.c: New test. * gcc.target/aarch64/torture/simd-abi-11.c: Likewise. diff --git a/gcc/testsuite/g++.dg/diagnostic/aka4.C b/gcc/testsuite/g++.dg/diagnostic/aka4.C new file mode 100644 index 0000000..da8c579 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/aka4.C @@ -0,0 +1,9 @@ +typedef unsigned int myvec __attribute__((vector_size (16))); + +void f (float x) +{ + myvec y = x; // { dg-error {cannot convert 'float' to 'myvec' {aka '__vector\([48]\) unsigned int'} in initialization} } + myvec *ptr = &x; // { dg-error {cannot convert 'float\*' to 'myvec\*' {aka '__vector\([48]\) unsigned int\*'} in initialization} } + const myvec *const_ptr = &x; // { dg-error {cannot convert 'float\*' to 'const myvec\*' {aka 'const __vector\([48]\) unsigned int\*'} in initialization} } + volatile myvec *volatile_ptr = &x; // { dg-error {cannot convert 'float\*' to 'volatile myvec\*' {aka 'volatile __vector\([48]\) unsigned int\*'} in initialization} } +} diff --git a/gcc/testsuite/gcc.dg/diag-aka-3.c b/gcc/testsuite/gcc.dg/diag-aka-3.c new file mode 100644 index 0000000..a3778ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/diag-aka-3.c @@ -0,0 +1,9 @@ +typedef unsigned int myvec __attribute__((vector_size (16))); + +void f (float x) +{ + myvec y = x; /* { dg-error {incompatible types when initializing type 'myvec' {aka '__vector\([48]\) unsigned int'} using type 'float'} } */ + myvec *ptr = &x; /* { dg-error {initialization of 'myvec \*' {aka '__vector\([48]\) unsigned int \*'} from incompatible pointer type 'float \*'} } */ + const myvec *const_ptr = &x; /* { dg-error {initialization of 'const myvec \*' {aka 'const __vector\([48]\) unsigned int \*'} from incompatible pointer type 'float \*'} } */ + volatile myvec *volatile_ptr = &x; /* { dg-error {initialization of 'volatile myvec \*' {aka 'volatile __vector\([48]\) unsigned int \*'} from incompatible pointer type 'float \*'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c b/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c new file mode 100644 index 0000000..59e24f4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c @@ -0,0 +1,14 @@ +#include + +typedef int16x4_t myvec; + +void f (float x) +{ + __Int8x8_t y1 = x; /* { dg-error {incompatible types when initializing type '__Int8x8_t' using type 'float'} } */ + __Int8x8_t *ptr1 = &x; /* { dg-error {initialization of '__Int8x8_t \*' from incompatible pointer type 'float \*'} } */ + int8x8_t y2 = x; /* { dg-error {incompatible types when initializing type 'int8x8_t' using type 'float'} } */ + int8x8_t *ptr2 = &x; /* { dg-error {initialization of 'int8x8_t \*' from incompatible pointer type 'float \*'} } */ + /* ??? For these it would be better to print an aka for 'int16x4_t'. */ + myvec y3 = x; /* { dg-error {incompatible types when initializing type 'myvec' using type 'float'} } */ + myvec *ptr3 = &x; /* { dg-error {initialization of 'myvec \*' from incompatible pointer type 'float \*'} } */ +} -- cgit v1.1 From 558798156b41fcbe5ba68b75171708cad135b041 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 08:56:25 +0000 Subject: [C] Avoid aka types that just add tags diag-aka-1.c tests that: struct T { int i; } T; void *a; T *t = a; produces: request for implicit conversion from 'void *' to 'T *' {aka 'struct T *'} ... But printing an aka for the tag seems a bit redundant when the tag name is the same as the typedef name. It's probably not going to be telling the user anything they don't already know, and can be distracting if "T" rather than "struct T" is the preferred choice for an exported interface. This is even more true if the tag is anonymous; e.g.: struct { int i; } T; void *a; T *t = a; gives: request for implicit conversion from 'void *' to 'T *' {aka 'struct *'} Rather than just drop the test above, the patch instead tests for: struct T { int i; } *T; where seeing the tag definitely helps. 2019-10-01 Richard Sandiford gcc/c/ * c-objc-common.c (useful_aka_type_p): New function. (print_type): Use it to decide whether an aka type is worth printing. gcc/testsuite/ * gcc.dg/diag-aka-1.c (T): Turn into a pointer typedef. (foo): Update accordingly. * gcc.dg/diag-aka-4.c: New test. From-SVN: r276395 --- gcc/c/ChangeLog | 5 +++ gcc/c/c-objc-common.c | 69 ++++++++++++++++++++++++++++++++++++- gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/gcc.dg/diag-aka-1.c | 4 +-- gcc/testsuite/gcc.dg/diag-aka-4.c | 72 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/diag-aka-4.c (limited to 'gcc') diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index fa0bbc8..3156e35 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Richard Sandiford + + * c-objc-common.c (useful_aka_type_p): New function. + (print_type): Use it to decide whether an aka type is worth printing. + 2019-09-27 Jakub Jelinek PR c++/88203 diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c index 2b76737..e1f3b2e 100644 --- a/gcc/c/c-objc-common.c +++ b/gcc/c/c-objc-common.c @@ -62,6 +62,73 @@ c_objc_common_init (void) return c_common_init (); } +/* Return true if it's worth saying that TYPE1 is also known as TYPE2. */ + +static bool +useful_aka_type_p (tree type1, tree type2) +{ + if (type1 == type2) + return false; + + if (type1 == error_mark_node || type2 == error_mark_node) + return false; + + if (TREE_CODE (type1) != TREE_CODE (type2)) + return true; + + if (typedef_variant_p (type1)) + { + /* Saying that "foo" is also known as "struct foo" or + "struct " is unlikely to be useful, since users of + structure-like types would already know that they're structures. + The same applies to unions and enums; in general, printing the + tag is only useful if it has a different name. */ + tree_code code = TREE_CODE (type2); + tree id2 = TYPE_IDENTIFIER (type2); + if ((code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + && (!id2 || TYPE_IDENTIFIER (type1) == id2)) + return false; + + return true; + } + else + { + switch (TREE_CODE (type1)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)); + + case ARRAY_TYPE: + return (useful_aka_type_p (TYPE_DOMAIN (type1), TYPE_DOMAIN (type2)) + || useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2))); + + case FUNCTION_TYPE: + { + tree args1 = TYPE_ARG_TYPES (type1); + tree args2 = TYPE_ARG_TYPES (type2); + while (args1 != args2) + { + /* Although this shouldn't happen, it seems to wrong to assert + for it in a diagnostic routine. */ + if (!args1 || args1 == void_type_node) + return true; + if (!args2 || args2 == void_type_node) + return true; + if (useful_aka_type_p (TREE_VALUE (args1), TREE_VALUE (args2))) + return true; + args1 = TREE_CHAIN (args1); + args2 = TREE_CHAIN (args2); + } + return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)); + } + + default: + return true; + } + } +} + /* Print T to CPP. */ static void @@ -83,7 +150,7 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted) stripped version. But sometimes the stripped version looks exactly the same, so we don't want it after all. To avoid printing it in that case, we play ugly obstack games. */ - if (TYPE_CANONICAL (t) && t != TYPE_CANONICAL (t)) + if (TYPE_CANONICAL (t) && useful_aka_type_p (t, TYPE_CANONICAL (t))) { c_pretty_printer cpp2; /* Print the stripped version into a temporary printer. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index af7f6a2..891b2bf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2019-10-01 Richard Sandiford + * gcc.dg/diag-aka-1.c (T): Turn into a pointer typedef. + (foo): Update accordingly. + * gcc.dg/diag-aka-4.c: New test. + +2019-10-01 Richard Sandiford + * gcc.dg/diag-aka-3.c: New test. * gcc.target/aarch64/diag_aka_1.c: New test. * g++.dg/diagnostic/aka4.C: New test. diff --git a/gcc/testsuite/gcc.dg/diag-aka-1.c b/gcc/testsuite/gcc.dg/diag-aka-1.c index fde4ca7..3383c1c 100644 --- a/gcc/testsuite/gcc.dg/diag-aka-1.c +++ b/gcc/testsuite/gcc.dg/diag-aka-1.c @@ -2,7 +2,7 @@ /* { dg-options "-Wc++-compat" } */ typedef struct A { int i; } B; -typedef struct T { int i; } T; +typedef struct T { int i; } *T; /* { dg-warning "using 'T' as both a typedef and a tag is invalid" } */ typedef const float TFA; typedef TFA TFB; typedef TFB TFC; @@ -24,6 +24,6 @@ bar (B *b, int *i) int foo (void *a) { - T *t = a; /* { dg-warning "request for implicit conversion from 'void \\*' to 'T \\*' {aka 'struct T \\*'} not" } */ + T t = a; /* { dg-warning "request for implicit conversion from 'void \\*' to 'T' {aka 'struct T \\*'} not" } */ return t->i; } diff --git a/gcc/testsuite/gcc.dg/diag-aka-4.c b/gcc/testsuite/gcc.dg/diag-aka-4.c new file mode 100644 index 0000000..cf98dd9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/diag-aka-4.c @@ -0,0 +1,72 @@ +typedef struct struct_wrapper { int i; } struct_wrapper; +typedef struct { int i; } anon_struct_wrapper; + +typedef union union_wrapper { int i; } union_wrapper; +typedef union { int i; } anon_union_wrapper; + +typedef enum enum_wrapper { A, B } enum_wrapper; +typedef enum { C, D } anon_enum_wrapper; + +void test_struct_wrapper (struct_wrapper y, int x) +{ + struct_wrapper *ptr = &x; /* { dg-error {initialization of 'struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + const struct_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile struct_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + struct_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'struct_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + struct_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'struct_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(struct_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(struct_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'struct_wrapper' from type 'int'} } */ +} + +void test_anon_struct_wrapper (anon_struct_wrapper y, int x) +{ + anon_struct_wrapper *ptr = &x; /* { dg-error {initialization of 'anon_struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + const anon_struct_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const anon_struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile anon_struct_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile anon_struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + anon_struct_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'anon_struct_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + anon_struct_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'anon_struct_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(anon_struct_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(anon_struct_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'anon_struct_wrapper' from type 'int'} } */ +} + +void test_union_wrapper (union_wrapper y, int x) +{ + union_wrapper *ptr = &x; /* { dg-error {initialization of 'union_wrapper \*' from incompatible pointer type 'int \*'} } */ + const union_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const union_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile union_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile union_wrapper \*' from incompatible pointer type 'int \*'} } */ + union_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'union_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + union_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'union_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(union_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(union_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'union_wrapper' from type 'int'} } */ +} + +void test_anon_union_wrapper (anon_union_wrapper y, int x) +{ + anon_union_wrapper *ptr = &x; /* { dg-error {initialization of 'anon_union_wrapper \*' from incompatible pointer type 'int \*'} } */ + const anon_union_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const anon_union_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile anon_union_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile anon_union_wrapper \*' from incompatible pointer type 'int \*'} } */ + anon_union_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'anon_union_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + anon_union_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'anon_union_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(anon_union_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(anon_union_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'anon_union_wrapper' from type 'int'} } */ +} + +void test_enum_wrapper (enum_wrapper y, int x) +{ + enum_wrapper *ptr = &x; /* { dg-error {initialization of 'enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + const enum_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile enum_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + enum_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'enum_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + enum_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'enum_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(enum_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(enum_wrapper\)' from incompatible pointer type 'int \*'} } */ +} + +void test_anon_enum_wrapper (anon_enum_wrapper y, int x) +{ + anon_enum_wrapper *ptr = &x; /* { dg-error {initialization of 'anon_enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + const anon_enum_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const anon_enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile anon_enum_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile anon_enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + anon_enum_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'anon_enum_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + anon_enum_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'anon_enum_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(anon_enum_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(anon_enum_wrapper\)' from incompatible pointer type 'int \*'} } */ +} -- cgit v1.1 From 58e721d255c111b2ae012bb452cf39a0ee58ed27 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 1 Oct 2019 13:12:03 +0200 Subject: regrename: Use PC instead of CC0 to hide operands The regrename pass temporarily changes some operand RTL to CC0 so that note_stores and scan_rtx don't see those operands. CC0 is deprecated and we want to remove it, so we need to use something else here. PC fits the bill fine. * regrename.c (hide_operands): Use pc_rtx instead of cc0_rtx. (build_def_use): Use PC instead of CC0 in a comment. From-SVN: r276401 --- gcc/ChangeLog | 5 +++++ gcc/regrename.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2c515e1..4d0ce47 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Segher Boessenkool + + * regrename.c (hide_operands): Use pc_rtx instead of cc0_rtx. + (build_def_use): Use PC instead of CC0 in a comment. + 2019-10-01 Richard Sandiford * rtl.def (CLOBBER_HIGH): Delete. diff --git a/gcc/regrename.c b/gcc/regrename.c index 8c3bae8..408bccc 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -1517,7 +1517,7 @@ scan_rtx (rtx_insn *insn, rtx *loc, enum reg_class cl, enum scan_actions action, } /* Hide operands of the current insn (of which there are N_OPS) by - substituting cc0 for them. + substituting pc for them. Previous values are stored in the OLD_OPERANDS and OLD_DUPS. For every bit set in DO_NOT_HIDE, we leave the operand alone. If INOUT_AND_EC_ONLY is set, we only do this for OP_INOUT type operands @@ -1541,7 +1541,7 @@ hide_operands (int n_ops, rtx *old_operands, rtx *old_dups, continue; if (!inout_and_ec_only || recog_data.operand_type[i] == OP_INOUT || op_alt[i].earlyclobber) - *recog_data.operand_loc[i] = cc0_rtx; + *recog_data.operand_loc[i] = pc_rtx; } for (i = 0; i < recog_data.n_dups; i++) { @@ -1551,7 +1551,7 @@ hide_operands (int n_ops, rtx *old_operands, rtx *old_dups, continue; if (!inout_and_ec_only || recog_data.operand_type[opn] == OP_INOUT || op_alt[opn].earlyclobber) - *recog_data.dup_loc[i] = cc0_rtx; + *recog_data.dup_loc[i] = pc_rtx; } } @@ -1754,7 +1754,7 @@ build_def_use (basic_block bb) /* Step 2: Mark chains for which we have reads outside operands as unrenamable. - We do this by munging all operands into CC0, and closing + We do this by munging all operands into PC, and closing everything remaining. */ hide_operands (n_ops, old_operands, old_dups, untracked_operands, -- cgit v1.1 From c7ea76ea5629e9f0357de49847274cf80e35f2f8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 1 Oct 2019 11:20:27 +0000 Subject: tree-vect-loop.c (vectorizable_reduction): Move variables to where they are used. 2019-10-01 Richard Biener * tree-vect-loop.c (vectorizable_reduction): Move variables to where they are used. From-SVN: r276402 --- gcc/ChangeLog | 5 +++++ gcc/tree-vect-loop.c | 36 +++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4d0ce47..7c3eb33 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Richard Biener + + * tree-vect-loop.c (vectorizable_reduction): Move variables + to where they are used. + 2019-10-01 Segher Boessenkool * regrename.c (hide_operands): Use pc_rtx instead of cc0_rtx. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 69cd683..350cee5 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -5767,7 +5767,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, slp_instance slp_node_instance, stmt_vector_for_cost *cost_vec) { - tree vec_dest; tree scalar_dest; tree vectype_out = STMT_VINFO_VECTYPE (stmt_info); tree vectype_in = NULL_TREE; @@ -5778,29 +5777,21 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, machine_mode vec_mode; int op_type; optab optab; - tree new_temp = NULL_TREE; enum vect_def_type dt, cond_reduc_dt = vect_unknown_def_type; stmt_vec_info cond_stmt_vinfo = NULL; tree scalar_type; bool is_simple_use; int i; int ncopies; - stmt_vec_info prev_stmt_info, prev_phi_info; + stmt_vec_info prev_phi_info; bool single_defuse_cycle = false; - stmt_vec_info new_stmt_info = NULL; int j; tree ops[3]; enum vect_def_type dts[3]; bool nested_cycle = false, found_nested_cycle_def = false; bool double_reduc = false; - basic_block def_bb; - class loop * def_stmt_loop; - tree def_arg; - auto_vec vec_oprnds0; - auto_vec vec_oprnds1; - auto_vec vec_oprnds2; int vec_num; - tree def0, tem; + tree tem; tree cr_index_scalar_type = NULL_TREE, cr_index_vector_type = NULL_TREE; tree cond_reduc_val = NULL_TREE; @@ -5900,7 +5891,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } /* Create the destination vector */ - vec_dest = vect_create_destination_var (phi_result, vectype_out); + tree vec_dest = vect_create_destination_var (phi_result, vectype_out); /* Get the loop-entry arguments. */ tree vec_initial_def; @@ -6348,15 +6339,16 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, if (nested_cycle) { - def_bb = gimple_bb (reduc_def_phi); - def_stmt_loop = def_bb->loop_father; - def_arg = PHI_ARG_DEF_FROM_EDGE (reduc_def_phi, - loop_preheader_edge (def_stmt_loop)); + basic_block def_bb = gimple_bb (reduc_def_phi); + class loop *def_stmt_loop = def_bb->loop_father; + tree def_arg = PHI_ARG_DEF_FROM_EDGE (reduc_def_phi, + loop_preheader_edge (def_stmt_loop)); stmt_vec_info def_arg_stmt_info = loop_vinfo->lookup_def (def_arg); if (def_arg_stmt_info && (STMT_VINFO_DEF_TYPE (def_arg_stmt_info) == vect_double_reduction_def)) double_reduc = true; + gcc_assert (!double_reduc || STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_outer_by_reduction); } vect_reduction_type reduction_type @@ -6670,6 +6662,8 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, if (code == DOT_PROD_EXPR && !types_compatible_p (TREE_TYPE (ops[0]), TREE_TYPE (ops[1]))) { + gcc_unreachable (); + /* No testcase for this. PR49478. */ if (TREE_CODE (ops[0]) == INTEGER_CST) ops[0] = fold_convert (TREE_TYPE (ops[1]), ops[0]); else if (TREE_CODE (ops[1]) == INTEGER_CST) @@ -6812,7 +6806,15 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, return true; } + /* Transform. */ + stmt_vec_info new_stmt_info = NULL; + stmt_vec_info prev_stmt_info; + tree new_temp = NULL_TREE; + auto_vec vec_oprnds0; + auto_vec vec_oprnds1; + auto_vec vec_oprnds2; + tree def0; if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "transform reduction.\n"); @@ -6836,7 +6838,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } /* Create the destination vector */ - vec_dest = vect_create_destination_var (scalar_dest, vectype_out); + tree vec_dest = vect_create_destination_var (scalar_dest, vectype_out); prev_stmt_info = NULL; prev_phi_info = NULL; -- cgit v1.1 From 31632e2c4327146ea8d21cff33adaa505b17d2bd Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Tue, 1 Oct 2019 11:36:31 +0000 Subject: DWARF array bounds missing from C++ array definitions A variable redeclaration or definition that provides additional type information for it, e.g. outermost array bounds, is not reflected in the debug information for the variable. With this patch, the debug info of the variable specialization gets a type attribute with the adjusted type. This patch affects mostly only array bounds. However, when the symbolic type used in a declaration and in a definition are different, although they refer to the same type, debug information will end up (correctly?) naming different symbolic types in the specification and the definition. Also, when a readonly declaration of an array loses the readonly flag at the definition because of the initializer, the definition may end up referencing a type while the specification refers to a const-qualified version of that type. If the type of the variable is already const-qualified, e.g. an array of a const type, the difference is meaningless. for gcc/ChangeLog PR debug/91507 * dwarf2out.c (override_type_for_decl_p): New. (gen_variable_die): Use it. for gcc/testsuite/ChangeLog PR debug/91507 * gcc.dg/debug/dwarf2/array-0.c: New. * gcc.dg/debug/dwarf2/array-1.c: New. * gcc.dg/debug/dwarf2/array-2.c: New. * gcc.dg/debug/dwarf2/array-3.c: New. * g++.dg/debug/dwarf2/array-0.C: New. * g++.dg/debug/dwarf2/array-1.C: New. * g++.dg/debug/dwarf2/array-2.C: New. Based on libstdc++-v3's src/c++98/pool_allocator.cc:__pool_alloc_base::_S_heap_size. * g++.dg/debug/dwarf2/array-3.C: New. Based on gcc's config/i386/i386-features.c:xlogue_layout::s_instances. * g++.dg/debug/dwarf2/array-4.C: New. From-SVN: r276403 --- gcc/ChangeLog | 6 ++++++ gcc/dwarf2out.c | 32 ++++++++++++++++++++++++++++- gcc/testsuite/ChangeLog | 15 ++++++++++++++ gcc/testsuite/g++.dg/debug/dwarf2/array-0.C | 13 ++++++++++++ gcc/testsuite/g++.dg/debug/dwarf2/array-1.C | 13 ++++++++++++ gcc/testsuite/g++.dg/debug/dwarf2/array-2.C | 15 ++++++++++++++ gcc/testsuite/g++.dg/debug/dwarf2/array-3.C | 20 ++++++++++++++++++ gcc/testsuite/g++.dg/debug/dwarf2/array-4.C | 16 +++++++++++++++ gcc/testsuite/gcc.dg/debug/dwarf2/array-0.c | 10 +++++++++ gcc/testsuite/gcc.dg/debug/dwarf2/array-1.c | 10 +++++++++ gcc/testsuite/gcc.dg/debug/dwarf2/array-2.c | 8 ++++++++ gcc/testsuite/gcc.dg/debug/dwarf2/array-3.c | 8 ++++++++ 12 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/array-0.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/array-1.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/array-2.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/array-3.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/array-4.C create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/array-0.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/array-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/array-2.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/array-3.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7c3eb33..13f2355 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Alexandre Oliva + + PR debug/91507 + * dwarf2out.c (override_type_for_decl_p): New. + (gen_variable_die): Use it. + 2019-10-01 Richard Biener * tree-vect-loop.c (vectorizable_reduction): Move variables diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index d33f19b..bf69ce4 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -23705,6 +23705,34 @@ local_function_static (tree decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL; } +/* Return true iff DECL overrides (presumably completes) the type of + OLD_DIE within CONTEXT_DIE. */ + +static bool +override_type_for_decl_p (tree decl, dw_die_ref old_die, + dw_die_ref context_die) +{ + tree type = TREE_TYPE (decl); + int cv_quals; + + if (decl_by_reference_p (decl)) + { + type = TREE_TYPE (type); + cv_quals = TYPE_UNQUALIFIED; + } + else + cv_quals = decl_quals (decl); + + dw_die_ref type_die = modified_type_die (type, + cv_quals | TYPE_QUALS (type), + false, + context_die); + + dw_die_ref old_type_die = get_AT_ref (old_die, DW_AT_type); + + return type_die != old_type_die; +} + /* Generate a DIE to represent a declared data object. Either DECL or ORIGIN must be non-null. */ @@ -23957,7 +23985,9 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) && !DECL_ABSTRACT_P (decl_or_origin) && variably_modified_type_p (TREE_TYPE (decl_or_origin), decl_function_context - (decl_or_origin)))) + (decl_or_origin))) + || (old_die && specialization_p + && override_type_for_decl_p (decl_or_origin, old_die, context_die))) { tree type = TREE_TYPE (decl_or_origin); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 891b2bf..9923029 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2019-10-01 Alexandre Oliva + + PR debug/91507 + * gcc.dg/debug/dwarf2/array-0.c: New. + * gcc.dg/debug/dwarf2/array-1.c: New. + * gcc.dg/debug/dwarf2/array-2.c: New. + * gcc.dg/debug/dwarf2/array-3.c: New. + * g++.dg/debug/dwarf2/array-0.C: New. + * g++.dg/debug/dwarf2/array-1.C: New. + * g++.dg/debug/dwarf2/array-2.C: New. Based on libstdc++-v3's + src/c++98/pool_allocator.cc:__pool_alloc_base::_S_heap_size. + * g++.dg/debug/dwarf2/array-3.C: New. Based on + gcc's config/i386/i386-features.c:xlogue_layout::s_instances. + * g++.dg/debug/dwarf2/array-4.C: New. + 2019-10-01 Richard Sandiford * gcc.dg/diag-aka-1.c (T): Turn into a pointer typedef. diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/array-0.C b/gcc/testsuite/g++.dg/debug/dwarf2/array-0.C new file mode 100644 index 0000000..a3458bd --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/array-0.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +struct S +{ + static int array[42]; +}; + +int S::array[42]; + +/* Verify that we get only one DW_TAG_subrange_type with a + DW_AT_upper_bound. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 2 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/array-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/array-1.C new file mode 100644 index 0000000..e8fd6f8 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/array-1.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +struct S +{ + static int array[]; +}; + +int S::array[42]; + +/* Verify that we get two DW_TAG_subrange_type, only one of which with + a DW_AT_upper_bound. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 4 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/array-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/array-2.C new file mode 100644 index 0000000..dd17812 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/array-2.C @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +struct S +{ + typedef int i_t; + static i_t array[42]; +}; + +int S::array[42]; + +/* Verify that we get two DW_TAG_subrange_type (plus abbrev), and two + DW_AT_upper_bound, because a different symbolic name is used for + the array element type. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 3 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 2 } } */ diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/array-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/array-3.C new file mode 100644 index 0000000..8db6133 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/array-3.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +struct S +{ + S() {} + ~S() {} + static const S array[2]; +}; + +const S S::array[2] = { S(), S() }; + +/* Verify that we get only one DW_TAG_subrange_type (plus the abbrev), + and one DW_AT_upper_bound (non-abbrev), because the array + definition loses the readonly wrapper for the array type because of + the dynamic initializers. The const types are 4: S, S*, int, and + S[4], plus the abbrev. A const version of S[4] doesn't make sense, + but we output it. */ +/* { dg-final { scan-assembler-times " DW_TAG_const_type" 5 } } */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 2 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/array-4.C b/gcc/testsuite/g++.dg/debug/dwarf2/array-4.C new file mode 100644 index 0000000..6b3f546 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/array-4.C @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +struct S +{ + S() {} + ~S() {} +}; + +const S array[2] = { S(), S() }; + +/* Like array-3, but with a non-member array without a separate + declaration, to check that we don't issue the nonsensical + DW_TAG_const_type used by the member array declaration there. */ +/* { dg-final { scan-assembler-times " DW_TAG_const_type" 4 } } */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 2 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/array-0.c b/gcc/testsuite/gcc.dg/debug/dwarf2/array-0.c new file mode 100644 index 0000000..b06392e --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/array-0.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +extern int array[42]; + +int array[42]; + +/* Verify that we get only one DW_TAG_subtrange_type (plus abbrev), + with a DW_AT_upper_bound. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 2 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/array-1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/array-1.c new file mode 100644 index 0000000..ad8f466 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/array-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +extern int array[]; + +int array[42]; + +/* Verify that we get two DW_TAG_subtrange_type (each with an abbrev), + but only one DW_AT_upper_bound. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 4 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/array-2.c b/gcc/testsuite/gcc.dg/debug/dwarf2/array-2.c new file mode 100644 index 0000000..5d1606f --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/array-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +int array[42]; + +/* Verify that we get only one DW_TAG_subtrange_type (plus abbrev) + with DW_AT_upper_bound. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 2 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/array-3.c b/gcc/testsuite/gcc.dg/debug/dwarf2/array-3.c new file mode 100644 index 0000000..077a62e --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/array-3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-gdwarf-2 -dA" } */ +int array[] = { 0, 1, 2 }; + +/* Verify that we get only one DW_TAG_subtrange_type (plus abbrev) + with DW_AT_upper_bound. */ +/* { dg-final { scan-assembler-times " DW_TAG_subrange_type" 2 } } */ +/* { dg-final { scan-assembler-times " DW_AT_upper_bound" 1 } } */ -- cgit v1.1 From 676e38c2a93311bc847c1034637efc935e527f8f Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Tue, 1 Oct 2019 11:36:47 +0000 Subject: Store float for pow result test Optimizing gcc.dg/torture/pr41094.c, the compiler computes the constant value and short-circuits the whole thing. At -O0, however, on 32-bit x86, the call to pow() remains, and the program compares the returned value in a stack register, with excess precision, with the exact return value expected from pow(). If libm's pow() returns a slightly off result, the compare fails. If the value in the register is stored in a separate variable, so it gets rounded to double precision, and then compared, the compare passes. It's not clear that the test was meant to detect libm's reliance on rounding off the excess precision, but I guess it wasn't, so I propose this slight change that enables it to pass regardless of the slight inaccuracy of the C library in use. for gcc/testsuite/ChangeLog * gcc.dg/torture/pr41094.c: Introduce intermediate variable. From-SVN: r276404 --- gcc/testsuite/ChangeLog | 2 ++ gcc/testsuite/gcc.dg/torture/pr41094.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9923029..4f876e5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2019-10-01 Alexandre Oliva + * gcc.dg/torture/pr41094.c: Introduce intermediate variable. + PR debug/91507 * gcc.dg/debug/dwarf2/array-0.c: New. * gcc.dg/debug/dwarf2/array-1.c: New. diff --git a/gcc/testsuite/gcc.dg/torture/pr41094.c b/gcc/testsuite/gcc.dg/torture/pr41094.c index 2a4e961..9219a17 100644 --- a/gcc/testsuite/gcc.dg/torture/pr41094.c +++ b/gcc/testsuite/gcc.dg/torture/pr41094.c @@ -13,7 +13,8 @@ double foo(void) int main() { - if (foo() != 2.0) + double r = foo (); + if (r != 2.0) abort (); return 0; } -- cgit v1.1 From 6bc89193bcf3c616e22d0f422e42e685f1d7796a Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Tue, 1 Oct 2019 11:37:01 +0000 Subject: recompute opt flags after opt level change flag_omit_frame_pointer is set in machine-independent code depending on the optimization level. It is then overridden in x86 target-specific code depending on a macro defined by --enable-frame-pointer. Uses of attribute optimize go through machine-independent overriding of flag_omit_frame_pointer, but the x86-specific overriding code did NOT cover this flag, so, even if the attribute does not change the optimization level, flag_omit_frame_pointer may end up with a different value, and prevent inlining because of incompatible flags, as detected by the gcc.dg/ipa/iinline-attr.c test on an --enable-frame-pointer x86 toolchain. for gcc/ChangeLog * config/i386/i386-options.c (ix86_recompute_optlev_based_flags): New, moved out of... (ix86_option_override_internal): ... this. Call it. (ix86_override_options_after_change): Call it here too. From-SVN: r276405 --- gcc/ChangeLog | 5 +++ gcc/config/i386/i386-options.c | 89 ++++++++++++++++++++++++------------------ 2 files changed, 55 insertions(+), 39 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 13f2355..ce7109f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-10-01 Alexandre Oliva + * config/i386/i386-options.c + (ix86_recompute_optlev_based_flags): New, moved out of... + (ix86_option_override_internal): ... this. Call it. + (ix86_override_options_after_change): Call it here too. + PR debug/91507 * dwarf2out.c (override_type_for_decl_p): New. (gen_variable_die): Use it. diff --git a/gcc/config/i386/i386-options.c b/gcc/config/i386/i386-options.c index c148aa2..ed286bf 100644 --- a/gcc/config/i386/i386-options.c +++ b/gcc/config/i386/i386-options.c @@ -1527,12 +1527,61 @@ ix86_default_align (struct gcc_options *opts) opts->x_str_align_functions = processor_cost_table[ix86_tune]->align_func; } +#ifndef USE_IX86_FRAME_POINTER +#define USE_IX86_FRAME_POINTER 0 +#endif + +/* (Re)compute option overrides affected by optimization levels in + target-specific ways. */ + +static void +ix86_recompute_optlev_based_flags (struct gcc_options *opts, + struct gcc_options *opts_set) +{ + /* Set the default values for switches whose default depends on TARGET_64BIT + in case they weren't overwritten by command line options. */ + if (TARGET_64BIT_P (opts->x_ix86_isa_flags)) + { + if (opts->x_optimize >= 1 && !opts_set->x_flag_omit_frame_pointer) + opts->x_flag_omit_frame_pointer = !USE_IX86_FRAME_POINTER; + if (opts->x_flag_asynchronous_unwind_tables + && !opts_set->x_flag_unwind_tables + && TARGET_64BIT_MS_ABI) + opts->x_flag_unwind_tables = 1; + if (opts->x_flag_asynchronous_unwind_tables == 2) + opts->x_flag_unwind_tables + = opts->x_flag_asynchronous_unwind_tables = 1; + if (opts->x_flag_pcc_struct_return == 2) + opts->x_flag_pcc_struct_return = 0; + } + else + { + if (opts->x_optimize >= 1 && !opts_set->x_flag_omit_frame_pointer) + opts->x_flag_omit_frame_pointer + = !(USE_IX86_FRAME_POINTER || opts->x_optimize_size); + if (opts->x_flag_asynchronous_unwind_tables == 2) + opts->x_flag_asynchronous_unwind_tables = !USE_IX86_FRAME_POINTER; + if (opts->x_flag_pcc_struct_return == 2) + { + /* Intel MCU psABI specifies that -freg-struct-return should + be on. Instead of setting DEFAULT_PCC_STRUCT_RETURN to 1, + we check -miamcu so that -freg-struct-return is always + turned on if -miamcu is used. */ + if (TARGET_IAMCU_P (opts->x_target_flags)) + opts->x_flag_pcc_struct_return = 0; + else + opts->x_flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN; + } + } +} + /* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE hook. */ void ix86_override_options_after_change (void) { ix86_default_align (&global_options); + ix86_recompute_optlev_based_flags (&global_options, &global_options_set); } /* Clear stack slot assignments remembered from previous functions. @@ -2220,45 +2269,7 @@ ix86_option_override_internal (bool main_args_p, set_ix86_tune_features (ix86_tune, opts->x_ix86_dump_tunes); -#ifndef USE_IX86_FRAME_POINTER -#define USE_IX86_FRAME_POINTER 0 -#endif - - /* Set the default values for switches whose default depends on TARGET_64BIT - in case they weren't overwritten by command line options. */ - if (TARGET_64BIT_P (opts->x_ix86_isa_flags)) - { - if (opts->x_optimize >= 1 && !opts_set->x_flag_omit_frame_pointer) - opts->x_flag_omit_frame_pointer = !USE_IX86_FRAME_POINTER; - if (opts->x_flag_asynchronous_unwind_tables - && !opts_set->x_flag_unwind_tables - && TARGET_64BIT_MS_ABI) - opts->x_flag_unwind_tables = 1; - if (opts->x_flag_asynchronous_unwind_tables == 2) - opts->x_flag_unwind_tables - = opts->x_flag_asynchronous_unwind_tables = 1; - if (opts->x_flag_pcc_struct_return == 2) - opts->x_flag_pcc_struct_return = 0; - } - else - { - if (opts->x_optimize >= 1 && !opts_set->x_flag_omit_frame_pointer) - opts->x_flag_omit_frame_pointer - = !(USE_IX86_FRAME_POINTER || opts->x_optimize_size); - if (opts->x_flag_asynchronous_unwind_tables == 2) - opts->x_flag_asynchronous_unwind_tables = !USE_IX86_FRAME_POINTER; - if (opts->x_flag_pcc_struct_return == 2) - { - /* Intel MCU psABI specifies that -freg-struct-return should - be on. Instead of setting DEFAULT_PCC_STRUCT_RETURN to 1, - we check -miamcu so that -freg-struct-return is always - turned on if -miamcu is used. */ - if (TARGET_IAMCU_P (opts->x_target_flags)) - opts->x_flag_pcc_struct_return = 0; - else - opts->x_flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN; - } - } + ix86_recompute_optlev_based_flags (opts, opts_set); ix86_tune_cost = processor_cost_table[ix86_tune]; /* TODO: ix86_cost should be chosen at instruction or function granuality -- cgit v1.1 From 3366b37850b0b41d1cc80d82224b4c7804ad2158 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2019 12:55:16 +0000 Subject: Fix reload after function-abi patches (PR91948) The code was passing a pseudo rather than its allocated hard reg to ira_need_caller_save_p. Running under valgrind to reproduce the failure also showed that ALLOCNO_CROSSED_CALLS_ABIS wasn't being explicitly initialised. 2019-10-01 Richard Sandiford gcc/ PR rtl-optimization/91948 * ira-build.c (ira_create_allocno): Initialize ALLOCNO_CROSSED_CALLS_ABIS. * ira-color.c (allocno_reload_assign): Pass hard_regno rather than regno to ira_need_caller_save_p. From-SVN: r276407 --- gcc/ChangeLog | 8 ++++++++ gcc/ira-build.c | 1 + gcc/ira-color.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ce7109f..ab81f41 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-10-01 Richard Sandiford + + PR rtl-optimization/91948 + * ira-build.c (ira_create_allocno): Initialize + ALLOCNO_CROSSED_CALLS_ABIS. + * ira-color.c (allocno_reload_assign): Pass hard_regno rather + than regno to ira_need_caller_save_p. + 2019-10-01 Alexandre Oliva * config/i386/i386-options.c diff --git a/gcc/ira-build.c b/gcc/ira-build.c index 222956e..47ce189 100644 --- a/gcc/ira-build.c +++ b/gcc/ira-build.c @@ -504,6 +504,7 @@ ira_create_allocno (int regno, bool cap_p, ALLOCNO_CALL_FREQ (a) = 0; ALLOCNO_CALLS_CROSSED_NUM (a) = 0; ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a) = 0; + ALLOCNO_CROSSED_CALLS_ABIS (a) = 0; CLEAR_HARD_REG_SET (ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a)); #ifdef STACK_REGS ALLOCNO_NO_STACK_REG_P (a) = false; diff --git a/gcc/ira-color.c b/gcc/ira-color.c index 9197db9..42309b9 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -4398,7 +4398,7 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs) ? ALLOCNO_CLASS_COST (a) : ALLOCNO_HARD_REG_COSTS (a)[ira_class_hard_reg_index [aclass][hard_regno]])); - if (ira_need_caller_save_p (a, regno)) + if (ira_need_caller_save_p (a, hard_regno)) { ira_assert (flag_caller_saves); caller_save_needed = 1; -- cgit v1.1 From b4363c5a269b8ac870921177e8024e3bf9eb0c23 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 1 Oct 2019 14:03:08 +0000 Subject: S/390: Implement vcond expander for V1TI,V1TF Currently gcc does not emit wf{c,k}* instructions when comparing long double values. Middle-end actually adds them in the first place, but then veclower pass replaces them with floating point register pair operations, because the corresponding expander is missing. gcc/ChangeLog: 2019-10-01 Ilya Leoshkevich PR target/77918 * config/s390/vector.md (V_HW): Add V1TI in order to make vcond$a$b generate vcondv1tiv1tf. From-SVN: r276408 --- gcc/ChangeLog | 6 ++++++ gcc/config/s390/vector.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ab81f41..60c8f9f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Ilya Leoshkevich + + PR target/77918 + * config/s390/vector.md (V_HW): Add V1TI in order to make + vcond$a$b generate vcondv1tiv1tf. + 2019-10-01 Richard Sandiford PR rtl-optimization/91948 diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 961d2c6..d624d3f 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -29,7 +29,7 @@ ; All modes directly supported by the hardware having full vector reg size ; V_HW2 is duplicate of V_HW for having two iterators expanding ; independently e.g. vcond -(define_mode_iterator V_HW [V16QI V8HI V4SI V2DI V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")]) +(define_mode_iterator V_HW [V16QI V8HI V4SI V2DI (V1TI "TARGET_VXE") V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")]) (define_mode_iterator V_HW2 [V16QI V8HI V4SI V2DI V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")]) (define_mode_iterator V_HW_64 [V2DI V2DF]) -- cgit v1.1 From a1bfb5b16b4b55ae875d346a7b462a18316ad959 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 1 Oct 2019 14:04:08 +0000 Subject: S/390: Remove code duplication in vec_* comparison expanders s390.md uses a lot of near-identical expanders that perform dispatching to other expanders based on operand types. Since the following patch would require even more of these, avoid copy-pasting the code by generating these expanders using an iterator. gcc/ChangeLog: 2019-10-01 Ilya Leoshkevich PR target/77918 * config/s390/s390.c (s390_expand_vec_compare): Use gen_vec_cmpordered and gen_vec_cmpunordered. * config/s390/vector.md (vec_cmpuneq, vec_cmpltgt, vec_ordered, vec_unordered): Delete. (vec_ordered): Rename to vec_cmpordered. (vec_unordered): Rename to vec_cmpunordered. (VEC_CMP_EXPAND): New iterator for the generic dispatcher. (vec_cmp): Generic dispatcher. From-SVN: r276409 --- gcc/ChangeLog | 12 +++++++++ gcc/config/s390/s390.c | 4 +-- gcc/config/s390/vector.md | 67 ++++++++--------------------------------------- 3 files changed, 25 insertions(+), 58 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 60c8f9f..c32bf84 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,18 @@ 2019-10-01 Ilya Leoshkevich PR target/77918 + * config/s390/s390.c (s390_expand_vec_compare): Use + gen_vec_cmpordered and gen_vec_cmpunordered. + * config/s390/vector.md (vec_cmpuneq, vec_cmpltgt, vec_ordered, + vec_unordered): Delete. + (vec_ordered): Rename to vec_cmpordered. + (vec_unordered): Rename to vec_cmpunordered. + (VEC_CMP_EXPAND): New iterator for the generic dispatcher. + (vec_cmp): Generic dispatcher. + +2019-10-01 Ilya Leoshkevich + + PR target/77918 * config/s390/vector.md (V_HW): Add V1TI in order to make vcond$a$b generate vcondv1tiv1tf. diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 1764c34..062cbd8 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -6523,10 +6523,10 @@ s390_expand_vec_compare (rtx target, enum rtx_code cond, emit_insn (gen_vec_cmpltgt (target, cmp_op1, cmp_op2)); return; case ORDERED: - emit_insn (gen_vec_ordered (target, cmp_op1, cmp_op2)); + emit_insn (gen_vec_cmpordered (target, cmp_op1, cmp_op2)); return; case UNORDERED: - emit_insn (gen_vec_unordered (target, cmp_op1, cmp_op2)); + emit_insn (gen_vec_cmpunordered (target, cmp_op1, cmp_op2)); return; default: break; } diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index d624d3f..451d07d 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -1472,22 +1472,6 @@ operands[3] = gen_reg_rtx (mode); }) -(define_expand "vec_cmpuneq" - [(match_operand 0 "register_operand" "") - (match_operand 1 "register_operand" "") - (match_operand 2 "register_operand" "")] - "TARGET_VX" -{ - if (GET_MODE (operands[1]) == V4SFmode) - emit_insn (gen_vec_cmpuneqv4sf (operands[0], operands[1], operands[2])); - else if (GET_MODE (operands[1]) == V2DFmode) - emit_insn (gen_vec_cmpuneqv2df (operands[0], operands[1], operands[2])); - else - gcc_unreachable (); - - DONE; -}) - ; LTGT a <> b -> a > b | b > a (define_expand "vec_cmpltgt" [(set (match_operand: 0 "register_operand" "=v") @@ -1500,24 +1484,8 @@ operands[3] = gen_reg_rtx (mode); }) -(define_expand "vec_cmpltgt" - [(match_operand 0 "register_operand" "") - (match_operand 1 "register_operand" "") - (match_operand 2 "register_operand" "")] - "TARGET_VX" -{ - if (GET_MODE (operands[1]) == V4SFmode) - emit_insn (gen_vec_cmpltgtv4sf (operands[0], operands[1], operands[2])); - else if (GET_MODE (operands[1]) == V2DFmode) - emit_insn (gen_vec_cmpltgtv2df (operands[0], operands[1], operands[2])); - else - gcc_unreachable (); - - DONE; -}) - ; ORDERED (a, b): a >= b | b > a -(define_expand "vec_ordered" +(define_expand "vec_cmpordered" [(set (match_operand: 0 "register_operand" "=v") (ge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v"))) @@ -1528,45 +1496,32 @@ operands[3] = gen_reg_rtx (mode); }) -(define_expand "vec_ordered" - [(match_operand 0 "register_operand" "") - (match_operand 1 "register_operand" "") - (match_operand 2 "register_operand" "")] - "TARGET_VX" -{ - if (GET_MODE (operands[1]) == V4SFmode) - emit_insn (gen_vec_orderedv4sf (operands[0], operands[1], operands[2])); - else if (GET_MODE (operands[1]) == V2DFmode) - emit_insn (gen_vec_orderedv2df (operands[0], operands[1], operands[2])); - else - gcc_unreachable (); - - DONE; -}) - ; UNORDERED (a, b): !ORDERED (a, b) -(define_expand "vec_unordered" +(define_expand "vec_cmpunordered" [(match_operand: 0 "register_operand" "=v") (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")] "TARGET_VX" { - emit_insn (gen_vec_ordered (operands[0], operands[1], operands[2])); + emit_insn (gen_vec_cmpordered (operands[0], operands[1], operands[2])); emit_insn (gen_rtx_SET (operands[0], gen_rtx_NOT (mode, operands[0]))); DONE; }) -(define_expand "vec_unordered" +(define_code_iterator VEC_CMP_EXPAND + [uneq ltgt ordered unordered]) + +(define_expand "vec_cmp" [(match_operand 0 "register_operand" "") - (match_operand 1 "register_operand" "") - (match_operand 2 "register_operand" "")] + (VEC_CMP_EXPAND (match_operand 1 "register_operand" "") + (match_operand 2 "register_operand" ""))] "TARGET_VX" { if (GET_MODE (operands[1]) == V4SFmode) - emit_insn (gen_vec_unorderedv4sf (operands[0], operands[1], operands[2])); + emit_insn (gen_vec_cmpv4sf (operands[0], operands[1], operands[2])); else if (GET_MODE (operands[1]) == V2DFmode) - emit_insn (gen_vec_unorderedv2df (operands[0], operands[1], operands[2])); + emit_insn (gen_vec_cmpv2df (operands[0], operands[1], operands[2])); else gcc_unreachable (); -- cgit v1.1 From 2a2592a10c13c53fc1fbac0bfe9e661201dab53f Mon Sep 17 00:00:00 2001 From: William Schmidt Date: Tue, 1 Oct 2019 14:27:44 +0000 Subject: rs6000-p8swap.c (rtx_is_swappable_p): Don't swap vpmsumd. [gcc] 2019-10-01 Bill Schmidt * config/rs6000/rs6000-p8swap.c (rtx_is_swappable_p): Don't swap vpmsumd. [gcc/testsuite] 2019-10-01 Bill Schmidt * gcc.target/powerpc/pr91275.c: New. From-SVN: r276410 --- gcc/ChangeLog | 5 +++++ gcc/config/rs6000/rs6000-p8swap.c | 5 +++++ gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gcc.target/powerpc/pr91275.c | 21 +++++++++++++++++++++ 4 files changed, 35 insertions(+) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr91275.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c32bf84..b671ae6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Bill Schmidt + + * config/rs6000/rs6000-p8swap.c (rtx_is_swappable_p): Don't swap + vpmsumd. + 2019-10-01 Ilya Leoshkevich PR target/77918 diff --git a/gcc/config/rs6000/rs6000-p8swap.c b/gcc/config/rs6000/rs6000-p8swap.c index c3b9831..d30e5de 100644 --- a/gcc/config/rs6000/rs6000-p8swap.c +++ b/gcc/config/rs6000/rs6000-p8swap.c @@ -791,6 +791,11 @@ rtx_is_swappable_p (rtx op, unsigned int *special) case UNSPEC_REDUC_PLUS: case UNSPEC_REDUC: return 1; + case UNSPEC_VPMSUM: + /* vpmsumd is not swappable, but vpmsum[bhw] are. */ + if (GET_MODE (op) == V2DImode) + return 0; + break; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4f876e5..995e1cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-01 Bill Schmidt + + * gcc.target/powerpc/pr91275.c: New. + 2019-10-01 Alexandre Oliva * gcc.dg/torture/pr41094.c: Introduce intermediate variable. diff --git a/gcc/testsuite/gcc.target/powerpc/pr91275.c b/gcc/testsuite/gcc.target/powerpc/pr91275.c new file mode 100644 index 0000000..b23d75b --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr91275.c @@ -0,0 +1,21 @@ +/* Test that we generate vpmsumd correctly without a swap error. */ + +/* { dg-do run { target { p8vector_hw } } } */ +/* { dg-options "-O2 -std=gnu11" } */ + +#include + +int main() { + + const unsigned long long r0l = 0x8e7dfceac070e3a0; + vector unsigned long long r0 = (vector unsigned long long) {r0l, 0}, v; + const vector unsigned long long pd + = (vector unsigned long) {0xc2LLU << 56, 0}; + + v = __builtin_crypto_vpmsumd ((vector unsigned long long) {r0[0], 0}, pd); + + if (v[0] != 0x4000000000000000 || v[1] != 0x65bd7ab605a4a8ff) + __builtin_abort (); + + return 0; +} -- cgit v1.1 From 04bf300e86bc88617a709bebe29787f95aec59cc Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Tue, 1 Oct 2019 14:55:34 +0000 Subject: re PR c++/88562 (Incorrect pointer incrementing on SH4) gcc/ 2019-10-01 Oleg Endo PR target/88562 * config/sh/sh.c (sh_extending_set_of_reg::use_as_extended_reg): Use sh_check_add_incdec_notes to preserve REG_INC notes when replacing a memory access insn. From-SVN: r276411 --- gcc/ChangeLog | 7 +++++++ gcc/config/sh/sh.c | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b671ae6..bb4de20 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-01 Oleg Endo + + PR target/88562 + * config/sh/sh.c (sh_extending_set_of_reg::use_as_extended_reg): Use + sh_check_add_incdec_notes to preserve REG_INC notes when replacing + a memory access insn. + 2019-10-01 Bill Schmidt * config/rs6000/rs6000-p8swap.c (rtx_is_swappable_p): Don't swap diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 9917f2b..ffab94f 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -12068,9 +12068,11 @@ sh_extending_set_of_reg::use_as_extended_reg (rtx_insn* use_at_insn) const rtx r = gen_reg_rtx (SImode); rtx_insn* i0; if (from_mode == QImode) - i0 = emit_insn_after (gen_extendqisi2 (r, set_src), insn); + i0 = sh_check_add_incdec_notes ( + emit_insn_after (gen_extendqisi2 (r, set_src), insn)); else if (from_mode == HImode) - i0 = emit_insn_after (gen_extendhisi2 (r, set_src), insn); + i0 = sh_check_add_incdec_notes ( + emit_insn_after (gen_extendhisi2 (r, set_src), insn)); else gcc_unreachable (); -- cgit v1.1 From 7552c36afa1f9058bb39f336ae84f019621885a0 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 1 Oct 2019 18:19:04 +0200 Subject: re PR c++/91925 (-fpack-struct causes a decltype with template to ICE) PR c++/91925 * c-warn.c (check_alignment_of_packed_member): Ignore FIELD_DECLs with NULL DECL_FIELD_OFFSET. * g++.dg/conversion/packed2.C: New test. From-SVN: r276415 --- gcc/c-family/ChangeLog | 6 ++++++ gcc/c-family/c-warn.c | 2 ++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/conversion/packed2.C | 15 +++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 gcc/testsuite/g++.dg/conversion/packed2.C (limited to 'gcc') diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index eaea04b..811947a 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Jakub Jelinek + + PR c++/91925 + * c-warn.c (check_alignment_of_packed_member): Ignore FIELD_DECLs + with NULL DECL_FIELD_OFFSET. + 2019-10-01 Richard Sandiford * c-pretty-print.c (pp_c_specifier_qualifier_list): If a vector type diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index bee5449..8236525 100644 --- a/gcc/c-family/c-warn.c +++ b/gcc/c-family/c-warn.c @@ -2798,6 +2798,8 @@ check_alignment_of_packed_member (tree type, tree field, bool rvalue) /* Check alignment of the data member. */ if (TREE_CODE (field) == FIELD_DECL && (DECL_PACKED (field) || TYPE_PACKED (TREE_TYPE (field))) + /* Ignore FIELDs not laid out yet. */ + && DECL_FIELD_OFFSET (field) && (!rvalue || TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)) { /* Check the expected alignment against the field alignment. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 995e1cb..df6105f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Jakub Jelinek + + PR c++/91925 + * g++.dg/conversion/packed2.C: New test. + 2019-10-01 Bill Schmidt * gcc.target/powerpc/pr91275.c: New. diff --git a/gcc/testsuite/g++.dg/conversion/packed2.C b/gcc/testsuite/g++.dg/conversion/packed2.C new file mode 100644 index 0000000..7df74dc --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/packed2.C @@ -0,0 +1,15 @@ +// PR c++/91925 +// { dg-do compile { target c++11 } } +// { dg-options "-fpack-struct" } + +struct A {}; +int foo (A); +struct B { + A a; + decltype (foo (a)) p; +}; +template T bar (T); +class C { + A a; + decltype (bar (a)) p; +}; -- cgit v1.1 From 0b92cf305dcf34387a8e2564e55ca8948df3b47a Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 1 Oct 2019 18:58:35 +0200 Subject: invoke.texi (early-inlining-insns-O2): Document. * doc/invoke.texi (early-inlining-insns-O2): Document. (early-inlining-insns): Update. * params.def (early-inlining-insns-O2): New bound. (early-inlining-insns): Update docs. * ipa-inline.c (want_early_inline_function_p): Use new bound. * g++.dg/tree-ssa/pr61034.C: Set early-inlining-insns-O2=14. * g++.dg/tree-ssa/pr8781.C: Likewise. * g++.dg/warn/Wstringop-truncation-1.C: Likewise. * gcc.dg/ipa/pr63416.c: likewise. * gcc.dg/vect/pr66142.c: Likewise. * gcc.dg/tree-ssa/ssa-thread-12.c: Mark compure_idf inline. From-SVN: r276416 --- gcc/ChangeLog | 8 ++++++++ gcc/doc/invoke.texi | 8 ++++++++ gcc/ipa-inline.c | 22 ++++++++++++++-------- gcc/params.def | 6 +++++- gcc/testsuite/ChangeLog | 9 +++++++++ gcc/testsuite/g++.dg/tree-ssa/pr61034.C | 2 +- gcc/testsuite/g++.dg/tree-ssa/pr8781.C | 2 +- gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C | 2 +- gcc/testsuite/gcc.dg/ipa/pr63416.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c | 2 +- gcc/testsuite/gcc.dg/vect/pr66142.c | 2 +- 11 files changed, 50 insertions(+), 15 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bb4de20..b4c4292 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-10-01 Jan Hubicka + + * doc/invoke.texi (early-inlining-insns-O2): Document. + (early-inlining-insns): Update. + * params.def (early-inlining-insns-O2): New bound. + (early-inlining-insns): Update docs. + * ipa-inline.c (want_early_inline_function_p): Use new bound. + 2019-10-01 Oleg Endo PR target/88562 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 83016a5..4281ee7 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -11291,9 +11291,17 @@ recursion depth can be guessed from the probability that function recurses via a given call expression. This parameter limits inlining only to call expressions whose probability exceeds the given threshold (in percents). +@item early-inlining-insns-O2 +Specify growth that the early inliner can make. In effect it increases +the amount of inlining for code having a large abstraction penalty. +This is applied to functions compiled with @option{-O1} or @option{-O2} +optimization levels. + @item early-inlining-insns Specify growth that the early inliner can make. In effect it increases the amount of inlining for code having a large abstraction penalty. +This is applied to functions compiled with @option{-O3} or @option{-Ofast} +optimization levels. @item max-early-inliner-iterations Limit of iterations of the early inliner. This basically bounds diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index b62d280..c8689c7 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -641,6 +641,10 @@ want_early_inline_function_p (struct cgraph_edge *e) { int growth = estimate_edge_growth (e); int n; + int early_inlining_insns = opt_for_fn (e->caller->decl, optimize) >= 3 + ? PARAM_VALUE (PARAM_EARLY_INLINING_INSNS) + : PARAM_VALUE (PARAM_EARLY_INLINING_INSNS_O2); + if (growth <= PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SIZE)) ; @@ -654,26 +658,28 @@ want_early_inline_function_p (struct cgraph_edge *e) growth); want_inline = false; } - else if (growth > PARAM_VALUE (PARAM_EARLY_INLINING_INSNS)) + else if (growth > early_inlining_insns) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, e->call_stmt, " will not early inline: %C->%C, " - "growth %i exceeds --param early-inlining-insns\n", - e->caller, callee, - growth); + "growth %i exceeds --param early-inlining-insns%s\n", + e->caller, callee, growth, + opt_for_fn (e->caller->decl, optimize) >= 3 + ? "" : "-O2"); want_inline = false; } else if ((n = num_calls (callee)) != 0 - && growth * (n + 1) > PARAM_VALUE (PARAM_EARLY_INLINING_INSNS)) + && growth * (n + 1) > early_inlining_insns) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, e->call_stmt, " will not early inline: %C->%C, " - "growth %i exceeds --param early-inlining-insns " + "growth %i exceeds --param early-inlining-insns%s " "divided by number of calls\n", - e->caller, callee, - growth); + e->caller, callee, growth, + opt_for_fn (e->caller->decl, optimize) >= 3 + ? "" : "-O2"); want_inline = false; } } diff --git a/gcc/params.def b/gcc/params.def index d2d957f..0acf29b 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -233,8 +233,12 @@ DEFPARAM(PARAM_IPCP_UNIT_GROWTH, 10, 0, 0) DEFPARAM(PARAM_EARLY_INLINING_INSNS, "early-inlining-insns", - "Maximal estimated growth of function body caused by early inlining of single call.", + "Maximal estimated growth of function body caused by early inlining of single call with -O3 and -Ofast.", 14, 0, 0) +DEFPARAM(PARAM_EARLY_INLINING_INSNS_O2, + "early-inlining-insns-O2", + "Maximal estimated growth of function body caused by early inlining of single call with -O1 and -O2.", + 6, 0, 0) DEFPARAM(PARAM_LARGE_STACK_FRAME, "large-stack-frame", "The size of stack frame to be considered large.", diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index df6105f..0dcaf4b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-10-01 Jan Hubicka + + * g++.dg/tree-ssa/pr61034.C: Set early-inlining-insns-O2=14. + * g++.dg/tree-ssa/pr8781.C: Likewise. + * g++.dg/warn/Wstringop-truncation-1.C: Likewise. + * gcc.dg/ipa/pr63416.c: likewise. + * gcc.dg/vect/pr66142.c: Likewise. + * gcc.dg/tree-ssa/ssa-thread-12.c: Mark compure_idf inline. + 2019-10-01 Jakub Jelinek PR c++/91925 diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr61034.C b/gcc/testsuite/g++.dg/tree-ssa/pr61034.C index 870b237..2e3dfec 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr61034.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr61034.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-options "-O2 -fdump-tree-fre3 -fdump-tree-optimized -fdelete-null-pointer-checks" } +// { dg-options "-O2 -fdump-tree-fre3 -fdump-tree-optimized -fdelete-null-pointer-checks --param early-inlining-insns-O2=14" } #define assume(x) if(!(x))__builtin_unreachable() diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C index 1f115b2..5bc1ef0 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */ +/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1 --param early-inlining-insns-O2=14" } */ int f(); diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C index 8306601..49dde0a 100644 --- a/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C +++ b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C @@ -1,7 +1,7 @@ /* PR/tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with an inlined string literal { dg-do compile } - { dg-options "-O2 -Wstringop-truncation" } */ + { dg-options "-O2 -Wstringop-truncation --param early-inlining-insns-O2=14" } */ #include diff --git a/gcc/testsuite/gcc.dg/ipa/pr63416.c b/gcc/testsuite/gcc.dg/ipa/pr63416.c index b5374c5..5873954 100644 --- a/gcc/testsuite/gcc.dg/ipa/pr63416.c +++ b/gcc/testsuite/gcc.dg/ipa/pr63416.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-options "-O2 -fdump-tree-optimized --param early-inlining-insns-O2=14" } */ #define _UNUSED_ __attribute__((__unused__)) typedef int TEST_F30 (int *v); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c index 6752676..216de23 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c @@ -56,7 +56,7 @@ bmp_iter_and_compl (bitmap_iterator * bi, unsigned *bit_no) } extern int VEC_int_base_length (VEC_int_base *); -bitmap +inline bitmap compute_idf (bitmap def_blocks, bitmap_head * dfs) { bitmap_iterator bi; diff --git a/gcc/testsuite/gcc.dg/vect/pr66142.c b/gcc/testsuite/gcc.dg/vect/pr66142.c index 8c79f29..a0316f1 100644 --- a/gcc/testsuite/gcc.dg/vect/pr66142.c +++ b/gcc/testsuite/gcc.dg/vect/pr66142.c @@ -1,6 +1,6 @@ /* PR middle-end/66142 */ /* { dg-do compile } */ -/* { dg-additional-options "-ffast-math -fopenmp-simd" } */ +/* { dg-additional-options "-ffast-math -fopenmp-simd --param early-inlining-insns-O2=14" } */ /* { dg-additional-options "-mavx" { target avx_runtime } } */ struct A { float x, y; }; -- cgit v1.1 From f30b3d2891cef9803badb3f85d739c0fcfafd585 Mon Sep 17 00:00:00 2001 From: Prathamesh Kulkarni Date: Tue, 1 Oct 2019 17:10:01 +0000 Subject: tree-if-conv.c (tree_if_conversion): Move call to ifcvt_local_dce after local CSE. 2019-10-01 Prathamesh Kulkarni * tree-if-conv.c (tree_if_conversion): Move call to ifcvt_local_dce after local CSE. From-SVN: r276417 --- gcc/ChangeLog | 5 +++++ gcc/tree-if-conv.c | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b4c4292..08951d9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Prathamesh Kulkarni + + * tree-if-conv.c (tree_if_conversion): Move call to ifcvt_local_dce + after local CSE. + 2019-10-01 Jan Hubicka * doc/invoke.texi (early-inlining-insns-O2): Document. diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 40ad4c5..822aae5 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -3060,9 +3060,6 @@ tree_if_conversion (class loop *loop, vec *preds) on-the-fly. */ combine_blocks (loop); - /* Delete dead predicate computations. */ - ifcvt_local_dce (loop->header); - /* Perform local CSE, this esp. helps the vectorizer analysis if loads and stores are involved. CSE only the loop body, not the entry PHIs, those are to be kept in sync with the non-if-converted copy. @@ -3071,6 +3068,9 @@ tree_if_conversion (class loop *loop, vec *preds) bitmap_set_bit (exit_bbs, single_exit (loop)->dest->index); bitmap_set_bit (exit_bbs, loop->latch->index); todo |= do_rpo_vn (cfun, loop_preheader_edge (loop), exit_bbs); + + /* Delete dead predicate computations. */ + ifcvt_local_dce (loop->header); BITMAP_FREE (exit_bbs); todo |= TODO_cleanup_cfg; -- cgit v1.1 From a9346b558b58edbc9ffceacbb23a26c61eac4bf9 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 1 Oct 2019 20:03:13 +0200 Subject: ssa-thread-12.c: Fix warning introduced by my previous change. * gcc.dg/tree-ssa/ssa-thread-12.c: Fix warning introduced by my previous change. From-SVN: r276418 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0dcaf4b..797c50f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-10-01 Jan Hubicka + * gcc.dg/tree-ssa/ssa-thread-12.c: Fix warning introduced by my + previous change. + +2019-10-01 Jan Hubicka + * g++.dg/tree-ssa/pr61034.C: Set early-inlining-insns-O2=14. * g++.dg/tree-ssa/pr8781.C: Likewise. * g++.dg/warn/Wstringop-truncation-1.C: Likewise. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c index 216de23..1bf79fc 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c @@ -56,7 +56,7 @@ bmp_iter_and_compl (bitmap_iterator * bi, unsigned *bit_no) } extern int VEC_int_base_length (VEC_int_base *); -inline bitmap +static __inline__ bitmap compute_idf (bitmap def_blocks, bitmap_head * dfs) { bitmap_iterator bi; -- cgit v1.1 From 56f1a16caeb447934c4c5209664984560b17e63a Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 1 Oct 2019 20:21:31 +0200 Subject: re PR c++/91222 (507.cactuBSSN_r build fails in warn_types_mismatch at ipa-devirt.c:1006 since r273571) PR lto/91222 * ipa-devirt.c (warn_types_mismatch): Do not ICE when anonymous type is matched with non-C++ type * g++.dg/lto/odr-6_0.C: New testcase. * g++.dg/lto/odr-6_1.c: New testcase. From-SVN: r276420 --- gcc/ChangeLog | 6 ++++++ gcc/ipa-devirt.c | 10 +++++----- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/lto/odr-6_0.C | 8 ++++++++ gcc/testsuite/g++.dg/lto/odr-6_1.c | 4 ++++ 5 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lto/odr-6_0.C create mode 100644 gcc/testsuite/g++.dg/lto/odr-6_1.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 08951d9..be78525 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Jan Hubicka + + PR lto/91222 + * ipa-devirt.c (warn_types_mismatch): Do not ICE when anonymous type + is matched with non-C++ type + 2019-10-01 Prathamesh Kulkarni * tree-if-conv.c (tree_if_conversion): Move call to ifcvt_local_dce diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index e5028bc..3423c40 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -992,14 +992,14 @@ warn_types_mismatch (tree t1, tree t2, location_t loc1, location_t loc2) std::swap (t1, t2); std::swap (loc_t1, loc_t2); } - gcc_assert (TYPE_NAME (t1) && TYPE_NAME (t2) - && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL - && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL); + gcc_assert (TYPE_NAME (t1) + && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL); tree n1 = TYPE_NAME (t1); - tree n2 = TYPE_NAME (t2); + tree n2 = TYPE_NAME (t2) ? TYPE_NAME (t2) : NULL; + if (TREE_CODE (n1) == TYPE_DECL) n1 = DECL_NAME (n1); - if (TREE_CODE (n2) == TYPE_DECL) + if (n2 && TREE_CODE (n2) == TYPE_DECL) n2 = DECL_NAME (n2); /* Most of the time, the type names will match, do not be unnecesarily verbose. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 797c50f..ac73d3e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-10-01 Jan Hubicka + * g++.dg/lto/odr-6_0.C: New testcase. + * g++.dg/lto/odr-6_1.c: New testcase. + +2019-10-01 Jan Hubicka + * gcc.dg/tree-ssa/ssa-thread-12.c: Fix warning introduced by my previous change. diff --git a/gcc/testsuite/g++.dg/lto/odr-6_0.C b/gcc/testsuite/g++.dg/lto/odr-6_0.C new file mode 100644 index 0000000..a03483f --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/odr-6_0.C @@ -0,0 +1,8 @@ +// { dg-lto-do link } +extern "C" { +struct { // { dg-lto-message "" 2 } +} admbaserest_; +} +int main() +{ +} diff --git a/gcc/testsuite/g++.dg/lto/odr-6_1.c b/gcc/testsuite/g++.dg/lto/odr-6_1.c new file mode 100644 index 0000000..ee4bff4 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/odr-6_1.c @@ -0,0 +1,4 @@ +struct {} admbaserest_; // { dg-lto-message "type of " 2 } + + + -- cgit v1.1 From 8951374df1e7139b163129c9e18161c5253d0fe2 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 1 Oct 2019 18:38:58 +0000 Subject: libada: Remove racy duplicate gnatlib installation For some reason, presumably historical, the `install-gnatlib' target for the default multilib is invoked twice, once via the `ada.install-common' target in `gcc/ada/gcc-interface/Make-lang.in' invoked from gcc/ and again via the `install-libada' target in libada/. Apart from doing the same twice this is actually harmful in sufficiently parallelized `make' invocation, as the removal of old files performed within the `install-gnatlib' recipe in the former case actually races with the installation of new files done in the latter case, causing the recipe to fail and abort, however non-fatally, having not completed the installation of all the built files needed for the newly-built compiler to work correctly. This can be observed with a native `x86_64-linux-gnu' bootstrap: make[4]: Entering directory '.../gcc/ada' rm -rf .../lib/gcc/x86_64-linux-gnu/10.0.0/adalib rm: cannot remove '.../lib/gcc/x86_64-linux-gnu/10.0.0/adalib': Directory not empty make[4]: *** [gcc-interface/Makefile:512: install-gnatlib] Error 1 make[4]: Leaving directory '.../gcc/ada' make[3]: *** [.../gcc/ada/gcc-interface/Make-lang.in:853: install-gnatlib] Error 2 make[2]: [.../gcc/ada/gcc-interface/Make-lang.in:829: ada.install-common] Error 2 (ignored) which then causes missing files to be reported when an attempt is made to use the newly-installed non-functional compiler to build a `riscv-linux-gnu' cross-compiler: (cd ada/bldtools/sinfo; gnatmake -q xsinfo ; ./xsinfo sinfo.h ) error: "ada.ali" not found, "ada.ads" must be compiled error: "s-memory.ali" not found, "s-memory.adb" must be compiled gnatmake: *** bind failed. /bin/sh: ./xsinfo: No such file or directory make[2]: *** [.../gcc/ada/Make-generated.in:45: ada/sinfo.h] Error 127 make[2]: Leaving directory '.../gcc' make[1]: *** [Makefile:4369: all-gcc] Error 2 make[1]: Leaving directory '...' make: *** [Makefile:965: all] Error 2 Depending on timing `.../lib/gcc/x86_64-linux-gnu/10.0.0/adainclude' may cause an installation failure instead and the resulting compiler may be non-functional in a different way. Only invoke `install-gnatlib' from within gcc/ then if a legacy build process is being used with libada disabled and gnatlib built manually with `make -C gcc gnatlib'. gcc/ * Makefile.in (gnat_install_lib): New variable. * configure.ac: Substitute it. * configure: Regenerate. gcc/ada/ * gcc-interface/Make-lang.in (ada.install-common): Split into... (gnat-install-tools, gnat-install-lib): ... these. From-SVN: r276422 --- gcc/ChangeLog | 6 ++++++ gcc/Makefile.in | 4 ++++ gcc/ada/ChangeLog | 5 +++++ gcc/ada/gcc-interface/Make-lang.in | 5 ++++- gcc/configure | 15 +++++++++++++-- gcc/configure.ac | 10 ++++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index be78525..0f96dde 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Maciej W. Rozycki + + * Makefile.in (gnat_install_lib): New variable. + * configure.ac: Substitute it. + * configure: Regenerate. + 2019-10-01 Jan Hubicka PR lto/91222 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index d796c14..ca03cfd 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1706,6 +1706,10 @@ $(FULL_DRIVER_NAME): ./xgcc # language hooks, generated by configure @language_hooks@ +# Wire in install-gnatlib invocation with `make install' for a configuration +# with top-level libada disabled. +gnat_install_lib = @gnat_install_lib@ + # per-language makefile fragments ifneq ($(LANG_MAKEFRAGS),) include $(LANG_MAKEFRAGS) diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 8e5a19b..ecc2e25 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Maciej W. Rozycki + + * gcc-interface/Make-lang.in (ada.install-common): Split into... + (gnat-install-tools, gnat-install-lib): ... these. + 2019-09-26 Alexandre Oliva * gcc-interface/decl.c (components_to_record): Set diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 276c41c..acbe2b87 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -822,7 +822,9 @@ doc/gnat-style.pdf: ada/gnat-style.texi $(gcc_docdir)/include/fdl.texi # gnatlink, gnatls, gnatmake, gnatname, gnatprep, gnatxref, gnatfind, # gnatclean). # gnatdll is only used on Windows. -ada.install-common: +ada.install-common: $(gnat_install_lib) gnat-install-tools + +gnat-install-tools: $(MKDIR) $(DESTDIR)$(bindir) -if [ -f gnat1$(exeext) ] ; \ then \ @@ -843,6 +845,7 @@ ada.install-common: # # Finally, install the library # +gnat-install-lib: | gnat-install-tools -if [ -f gnat1$(exeext) ] ; \ then \ $(MAKE) $(COMMON_FLAGS_TO_PASS) $(ADA_FLAGS_TO_PASS) install-gnatlib; \ diff --git a/gcc/configure b/gcc/configure index f90472d..893a9e6 100755 --- a/gcc/configure +++ b/gcc/configure @@ -814,6 +814,7 @@ SET_MAKE accel_dir_suffix real_target_noncanonical enable_as_accelerator +gnat_install_lib REPORT_BUGS_TEXI REPORT_BUGS_TO PKGVERSION @@ -7826,6 +7827,16 @@ else fi +# If top-level libada has been disabled, then wire in install-gnatlib +# invocation with `make install', so that one can build and install +# the library manually with `make -C gcc all gnatlib gnattools install'. +if test x"$enable_libada" = xno; then + gnat_install_lib=gnat-install-lib +else + gnat_install_lib= +fi + + if test x"$enable_as_accelerator_for" != x; then $as_echo "#define ACCEL_COMPILER 1" >>confdefs.h @@ -18819,7 +18830,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18822 "configure" +#line 18833 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18925,7 +18936,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18928 "configure" +#line 18939 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/gcc/configure.ac b/gcc/configure.ac index 5c60d0f..eff849f 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -982,6 +982,16 @@ AC_ARG_ENABLE(languages, esac], [enable_languages=c]) +# If top-level libada has been disabled, then wire in install-gnatlib +# invocation with `make install', so that one can build and install +# the library manually with `make -C gcc all gnatlib gnattools install'. +if test x"$enable_libada" = xno; then + gnat_install_lib=gnat-install-lib +else + gnat_install_lib= +fi +AC_SUBST(gnat_install_lib) + if test x"$enable_as_accelerator_for" != x; then AC_DEFINE(ACCEL_COMPILER, 1, [Define if this compiler should be built as the offload target compiler.]) -- cgit v1.1 From 13681906ff1d22ee9dd6f6c58dff6539c2cc89c7 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 1 Oct 2019 19:14:11 +0000 Subject: libada: Respect `--enable-version-specific-runtime-libs' Respect the `--enable-version-specific-runtime-libs' configuration option in libada/, so that shared gnatlib libraries will be installed in non-version-specific $(toolexeclibdir) if requested. In a cross-compilation environment this helps setting up a consistent sysroot, which can then be shared between the host and the target system. This lets one have `libgnarl-10.so' and `libgnat-10.so' installed in say /usr/lib and /usr/$(target_alias)/lib for a native and a cross-build respectively, rather than in /usr/lib/gcc/$(target_alias)/10.0.0/adalib. Update the settings of $(toolexecdir) and $(toolexeclibdir), unused till now, to keep the current arrangement in the version-specific case and make the new option to be enabled by default, unlike with the other target libraries, so as to keep existing people's build infrastructure unaffected. Of course if someone does use `--disable-version-specific-runtime-libs' already, then the installation location of shared gnatlib libraries will change, but presumably this is what they do want anyway as the current situation where the option is ignored in libada/ only is an anomaly really rather than one that is expected or desired. gcc/ada/ * gcc-interface/Makefile.in (ADA_RTL_DSO_DIR): New variable. (install-gnatlib): Use it in place of ADA_RTL_OBJ_DIR for shared library installation. libada/ * Makefile.in (toolexecdir, toolexeclibdir): New variables. (LIBADA_FLAGS_TO_PASS): Add `toolexeclibdir'. * configure.ac: Add `--enable-version-specific-runtime-libs'. Update version-specific `toolexecdir' and `toolexeclibdir' from ADA_RTL_OBJ_DIR from gcc/ada/gcc-interface/Makefile.in. * configure: Regenerate. From-SVN: r276424 --- gcc/ada/ChangeLog | 6 ++++++ gcc/ada/gcc-interface/Makefile.in | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index ecc2e25..6a84b7b 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,5 +1,11 @@ 2019-10-01 Maciej W. Rozycki + * gcc-interface/Makefile.in (ADA_RTL_DSO_DIR): New variable. + (install-gnatlib): Use it in place of ADA_RTL_OBJ_DIR for shared + library installation. + +2019-10-01 Maciej W. Rozycki + * gcc-interface/Make-lang.in (ada.install-common): Split into... (gnat-install-tools, gnat-install-lib): ... these. diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in index d4c9d15..8deffb6 100644 --- a/gcc/ada/gcc-interface/Makefile.in +++ b/gcc/ada/gcc-interface/Makefile.in @@ -534,15 +534,15 @@ install-gnatlib: ../stamp-gnatlib-$(RTSDIR) install-gcc-specs for file in gnat gnarl; do \ if [ -f $(RTSDIR)/lib$${file}$(hyphen)$(LIBRARY_VERSION)$(soext) ]; then \ $(INSTALL) $(RTSDIR)/lib$${file}$(hyphen)$(LIBRARY_VERSION)$(soext) \ - $(DESTDIR)$(ADA_RTL_OBJ_DIR); \ + $(DESTDIR)$(ADA_RTL_DSO_DIR); \ fi; \ if [ -f $(RTSDIR)/lib$${file}$(soext) ]; then \ $(LN_S) lib$${file}$(hyphen)$(LIBRARY_VERSION)$(soext) \ - $(DESTDIR)$(ADA_RTL_OBJ_DIR)/lib$${file}$(soext); \ + $(DESTDIR)$(ADA_RTL_DSO_DIR)/lib$${file}$(soext); \ fi; \ if [ -d $(RTSDIR)/lib$${file}$(hyphen)$(LIBRARY_VERSION)$(soext).dSYM ]; then \ $(CP) -r $(RTSDIR)/lib$${file}$(hyphen)$(LIBRARY_VERSION)$(soext).dSYM \ - $(DESTDIR)$(ADA_RTL_OBJ_DIR); \ + $(DESTDIR)$(ADA_RTL_DSO_DIR); \ fi; \ done # This copy must be done preserving the date on the original file. @@ -882,6 +882,7 @@ b_gnatm.o : b_gnatm.adb ADA_INCLUDE_DIR = $(libsubdir)/adainclude ADA_RTL_OBJ_DIR = $(libsubdir)/adalib +ADA_RTL_DSO_DIR = $(toolexeclibdir) # Special flags -- cgit v1.1 From 11f2ce1f49f480c7ef0951bdee5c35bd7449f2bd Mon Sep 17 00:00:00 2001 From: Maya Rashish Date: Tue, 1 Oct 2019 19:25:31 +0000 Subject: re PR target/85401 (segfault building code for VAX) PR target/85401 * ira-color.c (allocno_copy_cost_saving): Call ira_init_register_move_cost_if_necessary. From-SVN: r276426 --- gcc/ChangeLog | 6 ++++++ gcc/ira-color.c | 1 + 2 files changed, 7 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0f96dde..4ca92c2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Maya Rashish + + PR target/85401 + * ira-color.c (allocno_copy_cost_saving): Call + ira_init_register_move_cost_if_necessary. + 2019-10-01 Maciej W. Rozycki * Makefile.in (gnat_install_lib): New variable. diff --git a/gcc/ira-color.c b/gcc/ira-color.c index 42309b9..ce5141b 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -2817,6 +2817,7 @@ allocno_copy_cost_saving (ira_allocno_t allocno, int hard_regno) } else gcc_unreachable (); + ira_init_register_move_cost_if_necessary (allocno_mode); cost += cp->freq * ira_register_move_cost[allocno_mode][rclass][rclass]; } return cost; -- cgit v1.1 From ede31f6ffe73357705e95016046e77c7e3d6ad13 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 1 Oct 2019 21:46:09 +0200 Subject: tree-ssa-alias.c (nonoverlapping_component_refs_since_match_p): Rename to ... * tree-ssa-alias.c (nonoverlapping_component_refs_since_match_p): Rename to ... (nonoverlapping_refs_since_match_p): ... this; handle also ARRAY_REFs. (alias_stats): Update stats. (dump_alias_stats): Likewise. (cheap_array_ref_low_bound): New function. (aliasing_matching_component_refs_p): Add partial_overlap argument; pass it to nonoverlapping_refs_since_match_p. (aliasing_component_refs_walk): Update call of aliasing_matching_component_refs_p (nonoverlapping_array_refs_p): New function. (decl_refs_may_alias_p, indirect_ref_may_alias_decl_p, indirect_refs_may_alias_p): Update calls of nonoverlapping_refs_since_match_p. * gcc.dg/tree-ssa/alias-access-path-10.c: New testcase. * gcc.dg/tree-ssa/alias-access-path-11.c: New testcase. From-SVN: r276427 --- gcc/ChangeLog | 19 ++ gcc/testsuite/ChangeLog | 5 + .../gcc.dg/tree-ssa/alias-access-path-10.c | 12 + .../gcc.dg/tree-ssa/alias-access-path-11.c | 15 ++ gcc/tree-ssa-alias.c | 291 ++++++++++++++++----- 5 files changed, 279 insertions(+), 63 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-10.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-11.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4ca92c2..b7feecc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2019-10-01 Jan Hubicka + + * tree-ssa-alias.c (nonoverlapping_component_refs_since_match_p): + Rename to ... + (nonoverlapping_refs_since_match_p): ... this; handle also + ARRAY_REFs. + (alias_stats): Update stats. + (dump_alias_stats): Likewise. + (cheap_array_ref_low_bound): New function. + (aliasing_matching_component_refs_p): Add partial_overlap + argument; + pass it to nonoverlapping_refs_since_match_p. + (aliasing_component_refs_walk): Update call of + aliasing_matching_component_refs_p + (nonoverlapping_array_refs_p): New function. + (decl_refs_may_alias_p, indirect_ref_may_alias_decl_p, + indirect_refs_may_alias_p): Update calls of + nonoverlapping_refs_since_match_p. + 2019-10-01 Maya Rashish PR target/85401 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ac73d3e..f7256b5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-10-01 Jan Hubicka + * gcc.dg/tree-ssa/alias-access-path-10.c: New testcase. + * gcc.dg/tree-ssa/alias-access-path-11.c: New testcase. + +2019-10-01 Jan Hubicka + * g++.dg/lto/odr-6_0.C: New testcase. * g++.dg/lto/odr-6_1.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-10.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-10.c new file mode 100644 index 0000000..c42a6ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-10.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-fre1" } */ + +struct a {int array[3];} a[10]; +int +test(int i,int j) +{ + a[i].array[1]=123; + a[j].array[2]=2; + return a[i].array[1]; +} +/* { dg-final { scan-tree-dump-times "return 123" 1 "fre1"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-11.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-11.c new file mode 100644 index 0000000..1f83714 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-11.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-strict-aliasing -fdump-tree-fre3" } */ +typedef int outerarray[10][10][10]; +typedef int innerarray[10][10]; +outerarray *barptr; + +int +test(int i,int j) +{ + innerarray *innerptr = (innerarray *)barptr; + (*barptr)[i][2][j]=10;; + (*innerptr)[3][j]=11; + return (*barptr)[i][2][j]; +} +/* { dg-final { scan-tree-dump-times "return 10" 1 "fre3"} } */ diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 52cda38..d6c4438 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -87,7 +87,7 @@ along with GCC; see the file COPYING3. If not see this file. Low-level disambiguators dealing with points-to information are in tree-ssa-structalias.c. */ -static int nonoverlapping_component_refs_since_match_p (tree, tree, tree, tree); +static int nonoverlapping_refs_since_match_p (tree, tree, tree, tree, bool); static bool nonoverlapping_component_refs_p (const_tree, const_tree); /* Query statistics for the different low-level disambiguators. @@ -104,9 +104,9 @@ static struct { unsigned HOST_WIDE_INT aliasing_component_refs_p_no_alias; unsigned HOST_WIDE_INT nonoverlapping_component_refs_p_may_alias; unsigned HOST_WIDE_INT nonoverlapping_component_refs_p_no_alias; - unsigned HOST_WIDE_INT nonoverlapping_component_refs_since_match_p_may_alias; - unsigned HOST_WIDE_INT nonoverlapping_component_refs_since_match_p_must_overlap; - unsigned HOST_WIDE_INT nonoverlapping_component_refs_since_match_p_no_alias; + unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_may_alias; + unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_must_overlap; + unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_no_alias; } alias_stats; void @@ -137,15 +137,15 @@ dump_alias_stats (FILE *s) alias_stats.nonoverlapping_component_refs_p_no_alias, alias_stats.nonoverlapping_component_refs_p_no_alias + alias_stats.nonoverlapping_component_refs_p_may_alias); - fprintf (s, " nonoverlapping_component_refs_since_match_p: " + fprintf (s, " nonoverlapping_refs_since_match_p: " HOST_WIDE_INT_PRINT_DEC" disambiguations, " HOST_WIDE_INT_PRINT_DEC" must overlaps, " HOST_WIDE_INT_PRINT_DEC" queries\n", - alias_stats.nonoverlapping_component_refs_since_match_p_no_alias, - alias_stats.nonoverlapping_component_refs_since_match_p_must_overlap, - alias_stats.nonoverlapping_component_refs_since_match_p_no_alias - + alias_stats.nonoverlapping_component_refs_since_match_p_may_alias - + alias_stats.nonoverlapping_component_refs_since_match_p_must_overlap); + alias_stats.nonoverlapping_refs_since_match_p_no_alias, + alias_stats.nonoverlapping_refs_since_match_p_must_overlap, + alias_stats.nonoverlapping_refs_since_match_p_no_alias + + alias_stats.nonoverlapping_refs_since_match_p_may_alias + + alias_stats.nonoverlapping_refs_since_match_p_must_overlap); fprintf (s, " aliasing_component_refs_p: " HOST_WIDE_INT_PRINT_DEC" disambiguations, " HOST_WIDE_INT_PRINT_DEC" queries\n", @@ -856,7 +856,8 @@ type_has_components_p (tree type) /* MATCH1 and MATCH2 which are part of access path of REF1 and REF2 respectively are either pointing to same address or are completely - disjoint. + disjoint. If PARITAL_OVERLAP is true, assume that outermost arrays may + just partly overlap. Try to disambiguate using the access path starting from the match and return false if there is no conflict. @@ -867,24 +868,27 @@ static bool aliasing_matching_component_refs_p (tree match1, tree ref1, poly_int64 offset1, poly_int64 max_size1, tree match2, tree ref2, - poly_int64 offset2, poly_int64 max_size2) + poly_int64 offset2, poly_int64 max_size2, + bool partial_overlap) { poly_int64 offadj, sztmp, msztmp; bool reverse; - - get_ref_base_and_extent (match2, &offadj, &sztmp, &msztmp, &reverse); - offset2 -= offadj; - get_ref_base_and_extent (match1, &offadj, &sztmp, &msztmp, &reverse); - offset1 -= offadj; - if (!ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2)) + if (!partial_overlap) { - ++alias_stats.aliasing_component_refs_p_no_alias; - return false; + get_ref_base_and_extent (match2, &offadj, &sztmp, &msztmp, &reverse); + offset2 -= offadj; + get_ref_base_and_extent (match1, &offadj, &sztmp, &msztmp, &reverse); + offset1 -= offadj; + if (!ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2)) + { + ++alias_stats.aliasing_component_refs_p_no_alias; + return false; + } } - int cmp = nonoverlapping_component_refs_since_match_p (match1, ref1, - match2, ref2); + int cmp = nonoverlapping_refs_since_match_p (match1, ref1, match2, ref2, + partial_overlap); if (cmp == 1 || (cmp == -1 && nonoverlapping_component_refs_p (ref1, ref2))) { @@ -964,6 +968,8 @@ aliasing_component_refs_walk (tree ref1, tree type1, tree base1, } if (same_p == 1) { + bool partial_overlap = false; + /* We assume that arrays can overlap by multiple of their elements size as tested in gcc.dg/torture/alias-2.c. This partial overlap happen only when both arrays are bases of @@ -973,15 +979,18 @@ aliasing_component_refs_walk (tree ref1, tree type1, tree base1, && (!TYPE_SIZE (TREE_TYPE (base1)) || TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) != INTEGER_CST || ref == base2)) - /* Setting maybe_match to true triggers - nonoverlapping_component_refs_p test later that still may do - useful disambiguation. */ - *maybe_match = true; - else - return aliasing_matching_component_refs_p (base1, ref1, - offset1, max_size1, - ref, ref2, - offset2, max_size2); + { + /* Setting maybe_match to true triggers + nonoverlapping_component_refs_p test later that still may do + useful disambiguation. */ + *maybe_match = true; + partial_overlap = true; + } + return aliasing_matching_component_refs_p (base1, ref1, + offset1, max_size1, + ref, ref2, + offset2, max_size2, + partial_overlap); } return -1; } @@ -1225,10 +1234,98 @@ nonoverlapping_component_refs_p_1 (const_tree field1, const_tree field2) return -1; } +/* Return low bound of array. Do not produce new trees + and thus do not care about particular type of integer constant + and placeholder exprs. */ + +static tree +cheap_array_ref_low_bound (tree ref) +{ + tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0))); + + /* Avoid expensive array_ref_low_bound. + low bound is either stored in operand2, or it is TYPE_MIN_VALUE of domain + type or it is zero. */ + if (TREE_OPERAND (ref, 2)) + return TREE_OPERAND (ref, 2); + else if (domain_type && TYPE_MIN_VALUE (domain_type)) + return TYPE_MIN_VALUE (domain_type); + else + return integer_zero_node; +} + +/* REF1 and REF2 are ARRAY_REFs with either same base address or which are + completely disjoint. + + Return 1 if the refs are non-overlapping. + Return 0 if they are possibly overlapping but if so the overlap again + starts on the same address. + Return -1 otherwise. */ + +int +nonoverlapping_array_refs_p (tree ref1, tree ref2) +{ + tree index1 = TREE_OPERAND (ref1, 1); + tree index2 = TREE_OPERAND (ref2, 1); + tree low_bound1 = cheap_array_ref_low_bound(ref1); + tree low_bound2 = cheap_array_ref_low_bound(ref2); + + /* Handle zero offsets first: we do not need to match type size in this + case. */ + if (operand_equal_p (index1, low_bound1, 0) + && operand_equal_p (index2, low_bound2, 0)) + return 0; + + /* If type sizes are different, give up. + + Avoid expensive array_ref_element_size. + If operand 3 is present it denotes size in the alignmnet units. + Otherwise size is TYPE_SIZE of the element type. + Handle only common cases where types are of the same "kind". */ + if ((TREE_OPERAND (ref1, 3) == NULL) != (TREE_OPERAND (ref2, 3) == NULL)) + return -1; + + tree elmt_type1 = TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref1, 0))); + tree elmt_type2 = TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref2, 0))); + + if (TREE_OPERAND (ref1, 3)) + { + if (TYPE_ALIGN (elmt_type1) != TYPE_ALIGN (elmt_type2) + || !operand_equal_p (TREE_OPERAND (ref1, 3), + TREE_OPERAND (ref2, 3), 0)) + return -1; + } + else + { + if (!operand_equal_p (TYPE_SIZE_UNIT (elmt_type1), + TYPE_SIZE_UNIT (elmt_type2), 0)) + return -1; + } + + /* Since we know that type sizes are the same, there is no need to return + -1 after this point. Partial overlap can not be introduced. */ + + /* We may need to fold trees in this case. + TODO: Handle integer constant case at least. */ + if (!operand_equal_p (low_bound1, low_bound2, 0)) + return 0; + + if (TREE_CODE (index1) == INTEGER_CST && TREE_CODE (index2) == INTEGER_CST) + { + if (tree_int_cst_equal (index1, index2)) + return 0; + return 1; + } + /* TODO: We can use VRP to further disambiguate here. */ + return 0; +} + /* Try to disambiguate REF1 and REF2 under the assumption that MATCH1 and MATCH2 either point to the same address or are disjoint. MATCH1 and MATCH2 are assumed to be ref in the access path of REF1 and REF2 respectively or NULL in the case we established equivalence of bases. + If PARTIAL_OVERLAP is true assume that the toplevel arrays may actually + overlap by exact multiply of their element size. This test works by matching the initial segment of the access path and does not rely on TBAA thus is safe for !flag_strict_aliasing if @@ -1247,8 +1344,9 @@ nonoverlapping_component_refs_p_1 (const_tree field1, const_tree field2) oracles. */ static int -nonoverlapping_component_refs_since_match_p (tree match1, tree ref1, - tree match2, tree ref2) +nonoverlapping_refs_since_match_p (tree match1, tree ref1, + tree match2, tree ref2, + bool partial_overlap) { /* Early return if there are no references to match, we do not need to walk the access paths. @@ -1301,7 +1399,7 @@ nonoverlapping_component_refs_since_match_p (tree match1, tree ref1, && !tree_int_cst_equal (TREE_OPERAND (ref1, 1), TREE_OPERAND (ref2, 1)))) { - ++alias_stats.nonoverlapping_component_refs_since_match_p_may_alias; + ++alias_stats.nonoverlapping_refs_since_match_p_may_alias; return -1; } @@ -1318,18 +1416,78 @@ nonoverlapping_component_refs_since_match_p (tree match1, tree ref1, case the return value will precisely be false. */ while (true) { - bool seen_noncomponent_ref_p = false; + /* Track if we seen unmatched ref with non-zero offset. In this case + we must look for partial overlaps. */ + bool seen_unmatched_ref_p = false; + + /* First match ARRAY_REFs an try to disambiguate. */ + if (!component_refs1.is_empty () + && !component_refs2.is_empty ()) + { + unsigned int narray_refs1=0, narray_refs2=0; + + /* We generally assume that both access paths starts by same sequence + of refs. However if number of array refs is not in sync, try + to recover and pop elts until number match. This helps the case + where one access path starts by array and other by element. */ + for (narray_refs1 = 0; narray_refs1 < component_refs1.length (); + narray_refs1++) + if (TREE_CODE (component_refs1 [component_refs1.length() + - 1 - narray_refs1]) != ARRAY_REF) + break; + + for (narray_refs2 = 0; narray_refs2 < component_refs2.length (); + narray_refs2++) + if (TREE_CODE (component_refs2 [component_refs2.length() + - 1 - narray_refs2]) != ARRAY_REF) + break; + for (; narray_refs1 > narray_refs2; narray_refs1--) + { + ref1 = component_refs1.pop (); + /* Track whether we possibly introduced partial overlap assuming + that innermost type sizes does not match. This only can + happen if the offset introduced by the ARRAY_REF + is non-zero. */ + if (!operand_equal_p (TREE_OPERAND (ref1, 1), + cheap_array_ref_low_bound (ref1), 0)) + seen_unmatched_ref_p = true; + } + for (; narray_refs2 > narray_refs1; narray_refs2--) + { + ref2 = component_refs2.pop (); + if (!operand_equal_p (TREE_OPERAND (ref2, 1), + cheap_array_ref_low_bound (ref2), 0)) + seen_unmatched_ref_p = true; + } + /* Try to disambiguate matched arrays. */ + for (unsigned int i = 0; i < narray_refs1; i++) + { + int cmp = nonoverlapping_array_refs_p (component_refs1.pop (), + component_refs2.pop ()); + if (cmp == 1 && !partial_overlap) + { + ++alias_stats + .nonoverlapping_refs_since_match_p_no_alias; + return 1; + } + partial_overlap = false; + if (cmp == -1) + seen_unmatched_ref_p = true; + } + } + + /* Next look for component_refs. */ do { if (component_refs1.is_empty ()) { ++alias_stats - .nonoverlapping_component_refs_since_match_p_must_overlap; + .nonoverlapping_refs_since_match_p_must_overlap; return 0; } ref1 = component_refs1.pop (); if (TREE_CODE (ref1) != COMPONENT_REF) - seen_noncomponent_ref_p = true; + seen_unmatched_ref_p = true; } while (!RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (ref1, 0)))); @@ -1338,12 +1496,12 @@ nonoverlapping_component_refs_since_match_p (tree match1, tree ref1, if (component_refs2.is_empty ()) { ++alias_stats - .nonoverlapping_component_refs_since_match_p_must_overlap; + .nonoverlapping_refs_since_match_p_must_overlap; return 0; } ref2 = component_refs2.pop (); if (TREE_CODE (ref2) != COMPONENT_REF) - seen_noncomponent_ref_p = true; + seen_unmatched_ref_p = true; } while (!RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (ref2, 0)))); @@ -1361,13 +1519,15 @@ nonoverlapping_component_refs_since_match_p (tree match1, tree ref1, tree type1 = DECL_CONTEXT (field1); tree type2 = DECL_CONTEXT (field2); + partial_overlap = false; + /* If we skipped array refs on type of different sizes, we can no longer be sure that there are not partial overlaps. */ - if (seen_noncomponent_ref_p + if (seen_unmatched_ref_p && !operand_equal_p (TYPE_SIZE (type1), TYPE_SIZE (type2), 0)) { ++alias_stats - .nonoverlapping_component_refs_since_match_p_may_alias; + .nonoverlapping_refs_since_match_p_may_alias; return -1; } @@ -1375,18 +1535,18 @@ nonoverlapping_component_refs_since_match_p (tree match1, tree ref1, if (cmp == -1) { ++alias_stats - .nonoverlapping_component_refs_since_match_p_may_alias; + .nonoverlapping_refs_since_match_p_may_alias; return -1; } else if (cmp == 1) { ++alias_stats - .nonoverlapping_component_refs_since_match_p_no_alias; + .nonoverlapping_refs_since_match_p_no_alias; return 1; } } - ++alias_stats.nonoverlapping_component_refs_since_match_p_must_overlap; + ++alias_stats.nonoverlapping_refs_since_match_p_must_overlap; return 0; } @@ -1583,8 +1743,7 @@ decl_refs_may_alias_p (tree ref1, tree base1, so we disambiguate component references manually. */ if (ref1 && ref2 && handled_component_p (ref1) && handled_component_p (ref2) - && nonoverlapping_component_refs_since_match_p (NULL, ref1, - NULL, ref2) == 1) + && nonoverlapping_refs_since_match_p (NULL, ref1, NULL, ref2, false) == 1) return false; return true; @@ -1709,19 +1868,22 @@ indirect_ref_may_alias_decl_p (tree ref1 ATTRIBUTE_UNUSED, tree base1, || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1))) && (TREE_CODE (dbase2) != TARGET_MEM_REF || (!TMR_INDEX (dbase2) && !TMR_INDEX2 (dbase2)))) - && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1 - && (TREE_CODE (TREE_TYPE (base1)) != ARRAY_TYPE - || (TYPE_SIZE (TREE_TYPE (base1)) - && TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) == INTEGER_CST))) + && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1) { - if (!ranges_maybe_overlap_p (doffset1, max_size1, doffset2, max_size2)) + bool partial_overlap = (TREE_CODE (TREE_TYPE (base1)) == ARRAY_TYPE + && (TYPE_SIZE (TREE_TYPE (base1)) + && TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) + != INTEGER_CST)); + if (!partial_overlap + && !ranges_maybe_overlap_p (doffset1, max_size1, doffset2, max_size2)) return false; if (!ref1 || !ref2 /* If there is must alias, there is no use disambiguating further. */ - || (known_eq (size1, max_size1) && known_eq (size2, max_size2))) + || (!partial_overlap + && known_eq (size1, max_size1) && known_eq (size2, max_size2))) return true; - int res = nonoverlapping_component_refs_since_match_p (base1, ref1, - base2, ref2); + int res = nonoverlapping_refs_since_match_p (base1, ref1, base2, ref2, + partial_overlap); if (res == -1) return !nonoverlapping_component_refs_p (ref1, ref2); return !res; @@ -1805,8 +1967,8 @@ indirect_refs_may_alias_p (tree ref1 ATTRIBUTE_UNUSED, tree base1, return true; if (ref1 && ref2) { - int res = nonoverlapping_component_refs_since_match_p (NULL, ref1, - NULL, ref2); + int res = nonoverlapping_refs_since_match_p (NULL, ref1, NULL, ref2, + false); if (res != -1) return !res; } @@ -1844,19 +2006,22 @@ indirect_refs_may_alias_p (tree ref1 ATTRIBUTE_UNUSED, tree base1, && (TREE_CODE (base2) != TARGET_MEM_REF || (!TMR_INDEX (base2) && !TMR_INDEX2 (base2))) && same_type_for_tbaa (TREE_TYPE (ptrtype1), - TREE_TYPE (ptrtype2)) == 1 + TREE_TYPE (ptrtype2)) == 1) + { /* But avoid treating arrays as "objects", instead assume they can overlap by an exact multiple of their element size. See gcc.dg/torture/alias-2.c. */ - && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE) - { - if (!ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2)) + bool partial_overlap = TREE_CODE (TREE_TYPE (ptrtype1)) == ARRAY_TYPE; + + if (!partial_overlap + && !ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2)) return false; if (!ref1 || !ref2 - || (known_eq (size1, max_size1) && known_eq (size2, max_size2))) + || (!partial_overlap + && known_eq (size1, max_size1) && known_eq (size2, max_size2))) return true; - int res = nonoverlapping_component_refs_since_match_p (base1, ref1, - base2, ref2); + int res = nonoverlapping_refs_since_match_p (base1, ref1, base2, ref2, + partial_overlap); if (res == -1) return !nonoverlapping_component_refs_p (ref1, ref2); return !res; -- cgit v1.1 From e9c9a142b49d069c5b7c24d47b07756e9d591956 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 1 Oct 2019 21:58:17 +0000 Subject: Support prefixes in diagnostic_show_locus Previously, diagnostic_show_locus saved and restored the pretty_printer's prefix, clearing it for the duration of the call. I have a patch kit in development that can benefit from applying a prefix to the output of d_s_l, so this patch adds support to d_s_l for printing such prefixes. It moves the save and restore of the pp's prefix from d_s_l to all of its callers, and updates diagnostic-show-locus.c to properly handle prefixes. gcc/c-family/ChangeLog: * c-opts.c (c_diagnostic_finalizer): Temporarily clear prefix when calling diagnostic_show_locus, rather than destroying it afterwards. gcc/ChangeLog: * diagnostic-show-locus.c (layout::print_gap_in_line_numbering): Call pp_emit_prefix. (layout::print_source_line): Likewise. (layout::start_annotation_line): Likewise. (diagnostic_show_locus): Remove call to temporarily clear the prefix. (selftest::test_one_liner_fixit_remove): Add test coverage for the interaction of pp_set_prefix with rulers and fix-it hints. * diagnostic.c (default_diagnostic_finalizer): Temporarily clear prefix when calling diagnostic_show_locus, rather than destroying it afterwards. (print_parseable_fixits): Temporarily clear prefix. * pretty-print.c (pp_format): Save and restore line_length, rather than assuming it is zero. (pp_output_formatted_text): Remove assertion that line_length is zero. gcc/fortran/ChangeLog: * error.c (gfc_diagnostic_starter): Clear the prefix before calling diagnostic_show_locus. gcc/testsuite/ChangeLog: * gcc.dg/plugin/diagnostic_group_plugin.c (test_begin_group_cb): Clear the prefix before emitting the "END GROUP" line. * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c (custom_diagnostic_finalizer): Temporarily clear prefix when calling diagnostic_show_locus, rather than destroying it afterwards. From-SVN: r276433 --- gcc/ChangeLog | 19 +++++ gcc/c-family/ChangeLog | 5 ++ gcc/c-family/c-opts.c | 4 +- gcc/diagnostic-show-locus.c | 96 +++++++++++++++++++--- gcc/diagnostic.c | 9 +- gcc/fortran/ChangeLog | 5 ++ gcc/fortran/error.c | 1 + gcc/pretty-print.c | 4 +- gcc/testsuite/ChangeLog | 9 ++ .../gcc.dg/plugin/diagnostic_group_plugin.c | 1 + .../plugin/diagnostic_plugin_test_show_locus.c | 5 +- 11 files changed, 139 insertions(+), 19 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b7feecc..b3a42ae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2019-10-01 David Malcolm + + * diagnostic-show-locus.c (layout::print_gap_in_line_numbering): + Call pp_emit_prefix. + (layout::print_source_line): Likewise. + (layout::start_annotation_line): Likewise. + (diagnostic_show_locus): Remove call to temporarily clear the + prefix. + (selftest::test_one_liner_fixit_remove): Add test coverage for the + interaction of pp_set_prefix with rulers and fix-it hints. + * diagnostic.c (default_diagnostic_finalizer): Temporarily clear + prefix when calling diagnostic_show_locus, rather than destroying + it afterwards. + (print_parseable_fixits): Temporarily clear prefix. + * pretty-print.c (pp_format): Save and restore line_length, rather + than assuming it is zero. + (pp_output_formatted_text): Remove assertion that line_length is + zero. + 2019-10-01 Jan Hubicka * tree-ssa-alias.c (nonoverlapping_component_refs_since_match_p): diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 811947a..0eade3c 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 David Malcolm + + * c-opts.c (c_diagnostic_finalizer): Temporarily clear prefix when + calling diagnostic_show_locus, rather than destroying it afterwards. + 2019-10-01 Jakub Jelinek PR c++/91925 diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 23ab4cf..949d96a 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -168,11 +168,13 @@ c_diagnostic_finalizer (diagnostic_context *context, diagnostic_info *diagnostic, diagnostic_t) { + char *saved_prefix = pp_take_prefix (context->printer); + pp_set_prefix (context->printer, NULL); diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); /* By default print macro expansion contexts in the diagnostic finalizer -- for tokens resulting from macro expansion. */ virt_loc_aware_diagnostic_finalizer (context, diagnostic); - pp_destroy_prefix (context->printer); + pp_set_prefix (context->printer, saved_prefix); pp_flush (context->printer); } diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c index 6612cbb6..cb920f6 100644 --- a/gcc/diagnostic-show-locus.c +++ b/gcc/diagnostic-show-locus.c @@ -1039,6 +1039,8 @@ layout::print_gap_in_line_numbering () { gcc_assert (m_show_line_numbers_p); + pp_emit_prefix (m_pp); + for (int i = 0; i < m_linenum_width + 1; i++) pp_character (m_pp, '.'); @@ -1266,6 +1268,8 @@ layout::print_source_line (linenum_type row, const char *line, int line_width, line_width); line += m_x_offset; + pp_emit_prefix (m_pp); + if (m_show_line_numbers_p) { int width = num_digits (row); @@ -1346,6 +1350,7 @@ layout::should_print_annotation_line_p (linenum_type row) const void layout::start_annotation_line (char margin_char) const { + pp_emit_prefix (m_pp); if (m_show_line_numbers_p) { /* Print the margin. If MARGIN_CHAR != ' ', then print up to 3 @@ -2297,9 +2302,6 @@ diagnostic_show_locus (diagnostic_context * context, context->last_location = loc; - char *saved_prefix = pp_take_prefix (context->printer); - pp_set_prefix (context->printer, NULL); - layout layout (context, richloc, diagnostic_kind); for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans (); line_span_idx++) @@ -2329,8 +2331,6 @@ diagnostic_show_locus (diagnostic_context * context, row <= last_line; row++) layout.print_line (row); } - - pp_set_prefix (context->printer, saved_prefix); } #if CHECKING_P @@ -2463,23 +2463,93 @@ test_one_liner_fixit_insert_after () pp_formatted_text (dc.printer)); } -/* Removal fix-it hint: removal of the ".field". */ +/* Removal fix-it hint: removal of the ".field". + Also verify the interaction of pp_set_prefix with rulers and + fix-it hints. */ static void test_one_liner_fixit_remove () { - test_diagnostic_context dc; location_t start = linemap_position_for_column (line_table, 10); location_t finish = linemap_position_for_column (line_table, 15); location_t dot = make_location (start, start, finish); rich_location richloc (line_table, dot); richloc.add_fixit_remove (); - diagnostic_show_locus (&dc, &richloc, DK_ERROR); - ASSERT_STREQ ("\n" - " foo = bar.field;\n" - " ^~~~~~\n" - " ------\n", - pp_formatted_text (dc.printer)); + + /* Normal. */ + { + test_diagnostic_context dc; + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ^~~~~~\n" + " ------\n", + pp_formatted_text (dc.printer)); + } + + /* Test of adding a prefix. */ + { + test_diagnostic_context dc; + pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE; + pp_set_prefix (dc.printer, xstrdup ("TEST PREFIX:")); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + "TEST PREFIX: foo = bar.field;\n" + "TEST PREFIX: ^~~~~~\n" + "TEST PREFIX: ------\n", + pp_formatted_text (dc.printer)); + } + + /* Normal, with ruler. */ + { + test_diagnostic_context dc; + dc.show_ruler_p = true; + dc.caret_max_width = 104; + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " 0 0 0 0 0 0 0 0 0 1 \n" + " 1 2 3 4 5 6 7 8 9 0 \n" + " 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\n" + " foo = bar.field;\n" + " ^~~~~~\n" + " ------\n", + pp_formatted_text (dc.printer)); + } + + /* Test of adding a prefix, with ruler. */ + { + test_diagnostic_context dc; + dc.show_ruler_p = true; + dc.caret_max_width = 50; + pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE; + pp_set_prefix (dc.printer, xstrdup ("TEST PREFIX:")); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + "TEST PREFIX: 1 2 3 4 5\n" + "TEST PREFIX: 12345678901234567890123456789012345678901234567890\n" + "TEST PREFIX: foo = bar.field;\n" + "TEST PREFIX: ^~~~~~\n" + "TEST PREFIX: ------\n", + pp_formatted_text (dc.printer)); + } + + /* Test of adding a prefix, with ruler and line numbers. */ + { + test_diagnostic_context dc; + dc.show_ruler_p = true; + dc.caret_max_width = 50; + dc.show_line_numbers_p = true; + pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE; + pp_set_prefix (dc.printer, xstrdup ("TEST PREFIX:")); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + "TEST PREFIX: | 1 2 3 4 5\n" + "TEST PREFIX: | 12345678901234567890123456789012345678901234567890\n" + "TEST PREFIX: 1 | foo = bar.field;\n" + "TEST PREFIX: | ^~~~~~\n" + "TEST PREFIX: | ------\n", + pp_formatted_text (dc.printer)); + } } /* Replace fix-it hint: replacing "field" with "m_field". */ diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 96b6fa3..1b3306c 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -663,8 +663,10 @@ default_diagnostic_finalizer (diagnostic_context *context, diagnostic_info *diagnostic, diagnostic_t) { + char *saved_prefix = pp_take_prefix (context->printer); + pp_set_prefix (context->printer, NULL); diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); - pp_destroy_prefix (context->printer); + pp_set_prefix (context->printer, saved_prefix); pp_flush (context->printer); } @@ -811,6 +813,9 @@ print_parseable_fixits (pretty_printer *pp, rich_location *richloc) gcc_assert (pp); gcc_assert (richloc); + char *saved_prefix = pp_take_prefix (pp); + pp_set_prefix (pp, NULL); + for (unsigned i = 0; i < richloc->get_num_fixit_hints (); i++) { const fixit_hint *hint = richloc->get_fixit_hint (i); @@ -827,6 +832,8 @@ print_parseable_fixits (pretty_printer *pp, rich_location *richloc) print_escaped_string (pp, hint->get_string ()); pp_newline (pp); } + + pp_set_prefix (pp, saved_prefix); } /* Update the diag_class of DIAGNOSTIC based on its location diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 694fc32..63ee15b 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 David Malcolm + + * error.c (gfc_diagnostic_starter): Clear the prefix before + calling diagnostic_show_locus. + 2019-09-29 Steven G. Kargl PR fortran/91641 diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c index a0ce7a6..a7c27f0 100644 --- a/gcc/fortran/error.c +++ b/gcc/fortran/error.c @@ -1137,6 +1137,7 @@ gfc_diagnostic_starter (diagnostic_context *context, free (locus_prefix); /* Fortran uses an empty line between locus and caret line. */ pp_newline (context->printer); + pp_set_prefix (context->printer, NULL); diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); /* If the caret line was shown, the prefix does not contain the locus. */ diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c index 6948971..2b6c585 100644 --- a/gcc/pretty-print.c +++ b/gcc/pretty-print.c @@ -1192,6 +1192,7 @@ pp_format (pretty_printer *pp, text_info *text) /* Set output to the argument obstack, and switch line-wrapping and prefixing off. */ buffer->obstack = &buffer->chunk_obstack; + const int old_line_length = buffer->line_length; old_wrapping_mode = pp_set_verbatim_wrapping (pp); /* Second phase. Replace each formatter with the formatted text it @@ -1412,7 +1413,7 @@ pp_format (pretty_printer *pp, text_info *text) /* Revert to normal obstack and wrapping mode. */ buffer->obstack = &buffer->formatted_obstack; - buffer->line_length = 0; + buffer->line_length = old_line_length; pp_wrapping_mode (pp) = old_wrapping_mode; pp_clear_state (pp); } @@ -1427,7 +1428,6 @@ pp_output_formatted_text (pretty_printer *pp) const char **args = chunk_array->args; gcc_assert (buffer->obstack == &buffer->formatted_obstack); - gcc_assert (buffer->line_length == 0); /* This is a third phase, first 2 phases done in pp_format_args. Now we actually print it. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f7256b5..5949f0a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-10-01 David Malcolm + + * gcc.dg/plugin/diagnostic_group_plugin.c (test_begin_group_cb): + Clear the prefix before emitting the "END GROUP" line. + * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c + (custom_diagnostic_finalizer): Temporarily clear prefix when + calling diagnostic_show_locus, rather than destroying it + afterwards. + 2019-10-01 Jan Hubicka * gcc.dg/tree-ssa/alias-access-path-10.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c index 3083e12..67ca701 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c @@ -197,6 +197,7 @@ test_begin_group_cb (diagnostic_context * context) static void test_end_group_cb (diagnostic_context * context) { + pp_set_prefix (context->printer, NULL); pp_string (context->printer, "---------------------------------- END GROUP -------------------------------"); pp_newline_and_flush (context->printer); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c index fce68a1..3f62edd 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c @@ -135,10 +135,11 @@ custom_diagnostic_finalizer (diagnostic_context *context, bool old_show_color = pp_show_color (context->printer); if (force_show_locus_color) pp_show_color (context->printer) = true; + char *saved_prefix = pp_take_prefix (context->printer); + pp_set_prefix (context->printer, NULL); diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); pp_show_color (context->printer) = old_show_color; - - pp_destroy_prefix (context->printer); + pp_set_prefix (context->printer, saved_prefix); pp_flush (context->printer); } -- cgit v1.1 From 93313b94fe18f3c3de4f24f5bb3fafb4639f1c7e Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Wed, 2 Oct 2019 01:08:40 +0100 Subject: Handle :: tokens in C for C2x. As part of adding [[]]-style attributes, C2x adds the token :: for use in scoped attribute names. This patch adds corresponding support for that token in C to GCC. The token is supported both for C2x and for older gnu* standards (on the basis that extensions are normally supported in older gnu* versions; people will expect to be able to use [[]] attributes, before C2x is the default, without needing to use -std=gnu2x). There are no cases in older C standards where the token : can be followed by a token starting with : in syntactically valid sources; the only cases the :: token could break in older standard C thus are ones involving concatenation of pp-tokens where the result does not end up as tokens (e.g., gets stringized). In GNU C extensions, the main case where :: might appear in existing sources is in asm statements, and the C parser is thus made to handle it like two consecutive : tokens, which the C++ parser already does. A limited test of various positionings of :: in asm statements is added to the testsuite (in particular, to cover the syntax error when :: means too many colons but a single : would be OK), but existing tests cover a variety of styles there anyway. Technically there are cases in Objective-C and OpenMP for which this also changes how previously valid code is lexed: the objc-selector-arg syntax allows multiple consecutive : tokens (although I don't think they are particularly useful there), while OpenMP syntax includes array section syntax such as [:] which, before :: was a token, could also be written as [::> (there might be other OpenMP cases potentially affected, I didn't check all the OpenMP syntax in detail). I don't think either of those cases affects the basis for supporting the :: token in all -std=gnu* modes, or that there is any obvious need to special-case handling of CPP_SCOPE tokens for those constructs the way there is for asm statements. cpp_avoid_paste, which determines when spaces need adding between tokens in preprocessed output where there wouldn't otherwise be whitespace between them (e.g. if stringized), already inserts space between : and : unconditionally, rather than only for C++, so no change is needed there (but a C2x test is added that such space is indeed inserted). Bootstrapped with no regressions on x86-64-pc-linux-gnu. gcc/c: * c-parser.c (c_parser_asm_statement): Handle CPP_SCOPE like two CPP_COLON tokens. gcc/testsuite: * gcc.dg/asm-scope-1.c, gcc.dg/cpp/c11-scope-1.c, gcc.dg/cpp/c17-scope-1.c, gcc.dg/cpp/c2x-scope-1.c, gcc.dg/cpp/c2x-scope-2.c, gcc.dg/cpp/c90-scope-1.c, gcc.dg/cpp/c94-scope-1.c, gcc.dg/cpp/c99-scope-1.c, gcc.dg/cpp/gnu11-scope-1.c, gcc.dg/cpp/gnu17-scope-1.c, gcc.dg/cpp/gnu89-scope-1.c, gcc.dg/cpp/gnu99-scope-1.c: New tests. libcpp: * include/cpplib.h (struct cpp_options): Add member scope. * init.c (struct lang_flags, lang_defaults): Likewise. (cpp_set_lang): Set scope member of pfile. * lex.c (_cpp_lex_direct): Test CPP_OPTION (pfile, scope) not CPP_OPTION (pfile, cplusplus) for creating CPP_SCOPE tokens. From-SVN: r276434 --- gcc/c/ChangeLog | 5 +++++ gcc/c/c-parser.c | 25 +++++++++++++++++++------ gcc/testsuite/ChangeLog | 9 +++++++++ gcc/testsuite/gcc.dg/asm-scope-1.c | 27 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/cpp/c11-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/c17-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/c2x-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/c2x-scope-2.c | 11 +++++++++++ gcc/testsuite/gcc.dg/cpp/c90-scope-1.c | 7 +++++++ gcc/testsuite/gcc.dg/cpp/c94-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/c99-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/gnu11-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/gnu17-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/gnu89-scope-1.c | 8 ++++++++ gcc/testsuite/gcc.dg/cpp/gnu99-scope-1.c | 8 ++++++++ 15 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/asm-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c11-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c17-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c2x-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c2x-scope-2.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c90-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c94-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/c99-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/gnu11-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/gnu17-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/gnu89-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/cpp/gnu99-scope-1.c (limited to 'gcc') diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 3156e35..0f263f7 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Joseph Myers + + * c-parser.c (c_parser_asm_statement): Handle CPP_SCOPE like two + CPP_COLON tokens. + 2019-10-01 Richard Sandiford * c-objc-common.c (useful_aka_type_p): New function. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index c8afab2..6957297 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -6411,7 +6411,9 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, The form with asm-goto-operands is valid if and only if the asm-qualifier-list contains goto, and is the only allowed form in that case. - Duplicate asm-qualifiers are not allowed. */ + Duplicate asm-qualifiers are not allowed. + + The :: token is considered equivalent to two consecutive : tokens. */ static tree c_parser_asm_statement (c_parser *parser) @@ -6509,17 +6511,28 @@ c_parser_asm_statement (c_parser *parser) nsections = 3 + is_goto; for (section = 0; section < nsections; ++section) { - if (!c_parser_require (parser, CPP_COLON, - is_goto - ? G_("expected %<:%>") - : G_("expected %<:%> or %<)%>"), - UNKNOWN_LOCATION, is_goto)) + if (c_parser_next_token_is (parser, CPP_SCOPE)) + { + ++section; + if (section == nsections) + { + c_parser_error (parser, "expected %<)%>"); + goto error_close_paren; + } + c_parser_consume_token (parser); + } + else if (!c_parser_require (parser, CPP_COLON, + is_goto + ? G_("expected %<:%>") + : G_("expected %<:%> or %<)%>"), + UNKNOWN_LOCATION, is_goto)) goto error_close_paren; /* Once past any colon, we're no longer a simple asm. */ simple = false; if ((!c_parser_next_token_is (parser, CPP_COLON) + && !c_parser_next_token_is (parser, CPP_SCOPE) && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) || section == 3) switch (section) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5949f0a..834ee45 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-10-02 Joseph Myers + + * gcc.dg/asm-scope-1.c, gcc.dg/cpp/c11-scope-1.c, + gcc.dg/cpp/c17-scope-1.c, gcc.dg/cpp/c2x-scope-1.c, + gcc.dg/cpp/c2x-scope-2.c, gcc.dg/cpp/c90-scope-1.c, + gcc.dg/cpp/c94-scope-1.c, gcc.dg/cpp/c99-scope-1.c, + gcc.dg/cpp/gnu11-scope-1.c, gcc.dg/cpp/gnu17-scope-1.c, + gcc.dg/cpp/gnu89-scope-1.c, gcc.dg/cpp/gnu99-scope-1.c: New tests. + 2019-10-01 David Malcolm * gcc.dg/plugin/diagnostic_group_plugin.c (test_begin_group_cb): diff --git a/gcc/testsuite/gcc.dg/asm-scope-1.c b/gcc/testsuite/gcc.dg/asm-scope-1.c new file mode 100644 index 0000000..6439104 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asm-scope-1.c @@ -0,0 +1,27 @@ +/* Test :: token handling in asm. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu2x" } */ + +void +f (void) +{ + asm (""); + asm ("" : ); + asm ("" : :); + asm ("" ::); + asm ("" : : :); + asm ("" :: :); + asm ("" : ::); + asm goto ("" : : : : lab); + asm goto ("" :: : : lab); + asm goto ("" : :: : lab); + asm goto ("" : : :: lab); + asm goto ("" :: :: lab); + lab: ; + /* Test errors when :: is at the end of asm and only one : allowed. */ + asm ("" : : ::); /* { dg-error "expected" } */ + asm ("" :: ::); /* { dg-error "expected" } */ + asm goto ("" : : : :: lab); /* { dg-error "expected" } */ + asm goto ("" :: : :: lab); /* { dg-error "expected" } */ + asm goto ("" : :: :: lab); /* { dg-error "expected" } */ +} diff --git a/gcc/testsuite/gcc.dg/cpp/c11-scope-1.c b/gcc/testsuite/gcc.dg/cpp/c11-scope-1.c new file mode 100644 index 0000000..2db0516 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c11-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token not in C11. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */ +CONCAT (::, >) diff --git a/gcc/testsuite/gcc.dg/cpp/c17-scope-1.c b/gcc/testsuite/gcc.dg/cpp/c17-scope-1.c new file mode 100644 index 0000000..b5b366b --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c17-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token not in C17. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c17 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */ +CONCAT (::, >) diff --git a/gcc/testsuite/gcc.dg/cpp/c2x-scope-1.c b/gcc/testsuite/gcc.dg/cpp/c2x-scope-1.c new file mode 100644 index 0000000..8337ba7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c2x-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token in C2x. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) +CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/c2x-scope-2.c b/gcc/testsuite/gcc.dg/cpp/c2x-scope-2.c new file mode 100644 index 0000000..73b36e7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c2x-scope-2.c @@ -0,0 +1,11 @@ +/* Test :: token in C2x: preprocessed output. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c2x -pedantic-errors -P" } */ + +#define COLON() : +#define TEST() ABC + +/* This must have a space inserted between the two ':' tokens in + preprocessed output. */ +TEST()COLON()COLON()TEST() +/* { dg-final { scan-file c2x-scope-2.i "ABC: :ABC" } } */ diff --git a/gcc/testsuite/gcc.dg/cpp/c90-scope-1.c b/gcc/testsuite/gcc.dg/cpp/c90-scope-1.c new file mode 100644 index 0000000..4c23e21 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c90-scope-1.c @@ -0,0 +1,7 @@ +/* Test :: token not in C90. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c90 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/c94-scope-1.c b/gcc/testsuite/gcc.dg/cpp/c94-scope-1.c new file mode 100644 index 0000000..0e6da01 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c94-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token not in C94. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=iso9899:199409 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */ +CONCAT (::, >) diff --git a/gcc/testsuite/gcc.dg/cpp/c99-scope-1.c b/gcc/testsuite/gcc.dg/cpp/c99-scope-1.c new file mode 100644 index 0000000..e878286 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/c99-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token not in C99. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */ +CONCAT (::, >) diff --git a/gcc/testsuite/gcc.dg/cpp/gnu11-scope-1.c b/gcc/testsuite/gcc.dg/cpp/gnu11-scope-1.c new file mode 100644 index 0000000..2dea391 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/gnu11-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token in gnu11. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu11 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) +CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/gnu17-scope-1.c b/gcc/testsuite/gcc.dg/cpp/gnu17-scope-1.c new file mode 100644 index 0000000..0c5f20d --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/gnu17-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token in gnu17. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu17 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) +CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/gnu89-scope-1.c b/gcc/testsuite/gcc.dg/cpp/gnu89-scope-1.c new file mode 100644 index 0000000..812e62f --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/gnu89-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token in gnu89. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu89 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) +CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/gnu99-scope-1.c b/gcc/testsuite/gcc.dg/cpp/gnu99-scope-1.c new file mode 100644 index 0000000..5ba871d --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/gnu99-scope-1.c @@ -0,0 +1,8 @@ +/* Test :: token in gnu99. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu99 -pedantic-errors" } */ + +#define CONCAT(x, y) x ## y + +CONCAT (:, :) +CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */ -- cgit v1.1 From 8dc7a6f2a59b252cb756bd1f450558a4850cb6d2 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 2 Oct 2019 00:16:19 +0000 Subject: Daily bump. From-SVN: r276438 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 05ec96c..11b6d83 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20191001 +20191002 -- cgit v1.1 From 1bcb4c4faa4bd6b1c917c75b100d618faf9e628c Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 2 Oct 2019 07:37:10 +0000 Subject: [LRA] Don't make eliminable registers live (PR91957) One effect of https://gcc.gnu.org/ml/gcc-patches/2019-09/msg00802.html was to strengthen the sanity check in lra_assigns so that it checks whether reg_renumber is consistent with the whole conflict set. This duly tripped on csky for a pseudo that had been allocated to the eliminated frame pointer. (csky doesn't have a separate hard frame pointer.) lra-lives uses: /* Set of hard regs (except eliminable ones) currently live. */ static HARD_REG_SET hard_regs_live; to track the set of live directly-referenced hard registers, and it correctly implements the exclusion when setting up the initial set: hard_regs_live &= ~eliminable_regset; But later calls to make_hard_regno_live and make_hard_regno_dead would process eliminable registers like other registers, recording conflicts for them and potentially making them live. (Note that after r266086, make_hard_regno_dead adds conflicts for registers that are already marked dead.) I think this would have had the effect of pessimising targets without a separate hard frame pointer. 2019-10-02 Richard Sandiford gcc/ PR middle-end/91957 * lra-lives.c (make_hard_regno_dead): Don't record conflicts for eliminable registers. (make_hard_regno_live): Likewise, and don't make them live. From-SVN: r276440 --- gcc/ChangeLog | 7 +++++++ gcc/lra-lives.c | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3a42ae..69f5d71 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-02 Richard Sandiford + + PR middle-end/91957 + * lra-lives.c (make_hard_regno_dead): Don't record conflicts for + eliminable registers. + (make_hard_regno_live): Likewise, and don't make them live. + 2019-10-01 David Malcolm * diagnostic-show-locus.c (layout::print_gap_in_line_numbering): diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index 389a79d..1d1525c 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -281,7 +281,8 @@ static void make_hard_regno_live (int regno) { lra_assert (HARD_REGISTER_NUM_P (regno)); - if (TEST_HARD_REG_BIT (hard_regs_live, regno)) + if (TEST_HARD_REG_BIT (hard_regs_live, regno) + || TEST_HARD_REG_BIT (eliminable_regset, regno)) return; SET_HARD_REG_BIT (hard_regs_live, regno); sparseset_set_bit (start_living, regno); @@ -295,6 +296,9 @@ make_hard_regno_live (int regno) static void make_hard_regno_dead (int regno) { + if (TEST_HARD_REG_BIT (eliminable_regset, regno)) + return; + lra_assert (HARD_REGISTER_NUM_P (regno)); unsigned int i; EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i) -- cgit v1.1 From 291fa23ac04e317877c1e102937532f080180bb2 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 2 Oct 2019 09:21:57 +0000 Subject: tree-vectorizer.h (stmt_vec_info_type::cycle_phi_info_type): New. 2019-10-02 Richard Biener * tree-vectorizer.h (stmt_vec_info_type::cycle_phi_info_type): New. (vect_transform_cycle_phi): Declare. * tree-vect-stmts.c (vect_transform_stmt): Call vect_transform_cycle_phi. * tree-vect-loop.c (vectorizable_reduction): Split out PHI transformation stage to ... (vect_transform_cycle_phi): ... here. From-SVN: r276441 --- gcc/ChangeLog | 11 ++ gcc/tree-vect-loop.c | 418 ++++++++++++++++++++++++++------------------------ gcc/tree-vect-stmts.c | 6 + gcc/tree-vectorizer.h | 3 + 4 files changed, 239 insertions(+), 199 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 69f5d71..b7830a4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-10-02 Richard Biener + + * tree-vectorizer.h (stmt_vec_info_type::cycle_phi_info_type): + New. + (vect_transform_cycle_phi): Declare. + * tree-vect-stmts.c (vect_transform_stmt): Call + vect_transform_cycle_phi. + * tree-vect-loop.c (vectorizable_reduction): Split out + PHI transformation stage to ... + (vect_transform_cycle_phi): ... here. + 2019-10-02 Richard Sandiford PR middle-end/91957 diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 350cee5..a3fd011 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -5783,7 +5783,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, bool is_simple_use; int i; int ncopies; - stmt_vec_info prev_phi_info; bool single_defuse_cycle = false; int j; tree ops[3]; @@ -5811,207 +5810,15 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, gcc_assert (slp_node && REDUC_GROUP_FIRST_ELEMENT (stmt_info) == stmt_info); - if (gphi *phi = dyn_cast (stmt_info->stmt)) + if (is_a (stmt_info->stmt)) { - tree phi_result = gimple_phi_result (phi); /* Analysis is fully done on the reduction stmt invocation. */ - if (! vec_stmt) - { - if (slp_node) - slp_node_instance->reduc_phis = slp_node; - - STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type; - return true; - } - - if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION) - /* Leave the scalar phi in place. Note that checking - STMT_VINFO_VEC_REDUCTION_TYPE (as below) only works - for reductions involving a single statement. */ - return true; - - stmt_vec_info reduc_stmt_info = STMT_VINFO_REDUC_DEF (stmt_info); - reduc_stmt_info = vect_stmt_to_vectorize (reduc_stmt_info); - - if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) - == EXTRACT_LAST_REDUCTION) - /* Leave the scalar phi in place. */ - return true; - - if (gassign *reduc_stmt = dyn_cast (reduc_stmt_info->stmt)) - for (unsigned k = 1; k < gimple_num_ops (reduc_stmt); ++k) - { - tree op = gimple_op (reduc_stmt, k); - if (op == phi_result) - continue; - if (k == 1 && gimple_assign_rhs_code (reduc_stmt) == COND_EXPR) - continue; - bool is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt); - gcc_assert (is_simple_use); - if (dt == vect_constant_def || dt == vect_external_def) - continue; - if (!vectype_in - || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in))) - < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (op))))) - vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op)); - break; - } - /* For a nested cycle we might end up with an operation like - phi_result * phi_result. */ - if (!vectype_in) - vectype_in = STMT_VINFO_VECTYPE (stmt_info); - gcc_assert (vectype_in); + gcc_assert (! vec_stmt); if (slp_node) - { - /* The size vect_schedule_slp_instance computes is off for us. */ - vec_num = vect_get_num_vectors - (LOOP_VINFO_VECT_FACTOR (loop_vinfo) - * SLP_TREE_SCALAR_STMTS (slp_node).length (), vectype_in); - ncopies = 1; - } - else - { - vec_num = 1; - ncopies = vect_get_num_copies (loop_vinfo, vectype_in); - } - - /* Check whether we can use a single PHI node and accumulate - vectors to one before the backedge. */ - stmt_vec_info use_stmt_info; - if (ncopies > 1 - && STMT_VINFO_RELEVANT (reduc_stmt_info) <= vect_used_only_live - && (use_stmt_info = loop_vinfo->lookup_single_use (phi_result)) - && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) - || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) - && vect_stmt_to_vectorize (use_stmt_info) == reduc_stmt_info) - { - single_defuse_cycle = true; - ncopies = 1; - } - - /* Create the destination vector */ - tree vec_dest = vect_create_destination_var (phi_result, vectype_out); - - /* Get the loop-entry arguments. */ - tree vec_initial_def; - auto_vec vec_initial_defs; - if (slp_node) - { - vec_initial_defs.reserve (vec_num); - gcc_assert (slp_node == slp_node_instance->reduc_phis); - stmt_vec_info first = REDUC_GROUP_FIRST_ELEMENT (reduc_stmt_info); - tree neutral_op - = neutral_op_for_slp_reduction (slp_node, - STMT_VINFO_REDUC_CODE - (first ? first : reduc_stmt_info), - first != NULL); - get_initial_defs_for_reduction (slp_node_instance->reduc_phis, - &vec_initial_defs, vec_num, - first != NULL, neutral_op); - } - else - { - /* Get at the scalar def before the loop, that defines the initial - value of the reduction variable. */ - tree initial_def = PHI_ARG_DEF_FROM_EDGE (phi, - loop_preheader_edge (loop)); - /* Optimize: if initial_def is for REDUC_MAX smaller than the base - and we can't use zero for induc_val, use initial_def. Similarly - for REDUC_MIN and initial_def larger than the base. */ - if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) - == INTEGER_INDUC_COND_REDUCTION) - { - tree induc_val - = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info); - if (TREE_CODE (initial_def) == INTEGER_CST - && (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) - == INTEGER_INDUC_COND_REDUCTION) - && !integer_zerop (induc_val) - && (((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info) - == MAX_EXPR) - && tree_int_cst_lt (initial_def, induc_val)) - || ((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info) - == MIN_EXPR) - && tree_int_cst_lt (induc_val, initial_def)))) - { - induc_val = initial_def; - /* Communicate we used the initial_def to epilouge - generation. */ - STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info) - = NULL_TREE; - } - vec_initial_def = build_vector_from_val (vectype_out, induc_val); - } - else if (nested_cycle) - { - /* Do not use an adjustment def as that case is not supported - correctly if ncopies is not one. */ - vec_initial_def = vect_get_vec_def_for_operand (initial_def, - reduc_stmt_info); - } - else - { - tree adjustment_def = NULL_TREE; - tree *adjustment_defp = &adjustment_def; - enum tree_code code = STMT_VINFO_REDUC_CODE (reduc_stmt_info); - /* ??? For the outer loop PHI we have to do a bit of searching - to find the stmt with the code. reduc_stmt_info here is the - loop-closed PHI of the inner reduction which means we can look - at its single-arg def. */ - if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def) - { - tree def = gimple_phi_arg_def - (as_a (reduc_stmt_info->stmt), 0); - code = STMT_VINFO_REDUC_CODE - (vect_stmt_to_vectorize (loop_vinfo->lookup_def (def))); - adjustment_defp = NULL; - } - vec_initial_def - = get_initial_def_for_reduction (reduc_stmt_info, code, - initial_def, adjustment_defp); - STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (reduc_stmt_info) - = adjustment_def; - } - vec_initial_defs.create (1); - vec_initial_defs.quick_push (vec_initial_def); - } - - /* Generate the reduction PHIs upfront. */ - prev_phi_info = NULL; - for (i = 0; i < vec_num; i++) - { - tree vec_init_def = vec_initial_defs[i]; - for (j = 0; j < ncopies; j++) - { - /* Create the reduction-phi that defines the reduction - operand. */ - gphi *new_phi = create_phi_node (vec_dest, loop->header); - stmt_vec_info new_phi_info = loop_vinfo->add_stmt (new_phi); - - /* Set the loop-entry arg of the reduction-phi. */ - if (j != 0 && nested_cycle) - vec_init_def = vect_get_vec_def_for_stmt_copy (loop_vinfo, - vec_init_def); - add_phi_arg (new_phi, vec_init_def, loop_preheader_edge (loop), - UNKNOWN_LOCATION); - - /* The loop-latch arg is set in epilogue processing. */ - - if (slp_node) - SLP_TREE_VEC_STMTS (slp_node).quick_push (new_phi_info); - else - { - if (j == 0) - STMT_VINFO_VEC_STMT (stmt_info) - = *vec_stmt = new_phi_info; - else - STMT_VINFO_RELATED_STMT (prev_phi_info) = new_phi_info; - prev_phi_info = new_phi_info; - } - } - } + slp_node_instance->reduc_phis = slp_node; + STMT_VINFO_TYPE (stmt_info) = cycle_phi_info_type; return true; } @@ -6841,7 +6648,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, tree vec_dest = vect_create_destination_var (scalar_dest, vectype_out); prev_stmt_info = NULL; - prev_phi_info = NULL; if (!slp_node) { vec_oprnds0.create (1); @@ -6998,7 +6804,221 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, return true; } -/* Vectorizes LC PHIs of nested cycles (sofar). */ +/* Transform phase of a cycle PHI. */ + +bool +vect_transform_cycle_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt, + slp_tree slp_node, slp_instance slp_node_instance) +{ + tree vectype_out = STMT_VINFO_VECTYPE (stmt_info); + tree vectype_in = NULL_TREE; + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + enum vect_def_type dt; + int i; + int ncopies; + stmt_vec_info prev_phi_info; + int j; + bool nested_cycle = false; + int vec_num; + + if (nested_in_vect_loop_p (loop, stmt_info)) + { + loop = loop->inner; + nested_cycle = true; + } + + gphi *phi = as_a (stmt_info->stmt); + tree phi_result = gimple_phi_result (phi); + + if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION) + /* Leave the scalar phi in place. Note that checking + STMT_VINFO_VEC_REDUCTION_TYPE (as below) only works + for reductions involving a single statement. */ + return true; + + stmt_vec_info reduc_stmt_info = STMT_VINFO_REDUC_DEF (stmt_info); + reduc_stmt_info = vect_stmt_to_vectorize (reduc_stmt_info); + + if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) + == EXTRACT_LAST_REDUCTION) + /* Leave the scalar phi in place. */ + return true; + + if (gassign *reduc_stmt = dyn_cast (reduc_stmt_info->stmt)) + for (unsigned k = 1; k < gimple_num_ops (reduc_stmt); ++k) + { + tree op = gimple_op (reduc_stmt, k); + if (op == phi_result) + continue; + if (k == 1 && gimple_assign_rhs_code (reduc_stmt) == COND_EXPR) + continue; + bool is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt); + gcc_assert (is_simple_use); + if (dt == vect_constant_def || dt == vect_external_def) + continue; + if (!vectype_in + || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in))) + < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (op))))) + vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op)); + break; + } + /* For a nested cycle we might end up with an operation like + phi_result * phi_result. */ + if (!vectype_in) + vectype_in = STMT_VINFO_VECTYPE (stmt_info); + gcc_assert (vectype_in); + + if (slp_node) + { + /* The size vect_schedule_slp_instance computes is off for us. */ + vec_num = vect_get_num_vectors + (LOOP_VINFO_VECT_FACTOR (loop_vinfo) + * SLP_TREE_SCALAR_STMTS (slp_node).length (), vectype_in); + ncopies = 1; + } + else + { + vec_num = 1; + ncopies = vect_get_num_copies (loop_vinfo, vectype_in); + } + + /* Check whether we can use a single PHI node and accumulate + vectors to one before the backedge. */ + stmt_vec_info use_stmt_info; + if (ncopies > 1 + && STMT_VINFO_RELEVANT (reduc_stmt_info) <= vect_used_only_live + && (use_stmt_info = loop_vinfo->lookup_single_use (phi_result)) + && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) + || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) + && vect_stmt_to_vectorize (use_stmt_info) == reduc_stmt_info) + ncopies = 1; + + /* Create the destination vector */ + tree vec_dest = vect_create_destination_var (phi_result, vectype_out); + + /* Get the loop-entry arguments. */ + tree vec_initial_def; + auto_vec vec_initial_defs; + if (slp_node) + { + vec_initial_defs.reserve (vec_num); + gcc_assert (slp_node == slp_node_instance->reduc_phis); + stmt_vec_info first = REDUC_GROUP_FIRST_ELEMENT (reduc_stmt_info); + tree neutral_op + = neutral_op_for_slp_reduction (slp_node, + STMT_VINFO_REDUC_CODE + (first ? first : reduc_stmt_info), + first != NULL); + get_initial_defs_for_reduction (slp_node_instance->reduc_phis, + &vec_initial_defs, vec_num, + first != NULL, neutral_op); + } + else + { + /* Get at the scalar def before the loop, that defines the initial + value of the reduction variable. */ + tree initial_def = PHI_ARG_DEF_FROM_EDGE (phi, + loop_preheader_edge (loop)); + /* Optimize: if initial_def is for REDUC_MAX smaller than the base + and we can't use zero for induc_val, use initial_def. Similarly + for REDUC_MIN and initial_def larger than the base. */ + if (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + { + tree induc_val + = STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info); + if (TREE_CODE (initial_def) == INTEGER_CST + && (STMT_VINFO_VEC_REDUCTION_TYPE (reduc_stmt_info) + == INTEGER_INDUC_COND_REDUCTION) + && !integer_zerop (induc_val) + && (((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info) + == MAX_EXPR) + && tree_int_cst_lt (initial_def, induc_val)) + || ((STMT_VINFO_VEC_COND_REDUC_CODE (reduc_stmt_info) + == MIN_EXPR) + && tree_int_cst_lt (induc_val, initial_def)))) + { + induc_val = initial_def; + /* Communicate we used the initial_def to epilouge + generation. */ + STMT_VINFO_VEC_INDUC_COND_INITIAL_VAL (reduc_stmt_info) + = NULL_TREE; + } + vec_initial_def = build_vector_from_val (vectype_out, induc_val); + } + else if (nested_cycle) + { + /* Do not use an adjustment def as that case is not supported + correctly if ncopies is not one. */ + vec_initial_def = vect_get_vec_def_for_operand (initial_def, + reduc_stmt_info); + } + else + { + tree adjustment_def = NULL_TREE; + tree *adjustment_defp = &adjustment_def; + enum tree_code code = STMT_VINFO_REDUC_CODE (reduc_stmt_info); + /* ??? For the outer loop PHI we have to do a bit of searching + to find the stmt with the code. reduc_stmt_info here is the + loop-closed PHI of the inner reduction which means we can look + at its single-arg def. */ + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def) + { + tree def = gimple_phi_arg_def + (as_a (reduc_stmt_info->stmt), 0); + code = STMT_VINFO_REDUC_CODE + (vect_stmt_to_vectorize (loop_vinfo->lookup_def (def))); + adjustment_defp = NULL; + } + vec_initial_def + = get_initial_def_for_reduction (reduc_stmt_info, code, + initial_def, adjustment_defp); + STMT_VINFO_REDUC_EPILOGUE_ADJUSTMENT (reduc_stmt_info) + = adjustment_def; + } + vec_initial_defs.create (1); + vec_initial_defs.quick_push (vec_initial_def); + } + + /* Generate the reduction PHIs upfront. */ + prev_phi_info = NULL; + for (i = 0; i < vec_num; i++) + { + tree vec_init_def = vec_initial_defs[i]; + for (j = 0; j < ncopies; j++) + { + /* Create the reduction-phi that defines the reduction + operand. */ + gphi *new_phi = create_phi_node (vec_dest, loop->header); + stmt_vec_info new_phi_info = loop_vinfo->add_stmt (new_phi); + + /* Set the loop-entry arg of the reduction-phi. */ + if (j != 0 && nested_cycle) + vec_init_def = vect_get_vec_def_for_stmt_copy (loop_vinfo, + vec_init_def); + add_phi_arg (new_phi, vec_init_def, loop_preheader_edge (loop), + UNKNOWN_LOCATION); + + /* The loop-latch arg is set in epilogue processing. */ + + if (slp_node) + SLP_TREE_VEC_STMTS (slp_node).quick_push (new_phi_info); + else + { + if (j == 0) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_phi_info; + else + STMT_VINFO_RELATED_STMT (prev_phi_info) = new_phi_info; + prev_phi_info = new_phi_info; + } + } + } + + return true; +} + +/* Vectorizes LC PHIs. */ bool vectorizable_lc_phi (stmt_vec_info stmt_info, stmt_vec_info *vec_stmt, diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 7fcd2fa..ddc2f74 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -10824,6 +10824,12 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, gcc_assert (done); break; + case cycle_phi_info_type: + done = vect_transform_cycle_phi (stmt_info, &vec_stmt, slp_node, + slp_node_instance); + gcc_assert (done); + break; + case lc_phi_info_type: done = vectorizable_lc_phi (stmt_info, &vec_stmt, slp_node); gcc_assert (done); diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 462a968..eae9d4c 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -694,6 +694,7 @@ enum stmt_vec_info_type { type_promotion_vec_info_type, type_demotion_vec_info_type, type_conversion_vec_info_type, + cycle_phi_info_type, lc_phi_info_type, loop_exit_ctrl_vec_info_type }; @@ -1658,6 +1659,8 @@ extern bool vectorizable_reduction (stmt_vec_info, gimple_stmt_iterator *, extern bool vectorizable_induction (stmt_vec_info, gimple_stmt_iterator *, stmt_vec_info *, slp_tree, stmt_vector_for_cost *); +extern bool vect_transform_cycle_phi (stmt_vec_info, stmt_vec_info *, + slp_tree, slp_instance); extern bool vectorizable_lc_phi (stmt_vec_info, stmt_vec_info *, slp_tree); extern bool vect_worthwhile_without_simd_p (vec_info *, tree_code); extern int vect_get_known_peeling_cost (loop_vec_info, int, int *, -- cgit v1.1 From 9ff9a0a5e6edd8729f559bf86ca06f781c4da246 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 2 Oct 2019 12:18:50 +0200 Subject: re PR tree-optimization/91940 (__builtin_bswap16 loop optimization) PR tree-optimization/91940 * tree-vect-patterns.c: Include tree-vector-builder.h and vec-perm-indices.h. (vect_recog_rotate_pattern): Also handle __builtin_bswap16, either by unpromoting the argument back to uint16_t, or by converting into a rotate, or into shifts plus ior. * gcc.dg/vect/vect-bswap16.c: Add -msse4 on x86, run on all targets, expect vectorized 1 loops message on both vect_bswap and sse4_runtime targets. * gcc.dg/vect/vect-bswap16a.c: New test. From-SVN: r276442 --- gcc/ChangeLog | 9 ++ gcc/testsuite/ChangeLog | 8 ++ gcc/testsuite/gcc.dg/vect/vect-bswap16.c | 4 +- gcc/testsuite/gcc.dg/vect/vect-bswap16a.c | 5 + gcc/tree-vect-patterns.c | 148 +++++++++++++++++++++++++++--- 5 files changed, 157 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-bswap16a.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b7830a4..47093ed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2019-10-02 Jakub Jelinek + + PR tree-optimization/91940 + * tree-vect-patterns.c: Include tree-vector-builder.h and + vec-perm-indices.h. + (vect_recog_rotate_pattern): Also handle __builtin_bswap16, either by + unpromoting the argument back to uint16_t, or by converting into a + rotate, or into shifts plus ior. + 2019-10-02 Richard Biener * tree-vectorizer.h (stmt_vec_info_type::cycle_phi_info_type): diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 834ee45..4cb4303 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-10-02 Jakub Jelinek + + PR tree-optimization/91940 + * gcc.dg/vect/vect-bswap16.c: Add -msse4 on x86, run on all targets, + expect vectorized 1 loops message on both vect_bswap and sse4_runtime + targets. + * gcc.dg/vect/vect-bswap16a.c: New test. + 2019-10-02 Joseph Myers * gcc.dg/asm-scope-1.c, gcc.dg/cpp/c11-scope-1.c, diff --git a/gcc/testsuite/gcc.dg/vect/vect-bswap16.c b/gcc/testsuite/gcc.dg/vect/vect-bswap16.c index 3c98b07..d29b352 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bswap16.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bswap16.c @@ -1,4 +1,4 @@ -/* { dg-require-effective-target vect_bswap } */ +/* { dg-additional-options "-msse4" { target sse4_runtime } } */ #include "tree-vect.h" @@ -39,4 +39,4 @@ main (void) return 0; } -/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { vect_bswap || sse4_runtime } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-bswap16a.c b/gcc/testsuite/gcc.dg/vect/vect-bswap16a.c new file mode 100644 index 0000000..730dc4e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-bswap16a.c @@ -0,0 +1,5 @@ +/* { dg-additional-options "-msse2 -mno-sse3" { target sse2_runtime } } */ + +#include "vect-bswap16.c" + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { vect_shift } } } } */ diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 4dfebbe..09db74b 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -46,6 +46,8 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "omp-simd-clone.h" #include "predict.h" +#include "tree-vector-builder.h" +#include "vec-perm-indices.h" /* Return true if we have a useful VR_RANGE range for VAR, storing it in *MIN_VALUE and *MAX_VALUE if so. Note the range in the dump files. */ @@ -2168,24 +2170,107 @@ vect_recog_rotate_pattern (stmt_vec_info stmt_vinfo, tree *type_out) enum vect_def_type dt; optab optab1, optab2; edge ext_def = NULL; + bool bswap16_p = false; - if (!is_gimple_assign (last_stmt)) - return NULL; + if (is_gimple_assign (last_stmt)) + { + rhs_code = gimple_assign_rhs_code (last_stmt); + switch (rhs_code) + { + case LROTATE_EXPR: + case RROTATE_EXPR: + break; + default: + return NULL; + } - rhs_code = gimple_assign_rhs_code (last_stmt); - switch (rhs_code) + lhs = gimple_assign_lhs (last_stmt); + oprnd0 = gimple_assign_rhs1 (last_stmt); + type = TREE_TYPE (oprnd0); + oprnd1 = gimple_assign_rhs2 (last_stmt); + } + else if (gimple_call_builtin_p (last_stmt, BUILT_IN_BSWAP16)) { - case LROTATE_EXPR: - case RROTATE_EXPR: - break; - default: - return NULL; + /* __builtin_bswap16 (x) is another form of x r>> 8. + The vectorizer has bswap support, but only if the argument isn't + promoted. */ + lhs = gimple_call_lhs (last_stmt); + oprnd0 = gimple_call_arg (last_stmt, 0); + type = TREE_TYPE (oprnd0); + if (TYPE_PRECISION (TREE_TYPE (lhs)) != 16 + || TYPE_PRECISION (type) <= 16 + || TREE_CODE (oprnd0) != SSA_NAME + || BITS_PER_UNIT != 8 + || !TYPE_UNSIGNED (TREE_TYPE (lhs))) + return NULL; + + stmt_vec_info def_stmt_info; + if (!vect_is_simple_use (oprnd0, vinfo, &dt, &def_stmt_info, &def_stmt)) + return NULL; + + if (dt != vect_internal_def) + return NULL; + + if (gimple_assign_cast_p (def_stmt)) + { + def = gimple_assign_rhs1 (def_stmt); + if (INTEGRAL_TYPE_P (TREE_TYPE (def)) + && TYPE_PRECISION (TREE_TYPE (def)) == 16) + oprnd0 = def; + } + + type = TREE_TYPE (lhs); + vectype = get_vectype_for_scalar_type (type); + if (vectype == NULL_TREE) + return NULL; + + if (tree char_vectype = get_same_sized_vectype (char_type_node, vectype)) + { + /* The encoding uses one stepped pattern for each byte in the + 16-bit word. */ + vec_perm_builder elts (TYPE_VECTOR_SUBPARTS (char_vectype), 2, 3); + for (unsigned i = 0; i < 3; ++i) + for (unsigned j = 0; j < 2; ++j) + elts.quick_push ((i + 1) * 2 - j - 1); + + vec_perm_indices indices (elts, 1, + TYPE_VECTOR_SUBPARTS (char_vectype)); + if (can_vec_perm_const_p (TYPE_MODE (char_vectype), indices)) + { + /* vectorizable_bswap can handle the __builtin_bswap16 if we + undo the argument promotion. */ + if (!useless_type_conversion_p (type, TREE_TYPE (oprnd0))) + { + def = vect_recog_temp_ssa_var (type, NULL); + def_stmt = gimple_build_assign (def, NOP_EXPR, oprnd0); + append_pattern_def_seq (stmt_vinfo, def_stmt); + oprnd0 = def; + } + + /* Pattern detected. */ + vect_pattern_detected ("vect_recog_rotate_pattern", last_stmt); + + *type_out = vectype; + + /* Pattern supported. Create a stmt to be used to replace the + pattern, with the unpromoted argument. */ + var = vect_recog_temp_ssa_var (type, NULL); + pattern_stmt = gimple_build_call (gimple_call_fndecl (last_stmt), + 1, oprnd0); + gimple_call_set_lhs (pattern_stmt, var); + gimple_call_set_fntype (as_a (pattern_stmt), + gimple_call_fntype (last_stmt)); + return pattern_stmt; + } + } + + oprnd1 = build_int_cst (integer_type_node, 8); + rhs_code = LROTATE_EXPR; + bswap16_p = true; } + else + return NULL; - lhs = gimple_assign_lhs (last_stmt); - oprnd0 = gimple_assign_rhs1 (last_stmt); - type = TREE_TYPE (oprnd0); - oprnd1 = gimple_assign_rhs2 (last_stmt); if (TREE_CODE (oprnd0) != SSA_NAME || TYPE_PRECISION (TREE_TYPE (lhs)) != TYPE_PRECISION (type) || !INTEGRAL_TYPE_P (type) @@ -2210,14 +2295,39 @@ vect_recog_rotate_pattern (stmt_vec_info stmt_vinfo, tree *type_out) optab1 = optab_for_tree_code (rhs_code, vectype, optab_vector); if (optab1 && optab_handler (optab1, TYPE_MODE (vectype)) != CODE_FOR_nothing) - return NULL; + { + use_rotate: + if (bswap16_p) + { + if (!useless_type_conversion_p (type, TREE_TYPE (oprnd0))) + { + def = vect_recog_temp_ssa_var (type, NULL); + def_stmt = gimple_build_assign (def, NOP_EXPR, oprnd0); + append_pattern_def_seq (stmt_vinfo, def_stmt); + oprnd0 = def; + } + + /* Pattern detected. */ + vect_pattern_detected ("vect_recog_rotate_pattern", last_stmt); + + *type_out = vectype; + + /* Pattern supported. Create a stmt to be used to replace the + pattern. */ + var = vect_recog_temp_ssa_var (type, NULL); + pattern_stmt = gimple_build_assign (var, LROTATE_EXPR, oprnd0, + oprnd1); + return pattern_stmt; + } + return NULL; + } if (is_a (vinfo) || dt != vect_internal_def) { optab2 = optab_for_tree_code (rhs_code, vectype, optab_scalar); if (optab2 && optab_handler (optab2, TYPE_MODE (vectype)) != CODE_FOR_nothing) - return NULL; + goto use_rotate; } /* If vector/vector or vector/scalar shifts aren't supported by the target, @@ -2242,6 +2352,14 @@ vect_recog_rotate_pattern (stmt_vec_info stmt_vinfo, tree *type_out) *type_out = vectype; + if (bswap16_p && !useless_type_conversion_p (type, TREE_TYPE (oprnd0))) + { + def = vect_recog_temp_ssa_var (type, NULL); + def_stmt = gimple_build_assign (def, NOP_EXPR, oprnd0); + append_pattern_def_seq (stmt_vinfo, def_stmt); + oprnd0 = def; + } + if (dt == vect_external_def && TREE_CODE (oprnd1) == SSA_NAME) ext_def = vect_get_external_def_edge (vinfo, oprnd1); -- cgit v1.1 From 73a28634098cb1aba4a1773e62b6387af120dd9e Mon Sep 17 00:00:00 2001 From: Kwok Cheung Yeung Date: Wed, 2 Oct 2019 10:31:02 +0000 Subject: f95-lang.c (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Define to gfc_omp_is_optional_argument. 2019-10-02 Kwok Cheung Yeung gcc/fortran/ * f95-lang.c (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Define to gfc_omp_is_optional_argument. * trans-decl.c (create_function_arglist): Set GFC_DECL_OPTIONAL_ARGUMENT in the generated decl if the parameter is optional. * trans-openmp.c (gfc_omp_is_optional_argument): New. (gfc_omp_privatize_by_reference): Return true if the decl is an optional pass-by-reference argument. * trans.h (gfc_omp_is_optional_argument): New declaration. (lang_decl): Add new optional_arg field. (GFC_DECL_OPTIONAL_ARGUMENT): New macro. gcc/ * langhooks-def.h (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Default to false. (LANG_HOOKS_DECLS): Add LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT. * langhooks.h (omp_is_optional_argument): New hook. * omp-general.c (omp_is_optional_argument): New. * omp-general.h (omp_is_optional_argument): New declaration. * omp-low.c (lower_omp_target): Create temporary for received value and take the address for new_var if the original variable was a DECL_BY_REFERENCE. Use size of referenced object when a pass-by-reference optional argument used as argument to firstprivate. From-SVN: r276444 --- gcc/ChangeLog | 13 +++++++++++++ gcc/fortran/ChangeLog | 14 ++++++++++++++ gcc/fortran/f95-lang.c | 2 ++ gcc/fortran/trans-decl.c | 5 +++++ gcc/fortran/trans-openmp.c | 13 +++++++++++++ gcc/fortran/trans.h | 4 ++++ gcc/langhooks-def.h | 2 ++ gcc/langhooks.h | 3 +++ gcc/omp-general.c | 8 ++++++++ gcc/omp-general.h | 1 + gcc/omp-low.c | 3 ++- 11 files changed, 67 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 47093ed..7e46703 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2019-10-02 Kwok Cheung Yeung + + * langhooks-def.h (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Default to + false. + (LANG_HOOKS_DECLS): Add LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT. + * langhooks.h (omp_is_optional_argument): New hook. + * omp-general.c (omp_is_optional_argument): New. + * omp-general.h (omp_is_optional_argument): New declaration. + * omp-low.c (lower_omp_target): Create temporary for received value + and take the address for new_var if the original variable was a + DECL_BY_REFERENCE. Use size of referenced object when a + pass-by-reference optional argument used as argument to firstprivate. + 2019-10-02 Jakub Jelinek PR tree-optimization/91940 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 63ee15b..d8c891f 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,17 @@ +2019-10-02 Kwok Cheung Yeung + + * f95-lang.c (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Define to + gfc_omp_is_optional_argument. + * trans-decl.c (create_function_arglist): Set + GFC_DECL_OPTIONAL_ARGUMENT in the generated decl if the parameter is + optional. + * trans-openmp.c (gfc_omp_is_optional_argument): New. + (gfc_omp_privatize_by_reference): Return true if the decl is an + optional pass-by-reference argument. + * trans.h (gfc_omp_is_optional_argument): New declaration. + (lang_decl): Add new optional_arg field. + (GFC_DECL_OPTIONAL_ARGUMENT): New macro. + 2019-10-01 David Malcolm * error.c (gfc_diagnostic_starter): Clear the prefix before diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 6b9f490..2467cd9 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -113,6 +113,7 @@ static const struct attribute_spec gfc_attribute_table[] = #undef LANG_HOOKS_TYPE_FOR_MODE #undef LANG_HOOKS_TYPE_FOR_SIZE #undef LANG_HOOKS_INIT_TS +#undef LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE #undef LANG_HOOKS_OMP_PREDETERMINED_SHARING #undef LANG_HOOKS_OMP_REPORT_DECL @@ -145,6 +146,7 @@ static const struct attribute_spec gfc_attribute_table[] = #define LANG_HOOKS_TYPE_FOR_MODE gfc_type_for_mode #define LANG_HOOKS_TYPE_FOR_SIZE gfc_type_for_size #define LANG_HOOKS_INIT_TS gfc_init_ts +#define LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT gfc_omp_is_optional_argument #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE gfc_omp_privatize_by_reference #define LANG_HOOKS_OMP_PREDETERMINED_SHARING gfc_omp_predetermined_sharing #define LANG_HOOKS_OMP_REPORT_DECL gfc_omp_report_decl diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index c2c5d9d..a113f08 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -2687,6 +2687,11 @@ create_function_arglist (gfc_symbol * sym) && (!f->sym->attr.proc_pointer && f->sym->attr.flavor != FL_PROCEDURE)) DECL_BY_REFERENCE (parm) = 1; + if (f->sym->attr.optional) + { + gfc_allocate_lang_decl (parm); + GFC_DECL_OPTIONAL_ARGUMENT (parm) = 1; + } gfc_finish_decl (parm); gfc_finish_decl_attrs (parm, &f->sym->attr); diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index b4c77ae..88ecc33 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -47,6 +47,15 @@ along with GCC; see the file COPYING3. If not see int ompws_flags; +/* True if OpenMP should treat this DECL as an optional argument. */ + +bool +gfc_omp_is_optional_argument (const_tree decl) +{ + return (TREE_CODE (decl) == PARM_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_OPTIONAL_ARGUMENT (decl)); +} + /* True if OpenMP should privatize what this DECL points to rather than the DECL itself. */ @@ -59,6 +68,10 @@ gfc_omp_privatize_by_reference (const_tree decl) && (!DECL_ARTIFICIAL (decl) || TREE_CODE (decl) == PARM_DECL)) return true; + if (TREE_CODE (type) == POINTER_TYPE + && gfc_omp_is_optional_argument (decl)) + return true; + if (TREE_CODE (type) == POINTER_TYPE) { /* Array POINTER/ALLOCATABLE have aggregate types, all user variables diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 6ebb71d..405e88d 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -786,6 +786,7 @@ struct array_descr_info; bool gfc_get_array_descr_info (const_tree, struct array_descr_info *); /* In trans-openmp.c */ +bool gfc_omp_is_optional_argument (const_tree); bool gfc_omp_privatize_by_reference (const_tree); enum omp_clause_default_kind gfc_omp_predetermined_sharing (tree); tree gfc_omp_report_decl (tree); @@ -999,6 +1000,7 @@ struct GTY(()) lang_decl { tree token, caf_offset; unsigned int scalar_allocatable : 1; unsigned int scalar_pointer : 1; + unsigned int optional_arg : 1; }; @@ -1013,6 +1015,8 @@ struct GTY(()) lang_decl { (DECL_LANG_SPECIFIC (node)->scalar_allocatable) #define GFC_DECL_SCALAR_POINTER(node) \ (DECL_LANG_SPECIFIC (node)->scalar_pointer) +#define GFC_DECL_OPTIONAL_ARGUMENT(node) \ + (DECL_LANG_SPECIFIC (node)->optional_arg) #define GFC_DECL_GET_SCALAR_ALLOCATABLE(node) \ (DECL_LANG_SPECIFIC (node) ? GFC_DECL_SCALAR_ALLOCATABLE (node) : 0) #define GFC_DECL_GET_SCALAR_POINTER(node) \ diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index a059841..55d5fe0 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -236,6 +236,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree); #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL lhd_warn_unused_global_decl #define LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS NULL #define LANG_HOOKS_DECL_OK_FOR_SIBCALL lhd_decl_ok_for_sibcall +#define LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT hook_bool_const_tree_false #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE hook_bool_const_tree_false #define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing #define LANG_HOOKS_OMP_REPORT_DECL lhd_pass_through_t @@ -261,6 +262,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree); LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \ LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \ LANG_HOOKS_DECL_OK_FOR_SIBCALL, \ + LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT, \ LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE, \ LANG_HOOKS_OMP_PREDETERMINED_SHARING, \ LANG_HOOKS_OMP_REPORT_DECL, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index a45579b..9d2714a 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -222,6 +222,9 @@ struct lang_hooks_for_decls /* True if this decl may be called via a sibcall. */ bool (*ok_for_sibcall) (const_tree); + /* True if OpenMP should treat DECL as a Fortran optional argument. */ + bool (*omp_is_optional_argument) (const_tree); + /* True if OpenMP should privatize what this DECL points to rather than the DECL itself. */ bool (*omp_privatize_by_reference) (const_tree); diff --git a/gcc/omp-general.c b/gcc/omp-general.c index 66be94f..5ef6e25 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -48,6 +48,14 @@ omp_find_clause (tree clauses, enum omp_clause_code kind) return NULL_TREE; } +/* Return true if DECL is a Fortran optional argument. */ + +bool +omp_is_optional_argument (tree decl) +{ + return lang_hooks.decls.omp_is_optional_argument (decl); +} + /* Return true if DECL is a reference type. */ bool diff --git a/gcc/omp-general.h b/gcc/omp-general.h index 80d42af..bbaa7b1 100644 --- a/gcc/omp-general.h +++ b/gcc/omp-general.h @@ -73,6 +73,7 @@ struct omp_for_data #define OACC_FN_ATTRIB "oacc function" extern tree omp_find_clause (tree clauses, enum omp_clause_code kind); +extern bool omp_is_optional_argument (tree decl); extern bool omp_is_reference (tree decl); extern void omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2, tree v, tree step); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 5db182c..a0e5041 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -11395,7 +11395,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) { gcc_assert (is_gimple_omp_oacc (ctx->stmt)); if (omp_is_reference (new_var) - && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE) + && (TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE + || DECL_BY_REFERENCE (var))) { /* Create a local object to hold the instance value. */ -- cgit v1.1 From 67c259509c0ab6475a27e871afdf12434ac34d48 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 2 Oct 2019 10:33:42 +0000 Subject: Fix omp target issue with Fortran optional arguments gcc/ * omp-low.c (lower_omp_target): Dereference optional argument to work with the right pointer. gcc/testsuite/ * libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-1.f90: New. From-SVN: r276445 --- gcc/ChangeLog | 5 +++++ gcc/omp-low.c | 2 +- gcc/testsuite/ChangeLog | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7e46703..6f577c3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Tobias Burnus + + * omp-low.c (lower_omp_target): Dereference optional argument + to work with the right pointer. + 2019-10-02 Kwok Cheung Yeung * langhooks-def.h (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Default to diff --git a/gcc/omp-low.c b/gcc/omp-low.c index a0e5041..ca7dfdb 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -11870,7 +11870,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) var = build_fold_addr_expr (var); else { - if (omp_is_reference (ovar)) + if (omp_is_reference (ovar) || omp_is_optional_argument (ovar)) { type = TREE_TYPE (type); if (TREE_CODE (type) != ARRAY_TYPE diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4cb4303..d95e6e7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-02 Tobias Burnus + + * libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-1.f90: New. + 2019-10-02 Jakub Jelinek PR tree-optimization/91940 -- cgit v1.1 From 4aef466788a964688458f4e633398b140ad89e24 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 2 Oct 2019 10:41:59 +0000 Subject: Fix coding style comment, missed in last commit * trans-openmp.c (gfc_omp_is_optional_argument): Fix coding style. From-SVN: r276446 --- gcc/fortran/ChangeLog | 5 +++++ gcc/fortran/trans-openmp.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d8c891f..af0a0ac 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Tobias Burnus + + * trans-openmp.c (gfc_omp_is_optional_argument): Fix coding + style. + 2019-10-02 Kwok Cheung Yeung * f95-lang.c (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Define to diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 88ecc33..f83bab4 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -52,7 +52,8 @@ int ompws_flags; bool gfc_omp_is_optional_argument (const_tree decl) { - return (TREE_CODE (decl) == PARM_DECL && DECL_LANG_SPECIFIC (decl) + return (TREE_CODE (decl) == PARM_DECL + && DECL_LANG_SPECIFIC (decl) && GFC_DECL_OPTIONAL_ARGUMENT (decl)); } -- cgit v1.1 From ba045eb2297e8e51c7e99c2b2650f32cb642d209 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 2 Oct 2019 10:50:23 +0000 Subject: Improve OMP/ACC error diagnostic in Fortran gcc/fortran/ * openmp.c (gfc_match_omp_clauses): Show a clause-parsing error if none was rised before. * parse.c (matcha, matcho): If error occurred after OpenMP/OpenACC directive matched, do not try other directives. gcc/testsuite/ * gfortran.dg/goacc/asyncwait-1.f95: Handle new error message. * gfortran.dg/goacc/asyncwait-2.f95: Likewise * gfortran.dg/goacc/asyncwait-3.f95: Likewise * gfortran.dg/goacc/asyncwait-4.f95: Likewise * gfortran.dg/goacc/default-2.f: Likewise * gfortran.dg/goacc/enter-exit-data.f95: Likewise * gfortran.dg/goacc/if.f95: Likewise * gfortran.dg/goacc/list.f95: Likewise * gfortran.dg/goacc/literal.f95: Likewise * gfortran.dg/goacc/loop-2-kernels-tile.f: Likewise95 * gfortran.dg/goacc/loop-2-parallel-tile.f95: Likewise * gfortran.dg/goacc/loop-7.f95: Likewise * gfortran.dg/goacc/parallel-kernels-cla: Likewiseuses.f95 * gfortran.dg/goacc/routine-6.f90: Likewise * gfortran.dg/goacc/several-directives.f95: Likewise * gfortran.dg/goacc/sie.f95: Likewise * gfortran.dg/goacc/tile-1.f90: Likewise * gfortran.dg/goacc/update-if_present-2.: Likewisef90 * gfortran.dg/gomp/declare-simd-1.f90: Likewise * gfortran.dg/gomp/pr29759.f90: Likewise From-SVN: r276447 --- gcc/fortran/ChangeLog | 7 ++++ gcc/fortran/openmp.c | 2 + gcc/fortran/parse.c | 16 +++++++- gcc/testsuite/ChangeLog | 23 +++++++++++ gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 | 12 +++--- gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 | 4 +- gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 | 4 +- gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 | 20 +++++----- gcc/testsuite/gfortran.dg/goacc/default-2.f | 44 +++++++++++----------- .../gfortran.dg/goacc/enter-exit-data.f95 | 4 +- gcc/testsuite/gfortran.dg/goacc/if.f95 | 14 +++---- gcc/testsuite/gfortran.dg/goacc/list.f95 | 6 +-- gcc/testsuite/gfortran.dg/goacc/literal.f95 | 2 +- .../gfortran.dg/goacc/loop-2-kernels-tile.f95 | 4 +- .../gfortran.dg/goacc/loop-2-parallel-tile.f95 | 4 +- gcc/testsuite/gfortran.dg/goacc/loop-7.f95 | 20 +++++----- .../gfortran.dg/goacc/parallel-kernels-clauses.f95 | 28 +++++++------- gcc/testsuite/gfortran.dg/goacc/routine-6.f90 | 2 +- .../gfortran.dg/goacc/several-directives.f95 | 4 +- gcc/testsuite/gfortran.dg/goacc/sie.f95 | 12 +++--- gcc/testsuite/gfortran.dg/goacc/tile-1.f90 | 8 ++-- .../gfortran.dg/goacc/update-if_present-2.f90 | 16 ++++---- gcc/testsuite/gfortran.dg/gomp/declare-simd-1.f90 | 2 +- gcc/testsuite/gfortran.dg/gomp/pr29759.f90 | 8 ++-- 24 files changed, 155 insertions(+), 111 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index af0a0ac..075f3b9 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,12 @@ 2019-10-02 Tobias Burnus + * openmp.c (gfc_match_omp_clauses): Show a clause-parsing + error if none was rised before. + * parse.c (matcha, matcho): If error occurred after + OpenMP/OpenACC directive matched, do not try other directives. + +2019-10-02 Tobias Burnus + * trans-openmp.c (gfc_omp_is_optional_argument): Fix coding style. diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index bda7f28..2beac3d 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -1922,6 +1922,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if (gfc_match_omp_eos () != MATCH_YES) { + if (!gfc_error_flag_test ()) + gfc_error ("Failed to match clause at %C"); gfc_free_omp_clauses (c); return MATCH_ERROR; } diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 5bd04b8..4d34345 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -609,13 +609,18 @@ decode_statement (void) /* Like match and if spec_only, goto do_spec_only without actually matching. */ +/* If the directive matched but the clauses failed, do not start + matching the next directive in the same switch statement. */ #define matcha(keyword, subr, st) \ do { \ + match m2; \ if (spec_only && gfc_match (keyword) == MATCH_YES) \ goto do_spec_only; \ - else if (match_word (keyword, subr, &old_locus) \ + else if ((m2 = match_word (keyword, subr, &old_locus)) \ == MATCH_YES) \ return st; \ + else if (m2 == MATCH_ERROR) \ + goto error_handling; \ else \ undo_new_statement (); \ } while (0) @@ -711,6 +716,7 @@ decode_oacc_directive (void) /* Directive not found or stored an error message. Check and give up. */ + error_handling: if (gfc_error_check () == 0) gfc_error_now ("Unclassifiable OpenACC directive at %C"); @@ -746,18 +752,23 @@ decode_oacc_directive (void) /* Like match, but don't match anything if not -fopenmp and if spec_only, goto do_spec_only without actually matching. */ +/* If the directive matched but the clauses failed, do not start + matching the next directive in the same switch statement. */ #define matcho(keyword, subr, st) \ do { \ + match m2; \ if (!flag_openmp) \ ; \ else if (spec_only && gfc_match (keyword) == MATCH_YES) \ goto do_spec_only; \ - else if (match_word (keyword, subr, &old_locus) \ + else if ((m2 = match_word (keyword, subr, &old_locus)) \ == MATCH_YES) \ { \ ret = st; \ goto finish; \ } \ + else if (m2 == MATCH_ERROR) \ + goto error_handling; \ else \ undo_new_statement (); \ } while (0) @@ -1030,6 +1041,7 @@ decode_omp_directive (void) not -fopenmp and simd_matched is false, i.e. if a directive other than one marked with match has been seen. */ + error_handling: if (flag_openmp || simd_matched) { if (!gfc_error_check ()) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d95e6e7..a5a1cf3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,28 @@ 2019-10-02 Tobias Burnus + * gfortran.dg/goacc/asyncwait-1.f95: Handle new error message. + * gfortran.dg/goacc/asyncwait-2.f95: Likewise. + * gfortran.dg/goacc/asyncwait-3.f95: Likewise. + * gfortran.dg/goacc/asyncwait-4.f95: Likewise. + * gfortran.dg/goacc/default-2.f: Likewise. + * gfortran.dg/goacc/enter-exit-data.f95: Likewise. + * gfortran.dg/goacc/if.f95: Likewise. + * gfortran.dg/goacc/list.f95: Likewise. + * gfortran.dg/goacc/literal.f95: Likewise. + * gfortran.dg/goacc/loop-2-kernels-tile.f95: Likewise. + * gfortran.dg/goacc/loop-2-parallel-tile.f95: Likewise. + * gfortran.dg/goacc/loop-7.f95: Likewise. + * gfortran.dg/goacc/parallel-kernels-clauses.f95: Likewise. + * gfortran.dg/goacc/routine-6.f90: Likewise. + * gfortran.dg/goacc/several-directives.f95: Likewise. + * gfortran.dg/goacc/sie.f95: Likewise. + * gfortran.dg/goacc/tile-1.f90: Likewise. + * gfortran.dg/goacc/update-if_present-2.f90: Likewise. + * gfortran.dg/gomp/declare-simd-1.f90: Likewise. + * gfortran.dg/gomp/pr29759.f90: Likewise. + +2019-10-02 Tobias Burnus + * libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-1.f90: New. 2019-10-02 Jakub Jelinek diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 index d630d38..c8a72fa 100644 --- a/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 @@ -11,13 +11,13 @@ program asyncwait a(:) = 3.0 b(:) = 0.0 - !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1 2) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1 2) ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,) ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do @@ -29,25 +29,25 @@ program asyncwait end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2,) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2,) ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2 3) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2 3) ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2,,) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2,,) ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1 ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1 ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 index fe4e4ee..3663c9b 100644 --- a/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 @@ -83,13 +83,13 @@ program asyncwait end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) waitasync ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) waitasync ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } - !$acc parallel copyin (a(1:N)) copy (b(1:N)) asyncwait ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel copyin (a(1:N)) copy (b(1:N)) asyncwait ! { dg-error "Failed to match clause" } do i = 1, N b(i) = a(i) end do diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 index 5c55c36..815928a 100644 --- a/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 @@ -33,9 +33,9 @@ program asyncwait !$acc wait (1.0) ! { dg-error "WAIT clause at \\\(1\\\) requires a scalar INTEGER expression" } - !$acc wait 1 ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait 1 ! { dg-error "Failed to match clause" } - !$acc wait N ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait N ! { dg-error "Failed to match clause" } !$acc wait (1) end program asyncwait diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 index df31154..057d06b 100644 --- a/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 @@ -11,21 +11,21 @@ program asyncwait a(:) = 3.0 b(:) = 0.0 - !$acc wait async (1 2) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1 2) ! { dg-error "Failed to match clause" } - !$acc wait async (1,) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1,) ! { dg-error "Failed to match clause" } !$acc wait async (,1) ! { dg-error "Invalid character in name" } - !$acc wait async (1, 2, ) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1, 2, ) ! { dg-error "Failed to match clause" } - !$acc wait async (1, 2, ,) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1, 2, ,) ! { dg-error "Failed to match clause" } - !$acc wait async (1 ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1 ! { dg-error "Failed to match clause" } - !$acc wait async (1, *) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1, *) ! { dg-error "Failed to match clause" } - !$acc wait async (1, a) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async (1, a) ! { dg-error "Failed to match clause" } !$acc wait async (a) ! { dg-error "ASYNC clause at \\\(1\\\) requires a scalar INTEGER expression" } @@ -33,9 +33,9 @@ program asyncwait !$acc wait async (1.0) ! { dg-error "ASYNC clause at \\\(1\\\) requires a scalar INTEGER expression" } - !$acc wait async 1 ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait async 1 ! { dg-error "Failed to match clause" } - !$acc waitasync ! { dg-error "Unclassifiable OpenACC directive" } + !$acc waitasync ! { dg-error "Failed to match clause" } - !$acc wait,async ! { dg-error "Unclassifiable OpenACC directive" } + !$acc wait,async ! { dg-error "Failed to match clause" } end program asyncwait diff --git a/gcc/testsuite/gfortran.dg/goacc/default-2.f b/gcc/testsuite/gfortran.dg/goacc/default-2.f index 8f88688..ea82388 100644 --- a/gcc/testsuite/gfortran.dg/goacc/default-2.f +++ b/gcc/testsuite/gfortran.dg/goacc/default-2.f @@ -3,58 +3,58 @@ SUBROUTINE F1 IMPLICIT NONE -!$ACC KERNELS DEFAULT ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT ( ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT ( ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT ( ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT ( ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (, ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (, ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (, ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (, ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT () ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT () ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT () ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT () ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (,) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (,) ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (,) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (,) ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (FIRSTPRIVATE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (FIRSTPRIVATE) ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (FIRSTPRIVATE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (FIRSTPRIVATE) ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (PRIVATE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (PRIVATE) ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (PRIVATE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (PRIVATE) ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (SHARED) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (SHARED) ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (SHARED) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (SHARED) ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (NONE ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (NONE ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (NONE ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (NONE ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (NONE NONE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (NONE NONE) ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (NONE NONE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (NONE NONE) ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } -!$ACC KERNELS DEFAULT (NONE, NONE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC KERNELS DEFAULT (NONE, NONE) ! { dg-error "Failed to match clause" } !$ACC END KERNELS ! { dg-error "Unexpected" } -!$ACC PARALLEL DEFAULT (NONE, NONE) ! { dg-error "Unclassifiable OpenACC directive" } +!$ACC PARALLEL DEFAULT (NONE, NONE) ! { dg-error "Failed to match clause" } !$ACC END PARALLEL ! { dg-error "Unexpected" } END SUBROUTINE F1 diff --git a/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 b/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 index 805459c..a414df8 100644 --- a/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 @@ -28,7 +28,7 @@ contains !$acc enter data !$acc enter data if (.false.) !$acc enter data if (l) - !$acc enter data if (.false.) if (l) ! { dg-error "Unclassifiable" } + !$acc enter data if (.false.) if (l) ! { dg-error "Failed to match clause" } !$acc enter data if (i) ! { dg-error "LOGICAL" } !$acc enter data if (1) ! { dg-error "LOGICAL" } !$acc enter data if (a) ! { dg-error "LOGICAL" } @@ -63,7 +63,7 @@ contains !$acc exit data !$acc exit data if (.false.) !$acc exit data if (l) - !$acc exit data if (.false.) if (l) ! { dg-error "Unclassifiable" } + !$acc exit data if (.false.) if (l) ! { dg-error "Failed to match clause" } !$acc exit data if (i) ! { dg-error "LOGICAL" } !$acc exit data if (1) ! { dg-error "LOGICAL" } !$acc exit data if (a) ! { dg-error "LOGICAL" } diff --git a/gcc/testsuite/gfortran.dg/goacc/if.f95 b/gcc/testsuite/gfortran.dg/goacc/if.f95 index a45035d..35e9cfe 100644 --- a/gcc/testsuite/gfortran.dg/goacc/if.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/if.f95 @@ -6,7 +6,7 @@ program test logical :: x integer :: i - !$acc parallel if ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel if ! { dg-error "Failed to match clause" } !$acc parallel if () ! { dg-error "Invalid character" } !$acc parallel if (i) ! { dg-error "scalar LOGICAL expression" } !$acc end parallel @@ -14,11 +14,11 @@ program test !$acc end parallel !$acc kernels if (i) ! { dg-error "scalar LOGICAL expression" } !$acc end kernels - !$acc kernels if ! { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels if ! { dg-error "Failed to match clause" } !$acc kernels if () ! { dg-error "Invalid character" } !$acc kernels if (1) ! { dg-error "scalar LOGICAL expression" } !$acc end kernels - !$acc data if ! { dg-error "Unclassifiable OpenACC directive" } + !$acc data if ! { dg-error "Failed to match clause" } !$acc data if () ! { dg-error "Invalid character" } !$acc data if (i) ! { dg-error "scalar LOGICAL expression" } !$acc end data @@ -26,9 +26,9 @@ program test !$acc end data ! at most one if clause may appear - !$acc parallel if (.false.) if (.false.) { dg-error "Unclassifiable OpenACC directive" } - !$acc kernels if (.false.) if (.false.) { dg-error "Unclassifiable OpenACC directive" } - !$acc data if (.false.) if (.false.) { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel if (.false.) if (.false.) { dg-error "Failed to match clause" } + !$acc kernels if (.false.) if (.false.) { dg-error "Failed to match clause" } + !$acc data if (.false.) if (.false.) { dg-error "Failed to match clause" } !$acc parallel if (x) !$acc end parallel @@ -49,4 +49,4 @@ program test !$acc data if (i.gt.1) !$acc end data -end program test \ No newline at end of file +end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/list.f95 b/gcc/testsuite/gfortran.dg/goacc/list.f95 index 87c8408..d2f4c5e 100644 --- a/gcc/testsuite/gfortran.dg/goacc/list.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/list.f95 @@ -24,7 +24,7 @@ program test !$acc parallel private (i) private (j) !$acc end parallel - !$acc parallel private ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel private ! { dg-error "Failed to match clause" } !$acc parallel private() ! { dg-error "Syntax error" } @@ -56,7 +56,7 @@ program test !$acc parallel firstprivate (i) firstprivate (j) !$acc end parallel - !$acc parallel firstprivate ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel firstprivate ! { dg-error "Failed to match clause" } !$acc parallel firstprivate() ! { dg-error "Syntax error" } @@ -91,7 +91,7 @@ program test !$acc host_data use_device (i) use_device (j) ! { dg-error "neither a POINTER nor an array" } !$acc end host_data - !$acc host_data use_device ! { dg-error "Unclassifiable OpenACC directive" } + !$acc host_data use_device ! { dg-error "Failed to match clause" } !$acc host_data use_device() ! { dg-error "Syntax error" } diff --git a/gcc/testsuite/gfortran.dg/goacc/literal.f95 b/gcc/testsuite/gfortran.dg/goacc/literal.f95 index e6760d0..896749a 100644 --- a/gcc/testsuite/gfortran.dg/goacc/literal.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/literal.f95 @@ -10,7 +10,7 @@ contains !$acc end data ! { dg-error "Unexpected" } !$acc data deviceptr (10) ! { dg-error "Syntax error" } !$acc end data ! { dg-error "Unexpected" } - !$acc data private (10) ! { dg-error "Unclassifiable" } + !$acc data private (10) ! { dg-error "Failed to match clause" } !$acc end data ! { dg-error "Unexpected" } !$acc host_data use_device (10) ! { dg-error "Syntax error" } !$acc end host_data ! { dg-error "Unexpected" } diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-2-kernels-tile.f95 b/gcc/testsuite/gfortran.dg/goacc/loop-2-kernels-tile.f95 index 96e0ccb..afc8a27 100644 --- a/gcc/testsuite/gfortran.dg/goacc/loop-2-kernels-tile.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/loop-2-kernels-tile.f95 @@ -3,7 +3,7 @@ program test integer :: i, j !$acc kernels - !$acc loop tile ! { dg-error "Unclassifiable" } + !$acc loop tile ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop tile() ! { dg-error "Syntax error" } @@ -65,7 +65,7 @@ program test ENDDO !$acc end kernels - !$acc kernels loop tile ! { dg-error "Unclassifiable" } + !$acc kernels loop tile ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc kernels loop tile() ! { dg-error "Syntax error" } diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-2-parallel-tile.f95 b/gcc/testsuite/gfortran.dg/goacc/loop-2-parallel-tile.f95 index 3a4db5d..4bfca74 100644 --- a/gcc/testsuite/gfortran.dg/goacc/loop-2-parallel-tile.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/loop-2-parallel-tile.f95 @@ -3,7 +3,7 @@ program test integer :: i, j !$acc parallel - !$acc loop tile ! { dg-error "Unclassifiable" } + !$acc loop tile ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop tile() ! { dg-error "Syntax error" } @@ -56,7 +56,7 @@ program test ENDDO !$acc end parallel - !$acc parallel loop tile ! { dg-error "Unclassifiable" } + !$acc parallel loop tile ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc parallel loop tile() ! { dg-error "Syntax error" } diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-7.f95 b/gcc/testsuite/gfortran.dg/goacc/loop-7.f95 index 9ca8297..37d50d3 100644 --- a/gcc/testsuite/gfortran.dg/goacc/loop-7.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/loop-7.f95 @@ -30,13 +30,13 @@ program test !$acc loop gang(num:num, static:1) DO i = 1,10 ENDDO - !$acc loop gang(static:*, num:5, static:5) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop gang(static:*, num:5, static:5) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO - !$acc loop gang(1, num:2, static:3) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop gang(1, num:2, static:3) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO - !$acc loop gang(num:num static:1) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop gang(num:num static:1) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop gang(num) @@ -45,7 +45,7 @@ program test !$acc loop gang(num:num+1, static:1+num) DO i = 1,10 ENDDO - !$acc loop gang(length:num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop gang(length:num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO @@ -58,19 +58,19 @@ program test !$acc loop worker (num) DO i = 1,10 ENDDO - !$acc loop worker (static:num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop worker (static:num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop worker (num:,) ! { dg-error "Invalid character" } DO i = 1,10 ENDDO - !$acc loop worker (num:num:num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop worker (num:num:num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop worker (num:num*num) DO i = 1,10 ENDDO - !$acc loop worker (length:num*num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop worker (length:num*num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop worker (num:*) ! { dg-error "Invalid character" } @@ -89,13 +89,13 @@ program test !$acc loop vector (length) DO i = 1,10 ENDDO - !$acc loop vrctor (static:num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop vrctor (static:num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop vector (length:,) ! { dg-error "Invalid character" } DO i = 1,10 ENDDO - !$acc loop vector (length:num:num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop vector (length:num:num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop vector (length:static*num) @@ -107,7 +107,7 @@ program test !$acc loop vector (length:32) DO i = 1,10 ENDDO - !$acc loop vector (num:num*num) ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop vector (num:num*num) ! { dg-error "Failed to match clause" } DO i = 1,10 ENDDO !$acc loop vector (length:*) ! { dg-error "Invalid character" } diff --git a/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 b/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 index c37208c..72ba147 100644 --- a/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 @@ -16,8 +16,8 @@ program test !$acc parallel async(i) !$acc end parallel - !$acc kernels async(0, 1) { dg-error "Unclassifiable" } - !$acc parallel async(0, 1) { dg-error "Unclassifiable" } + !$acc kernels async(0, 1) { dg-error "Failed to match clause" } + !$acc parallel async(0, 1) { dg-error "Failed to match clause" } !$acc kernels async !$acc end kernels @@ -37,11 +37,11 @@ program test !$acc kernels async() { dg-error "Invalid character" } !$acc parallel async() { dg-error "Invalid character" } - !$acc kernels async("a") { dg-error "Unclassifiable" } - !$acc parallel async("a") { dg-error "Unclassifiable" } + !$acc kernels async("a") { dg-error "Failed to match clause" } + !$acc parallel async("a") { dg-error "Failed to match clause" } - !$acc kernels async(.true.) { dg-error "Unclassifiable" } - !$acc parallel async(.true.) { dg-error "Unclassifiable" } + !$acc kernels async(.true.) { dg-error "Failed to match clause" } + !$acc parallel async(.true.) { dg-error "Failed to match clause" } ! default(none) !$acc kernels default(none) @@ -59,17 +59,17 @@ program test !$acc parallel default ( none ) !$acc end parallel - !$acc kernels default { dg-error "Unclassifiable" } - !$acc parallel default { dg-error "Unclassifiable" } + !$acc kernels default { dg-error "Failed to match clause" } + !$acc parallel default { dg-error "Failed to match clause" } - !$acc kernels default() { dg-error "Unclassifiable" } - !$acc parallel default() { dg-error "Unclassifiable" } + !$acc kernels default() { dg-error "Failed to match clause" } + !$acc parallel default() { dg-error "Failed to match clause" } - !$acc kernels default(i) { dg-error "Unclassifiable" } - !$acc parallel default(i) { dg-error "Unclassifiable" } + !$acc kernels default(i) { dg-error "Failed to match clause" } + !$acc parallel default(i) { dg-error "Failed to match clause" } - !$acc kernels default(1) { dg-error "Unclassifiable" } - !$acc parallel default(1) { dg-error "Unclassifiable" } + !$acc kernels default(1) { dg-error "Failed to match clause" } + !$acc parallel default(1) { dg-error "Failed to match clause" } ! Wait !$acc kernels wait (l) ! { dg-error "INTEGER" } diff --git a/gcc/testsuite/gfortran.dg/goacc/routine-6.f90 b/gcc/testsuite/gfortran.dg/goacc/routine-6.f90 index cdf643f..f1e2aa3 100644 --- a/gcc/testsuite/gfortran.dg/goacc/routine-6.f90 +++ b/gcc/testsuite/gfortran.dg/goacc/routine-6.f90 @@ -108,7 +108,7 @@ subroutine subr4 (x) end subroutine subr4 subroutine subr10 (x) - !$acc routine (subr10) device ! { dg-error "Unclassifiable OpenACC directive" } + !$acc routine (subr10) device ! { dg-error "Failed to match clause" } integer, intent(inout) :: x if (x < 1) then x = 1 diff --git a/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 b/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 index 8fb97b5..e7610be 100644 --- a/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 @@ -2,5 +2,5 @@ program test ! only one directive-name may appear in directive - !$acc parallel kernels ! { dg-error "Unclassifiable OpenACC directive" } -end \ No newline at end of file + !$acc parallel kernels ! { dg-error "Failed to match clause" } +end diff --git a/gcc/testsuite/gfortran.dg/goacc/sie.f95 b/gcc/testsuite/gfortran.dg/goacc/sie.f95 index abfe28b..194a1da 100644 --- a/gcc/testsuite/gfortran.dg/goacc/sie.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/sie.f95 @@ -67,7 +67,7 @@ program test !$acc end kernels - !$acc parallel num_gangs ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel num_gangs ! { dg-error "Failed to match clause" } !$acc parallel num_gangs(3) !$acc end parallel @@ -95,7 +95,7 @@ program test !$acc parallel num_gangs("1") ! { dg-error "scalar INTEGER expression" } !$acc end parallel - !$acc kernels num_gangs ! { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels num_gangs ! { dg-error "Failed to match clause" } !$acc kernels num_gangs(3) !$acc end kernels @@ -124,7 +124,7 @@ program test !$acc end kernels - !$acc parallel num_workers ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel num_workers ! { dg-error "Failed to match clause" } !$acc parallel num_workers(3) !$acc end parallel @@ -152,7 +152,7 @@ program test !$acc parallel num_workers("1") ! { dg-error "scalar INTEGER expression" } !$acc end parallel - !$acc kernels num_workers ! { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels num_workers ! { dg-error "Failed to match clause" } !$acc kernels num_workers(3) !$acc end kernels @@ -181,7 +181,7 @@ program test !$acc end kernels - !$acc parallel vector_length ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel vector_length ! { dg-error "Failed to match clause" } !$acc parallel vector_length(3) !$acc end parallel @@ -209,7 +209,7 @@ program test !$acc parallel vector_length("1") ! { dg-error "scalar INTEGER expression" } !$acc end parallel - !$acc kernels vector_length ! { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels vector_length ! { dg-error "Failed to match clause" } !$acc kernels vector_length(3) !$acc end kernels diff --git a/gcc/testsuite/gfortran.dg/goacc/tile-1.f90 b/gcc/testsuite/gfortran.dg/goacc/tile-1.f90 index 3dbabda..f609b12 100644 --- a/gcc/testsuite/gfortran.dg/goacc/tile-1.f90 +++ b/gcc/testsuite/gfortran.dg/goacc/tile-1.f90 @@ -24,7 +24,7 @@ subroutine parloop end do end do - !$acc parallel loop tile ! { dg-error "Unclassifiable" } + !$acc parallel loop tile ! { dg-error "Failed to match clause" } do i = 1, n end do @@ -92,7 +92,7 @@ subroutine par integer i, j, k !$acc parallel - !$acc loop tile ! { dg-error "Unclassifiable" } + !$acc loop tile ! { dg-error "Failed to match clause" } do i = 1, n end do @@ -173,7 +173,7 @@ subroutine kern integer i, j, k !$acc kernels - !$acc loop tile ! { dg-error "Unclassifiable" } + !$acc loop tile ! { dg-error "Failed to match clause" } do i = 1, n end do @@ -275,7 +275,7 @@ subroutine kernsloop end do end do - !$acc kernels loop tile ! { dg-error "Unclassifiable" } + !$acc kernels loop tile ! { dg-error "Failed to match clause" } do i = 1, n end do diff --git a/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90 b/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90 index e73c2dc..bf8b319 100644 --- a/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90 +++ b/gcc/testsuite/gfortran.dg/goacc/update-if_present-2.f90 @@ -2,7 +2,7 @@ subroutine t1 implicit none - !$acc routine gang if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc routine gang if_present ! { dg-error "Failed to match clause" } integer a, b, c(10) real, allocatable :: x, y, z(:) @@ -12,10 +12,10 @@ subroutine t1 allocate (x, y, z(100)) - !$acc enter data copyin(a) if_present ! { dg-error "Unclassifiable OpenACC directive" } - !$acc exit data copyout(a) if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc enter data copyin(a) if_present ! { dg-error "Failed to match clause" } + !$acc exit data copyout(a) if_present ! { dg-error "Failed to match clause" } - !$acc data copy(a) if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc data copy(a) if_present ! { dg-error "Failed to match clause" } !$acc end data ! { dg-error "Unexpected ..ACC END DATA statement" } !$acc declare link(a) if_present ! { dg-error "Unexpected junk after" } @@ -23,7 +23,7 @@ subroutine t1 !$acc init if_present ! { dg-error "Unclassifiable OpenACC directive" } !$acc shutdown if_present ! { dg-error "Unclassifiable OpenACC directive" } - !$acc update self(a) device_type(nvidia) device(b) if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc update self(a) device_type(nvidia) device(b) if_present ! { dg-error "Failed to match clause" } end subroutine t1 subroutine t2 @@ -35,17 +35,17 @@ subroutine t2 c(:) = -1 !$acc parallel - !$acc loop if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc loop if_present ! { dg-error "Failed to match clause" } do b = 1, 10 end do !$acc end parallel - !$acc kernels loop if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels loop if_present ! { dg-error "Failed to match clause" } do b = 1, 10 end do !$acc end kernels loop ! { dg-error "Unexpected ..ACC END KERNELS LOOP statement" } - !$acc parallel loop if_present ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel loop if_present ! { dg-error "Failed to match clause" } do b = 1, 10 end do !$acc end parallel loop ! { dg-error "Unexpected ..ACC END PARALLEL LOOP statement" } diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-simd-1.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-simd-1.f90 index d6ae7c9..40169d3 100644 --- a/gcc/testsuite/gfortran.dg/gomp/declare-simd-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/declare-simd-1.f90 @@ -2,7 +2,7 @@ subroutine fn1 (x) integer :: x -!$omp declare simd (fn1) inbranch notinbranch uniform (x) ! { dg-error "Unclassifiable OpenMP directive" } +!$omp declare simd (fn1) inbranch notinbranch uniform (x) ! { dg-error "Failed to match clause" } end subroutine fn1 subroutine fn2 (x) !$omp declare simd (fn100) ! { dg-error "should refer to containing procedure" } diff --git a/gcc/testsuite/gfortran.dg/gomp/pr29759.f90 b/gcc/testsuite/gfortran.dg/gomp/pr29759.f90 index 39c59c5..1b1f379 100644 --- a/gcc/testsuite/gfortran.dg/gomp/pr29759.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/pr29759.f90 @@ -21,20 +21,20 @@ PROGRAM test_omp !$OMP END PARALLEL -!$OMP PARALLEL & ! { dg-error "Unclassifiable OpenMP" } +!$OMP PARALLEL & ! { dg-error "Failed to match clause" } !$ NUM_THREADS(2) !$OMP END PARALLEL ! { dg-error "Unexpected" } -!$OMP PARALLEL & ! { dg-error "Unclassifiable OpenMP" } +!$OMP PARALLEL & ! { dg-error "Failed to match clause" } !$ & NUM_THREADS(2) ! { dg-error "Invalid character" } !$OMP END PARALLEL ! { dg-error "Unexpected" } -!$OMP PARALLEL & ! { dg-error "Unclassifiable OpenMP" } +!$OMP PARALLEL & ! { dg-error "Failed to match clause" } ! !$ NUM_THREADS(2) !$OMP END PARALLEL ! { dg-error "Unexpected" } -!$OMP PARALLEL & ! { dg-error "Unclassifiable OpenMP" } +!$OMP PARALLEL & ! { dg-error "Failed to match clause" } ! !$ & NUM_THREADS(2) ! { dg-error "Invalid character" } !$OMP END PARALLEL ! { dg-error "Unexpected" } -- cgit v1.1 From fc1a202ca60def4894f2deeda8ae184527ee897e Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 2 Oct 2019 10:54:10 +0000 Subject: re PR c++/91606 (Optimization leads to invalid code) 2019-10-02 Richard Biener PR c++/91606 * decl.c (build_ptrmemfunc_type): Mark pointer-to-member fat pointer structure members as DECL_NONADDRESSABLE_P. * g++.dg/torture/pr91606.C: New testcase. From-SVN: r276448 --- gcc/cp/ChangeLog | 6 ++ gcc/cp/decl.c | 2 + gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/torture/pr91606.C | 109 +++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 gcc/testsuite/g++.dg/torture/pr91606.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a1e520a..bac74fe 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-10-02 Richard Biener + + PR c++/91606 + * decl.c (build_ptrmemfunc_type): Mark pointer-to-member + fat pointer structure members as DECL_NONADDRESSABLE_P. + 2019-09-28 Marek Polacek PR c++/91889 - follow-up fix for DR 2352. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 67c4521..c96294f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9665,10 +9665,12 @@ build_ptrmemfunc_type (tree type) TYPE_PTRMEMFUNC_FLAG (t) = 1; field = build_decl (input_location, FIELD_DECL, pfn_identifier, type); + DECL_NONADDRESSABLE_P (field) = 1; fields = field; field = build_decl (input_location, FIELD_DECL, delta_identifier, delta_type_node); + DECL_NONADDRESSABLE_P (field) = 1; DECL_CHAIN (field) = fields; fields = field; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a5a1cf3..3fbed65 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Richard Biener + + PR c++/91606 + * g++.dg/torture/pr91606.C: New testcase. + 2019-10-02 Tobias Burnus * gfortran.dg/goacc/asyncwait-1.f95: Handle new error message. diff --git a/gcc/testsuite/g++.dg/torture/pr91606.C b/gcc/testsuite/g++.dg/torture/pr91606.C new file mode 100644 index 0000000..37a05a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr91606.C @@ -0,0 +1,109 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fstrict-aliasing" } */ + +#include +#include +#include + +template +struct variant +{ + constexpr variant(T1 arg) + : f1(arg), + index(0) + {} + + constexpr variant(T2 arg) + : f2(arg), + index(1) + {} + + union + { + T1 f1; + T2 f2; + }; + std::size_t index = 0; +}; + +template +constexpr const T1* get_if(const variant* v) +{ + if (v->index != 0) + { + return nullptr; + } + return &v->f1; +} + +template +constexpr const T2* get_if(const variant* v) +{ + if (v->index != 1) + { + return nullptr; + } + return &v->f2; +} + +template +struct my_array +{ + constexpr const T* begin() const + { + return data; + } + + constexpr const T* end() const + { + return data + N; + } + + T data[N]; +}; + +template +constexpr auto get_array_of_variants(Ts ...ptrs) +{ + return std::array...>, sizeof...(Ts)>{ ptrs... }; +} + +template +constexpr auto get_member_functions(); + +template +constexpr int getFuncId(Member (Class::*memFuncPtr)) +{ + int idx = 0u; + for (auto &anyFunc : get_member_functions()) + { + if (auto *specificFunc = get_if(&anyFunc)) + { + if (*specificFunc == memFuncPtr) + { + return idx; + } + } + ++idx; + } + std::abort(); +} + +struct MyStruct +{ + void fun1(int /*a*/) {} + + int fun2(char /*b*/, short /*c*/, bool /*d*/) { return 0; } + +}; + +template <> +constexpr auto get_member_functions() +{ + return get_array_of_variants(&MyStruct::fun1, &MyStruct::fun2); +} + +int main() +{ + return getFuncId(&MyStruct::fun1); +} -- cgit v1.1 From ef4add8e543091083b1a30350b653968e7c58ab2 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 2 Oct 2019 10:57:54 +0000 Subject: Support OpenMP's use_device_addr in Fortran gcc/fortran/ * dump-parse-tree.c (show_omp_clauses): Handle OMP_LIST_USE_DEVICE_ADDR. * gfortran.h (enum): Add OMP_LIST_USE_DEVICE_ADDR. * openmp.c (omp_mask1): Likewise. (gfc_match_omp_clauses): Match 'use_device_addr'. (OMP_TARGET_DATA_CLAUSES): Add OMP_LIST_USE_DEVICE_ADDR. (resolve_omp_clauses): Add it; add is_device_ptr checks. gcc/testsuite/ * gfortran.dg/gomp/is_device_ptr-1.f90: New. From-SVN: r276449 --- gcc/fortran/ChangeLog | 9 +++++++ gcc/fortran/dump-parse-tree.c | 1 + gcc/fortran/gfortran.h | 1 + gcc/fortran/openmp.c | 30 +++++++++++++++++++--- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gfortran.dg/gomp/is_device_ptr-1.f90 | 27 +++++++++++++++++++ 6 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/is_device_ptr-1.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 075f3b9..8d7a2cf 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,14 @@ 2019-10-02 Tobias Burnus + * dump-parse-tree.c (show_omp_clauses): Handle OMP_LIST_USE_DEVICE_ADDR. + * gfortran.h (enum): Add OMP_LIST_USE_DEVICE_ADDR. + * openmp.c (omp_mask1): Likewise. + (gfc_match_omp_clauses): Match 'use_device_addr'. + (OMP_TARGET_DATA_CLAUSES): Add OMP_LIST_USE_DEVICE_ADDR. + (resolve_omp_clauses): Add it; add is_device_ptr checks. + +2019-10-02 Tobias Burnus + * openmp.c (gfc_match_omp_clauses): Show a clause-parsing error if none was rised before. * parse.c (matcha, matcho): If error occurred after diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 513f211..9d7b26f 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1507,6 +1507,7 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) case OMP_LIST_CACHE: type = "CACHE"; break; case OMP_LIST_IS_DEVICE_PTR: type = "IS_DEVICE_PTR"; break; case OMP_LIST_USE_DEVICE_PTR: type = "USE_DEVICE_PTR"; break; + case OMP_LIST_USE_DEVICE_ADDR: type = "USE_DEVICE_ADDR"; break; default: gcc_unreachable (); } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 6f7717d..a70978b 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1263,6 +1263,7 @@ enum OMP_LIST_CACHE, OMP_LIST_IS_DEVICE_PTR, OMP_LIST_USE_DEVICE_PTR, + OMP_LIST_USE_DEVICE_ADDR, OMP_LIST_NUM }; diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 2beac3d..7df7384 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -780,6 +780,7 @@ enum omp_mask1 OMP_CLAUSE_SIMD, OMP_CLAUSE_THREADS, OMP_CLAUSE_USE_DEVICE_PTR, + OMP_CLAUSE_USE_DEVICE_ADDR, /* Actually, OpenMP 5.0. */ OMP_CLAUSE_NOWAIT, /* This must come last. */ OMP_MASK1_LAST @@ -1849,6 +1850,11 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, ("use_device_ptr (", &c->lists[OMP_LIST_USE_DEVICE_PTR], false) == MATCH_YES) continue; + if ((mask & OMP_CLAUSE_USE_DEVICE_ADDR) + && gfc_match_omp_variable_list + ("use_device_addr (", + &c->lists[OMP_LIST_USE_DEVICE_ADDR], false) == MATCH_YES) + continue; break; case 'v': /* VECTOR_LENGTH must be matched before VECTOR, because the latter @@ -2479,7 +2485,7 @@ cleanup: | OMP_CLAUSE_IS_DEVICE_PTR) #define OMP_TARGET_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF \ - | OMP_CLAUSE_USE_DEVICE_PTR) + | OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR) #define OMP_TARGET_ENTER_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF \ | OMP_CLAUSE_DEPEND | OMP_CLAUSE_NOWAIT) @@ -4008,7 +4014,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, = { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED", "COPYIN", "UNIFORM", "ALIGNED", "LINEAR", "DEPEND", "MAP", "TO", "FROM", "REDUCTION", "DEVICE_RESIDENT", "LINK", "USE_DEVICE", - "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR" }; + "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR" }; if (omp_clauses == NULL) return; @@ -4565,8 +4571,26 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, } break; case OMP_LIST_IS_DEVICE_PTR: + if (!n->sym->attr.dummy) + gfc_error ("Non-dummy object %qs in %s clause at %L", + n->sym->name, name, &n->where); + if (n->sym->attr.allocatable + || (n->sym->ts.type == BT_CLASS + && CLASS_DATA (n->sym)->attr.allocatable)) + gfc_error ("ALLOCATABLE object %qs in %s clause at %L", + n->sym->name, name, &n->where); + if (n->sym->attr.pointer + || (n->sym->ts.type == BT_CLASS + && CLASS_DATA (n->sym)->attr.pointer)) + gfc_error ("POINTER object %qs in %s clause at %L", + n->sym->name, name, &n->where); + if (n->sym->attr.value) + gfc_error ("VALUE object %qs in %s clause at %L", + n->sym->name, name, &n->where); + break; case OMP_LIST_USE_DEVICE_PTR: - /* FIXME: Handle these. */ + case OMP_LIST_USE_DEVICE_ADDR: + /* FIXME: Handle OMP_LIST_USE_DEVICE_PTR. */ break; default: for (; n != NULL; n = n->next) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3fbed65..86b8f73 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-02 Tobias Burnus + + * gfortran.dg/gomp/is_device_ptr-1.f90: New. + 2019-10-02 Richard Biener PR c++/91606 diff --git a/gcc/testsuite/gfortran.dg/gomp/is_device_ptr-1.f90 b/gcc/testsuite/gfortran.dg/gomp/is_device_ptr-1.f90 new file mode 100644 index 0000000..0eeca0e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/is_device_ptr-1.f90 @@ -0,0 +1,27 @@ +! { dg-do compile } +subroutine test(b,c,d) + implicit none + integer, value, target :: b + integer, pointer :: c + integer, allocatable, target :: d + + integer, target :: a(5) + + !$omp target is_device_ptr(a) ! { dg-error "Non-dummy object .a. in IS_DEVICE_PTR clause" } + !$omp end target + + !$omp target is_device_ptr(b) ! { dg-error "VALUE object .b. in IS_DEVICE_PTR clause" } + !$omp end target + + !$omp target is_device_ptr(c) ! { dg-error "POINTER object .c. in IS_DEVICE_PTR clause" } + !$omp end target + + !$omp target is_device_ptr(d) ! { dg-error "ALLOCATABLE object .d. in IS_DEVICE_PTR clause" } + !$omp end target + + !$omp target data map(a) use_device_addr(a) ! Should be okay + !$omp end target data + + !$omp target data map(c) use_device_ptr(c) ! Should be okay + !$omp end target data +end subroutine test -- cgit v1.1 From 9f4d9a366b3299c276043ab987234c7bed7d29f2 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 2 Oct 2019 11:24:27 +0000 Subject: tree-vectorizer.h (vect_transform_reduction): Declare. 2019-10-02 Richard Biener * tree-vectorizer.h (vect_transform_reduction): Declare. * tree-vect-stmts.c (vect_transform_stmt): Use it. * tree-vect-loop.c (vectorizable_reduction): Split out reduction stmt transform to ... (vect_transform_reduction): ... this. From-SVN: r276452 --- gcc/ChangeLog | 8 ++ gcc/tree-vect-loop.c | 256 +++++++++++++++++++++++++++++++++++++++++++------- gcc/tree-vect-stmts.c | 3 +- gcc/tree-vectorizer.h | 2 + 4 files changed, 231 insertions(+), 38 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6f577c3..441e5bb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-10-02 Richard Biener + + * tree-vectorizer.h (vect_transform_reduction): Declare. + * tree-vect-stmts.c (vect_transform_stmt): Use it. + * tree-vect-loop.c (vectorizable_reduction): Split out reduction + stmt transform to ... + (vect_transform_reduction): ... this. + 2019-10-02 Tobias Burnus * omp-low.c (lower_omp_target): Dereference optional argument diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index a3fd011..31e7457 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -5784,7 +5784,6 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, int i; int ncopies; bool single_defuse_cycle = false; - int j; tree ops[3]; enum vect_def_type dts[3]; bool nested_cycle = false, found_nested_cycle_def = false; @@ -6576,43 +6575,224 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo); bool mask_by_cond_expr = use_mask_by_cond_expr_p (code, cond_fn, vectype_in); - if (!vec_stmt) /* transformation not required. */ + /* transformation not required. */ + gcc_assert (!vec_stmt); + + vect_model_reduction_cost (stmt_info, reduc_fn, ncopies, cost_vec); + if (loop_vinfo && LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo)) { - vect_model_reduction_cost (stmt_info, reduc_fn, ncopies, cost_vec); - if (loop_vinfo && LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo)) + if (reduction_type != FOLD_LEFT_REDUCTION + && !mask_by_cond_expr + && (cond_fn == IFN_LAST + || !direct_internal_fn_supported_p (cond_fn, vectype_in, + OPTIMIZE_FOR_SPEED))) { - if (reduction_type != FOLD_LEFT_REDUCTION - && !mask_by_cond_expr - && (cond_fn == IFN_LAST - || !direct_internal_fn_supported_p (cond_fn, vectype_in, - OPTIMIZE_FOR_SPEED))) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "can't use a fully-masked loop because no" - " conditional operation is available.\n"); - LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo) = false; - } - else if (reduc_index == -1) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "can't use a fully-masked loop for chained" - " reductions.\n"); - LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo) = false; - } - else - vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num, - vectype_in); + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "can't use a fully-masked loop because no" + " conditional operation is available.\n"); + LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo) = false; } - if (dump_enabled_p () - && reduction_type == FOLD_LEFT_REDUCTION) - dump_printf_loc (MSG_NOTE, vect_location, - "using an in-order (fold-left) reduction.\n"); - STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type; - return true; + else if (reduc_index == -1) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "can't use a fully-masked loop for chained" + " reductions.\n"); + LOOP_VINFO_CAN_FULLY_MASK_P (loop_vinfo) = false; + } + else + vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num, + vectype_in); + } + if (dump_enabled_p () + && reduction_type == FOLD_LEFT_REDUCTION) + dump_printf_loc (MSG_NOTE, vect_location, + "using an in-order (fold-left) reduction.\n"); + STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type; + return true; +} + +/* Transform the definition stmt STMT_INFO of a reduction PHI backedge + value. */ + +bool +vect_transform_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + stmt_vec_info *vec_stmt, slp_tree slp_node) +{ + tree vectype_out = STMT_VINFO_VECTYPE (stmt_info); + tree vectype_in = NULL_TREE; + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + enum tree_code code; + int op_type; + bool is_simple_use; + int i; + int ncopies; + bool single_defuse_cycle = false; + int j; + tree ops[3]; + bool nested_cycle = false; + int vec_num; + + if (nested_in_vect_loop_p (loop, stmt_info)) + { + loop = loop->inner; + nested_cycle = true; } + gassign *stmt = as_a (stmt_info->stmt); + + /* Flatten RHS. */ + switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))) + { + case GIMPLE_BINARY_RHS: + code = gimple_assign_rhs_code (stmt); + op_type = TREE_CODE_LENGTH (code); + gcc_assert (op_type == binary_op); + ops[0] = gimple_assign_rhs1 (stmt); + ops[1] = gimple_assign_rhs2 (stmt); + break; + + case GIMPLE_TERNARY_RHS: + code = gimple_assign_rhs_code (stmt); + op_type = TREE_CODE_LENGTH (code); + gcc_assert (op_type == ternary_op); + ops[0] = gimple_assign_rhs1 (stmt); + ops[1] = gimple_assign_rhs2 (stmt); + ops[2] = gimple_assign_rhs3 (stmt); + break; + + case GIMPLE_UNARY_RHS: + return false; + + default: + gcc_unreachable (); + } + + /* All uses but the last are expected to be defined in the loop. + The last use is the reduction variable. In case of nested cycle this + assumption is not true: we use reduc_index to record the index of the + reduction variable. */ + stmt_vec_info reduc_def_info + = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)); + gcc_assert (reduc_def_info); + gphi *reduc_def_phi = as_a (reduc_def_info->stmt); + tree reduc_def = PHI_RESULT (reduc_def_phi); + int reduc_index = -1; + for (i = 0; i < op_type; i++) + { + /* The condition of COND_EXPR is checked in vectorizable_condition(). */ + if (i == 0 && code == COND_EXPR) + continue; + + stmt_vec_info def_stmt_info; + enum vect_def_type dt; + tree tem; + is_simple_use = vect_is_simple_use (ops[i], loop_vinfo, &dt, &tem, + &def_stmt_info); + gcc_assert (is_simple_use); + if (dt == vect_reduction_def + && ops[i] == reduc_def) + { + reduc_index = i; + continue; + } + else if (tem) + { + /* To properly compute ncopies we are interested in the widest + input type in case we're looking at a widening accumulation. */ + if (!vectype_in + || (GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (vectype_in))) + < GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (tem))))) + vectype_in = tem; + } + + if (dt == vect_nested_cycle + && ops[i] == reduc_def) + { + reduc_index = i; + } + } + + if (!vectype_in) + vectype_in = vectype_out; + + if (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) == INTEGER_INDUC_COND_REDUCTION + && dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "condition expression based on " + "integer induction.\n"); + + if (slp_node) + ncopies = 1; + else + ncopies = vect_get_num_copies (loop_vinfo, vectype_in); + + vect_reduction_type reduction_type + = STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info); + + /* In case of widenning multiplication by a constant, we update the type + of the constant to be the type of the other operand. We check that the + constant fits the type in the pattern recognition pass. */ + if (code == DOT_PROD_EXPR + && !types_compatible_p (TREE_TYPE (ops[0]), TREE_TYPE (ops[1]))) + { + gcc_unreachable (); + /* No testcase for this. PR49478. */ + if (TREE_CODE (ops[0]) == INTEGER_CST) + ops[0] = fold_convert (TREE_TYPE (ops[1]), ops[0]); + else if (TREE_CODE (ops[1]) == INTEGER_CST) + ops[1] = fold_convert (TREE_TYPE (ops[0]), ops[1]); + } + + /* In case the vectorization factor (VF) is bigger than the number + of elements that we can fit in a vectype (nunits), we have to generate + more than one vector stmt - i.e - we need to "unroll" the + vector stmt by a factor VF/nunits. For more details see documentation + in vectorizable_operation. */ + + /* If the reduction is used in an outer loop we need to generate + VF intermediate results, like so (e.g. for ncopies=2): + r0 = phi (init, r0) + r1 = phi (init, r1) + r0 = x0 + r0; + r1 = x1 + r1; + (i.e. we generate VF results in 2 registers). + In this case we have a separate def-use cycle for each copy, and therefore + for each copy we get the vector def for the reduction variable from the + respective phi node created for this copy. + + Otherwise (the reduction is unused in the loop nest), we can combine + together intermediate results, like so (e.g. for ncopies=2): + r = phi (init, r) + r = x0 + r; + r = x1 + r; + (i.e. we generate VF/2 results in a single register). + In this case for each copy we get the vector def for the reduction variable + from the vectorized reduction operation generated in the previous iteration. + + This only works when we see both the reduction PHI and its only consumer + in vectorizable_reduction and there are no intermediate stmts + participating. */ + stmt_vec_info use_stmt_info; + tree reduc_phi_result = gimple_phi_result (reduc_def_phi); + if (ncopies > 1 + && (STMT_VINFO_RELEVANT (stmt_info) <= vect_used_only_live) + && (use_stmt_info = loop_vinfo->lookup_single_use (reduc_phi_result)) + && (!STMT_VINFO_IN_PATTERN_P (use_stmt_info) + || !STMT_VINFO_PATTERN_DEF_SEQ (use_stmt_info)) + && vect_stmt_to_vectorize (use_stmt_info) == stmt_info) + single_defuse_cycle = true; + + if (slp_node) + vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); + else + vec_num = 1; + + internal_fn cond_fn = get_conditional_internal_fn (code); + vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo); + bool mask_by_cond_expr = use_mask_by_cond_expr_p (code, cond_fn, vectype_in); /* Transform. */ stmt_vec_info new_stmt_info = NULL; @@ -6633,9 +6813,12 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo); if (reduction_type == FOLD_LEFT_REDUCTION) - return vectorize_fold_left_reduction - (stmt_info, gsi, vec_stmt, slp_node, reduc_def_phi, code, - reduc_fn, ops, vectype_in, reduc_index, masks); + { + internal_fn reduc_fn = STMT_VINFO_REDUC_FN (stmt_info); + return vectorize_fold_left_reduction + (stmt_info, gsi, vec_stmt, slp_node, reduc_def_phi, code, + reduc_fn, ops, vectype_in, reduc_index, masks); + } if (reduction_type == EXTRACT_LAST_REDUCTION) { @@ -6645,6 +6828,7 @@ vectorizable_reduction (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, } /* Create the destination vector */ + tree scalar_dest = gimple_assign_lhs (stmt); tree vec_dest = vect_create_destination_var (scalar_dest, vectype_out); prev_stmt_info = NULL; diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index ddc2f74..f997ad2 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -10819,8 +10819,7 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, break; case reduc_vec_info_type: - done = vectorizable_reduction (stmt_info, gsi, &vec_stmt, slp_node, - slp_node_instance, NULL); + done = vect_transform_reduction (stmt_info, gsi, &vec_stmt, slp_node); gcc_assert (done); break; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index eae9d4c..837fb5a 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1659,6 +1659,8 @@ extern bool vectorizable_reduction (stmt_vec_info, gimple_stmt_iterator *, extern bool vectorizable_induction (stmt_vec_info, gimple_stmt_iterator *, stmt_vec_info *, slp_tree, stmt_vector_for_cost *); +extern bool vect_transform_reduction (stmt_vec_info, gimple_stmt_iterator *, + stmt_vec_info *, slp_tree); extern bool vect_transform_cycle_phi (stmt_vec_info, stmt_vec_info *, slp_tree, slp_instance); extern bool vectorizable_lc_phi (stmt_vec_info, stmt_vec_info *, slp_tree); -- cgit v1.1 From d94b160233e3cef216075be86ca09a4f46b16891 Mon Sep 17 00:00:00 2001 From: Shahab Vahedi Date: Wed, 2 Oct 2019 11:26:15 +0000 Subject: [ARC] Pass along "-mcode-density" flag to "as" This change makes sure that if the driver is invoked with "-mcode-density" flag, then the assembler will receive it too. gcc/ xxxx-xx-xx Shahab Vahedi * config/arc/arc.h (ASM_SPEC): pass -mcode-density From-SVN: r276453 --- gcc/ChangeLog | 4 ++++ gcc/config/arc/arc.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 441e5bb..f76a6ce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2019-10-02 Shahab Vahedi + + * config/arc/arc.h (ASM_SPEC): Pass -mcode-density. + 2019-10-02 Richard Biener * tree-vectorizer.h (vect_transform_reduction): Declare. diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h index 4a9dd07..4d7ac32 100644 --- a/gcc/config/arc/arc.h +++ b/gcc/config/arc/arc.h @@ -97,7 +97,8 @@ extern const char *arc_cpu_to_as (int argc, const char **argv); #undef ASM_SPEC #define ASM_SPEC "%{mbig-endian|EB:-EB} %{EL} " \ - "%:cpu_to_as(%{mcpu=*:%*}) %{mspfp*} %{mdpfp*} %{mfpu=fpuda*:-mfpuda}" + "%:cpu_to_as(%{mcpu=*:%*}) %{mspfp*} %{mdpfp*} " \ + "%{mfpu=fpuda*:-mfpuda} %{mcode-density}" #define OPTION_DEFAULT_SPECS \ {"cpu", "%{!mcpu=*:%{!mARC*:%{!marc*:%{!mA7:%{!mA6:-mcpu=%(VALUE)}}}}}" } -- cgit v1.1 From 569651fd6fdb6455da58f7811e6296c22ce34df7 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 2 Oct 2019 14:41:36 +0200 Subject: re PR c++/91222 (507.cactuBSSN_r build fails in warn_types_mismatch at ipa-devirt.c:1006 since r273571) PR c++/91222 * ipa-devirt.c (warn_types_mismatch): Fix conditional on anonymous namespace types. From-SVN: r276454 --- gcc/ChangeLog | 6 ++++++ gcc/ipa-devirt.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f76a6ce..49ae8b2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Jan Hubicka + + PR c++/91222 + * ipa-devirt.c (warn_types_mismatch): Fix conditional on anonymous + namespace types. + 2019-10-02 Shahab Vahedi * config/arc/arc.h (ASM_SPEC): Pass -mcode-density. diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 3423c40..6c651a3 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -986,8 +986,8 @@ warn_types_mismatch (tree t1, tree t2, location_t loc1, location_t loc2) || (type_with_linkage_p (TYPE_MAIN_VARIANT (t2)) && type_in_anonymous_namespace_p (TYPE_MAIN_VARIANT (t2)))) { - if (type_with_linkage_p (TYPE_MAIN_VARIANT (t1)) - && !type_in_anonymous_namespace_p (TYPE_MAIN_VARIANT (t1))) + if (!type_with_linkage_p (TYPE_MAIN_VARIANT (t1)) + || !type_in_anonymous_namespace_p (TYPE_MAIN_VARIANT (t1))) { std::swap (t1, t2); std::swap (loc_t1, loc_t2); -- cgit v1.1 From 3187c8a5010f4245ff008a0fc2fb746a8bce4a00 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Wed, 2 Oct 2019 14:44:35 +0200 Subject: [PATCH] Do not check call type compatibility when cloning cgraph-edges 2019-10-02 Martin Jambor * cgraph.c (symbol_table::create_edge): New parameter cloning_p, do not compute some stuff when set. (cgraph_node::create_edge): Likewise. (cgraph_node::create_indirect_edge): Renamed last parameter to coning_p and flipped its meaning, don't even calculate inline_failed when set. * cgraph.h (cgraph_node::create_edge): Add new parameter. (symbol_table::::create_edge): Likewise. (cgraph_node::create_indirect_edge): Rename last parameter, flip the default value. * cgraphclones.c (cgraph_edge::clone): Pass true cloning_p to all call graph edge creating functions. From-SVN: r276455 --- gcc/ChangeLog | 15 +++++++++++++++ gcc/cgraph.c | 48 +++++++++++++++++++++++++++++------------------- gcc/cgraph.h | 12 +++++++----- gcc/cgraphclones.c | 6 +++--- 4 files changed, 54 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 49ae8b2..7b5777e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2019-10-02 Martin Jambor + + * cgraph.c (symbol_table::create_edge): New parameter cloning_p, + do not compute some stuff when set. + (cgraph_node::create_edge): Likewise. + (cgraph_node::create_indirect_edge): Renamed last parameter to + coning_p and flipped its meaning, don't even calculate + inline_failed when set. + * cgraph.h (cgraph_node::create_edge): Add new parameter. + (symbol_table::::create_edge): Likewise. + (cgraph_node::create_indirect_edge): Rename last parameter, flip + the default value. + * cgraphclones.c (cgraph_edge::clone): Pass true cloning_p to all + call graph edge creating functions. + 2019-10-01 Jan Hubicka PR c++/91222 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 19158f0..7748cef 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -824,12 +824,13 @@ cgraph_edge::set_call_stmt (gcall *new_stmt, bool update_speculative) /* Allocate a cgraph_edge structure and fill it with data according to the parameters of which only CALLEE can be NULL (when creating an indirect call - edge). */ + edge). CLONING_P should be set if properties that are copied from an + original edge should not be calculated. */ cgraph_edge * symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee, gcall *call_stmt, profile_count count, - bool indir_unknown_callee) + bool indir_unknown_callee, bool cloning_p) { cgraph_edge *edge; @@ -862,8 +863,17 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee, edge->lto_stmt_uid = 0; edge->count = count; - edge->call_stmt = call_stmt; + edge->indirect_info = NULL; + edge->indirect_inlining_edge = 0; + edge->speculative = false; + edge->indirect_unknown_callee = indir_unknown_callee; + if (call_stmt && caller->call_site_hash) + cgraph_add_edge_to_call_site_hash (edge); + + if (cloning_p) + return edge; + edge->can_throw_external = call_stmt ? stmt_can_throw_external (DECL_STRUCT_FUNCTION (caller->decl), call_stmt) : false; @@ -881,10 +891,6 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee, edge->call_stmt_cannot_inline_p = false; } - edge->indirect_info = NULL; - edge->indirect_inlining_edge = 0; - edge->speculative = false; - edge->indirect_unknown_callee = indir_unknown_callee; if (opt_for_fn (edge->caller->decl, flag_devirtualize) && call_stmt && DECL_STRUCT_FUNCTION (caller->decl)) edge->in_polymorphic_cdtor @@ -892,22 +898,23 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee, caller->decl); else edge->in_polymorphic_cdtor = caller->thunk.thunk_p; - if (call_stmt && caller->call_site_hash) - cgraph_add_edge_to_call_site_hash (edge); return edge; } -/* Create edge from a given function to CALLEE in the cgraph. */ +/* Create edge from a given function to CALLEE in the cgraph. CLONING_P should + be set if properties that are copied from an original edge should not be + calculated. */ cgraph_edge * cgraph_node::create_edge (cgraph_node *callee, - gcall *call_stmt, profile_count count) + gcall *call_stmt, profile_count count, bool cloning_p) { cgraph_edge *edge = symtab->create_edge (this, callee, call_stmt, count, - false); + false, cloning_p); - initialize_inline_failed (edge); + if (!cloning_p) + initialize_inline_failed (edge); edge->next_caller = callee->callers; if (callee->callers) @@ -935,25 +942,28 @@ cgraph_allocate_init_indirect_info (void) /* Create an indirect edge with a yet-undetermined callee where the call statement destination is a formal parameter of the caller with index - PARAM_INDEX. */ + PARAM_INDEX. CLONING_P should be set if properties that are copied from an + original edge should not be calculated and indirect_info structure should + not be calculated. */ cgraph_edge * cgraph_node::create_indirect_edge (gcall *call_stmt, int ecf_flags, profile_count count, - bool compute_indirect_info) + bool cloning_p) { - cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt, - count, true); + cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt, count, true, + cloning_p); tree target; - initialize_inline_failed (edge); + if (!cloning_p) + initialize_inline_failed (edge); edge->indirect_info = cgraph_allocate_init_indirect_info (); edge->indirect_info->ecf_flags = ecf_flags; edge->indirect_info->vptr_changed = true; /* Record polymorphic call info. */ - if (compute_indirect_info + if (!cloning_p && call_stmt && (target = gimple_call_fn (call_stmt)) && virtual_method_call_p (target)) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index c35b6b9..66a4dae 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1161,14 +1161,15 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node /* Create edge from a given function to CALLEE in the cgraph. */ cgraph_edge *create_edge (cgraph_node *callee, - gcall *call_stmt, profile_count count); + gcall *call_stmt, profile_count count, + bool cloning_p = false); /* Create an indirect edge with a yet-undetermined callee where the call statement destination is a formal parameter of the caller with index PARAM_INDEX. */ cgraph_edge *create_indirect_edge (gcall *call_stmt, int ecf_flags, profile_count count, - bool compute_indirect_info = true); + bool cloning_p = false); /* Like cgraph_create_edge walk the clone tree and update all clones sharing same function body. If clones already have edge for OLD_STMT; only @@ -2381,11 +2382,12 @@ private: inline cgraph_node * allocate_cgraph_symbol (void); /* Allocate a cgraph_edge structure and fill it with data according to the - parameters of which only CALLEE can be NULL (when creating an indirect call - edge). */ + parameters of which only CALLEE can be NULL (when creating an indirect + call edge). CLONING_P should be set if properties that are copied from an + original edge should not be calculated. */ cgraph_edge *create_edge (cgraph_node *caller, cgraph_node *callee, gcall *call_stmt, profile_count count, - bool indir_unknown_callee); + bool indir_unknown_callee, bool cloning_p); /* Put the edge onto the free list. */ void free_edge (cgraph_edge *e); diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index 909407b..087b5a2 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -104,19 +104,19 @@ cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid, { cgraph_node *callee = cgraph_node::get (decl); gcc_checking_assert (callee); - new_edge = n->create_edge (callee, call_stmt, prof_count); + new_edge = n->create_edge (callee, call_stmt, prof_count, true); } else { new_edge = n->create_indirect_edge (call_stmt, indirect_info->ecf_flags, - prof_count, false); + prof_count, true); *new_edge->indirect_info = *indirect_info; } } else { - new_edge = n->create_edge (callee, call_stmt, prof_count); + new_edge = n->create_edge (callee, call_stmt, prof_count, true); if (indirect_info) { new_edge->indirect_info -- cgit v1.1 From 4bdb8c3dca3b518a6ca8dbaf60068f7e897ccc0e Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 2 Oct 2019 13:11:45 +0000 Subject: Fix MIPS call-clobbered-*.c tests Jeff pointed out that gcc.target/mips/call-clobbered-4.c started failing after the function-abi series. This is because IRA used to treat partly call-clobbered registers as hard conflicts and so wouldn't consider them for -fcaller-saves. Now that we treat call clobbers the same way regardless of where they come from, we can use $f21 as a caller-save register. This in turn means that -Os is no longer a special case in call-clobbered-3.c. (The new code is the same size as the old code.) 2019-10-02 Richard Sandiford gcc/testsuite/ * gcc.target/mips/call-clobbered-3.c: Remove skip for -Os. * gcc.target/mips/call-clobbered-4.c: Delete. From-SVN: r276456 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/mips/call-clobbered-3.c | 2 -- gcc/testsuite/gcc.target/mips/call-clobbered-4.c | 23 ----------------------- 3 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 gcc/testsuite/gcc.target/mips/call-clobbered-4.c (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 86b8f73..9ca45cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Richard Sandiford + + * gcc.target/mips/call-clobbered-3.c: Remove skip for -Os. + * gcc.target/mips/call-clobbered-4.c: Delete. + 2019-10-02 Tobias Burnus * gfortran.dg/gomp/is_device_ptr-1.f90: New. diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-3.c b/gcc/testsuite/gcc.target/mips/call-clobbered-3.c index fce4d99..3a9e8d8 100644 --- a/gcc/testsuite/gcc.target/mips/call-clobbered-3.c +++ b/gcc/testsuite/gcc.target/mips/call-clobbered-3.c @@ -1,7 +1,5 @@ /* Check that we handle call-clobbered FPRs correctly. */ /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ -/* Refer to call-clobbered-4.c to see the expected output from -Os builds. */ -/* { dg-skip-if "uses callee-saved GPR" { *-*-* } { "-Os" } { "" } } */ /* { dg-options "-mabi=32 -modd-spreg -mfpxx -ffixed-f0 -ffixed-f1 -ffixed-f2 -ffixed-f3 -ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 -ffixed-f10 -ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 -ffixed-f16 -ffixed-f17 -ffixed-f18 -ffixed-f19 -ffixed-f20 -ffixed-f22 -ffixed-f24 -ffixed-f26 -ffixed-f28 -ffixed-f30" } */ void bar (void); diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-4.c b/gcc/testsuite/gcc.target/mips/call-clobbered-4.c deleted file mode 100644 index 51498b8..0000000 --- a/gcc/testsuite/gcc.target/mips/call-clobbered-4.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Check that we handle call-clobbered FPRs correctly. - This test differs from call-clobbered-3.c because when optimising for size - a callee-saved GPR is used for 'b' to cross the call. */ -/* { dg-skip-if "code quality test" { *-*-* } { "*" } { "-Os" } } */ -/* { dg-options "-mabi=32 -modd-spreg -mfpxx -ffixed-f0 -ffixed-f1 -ffixed-f2 -ffixed-f3 -ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 -ffixed-f10 -ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 -ffixed-f16 -ffixed-f17 -ffixed-f18 -ffixed-f19 -ffixed-f20 -ffixed-f22 -ffixed-f24 -ffixed-f26 -ffixed-f28 -ffixed-f30" } */ - -void bar (void); -float a; -float -foo () -{ - float b = a + 1.0f; - bar(); - return b; -} -/* { dg-final { scan-assembler-times "lwc1" 4 } } */ -/* { dg-final { scan-assembler-times "swc1" 2 } } */ -/* { dg-final { scan-assembler-times "mtc" 1 } } */ -/* { dg-final { scan-assembler-times "mfc" 1 } } */ -/* { dg-final { scan-assembler-not "mthc" } } */ -/* { dg-final { scan-assembler-not "mfhc" } } */ -/* { dg-final { scan-assembler-not "ldc1" } } */ -/* { dg-final { scan-assembler-not "sdc1" } } */ -- cgit v1.1 From ea4b29d53a6d8e3ab2655a5d13c99bc445b8f286 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 2 Oct 2019 13:12:37 +0000 Subject: Fix shadowing in globalize_reg 2019-10-02 Richard Sandiford gcc/ * reginfo.c (globalize_reg): Fix shadowed variable in function_abis walk. From-SVN: r276457 --- gcc/ChangeLog | 5 +++++ gcc/reginfo.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7b5777e..f9cc2d6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Richard Sandiford + + * reginfo.c (globalize_reg): Fix shadowed variable in + function_abis walk. + 2019-10-02 Martin Jambor * cgraph.c (symbol_table::create_edge): New parameter cloning_p, diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 6bed844..9813bab 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -731,8 +731,8 @@ globalize_reg (tree decl, int i) if (i != STACK_POINTER_REGNUM) { SET_HARD_REG_BIT (regs_invalidated_by_call, i); - for (unsigned int i = 0; i < NUM_ABI_IDS; ++i) - function_abis[i].add_full_reg_clobber (i); + for (unsigned int j = 0; j < NUM_ABI_IDS; ++j) + function_abis[j].add_full_reg_clobber (i); } /* If already fixed, nothing else to do. */ -- cgit v1.1 From 629387a6586a753166f5cf53d587026a34362523 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 2 Oct 2019 13:35:40 +0000 Subject: tree-eh.h (unsplit_eh_edges): Declare. * tree-eh.h (unsplit_eh_edges): Declare. * tree-eh.c (maybe_remove_unreachable_handlers): Detect more cases. (unsplit_eh_edges): New function wrapping unsplit_all_eh. * gimple-ssa-store-merging.c: Include cfganal.h cfgcleanup.h except.h. (struct store_immediate_info): Add lp_nr field. (store_immediate_info::store_immediate_info): Add NR2 parameter and initialize lp_nr with it. (struct merged_store_group): Add lp_nr and only_constants fields. (merged_store_group::merged_store_group): Initialize them. (merged_store_group::can_be_merged_into): Deal with them. (pass_store_merging): Rename terminate_and_release_chain into terminate_and_process_chain. (pass_store_merging::terminate_and_process_all_chains): Adjust to above renaming and remove useless assertions. (pass_store_merging::terminate_all_aliasing_chains): Small tweak. (stmts_may_clobber_ref_p): Be prepared for different basic blocks. (imm_store_chain_info::coalesce_immediate_stores): Use only_constants instead of always recomputing it and compare lp_nr. (imm_store_chain_info::output_merged_store): If the group is in an active EH region, register new stores if they can throw. Moreover, if the insertion has created new basic blocks, adjust the PHI nodes of the post landing pad. (imm_store_chain_info::output_merged_stores): If the original stores are in an active EH region, deregister them. (lhs_valid_for_store_merging_p): Prettify. (adjust_bit_pos): New function extracted from... (mem_valid_for_store_merging): ...here. Use it for the base address and also for the offset if it is the addition of a constant. (lp_nr_for_store): New function. (pass_store_merging::process_store): Change return type to bool. Call lp_nr_for_store to initialize the store info. Propagate the return status of various called functions to the return value. (store_valid_for_store_merging_p): New predicate. (enum basic_block_status): New enumeration. (get_status_for_store_merging): New function. (pass_store_merging::execute): If the function can throw and catch non-call exceptions, unsplit the EH edges on entry and clean up the CFG on exit if something changed. Call get_status_for_store_merging for every basic block and keep the chains open across basic blocks when possible. Terminate and process open chains at the end, if any. From-SVN: r276459 --- gcc/ChangeLog | 43 +++++ gcc/gimple-ssa-store-merging.c | 356 +++++++++++++++++++++++++++--------- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gnat.dg/opt82.adb | 14 ++ gcc/testsuite/gnat.dg/opt82_pkg.ads | 10 + gcc/tree-eh.c | 34 +++- gcc/tree-eh.h | 1 + 7 files changed, 370 insertions(+), 93 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/opt82.adb create mode 100644 gcc/testsuite/gnat.dg/opt82_pkg.ads (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f9cc2d6..d66b03e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,46 @@ +2019-10-02 Eric Botcazou + + * tree-eh.h (unsplit_eh_edges): Declare. + * tree-eh.c (maybe_remove_unreachable_handlers): Detect more cases. + (unsplit_eh_edges): New function wrapping unsplit_all_eh. + * gimple-ssa-store-merging.c: Include cfganal.h cfgcleanup.h except.h. + (struct store_immediate_info): Add lp_nr field. + (store_immediate_info::store_immediate_info): Add NR2 parameter and + initialize lp_nr with it. + (struct merged_store_group): Add lp_nr and only_constants fields. + (merged_store_group::merged_store_group): Initialize them. + (merged_store_group::can_be_merged_into): Deal with them. + (pass_store_merging): Rename terminate_and_release_chain into + terminate_and_process_chain. + (pass_store_merging::terminate_and_process_all_chains): Adjust to above + renaming and remove useless assertions. + (pass_store_merging::terminate_all_aliasing_chains): Small tweak. + (stmts_may_clobber_ref_p): Be prepared for different basic blocks. + (imm_store_chain_info::coalesce_immediate_stores): Use only_constants + instead of always recomputing it and compare lp_nr. + (imm_store_chain_info::output_merged_store): If the group is in an + active EH region, register new stores if they can throw. Moreover, + if the insertion has created new basic blocks, adjust the PHI nodes + of the post landing pad. + (imm_store_chain_info::output_merged_stores): If the original stores + are in an active EH region, deregister them. + (lhs_valid_for_store_merging_p): Prettify. + (adjust_bit_pos): New function extracted from... + (mem_valid_for_store_merging): ...here. Use it for the base address + and also for the offset if it is the addition of a constant. + (lp_nr_for_store): New function. + (pass_store_merging::process_store): Change return type to bool. + Call lp_nr_for_store to initialize the store info. Propagate the + return status of various called functions to the return value. + (store_valid_for_store_merging_p): New predicate. + (enum basic_block_status): New enumeration. + (get_status_for_store_merging): New function. + (pass_store_merging::execute): If the function can throw and catch + non-call exceptions, unsplit the EH edges on entry and clean up the + CFG on exit if something changed. Call get_status_for_store_merging + for every basic block and keep the chains open across basic blocks + when possible. Terminate and process open chains at the end, if any. + 2019-10-02 Richard Sandiford * reginfo.c (globalize_reg): Fix shadowed variable in diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c index 5abaa7d..270159b 100644 --- a/gcc/gimple-ssa-store-merging.c +++ b/gcc/gimple-ssa-store-merging.c @@ -159,7 +159,10 @@ #include "gimple-fold.h" #include "stor-layout.h" #include "timevar.h" +#include "cfganal.h" +#include "cfgcleanup.h" #include "tree-cfg.h" +#include "except.h" #include "tree-eh.h" #include "target.h" #include "gimplify-me.h" @@ -1375,13 +1378,15 @@ public: /* True if ops have been swapped and thus ops[1] represents rhs1 of BIT_{AND,IOR,XOR}_EXPR and ops[0] represents rhs2. */ bool ops_swapped_p; + /* The index number of the landing pad, or 0 if there is none. */ + int lp_nr; /* Operands. For BIT_*_EXPR rhs_code both operands are used, otherwise just the first one. */ store_operand_info ops[2]; store_immediate_info (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, gimple *, unsigned int, enum tree_code, - struct symbolic_number &, gimple *, bool, + struct symbolic_number &, gimple *, bool, int, const store_operand_info &, const store_operand_info &); }; @@ -1396,11 +1401,13 @@ store_immediate_info::store_immediate_info (unsigned HOST_WIDE_INT bs, struct symbolic_number &nr, gimple *ins_stmtp, bool bitnotp, + int nr2, const store_operand_info &op0r, const store_operand_info &op1r) : bitsize (bs), bitpos (bp), bitregion_start (brs), bitregion_end (bre), stmt (st), order (ord), rhs_code (rhscode), n (nr), - ins_stmt (ins_stmtp), bit_not_p (bitnotp), ops_swapped_p (false) + ins_stmt (ins_stmtp), bit_not_p (bitnotp), ops_swapped_p (false), + lp_nr (nr2) #if __cplusplus >= 201103L , ops { op0r, op1r } { @@ -1435,6 +1442,7 @@ public: bool bit_insertion; bool only_constants; unsigned int first_nonmergeable_order; + int lp_nr; auto_vec stores; /* We record the first and last original statements in the sequence because @@ -1862,6 +1870,7 @@ merged_store_group::merged_store_group (store_immediate_info *info) bit_insertion = false; only_constants = info->rhs_code == INTEGER_CST; first_nonmergeable_order = ~0U; + lp_nr = info->lp_nr; unsigned HOST_WIDE_INT align_bitpos = 0; get_object_alignment_1 (gimple_assign_lhs (info->stmt), &align, &align_bitpos); @@ -1904,6 +1913,9 @@ merged_store_group::can_be_merged_into (store_immediate_info *info) if (info->rhs_code == LROTATE_EXPR) return false; + if (info->lp_nr != lp_nr) + return false; + /* The canonical case. */ if (info->rhs_code == stores[0]->rhs_code) return true; @@ -2173,10 +2185,10 @@ private: decisions when going out of SSA). */ imm_store_chain_info *m_stores_head; - void process_store (gimple *); - bool terminate_and_process_all_chains (); + bool process_store (gimple *); + bool terminate_and_process_chain (imm_store_chain_info *); bool terminate_all_aliasing_chains (imm_store_chain_info **, gimple *); - bool terminate_and_release_chain (imm_store_chain_info *); + bool terminate_and_process_all_chains (); }; // class pass_store_merging /* Terminate and process all recorded chains. Return true if any changes @@ -2187,16 +2199,14 @@ pass_store_merging::terminate_and_process_all_chains () { bool ret = false; while (m_stores_head) - ret |= terminate_and_release_chain (m_stores_head); + ret |= terminate_and_process_chain (m_stores_head); gcc_assert (m_stores.is_empty ()); - gcc_assert (m_stores_head == NULL); - return ret; } /* Terminate all chains that are affected by the statement STMT. CHAIN_INFO is the chain we should ignore from the checks if - non-NULL. */ + non-NULL. Return true if any changes were made. */ bool pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info @@ -2233,8 +2243,7 @@ pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info fprintf (dump_file, "stmt causes chain termination:\n"); print_gimple_stmt (dump_file, stmt, 0); } - terminate_and_release_chain (cur); - ret = true; + ret |= terminate_and_process_chain (cur); break; } } @@ -2248,7 +2257,7 @@ pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info entry is removed after the processing in any case. */ bool -pass_store_merging::terminate_and_release_chain (imm_store_chain_info *chain_info) +pass_store_merging::terminate_and_process_chain (imm_store_chain_info *chain_info) { bool ret = chain_info->terminate_and_process_chain (); m_stores.remove (chain_info->base_addr); @@ -2257,9 +2266,9 @@ pass_store_merging::terminate_and_release_chain (imm_store_chain_info *chain_inf } /* Return true if stmts in between FIRST (inclusive) and LAST (exclusive) - may clobber REF. FIRST and LAST must be in the same basic block and - have non-NULL vdef. We want to be able to sink load of REF across - stores between FIRST and LAST, up to right before LAST. */ + may clobber REF. FIRST and LAST must have non-NULL vdef. We want to + be able to sink load of REF across stores between FIRST and LAST, up + to right before LAST. */ bool stmts_may_clobber_ref_p (gimple *first, gimple *last, tree ref) @@ -2270,7 +2279,10 @@ stmts_may_clobber_ref_p (gimple *first, gimple *last, tree ref) tree vop = gimple_vdef (last); gimple *stmt; - gcc_checking_assert (gimple_bb (first) == gimple_bb (last)); + /* Return true conservatively if the basic blocks are different. */ + if (gimple_bb (first) != gimple_bb (last)) + return true; + do { stmt = SSA_NAME_DEF_STMT (vop); @@ -2286,6 +2298,7 @@ stmts_may_clobber_ref_p (gimple *first, gimple *last, tree ref) vop = gimple_vuse (stmt); } while (stmt != first); + return false; } @@ -2759,7 +2772,9 @@ imm_store_chain_info::coalesce_immediate_stores () merged_store->start + merged_store->width - 1)) { /* Only allow overlapping stores of constants. */ - if (info->rhs_code == INTEGER_CST && merged_store->only_constants) + if (info->rhs_code == INTEGER_CST + && merged_store->only_constants + && info->lp_nr == merged_store->lp_nr) { unsigned int last_order = MAX (merged_store->last_order, info->order); @@ -4152,6 +4167,9 @@ imm_store_chain_info::output_merged_store (merged_store_group *group) gimple_set_vuse (stmt, new_vuse); gimple_seq_add_stmt_without_update (&seq, stmt); + if (group->lp_nr && stmt_could_throw_p (cfun, stmt)) + add_stmt_to_eh_lp (stmt, group->lp_nr); + tree new_vdef; if (i < split_stores.length () - 1) new_vdef = make_ssa_name (gimple_vop (cfun), stmt); @@ -4175,7 +4193,63 @@ imm_store_chain_info::output_merged_store (merged_store_group *group) if (dump_flags & TDF_DETAILS) print_gimple_seq (dump_file, seq, 0, TDF_VOPS | TDF_MEMSYMS); } - gsi_insert_seq_after (&last_gsi, seq, GSI_SAME_STMT); + + if (group->lp_nr > 0) + { + /* We're going to insert a sequence of (potentially) throwing stores + into an active EH region. This means that we're going to create + new basic blocks with EH edges pointing to the post landing pad + and, therefore, to have to update its PHI nodes, if any. For the + virtual PHI node, we're going to use the VDEFs created above, but + for the other nodes, we need to record the original reaching defs. */ + eh_landing_pad lp = get_eh_landing_pad_from_number (group->lp_nr); + basic_block lp_bb = label_to_block (cfun, lp->post_landing_pad); + basic_block last_bb = gimple_bb (group->last_stmt); + edge last_edge = find_edge (last_bb, lp_bb); + auto_vec last_defs; + gphi_iterator gpi; + for (gpi = gsi_start_phis (lp_bb); !gsi_end_p (gpi); gsi_next (&gpi)) + { + gphi *phi = gpi.phi (); + tree last_def; + if (virtual_operand_p (gimple_phi_result (phi))) + last_def = NULL_TREE; + else + last_def = gimple_phi_arg_def (phi, last_edge->dest_idx); + last_defs.safe_push (last_def); + } + + /* Do the insertion. Then, if new basic blocks have been created in the + process, rewind the chain of VDEFs create above to walk the new basic + blocks and update the corresponding arguments of the PHI nodes. */ + update_modified_stmts (seq); + if (gimple_find_sub_bbs (seq, &last_gsi)) + while (last_vdef != gimple_vuse (group->last_stmt)) + { + gimple *stmt = SSA_NAME_DEF_STMT (last_vdef); + if (stmt_could_throw_p (cfun, stmt)) + { + edge new_edge = find_edge (gimple_bb (stmt), lp_bb); + unsigned int i; + for (gpi = gsi_start_phis (lp_bb), i = 0; + !gsi_end_p (gpi); + gsi_next (&gpi), i++) + { + gphi *phi = gpi.phi (); + tree new_def; + if (virtual_operand_p (gimple_phi_result (phi))) + new_def = last_vdef; + else + new_def = last_defs[i]; + add_phi_arg (phi, new_def, new_edge, UNKNOWN_LOCATION); + } + } + last_vdef = gimple_vuse (stmt); + } + } + else + gsi_insert_seq_after (&last_gsi, seq, GSI_SAME_STMT); + for (int j = 0; j < 2; ++j) if (load_seq[j]) gsi_insert_seq_after (&load_gsi[j], load_seq[j], GSI_SAME_STMT); @@ -4206,6 +4280,8 @@ imm_store_chain_info::output_merged_stores () gimple *stmt = store->stmt; gimple_stmt_iterator gsi = gsi_for_stmt (stmt); gsi_remove (&gsi, true); + if (store->lp_nr) + remove_stmt_from_eh_lp (stmt); if (stmt != merged_store->last_stmt) { unlink_stmt_vdef (stmt); @@ -4258,14 +4334,22 @@ imm_store_chain_info::terminate_and_process_chain () static bool lhs_valid_for_store_merging_p (tree lhs) { - tree_code code = TREE_CODE (lhs); - - if (code == ARRAY_REF || code == ARRAY_RANGE_REF || code == MEM_REF - || code == COMPONENT_REF || code == BIT_FIELD_REF - || DECL_P (lhs)) + if (DECL_P (lhs)) return true; - return false; + switch (TREE_CODE (lhs)) + { + case ARRAY_REF: + case ARRAY_RANGE_REF: + case BIT_FIELD_REF: + case COMPONENT_REF: + case MEM_REF: + return true; + default: + return false; + } + + gcc_unreachable (); } /* Return true if the tree RHS is a constant we want to consider @@ -4286,6 +4370,40 @@ rhs_valid_for_store_merging_p (tree rhs) && native_encode_expr (rhs, NULL, size) != 0); } +/* Adjust *PBITPOS, *PBITREGION_START and *PBITREGION_END by BYTE_OFF bytes + and return true on success or false on failure. */ + +static bool +adjust_bit_pos (poly_offset_int byte_off, + poly_int64 *pbitpos, + poly_uint64 *pbitregion_start, + poly_uint64 *pbitregion_end) +{ + poly_offset_int bit_off = byte_off << LOG2_BITS_PER_UNIT; + bit_off += *pbitpos; + + if (known_ge (bit_off, 0) && bit_off.to_shwi (pbitpos)) + { + if (maybe_ne (*pbitregion_end, 0U)) + { + bit_off = byte_off << LOG2_BITS_PER_UNIT; + bit_off += *pbitregion_start; + if (bit_off.to_uhwi (pbitregion_start)) + { + bit_off = byte_off << LOG2_BITS_PER_UNIT; + bit_off += *pbitregion_end; + if (!bit_off.to_uhwi (pbitregion_end)) + *pbitregion_end = 0; + } + else + *pbitregion_end = 0; + } + return true; + } + else + return false; +} + /* If MEM is a memory reference usable for store merging (either as store destination or for loads), return the non-NULL base_addr and set *PBITSIZE, *PBITPOS, *PBITREGION_START and *PBITREGION_END. @@ -4330,27 +4448,8 @@ mem_valid_for_store_merging (tree mem, poly_uint64 *pbitsize, PR 23684 and this way we can catch more chains. */ else if (TREE_CODE (base_addr) == MEM_REF) { - poly_offset_int byte_off = mem_ref_offset (base_addr); - poly_offset_int bit_off = byte_off << LOG2_BITS_PER_UNIT; - bit_off += bitpos; - if (known_ge (bit_off, 0) && bit_off.to_shwi (&bitpos)) - { - if (maybe_ne (bitregion_end, 0U)) - { - bit_off = byte_off << LOG2_BITS_PER_UNIT; - bit_off += bitregion_start; - if (bit_off.to_uhwi (&bitregion_start)) - { - bit_off = byte_off << LOG2_BITS_PER_UNIT; - bit_off += bitregion_end; - if (!bit_off.to_uhwi (&bitregion_end)) - bitregion_end = 0; - } - else - bitregion_end = 0; - } - } - else + if (!adjust_bit_pos (mem_ref_offset (base_addr), &bitpos, + &bitregion_start, &bitregion_end)) return NULL_TREE; base_addr = TREE_OPERAND (base_addr, 0); } @@ -4363,14 +4462,7 @@ mem_valid_for_store_merging (tree mem, poly_uint64 *pbitsize, base_addr = build_fold_addr_expr (base_addr); } - if (known_eq (bitregion_end, 0U)) - { - bitregion_start = round_down_to_byte_boundary (bitpos); - bitregion_end = bitpos; - bitregion_end = round_up_to_byte_boundary (bitregion_end + bitsize); - } - - if (offset != NULL_TREE) + if (offset) { /* If the access is variable offset then a base decl has to be address-taken to be able to emit pointer-based stores to it. @@ -4378,14 +4470,26 @@ mem_valid_for_store_merging (tree mem, poly_uint64 *pbitsize, base up to the first variable part and then wrapping that inside a BIT_FIELD_REF. */ tree base = get_base_address (base_addr); - if (! base - || (DECL_P (base) && ! TREE_ADDRESSABLE (base))) + if (!base || (DECL_P (base) && !TREE_ADDRESSABLE (base))) return NULL_TREE; + /* Similarly to above for the base, remove constant from the offset. */ + if (TREE_CODE (offset) == PLUS_EXPR + && TREE_CODE (TREE_OPERAND (offset, 1)) == INTEGER_CST + && adjust_bit_pos (wi::to_poly_offset (TREE_OPERAND (offset, 1)), + &bitpos, &bitregion_start, &bitregion_end)) + offset = TREE_OPERAND (offset, 0); + base_addr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base_addr), base_addr, offset); } + if (known_eq (bitregion_end, 0U)) + { + bitregion_start = round_down_to_byte_boundary (bitpos); + bitregion_end = round_up_to_byte_boundary (bitpos + bitsize); + } + *pbitsize = bitsize; *pbitpos = bitpos; *pbitregion_start = bitregion_start; @@ -4448,10 +4552,24 @@ handled_load (gimple *stmt, store_operand_info *op, return false; } +/* Return the index number of the landing pad for STMT, if any. */ + +static int +lp_nr_for_store (gimple *stmt) +{ + if (!cfun->can_throw_non_call_exceptions || !cfun->eh) + return 0; + + if (!stmt_could_throw_p (cfun, stmt)) + return 0; + + return lookup_stmt_eh_lp (stmt); +} + /* Record the store STMT for store merging optimization if it can be - optimized. */ + optimized. Return true if any changes were made. */ -void +bool pass_store_merging::process_store (gimple *stmt) { tree lhs = gimple_assign_lhs (stmt); @@ -4462,7 +4580,7 @@ pass_store_merging::process_store (gimple *stmt) = mem_valid_for_store_merging (lhs, &bitsize, &bitpos, &bitregion_start, &bitregion_end); if (known_eq (bitsize, 0U)) - return; + return false; bool invalid = (base_addr == NULL_TREE || (maybe_gt (bitsize, @@ -4604,15 +4722,13 @@ pass_store_merging::process_store (gimple *stmt) || !bitpos.is_constant (&const_bitpos) || !bitregion_start.is_constant (&const_bitregion_start) || !bitregion_end.is_constant (&const_bitregion_end)) - { - terminate_all_aliasing_chains (NULL, stmt); - return; - } + return terminate_all_aliasing_chains (NULL, stmt); if (!ins_stmt) memset (&n, 0, sizeof (n)); class imm_store_chain_info **chain_info = NULL; + bool ret = false; if (base_addr) chain_info = m_stores.get (base_addr); @@ -4624,14 +4740,15 @@ pass_store_merging::process_store (gimple *stmt) const_bitregion_start, const_bitregion_end, stmt, ord, rhs_code, n, ins_stmt, - bit_not_p, ops[0], ops[1]); + bit_not_p, lp_nr_for_store (stmt), + ops[0], ops[1]); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Recording immediate store from stmt:\n"); print_gimple_stmt (dump_file, stmt, 0); } (*chain_info)->m_store_info.safe_push (info); - terminate_all_aliasing_chains (chain_info, stmt); + ret |= terminate_all_aliasing_chains (chain_info, stmt); /* If we reach the limit of stores to merge in a chain terminate and process the chain now. */ if ((*chain_info)->m_store_info.length () @@ -4640,13 +4757,13 @@ pass_store_merging::process_store (gimple *stmt) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Reached maximum number of statements to merge:\n"); - terminate_and_release_chain (*chain_info); + ret |= terminate_and_process_chain (*chain_info); } - return; + return ret; } /* Store aliases any existing chain? */ - terminate_all_aliasing_chains (NULL, stmt); + ret |= terminate_all_aliasing_chains (NULL, stmt); /* Start a new chain. */ class imm_store_chain_info *new_chain = new imm_store_chain_info (m_stores_head, base_addr); @@ -4654,7 +4771,8 @@ pass_store_merging::process_store (gimple *stmt) const_bitregion_start, const_bitregion_end, stmt, 0, rhs_code, n, ins_stmt, - bit_not_p, ops[0], ops[1]); + bit_not_p, lp_nr_for_store (stmt), + ops[0], ops[1]); new_chain->m_store_info.safe_push (info); m_stores.put (base_addr, new_chain); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -4665,6 +4783,52 @@ pass_store_merging::process_store (gimple *stmt) print_generic_expr (dump_file, base_addr); fprintf (dump_file, "\n"); } + return ret; +} + +/* Return true if STMT is a store valid for store merging. */ + +static bool +store_valid_for_store_merging_p (gimple *stmt) +{ + return gimple_assign_single_p (stmt) + && gimple_vdef (stmt) + && lhs_valid_for_store_merging_p (gimple_assign_lhs (stmt)) + && !gimple_has_volatile_ops (stmt); +} + +enum basic_block_status { BB_INVALID, BB_VALID, BB_EXTENDED_VALID }; + +/* Return the status of basic block BB wrt store merging. */ + +static enum basic_block_status +get_status_for_store_merging (basic_block bb) +{ + unsigned int num_statements = 0; + gimple_stmt_iterator gsi; + edge e; + + for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (is_gimple_debug (stmt)) + continue; + + if (store_valid_for_store_merging_p (stmt) && ++num_statements >= 2) + break; + } + + if (num_statements == 0) + return BB_INVALID; + + if (cfun->can_throw_non_call_exceptions && cfun->eh + && store_valid_for_store_merging_p (gimple_seq_last_stmt (bb_seq (bb))) + && (e = find_fallthru_edge (bb->succs)) + && e->dest == bb->next_bb) + return BB_EXTENDED_VALID; + + return num_statements >= 2 ? BB_VALID : BB_INVALID; } /* Entry point for the pass. Go over each basic block recording chains of @@ -4677,26 +4841,28 @@ pass_store_merging::execute (function *fun) { basic_block bb; hash_set orig_stmts; + bool changed = false, open_chains = false; + + /* If the function can throw and catch non-call exceptions, we'll be trying + to merge stores across different basic blocks so we need to first unsplit + the EH edges in order to streamline the CFG of the function. */ + if (cfun->can_throw_non_call_exceptions && cfun->eh) + unsplit_eh_edges (); calculate_dominance_info (CDI_DOMINATORS); FOR_EACH_BB_FN (bb, fun) { + const basic_block_status bb_status = get_status_for_store_merging (bb); gimple_stmt_iterator gsi; - unsigned HOST_WIDE_INT num_statements = 0; - /* Record the original statements so that we can keep track of - statements emitted in this pass and not re-process new - statements. */ - for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - if (is_gimple_debug (gsi_stmt (gsi))) - continue; - if (++num_statements >= 2) - break; + if (open_chains && (bb_status == BB_INVALID || !single_pred_p (bb))) + { + changed |= terminate_and_process_all_chains (); + open_chains = false; } - if (num_statements < 2) + if (bb_status == BB_INVALID) continue; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -4715,19 +4881,37 @@ pass_store_merging::execute (function *fun) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Volatile access terminates " "all chains\n"); - terminate_and_process_all_chains (); + changed |= terminate_and_process_all_chains (); + open_chains = false; continue; } - if (gimple_assign_single_p (stmt) && gimple_vdef (stmt) - && !stmt_can_throw_internal (cfun, stmt) - && lhs_valid_for_store_merging_p (gimple_assign_lhs (stmt))) - process_store (stmt); + if (store_valid_for_store_merging_p (stmt)) + changed |= process_store (stmt); else - terminate_all_aliasing_chains (NULL, stmt); + changed |= terminate_all_aliasing_chains (NULL, stmt); + } + + if (bb_status == BB_EXTENDED_VALID) + open_chains = true; + else + { + changed |= terminate_and_process_all_chains (); + open_chains = false; } - terminate_and_process_all_chains (); } + + if (open_chains) + changed |= terminate_and_process_all_chains (); + + /* If the function can throw and catch non-call exceptions and something + changed during the pass, then the CFG has (very likely) changed too. */ + if (cfun->can_throw_non_call_exceptions && cfun->eh && changed) + { + free_dominance_info (CDI_DOMINATORS); + return TODO_cleanup_cfg; + } + return 0; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9ca45cb..1895d84 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Eric Botcazou + + * gnat.dg/opt82.adb: New test. + * gnat.dg/opt82_pkg.ads: New helper. + 2019-10-02 Richard Sandiford * gcc.target/mips/call-clobbered-3.c: Remove skip for -Os. diff --git a/gcc/testsuite/gnat.dg/opt82.adb b/gcc/testsuite/gnat.dg/opt82.adb new file mode 100644 index 0000000..9e8e7bb --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt82.adb @@ -0,0 +1,14 @@ +-- { dg-do compile } +-- { dg-options "-O2 -fdump-tree-optimized" } + +with Opt82_Pkg; use Opt82_Pkg; + +procedure Opt82 (R : access Rec) is +begin + R.A := 'A'; + R.B := 'B'; + R.C := 'C'; + R.D := 'D'; +exception + when Storage_Error => R.A := 'E'; +end; diff --git a/gcc/testsuite/gnat.dg/opt82_pkg.ads b/gcc/testsuite/gnat.dg/opt82_pkg.ads new file mode 100644 index 0000000..7b67890 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt82_pkg.ads @@ -0,0 +1,10 @@ + +-- { dg-final { scan-tree-dump "= 1145258561|= 1094861636" "optimized" } } + +package Opt82_Pkg is + + type Rec is record + A, B, C, D : Character; + end record; + +end Opt82_Pkg; diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 5bb07e4..1aba733 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -4040,15 +4040,14 @@ maybe_remove_unreachable_handlers (void) if (cfun->eh == NULL) return; - + FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp) - if (lp && lp->post_landing_pad) + if (lp + && (lp->post_landing_pad == NULL_TREE + || label_to_block (cfun, lp->post_landing_pad) == NULL)) { - if (label_to_block (cfun, lp->post_landing_pad) == NULL) - { - remove_unreachable_handlers (); - return; - } + remove_unreachable_handlers (); + return; } } @@ -4211,6 +4210,27 @@ unsplit_all_eh (void) return changed; } +/* Wrapper around unsplit_all_eh that makes it usable everywhere. */ + +void +unsplit_eh_edges (void) +{ + bool changed; + + /* unsplit_all_eh can die looking up unreachable landing pads. */ + maybe_remove_unreachable_handlers (); + + changed = unsplit_all_eh (); + + /* If EH edges have been unsplit, delete unreachable forwarder blocks. */ + if (changed) + { + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + delete_unreachable_blocks (); + } +} + /* A subroutine of cleanup_empty_eh. Redirect all EH edges incoming to OLD_BB to NEW_BB; return true on success, false on failure. diff --git a/gcc/tree-eh.h b/gcc/tree-eh.h index a588c10..511bb84 100644 --- a/gcc/tree-eh.h +++ b/gcc/tree-eh.h @@ -50,6 +50,7 @@ extern bool maybe_duplicate_eh_stmt_fn (struct function *, gimple *, hash_map *, int); extern bool maybe_duplicate_eh_stmt (gimple *, gimple *); extern void maybe_remove_unreachable_handlers (void); +extern void unsplit_eh_edges (void); extern bool verify_eh_edges (gimple *); extern bool verify_eh_dispatch_edge (geh_dispatch *); -- cgit v1.1 From 03a9b90aa6df28dde083efd17e8b7ae76b943fe7 Mon Sep 17 00:00:00 2001 From: Aaron Sawdey Date: Wed, 2 Oct 2019 14:23:51 +0000 Subject: builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm. 2019-10-02 Aaron Sawdey * builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm. (expand_builtin_memcpy): Use might_overlap parm. (expand_builtin_mempcpy_args): Use might_overlap parm. (expand_builtin_memmove): Call expand_builtin_memory_copy_args. (expand_builtin_memory_copy_args): Add might_overlap parm. * expr.c (emit_block_move_via_cpymem): Rename to emit_block_move_via_pattern, add might_overlap parm, use cpymem or movmem optab as appropriate. (emit_block_move_hints): Add might_overlap parm, do the right thing for might_overlap==true. * expr.h (emit_block_move_hints): Update prototype. From-SVN: r276461 --- gcc/ChangeLog | 14 +++++++++++ gcc/builtins.c | 27 ++++++++++++++-------- gcc/expr.c | 73 +++++++++++++++++++++++++++++++++++++++++++--------------- gcc/expr.h | 3 ++- 4 files changed, 87 insertions(+), 30 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d66b03e..fe14577 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2019-10-02 Aaron Sawdey + + * builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm. + (expand_builtin_memcpy): Use might_overlap parm. + (expand_builtin_mempcpy_args): Use might_overlap parm. + (expand_builtin_memmove): Call expand_builtin_memory_copy_args. + (expand_builtin_memory_copy_args): Add might_overlap parm. + * expr.c (emit_block_move_via_cpymem): Rename to + emit_block_move_via_pattern, add might_overlap parm, use cpymem + or movmem optab as appropriate. + (emit_block_move_hints): Add might_overlap parm, do the right + thing for might_overlap==true. + * expr.h (emit_block_move_hints): Update prototype. + 2019-10-02 Eric Botcazou * tree-eh.h (unsplit_eh_edges): Declare. diff --git a/gcc/builtins.c b/gcc/builtins.c index 1fd4b88..fa17afd 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -127,7 +127,8 @@ static rtx expand_builtin_memchr (tree, rtx); static rtx expand_builtin_memcpy (tree, rtx); static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len, rtx target, tree exp, - memop_ret retmode); + memop_ret retmode, + bool might_overlap); static rtx expand_builtin_memmove (tree, rtx); static rtx expand_builtin_mempcpy (tree, rtx); static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret); @@ -3790,14 +3791,14 @@ expand_builtin_memcpy (tree exp, rtx target) check_memop_access (exp, dest, src, len); return expand_builtin_memory_copy_args (dest, src, len, target, exp, - /*retmode=*/ RETURN_BEGIN); + /*retmode=*/ RETURN_BEGIN, false); } /* Check a call EXP to the memmove built-in for validity. Return NULL_RTX on both success and failure. */ static rtx -expand_builtin_memmove (tree exp, rtx) +expand_builtin_memmove (tree exp, rtx target) { if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -3809,7 +3810,8 @@ expand_builtin_memmove (tree exp, rtx) check_memop_access (exp, dest, src, len); - return NULL_RTX; + return expand_builtin_memory_copy_args (dest, src, len, target, exp, + /*retmode=*/ RETURN_BEGIN, true); } /* Expand a call EXP to the mempcpy builtin. @@ -3858,7 +3860,8 @@ expand_builtin_mempcpy (tree exp, rtx target) static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len, - rtx target, tree exp, memop_ret retmode) + rtx target, tree exp, memop_ret retmode, + bool might_overlap) { const char *src_str; unsigned int src_align = get_pointer_alignment (src); @@ -3894,9 +3897,12 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len, &probable_max_size); src_str = c_getstr (src); - /* If SRC is a string constant and block move would be done - by pieces, we can avoid loading the string from memory - and only stored the computed constants. */ + /* If SRC is a string constant and block move would be done by + pieces, we can avoid loading the string from memory and only + stored the computed constants. This works in the overlap + (memmove) case as well because store_by_pieces just generates a + series of stores of constants from the string constant returned + by c_getstr(). */ if (src_str && CONST_INT_P (len_rtx) && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 @@ -3923,13 +3929,14 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len, method = BLOCK_OP_TAILCALL; bool use_mempcpy_call = (targetm.libc_has_fast_function (BUILT_IN_MEMPCPY) && retmode == RETURN_END + && !might_overlap && target != const0_rtx); if (use_mempcpy_call) method = BLOCK_OP_NO_LIBCALL_RET; dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method, expected_align, expected_size, min_size, max_size, probable_max_size, - use_mempcpy_call, &is_move_done); + use_mempcpy_call, &is_move_done, might_overlap); /* Bail out when a mempcpy call would be expanded as libcall and when we have a target that provides a fast implementation @@ -3962,7 +3969,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, rtx target, tree orig_exp, memop_ret retmode) { return expand_builtin_memory_copy_args (dest, src, len, target, orig_exp, - retmode); + retmode, false); } /* Expand into a movstr instruction, if one is available. Return NULL_RTX if diff --git a/gcc/expr.c b/gcc/expr.c index 7a70706..bd6a71a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -73,9 +73,10 @@ along with GCC; see the file COPYING3. If not see int cse_not_expected; static bool block_move_libcall_safe_for_call_parm (void); -static bool emit_block_move_via_cpymem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT, - unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - unsigned HOST_WIDE_INT); +static bool emit_block_move_via_pattern (rtx, rtx, rtx, unsigned, unsigned, + HOST_WIDE_INT, unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT, bool); static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned); static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int); static rtx_insn *compress_float_constant (rtx, rtx); @@ -1562,7 +1563,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, unsigned HOST_WIDE_INT min_size, unsigned HOST_WIDE_INT max_size, unsigned HOST_WIDE_INT probable_max_size, - bool bail_out_libcall, bool *is_move_done) + bool bail_out_libcall, bool *is_move_done, + bool might_overlap) { int may_use_call; rtx retval = 0; @@ -1622,13 +1624,30 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, set_mem_size (y, const_size); } - if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align)) - move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN); - else if (emit_block_move_via_cpymem (x, y, size, align, - expected_align, expected_size, - min_size, max_size, probable_max_size)) + bool pieces_ok = can_move_by_pieces (INTVAL (size), align); + bool pattern_ok = false; + + if (!CONST_INT_P (size) || !pieces_ok || might_overlap) + { + pattern_ok = + emit_block_move_via_pattern (x, y, size, align, + expected_align, expected_size, + min_size, max_size, probable_max_size, + might_overlap); + if (!pattern_ok && might_overlap) + { + /* Do not try any of the other methods below as they are not safe + for overlapping moves. */ + *is_move_done = false; + return retval; + } + } + + if (pattern_ok) ; - else if (may_use_call + else if (CONST_INT_P (size) && pieces_ok) + move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN); + else if (may_use_call && !might_overlap && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y))) { @@ -1645,7 +1664,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, retval = emit_block_copy_via_libcall (x, y, size, method == BLOCK_OP_TAILCALL); } - + else if (might_overlap) + *is_move_done = false; else emit_block_move_via_loop (x, y, size, align); @@ -1721,15 +1741,26 @@ block_move_libcall_safe_for_call_parm (void) return true; } -/* A subroutine of emit_block_move. Expand a cpymem pattern; - return true if successful. */ +/* A subroutine of emit_block_move. Expand a cpymem or movmem pattern; + return true if successful. + + X is the destination of the copy or move. + Y is the source of the copy or move. + SIZE is the size of the block to be moved. + + MIGHT_OVERLAP indicates this originated with expansion of a + builtin_memmove() and the source and destination blocks may + overlap. + */ static bool -emit_block_move_via_cpymem (rtx x, rtx y, rtx size, unsigned int align, - unsigned int expected_align, HOST_WIDE_INT expected_size, - unsigned HOST_WIDE_INT min_size, - unsigned HOST_WIDE_INT max_size, - unsigned HOST_WIDE_INT probable_max_size) +emit_block_move_via_pattern (rtx x, rtx y, rtx size, unsigned int align, + unsigned int expected_align, + HOST_WIDE_INT expected_size, + unsigned HOST_WIDE_INT min_size, + unsigned HOST_WIDE_INT max_size, + unsigned HOST_WIDE_INT probable_max_size, + bool might_overlap) { if (expected_align < align) expected_align = align; @@ -1752,7 +1783,11 @@ emit_block_move_via_cpymem (rtx x, rtx y, rtx size, unsigned int align, FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT) { scalar_int_mode mode = mode_iter.require (); - enum insn_code code = direct_optab_handler (cpymem_optab, mode); + enum insn_code code; + if (might_overlap) + code = direct_optab_handler (movmem_optab, mode); + else + code = direct_optab_handler (cpymem_optab, mode); if (code != CODE_FOR_nothing /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT diff --git a/gcc/expr.h b/gcc/expr.h index 6eb70bf..17c9163 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -116,7 +116,8 @@ extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, bool bail_out_libcall = false, - bool *is_move_done = NULL); + bool *is_move_done = NULL, + bool might_overlap = false); extern rtx emit_block_cmp_hints (rtx, rtx, rtx, tree, rtx, bool, by_pieces_constfn, void *); extern bool emit_storent_insn (rtx to, rtx from); -- cgit v1.1 From c8241327cd156ed15fb136e0b0eaace263aba717 Mon Sep 17 00:00:00 2001 From: Aaron Sawdey Date: Wed, 2 Oct 2019 14:26:09 +0000 Subject: rs6000-protos.h (expand_block_move): Change prototype. 2019-10-02 Aaron Sawdey * config/rs6000/rs6000-protos.h (expand_block_move): Change prototype. * config/rs6000/rs6000-string.c (expand_block_move): Add might_overlap parm. * config/rs6000/rs6000.md (movmemsi): Add new pattern. (cpymemsi): Add might_overlap parm to expand_block_move() call. From-SVN: r276462 --- gcc/ChangeLog | 8 ++++++ gcc/config/rs6000/rs6000-protos.h | 2 +- gcc/config/rs6000/rs6000-string.c | 51 +++++++++++++++------------------------ gcc/config/rs6000/rs6000.md | 24 ++++++++++++++++-- 4 files changed, 51 insertions(+), 34 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fe14577..5dc5331 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2019-10-02 Aaron Sawdey + * config/rs6000/rs6000-protos.h (expand_block_move): Change prototype. + * config/rs6000/rs6000-string.c (expand_block_move): Add + might_overlap parm. + * config/rs6000/rs6000.md (movmemsi): Add new pattern. + (cpymemsi): Add might_overlap parm to expand_block_move() call. + +2019-10-02 Aaron Sawdey + * builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm. (expand_builtin_memcpy): Use might_overlap parm. (expand_builtin_mempcpy_args): Use might_overlap parm. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index c51b768..08dd88c 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -69,7 +69,7 @@ extern void rs6000_generate_float2_code (bool, rtx, rtx, rtx); extern void rs6000_generate_float2_double_code (rtx, rtx, rtx); extern void rs6000_generate_vsigned2_code (bool, rtx, rtx, rtx); extern int expand_block_clear (rtx[]); -extern int expand_block_move (rtx[]); +extern int expand_block_move (rtx[], bool); extern bool expand_block_compare (rtx[]); extern bool expand_strn_compare (rtx[], int); extern bool rs6000_is_valid_mask (rtx, int *, int *, machine_mode); diff --git a/gcc/config/rs6000/rs6000-string.c b/gcc/config/rs6000/rs6000-string.c index b939185..3bc359e 100644 --- a/gcc/config/rs6000/rs6000-string.c +++ b/gcc/config/rs6000/rs6000-string.c @@ -2719,7 +2719,7 @@ gen_lvx_v4si_move (rtx dest, rtx src) #define MAX_MOVE_REG 4 int -expand_block_move (rtx operands[]) +expand_block_move (rtx operands[], bool might_overlap) { rtx orig_dest = operands[0]; rtx orig_src = operands[1]; @@ -2730,6 +2730,7 @@ expand_block_move (rtx operands[]) int bytes; int offset; int move_bytes; + rtx loads[MAX_MOVE_REG]; rtx stores[MAX_MOVE_REG]; int num_reg = 0; @@ -2817,47 +2818,35 @@ expand_block_move (rtx operands[]) gen_func.mov = gen_movqi; } + /* Mode is always set to something other than BLKmode by one of the + cases of the if statement above. */ + gcc_assert (mode != BLKmode); + src = adjust_address (orig_src, mode, offset); dest = adjust_address (orig_dest, mode, offset); - if (mode != BLKmode) - { - rtx tmp_reg = gen_reg_rtx (mode); + rtx tmp_reg = gen_reg_rtx (mode); + + loads[num_reg] = (*gen_func.mov) (tmp_reg, src); + stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg); - emit_insn ((*gen_func.mov) (tmp_reg, src)); - stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg); - } + /* If we didn't succeed in doing it in one pass, we can't do it in the + might_overlap case. Bail out and return failure. */ + if (might_overlap && num_reg >= MAX_MOVE_REG + && bytes > move_bytes) + return 0; - if (mode == BLKmode || num_reg >= MAX_MOVE_REG || bytes == move_bytes) + /* Emit loads and stores saved up. */ + if (num_reg >= MAX_MOVE_REG || bytes == move_bytes) { int i; for (i = 0; i < num_reg; i++) + emit_insn (loads[i]); + for (i = 0; i < num_reg; i++) emit_insn (stores[i]); num_reg = 0; } - - if (mode == BLKmode) - { - /* Move the address into scratch registers. The movmemsi - patterns require zero offset. */ - if (!REG_P (XEXP (src, 0))) - { - rtx src_reg = copy_addr_to_reg (XEXP (src, 0)); - src = replace_equiv_address (src, src_reg); - } - set_mem_size (src, move_bytes); - - if (!REG_P (XEXP (dest, 0))) - { - rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0)); - dest = replace_equiv_address (dest, dest_reg); - } - set_mem_size (dest, move_bytes); - - emit_insn ((*gen_func.movmemsi) (dest, src, - GEN_INT (move_bytes & 31), - align_rtx)); - } + } return 1; diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 4f27f13..2dca269 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -9107,7 +9107,7 @@ FAIL; }) -;; String/block move insn. +;; String/block copy insn (source and destination must not overlap). ;; Argument 0 is the destination ;; Argument 1 is the source ;; Argument 2 is the length @@ -9120,11 +9120,31 @@ (use (match_operand:SI 3 ""))])] "" { - if (expand_block_move (operands)) + if (expand_block_move (operands, false)) DONE; else FAIL; }) + +;; String/block move insn (source and destination may overlap). +;; Argument 0 is the destination +;; Argument 1 is the source +;; Argument 2 is the length +;; Argument 3 is the alignment + +(define_expand "movmemsi" + [(parallel [(set (match_operand:BLK 0 "") + (match_operand:BLK 1 "")) + (use (match_operand:SI 2 "")) + (use (match_operand:SI 3 ""))])] + "" +{ + if (expand_block_move (operands, true)) + DONE; + else + FAIL; +}) + ;; Define insns that do load or store with update. Some of these we can ;; get by using pre-decrement or pre-increment, but the hardware can also -- cgit v1.1 From 408b33fcc39bc1d8c12e41fa6149ed404b23f50f Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 2 Oct 2019 15:07:52 +0000 Subject: module.c (load_commons): Initialize flags to 0 to silecne -Wmaybe-uninitialized warning. * module.c (load_commons): Initialize flags to 0 to silecne -Wmaybe-uninitialized warning. (read_module): Likewise for n and comp_name. From-SVN: r276464 --- gcc/fortran/ChangeLog | 7 +++++++ gcc/fortran/module.c | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8d7a2cf..51c393a 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Jan Hubicka + + * module.c (load_commons): Initialize flags to 0 to silecne + -Wmaybe-uninitialized warning. + (read_module): Likewise for n and comp_name. + 2019-10-02 Tobias Burnus * dump-parse-tree.c (show_omp_clauses): Handle OMP_LIST_USE_DEVICE_ADDR. @@ -33,6 +39,7 @@ (lang_decl): Add new optional_arg field. (GFC_DECL_OPTIONAL_ARGUMENT): New macro. +>>>>>>> .r276463 2019-10-01 David Malcolm * error.c (gfc_diagnostic_starter): Clear the prefix before diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c index 533445e..1ca1535 100644 --- a/gcc/fortran/module.c +++ b/gcc/fortran/module.c @@ -4745,7 +4745,7 @@ load_commons (void) while (peek_atom () != ATOM_RPAREN) { - int flags; + int flags = 0; char* label; mio_lparen (); mio_internal_string (name); @@ -5243,8 +5243,8 @@ read_module (void) for (c = sym->components; c; c = c->next) { pointer_info *p; - const char *comp_name; - int n; + const char *comp_name = NULL; + int n = 0; mio_lparen (); /* component opening. */ mio_integer (&n); -- cgit v1.1 From a264ea9a5bbbbf78ea8c53b675584d1f218e20db Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Wed, 2 Oct 2019 17:09:37 +0200 Subject: [PR testsuite/91842] Skip gcc.dg/ipa/ipa-sra-19.c on power 2019-10-02 Martin Jambor PR testsuite/91842 * gcc.dg/ipa/ipa-sra-19.c: Skip on powerpc. From-SVN: r276465 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c | 1 + 2 files changed, 6 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1895d84..f09db23 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Martin Jambor + + PR testsuite/91842 + * gcc.dg/ipa/ipa-sra-19.c: Skip on powerpc. + 2019-10-02 Eric Botcazou * gnat.dg/opt82.adb: New test. diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c index adebaa5..d219411 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2" } */ +/* { dg-skip-if "" { powerpc*-*-* } } */ typedef int __attribute__((__vector_size__(16))) vectype; -- cgit v1.1 From 1764d63bd98c6c08e993f5c39dfa0247985b1642 Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Wed, 2 Oct 2019 18:37:12 +0300 Subject: ifcvt: improve cost estimation (PR 87047) PR rtl-optimization/87047 * ifcvt.c (average_cost): New static function. Use it... (noce_process_if_block): ... here. testsuite/ * gcc.dg/pr87047.c: New test. From-SVN: r276466 --- gcc/ChangeLog | 6 ++++++ gcc/ifcvt.c | 17 +++++++++++++---- gcc/ifcvt.h | 4 ++-- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.dg/pr87047.c | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr87047.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5dc5331..4f7edd2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-02 Alexander Monakov + + PR rtl-optimization/87047 + * ifcvt.c (average_cost): New static function. Use it... + (noce_process_if_block): ... here. + 2019-10-02 Aaron Sawdey * config/rs6000/rs6000-protos.h (expand_block_move): Change prototype. diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index e0c9522..8bc6f53 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -3358,6 +3358,16 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb) return count > 1 && count <= param; } +/* Compute average of two given costs weighted by relative probabilities + of respective basic blocks in an IF-THEN-ELSE. E is the IF-THEN edge. + With P as the probability to take the IF-THEN branch, return + P * THEN_COST + (1 - P) * ELSE_COST. */ +static unsigned +average_cost (unsigned then_cost, unsigned else_cost, edge e) +{ + return else_cost + e->probability.apply ((signed) (then_cost - else_cost)); +} + /* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert it without using conditional execution. Return TRUE if we were successful at converting the block. */ @@ -3413,10 +3423,9 @@ noce_process_if_block (struct noce_if_info *if_info) &if_info->else_simple)) return false; - if (else_bb == NULL) - if_info->original_cost += then_cost; - else if (speed_p) - if_info->original_cost += MIN (then_cost, else_cost); + if (speed_p) + if_info->original_cost += average_cost (then_cost, else_cost, + find_edge (test_bb, then_bb)); else if_info->original_cost += then_cost + else_cost; diff --git a/gcc/ifcvt.h b/gcc/ifcvt.h index 153ad96..40ad744 100644 --- a/gcc/ifcvt.h +++ b/gcc/ifcvt.h @@ -97,8 +97,8 @@ struct noce_if_info /* An estimate of the original costs. When optimizing for size, this is the combined cost of COND, JUMP and the costs for THEN_BB and ELSE_BB. - When optimizing for speed, we use the costs of COND plus the minimum of - the costs for THEN_BB and ELSE_BB, as computed in the next field. */ + When optimizing for speed, we use the costs of COND plus weighted average + of the costs for THEN_BB and ELSE_BB, as computed in the next field. */ unsigned int original_cost; /* Maximum permissible cost for the unconditional sequence we should diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f09db23..d6cd8ca 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Alexander Monakov + + PR rtl-optimization/87047 + * gcc.dg/pr87047.c: New test. + 2019-10-02 Martin Jambor PR testsuite/91842 diff --git a/gcc/testsuite/gcc.dg/pr87047.c b/gcc/testsuite/gcc.dg/pr87047.c new file mode 100644 index 0000000..cb26ea4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr87047.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } */ +/* { dg-options "-fdump-rtl-ce1 -O2" } */ + +typedef unsigned long long uint64_t; + +static uint64_t umulh(uint64_t a, uint64_t b) +{ + return (unsigned __int128)a*b >> 64; +} + +uint64_t f(uint64_t a, uint64_t b, int c) +{ + if (c) + a = umulh(a, (b-umulh(a,b))<<44) << 1; + return a; +} + +/* { dg-final { scan-rtl-dump "0 true changes made" "ce1" } } */ +/* { dg-final { scan-assembler-not "cmov" } } */ -- cgit v1.1 From 562d1e9556777988ae46c5d1357af2636bc272ea Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 2 Oct 2019 16:01:47 +0000 Subject: cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT, [...]): New. * cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT, MAX_INLINE_INSNS_AUTO_O2_LIMIT): New. * ipa-inline.c (inline_insns_single, inline_insns_auto): New functions. (can_inline_edge_by_limits_p): Use it. (big_speedup_p): Use PARAM_INLINE_MIN_SPEEDUP_O2. (want_inline_small_function_p): Use O2 bounds. (edge_badness): LIkewise. * opts.c (default_options): Add OPT_finline_functions. * params.def (PARAM_INLINE_MIN_SPEEDUP_O2, PARAM_MAX_INLINE_INSNS_SINGLE_O2, PARAM_MAX_INLINE_INSNS_AUTO_O2): New parameters. * g++.dg/tree-ssa/pr53844.C: Add -fno-inline-functions --param max-inline-insns-single-O2=200. * gcc.c-torture/execute/builtins/builtins.exp: Add -fno-inline-functions to additional_flags. * gcc.dg/ipa/inline-7.c: Add -fno-inline-functions. * gcc.dg/optimize-bswapsi-5.c: Add -fno-inline-functions. * gcc.dg/tree-ssa/ssa-thread-12.c: Add --param early-inlining-insns-O2=14 -fno-inline-functions; revert previous change. * gcc.dg/winline-3.c: Use --param max-inline-insns-single-O2=1 --param inline-min-speedup-O2=100 instead of --param max-inline-insns-single=1 --param inline-min-speedup=100 * invoke.texi (-finline-functions): Update documentation. (max-inline-insns-single-O2, max-inline-insns-auto-O2, inline-min-speedup-O2): Document. (early-inlining-insns-O2): Simplify docs. From-SVN: r276469 --- gcc/cif-code.def | 4 + gcc/doc/invoke.texi | 41 ++++++---- gcc/ipa-inline.c | 95 +++++++++++++++------- gcc/opts.c | 4 +- gcc/params.def | 21 ++++- gcc/testsuite/g++.dg/tree-ssa/pr53844.C | 2 +- .../gcc.c-torture/execute/builtins/builtins.exp | 2 +- gcc/testsuite/gcc.dg/ipa/inline-7.c | 2 +- gcc/testsuite/gcc.dg/optimize-bswapsi-5.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c | 4 +- gcc/testsuite/gcc.dg/winline-3.c | 2 +- 11 files changed, 124 insertions(+), 55 deletions(-) (limited to 'gcc') diff --git a/gcc/cif-code.def b/gcc/cif-code.def index ccd08e2..8676ee1 100644 --- a/gcc/cif-code.def +++ b/gcc/cif-code.def @@ -70,8 +70,12 @@ DEFCIFCODE(LARGE_STACK_FRAME_GROWTH_LIMIT, CIF_FINAL_NORMAL, N_("--param large-stack-frame-growth limit reached")) DEFCIFCODE(MAX_INLINE_INSNS_SINGLE_LIMIT, CIF_FINAL_NORMAL, N_("--param max-inline-insns-single limit reached")) +DEFCIFCODE(MAX_INLINE_INSNS_SINGLE_O2_LIMIT, CIF_FINAL_NORMAL, + N_("--param max-inline-insns-single-O2 limit reached")) DEFCIFCODE(MAX_INLINE_INSNS_AUTO_LIMIT, CIF_FINAL_NORMAL, N_("--param max-inline-insns-auto limit reached")) +DEFCIFCODE(MAX_INLINE_INSNS_AUTO_O2_LIMIT, CIF_FINAL_NORMAL, + N_("--param max-inline-insns-auto-O2 limit reached")) DEFCIFCODE(INLINE_UNIT_GROWTH_LIMIT, CIF_FINAL_NORMAL, N_("--param inline-unit-growth limit reached")) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4281ee7..4861920 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -8346,6 +8346,7 @@ also turns on the following optimization flags: -ffinite-loops @gol -fgcse -fgcse-lm @gol -fhoist-adjacent-loads @gol +-finline-functions @gol -finline-small-functions @gol -findirect-inlining @gol -fipa-bit-cp -fipa-cp -fipa-icf @gol @@ -8379,7 +8380,6 @@ by @option{-O2} and also turns on the following optimization flags: @c Please keep the following list alphabetized! @gccoptlist{-fgcse-after-reload @gol --finline-functions @gol -fipa-cp-clone -floop-interchange @gol -floop-unroll-and-jam @gol @@ -8559,7 +8559,7 @@ If all calls to a given function are integrated, and the function is declared @code{static}, then the function is normally not output as assembler code in its own right. -Enabled at levels @option{-O3}, @option{-Os}. Also enabled +Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. Also enabled by @option{-fprofile-use} and @option{-fauto-profile}. @item -finline-functions-called-once @@ -11175,19 +11175,30 @@ when modulo scheduling a loop. Larger values can exponentially increase compilation time. @item max-inline-insns-single -Several parameters control the tree inliner used in GCC@. -This number sets the maximum number of instructions (counted in GCC's -internal representation) in a single function that the tree inliner -considers for inlining. This only affects functions declared -inline and methods implemented in a class declaration (C++). +@item max-inline-insns-single-O2 +Several parameters control the tree inliner used in GCC@. This number sets the +maximum number of instructions (counted in GCC's internal representation) in a +single function that the tree inliner considers for inlining. This only +affects functions declared inline and methods implemented in a class +declaration (C++). + +For functions compiled with optimization levels +@option{-O3} and @option{-Ofast} parameter @option{max-inline-insns-single} is +applied. In other cases @option{max-inline-insns-single-O2} is applied. + @item max-inline-insns-auto +@item max-inline-insns-auto-O2 When you use @option{-finline-functions} (included in @option{-O3}), a lot of functions that would otherwise not be considered for inlining by the compiler are investigated. To those functions, a different (more restrictive) limit compared to functions declared inline can be applied. +For functions compiled with optimization levels +@option{-O3} and @option{-Ofast} parameter @option{max-inline-insns-auto} is +applied. In other cases @option{max-inline-insns-auto-O2} is applied. + @item max-inline-insns-small This is bound applied to calls which are considered relevant with @option{-finline-small-functions}. @@ -11210,11 +11221,16 @@ Same as @option{--param uninlined-function-insns} and @option{--param uninlined-function-time} but applied to function thunks @item inline-min-speedup +@item inline-min-speedup-O2 When estimated performance improvement of caller + callee runtime exceeds this threshold (in percent), the function can be inlined regardless of the limit on @option{--param max-inline-insns-single} and @option{--param max-inline-insns-auto}. +For functions compiled with optimization levels +@option{-O3} and @option{-Ofast} parameter @option{inline-min-speedup} is +applied. In other cases @option{inline-min-speedup-O2} is applied. + @item large-function-insns The limit specifying really large functions. For functions larger than this limit after inlining, inlining is constrained by @@ -11291,17 +11307,14 @@ recursion depth can be guessed from the probability that function recurses via a given call expression. This parameter limits inlining only to call expressions whose probability exceeds the given threshold (in percents). +@item early-inlining-insns @item early-inlining-insns-O2 Specify growth that the early inliner can make. In effect it increases the amount of inlining for code having a large abstraction penalty. -This is applied to functions compiled with @option{-O1} or @option{-O2} -optimization levels. -@item early-inlining-insns -Specify growth that the early inliner can make. In effect it increases -the amount of inlining for code having a large abstraction penalty. -This is applied to functions compiled with @option{-O3} or @option{-Ofast} -optimization levels. +For functions compiled with optimization levels +@option{-O3} and @option{-Ofast} parameter @option{early-inlining-insns} is +applied. In other cases @option{early-inlining-insns-O2} is applied. @item max-early-inliner-iterations Limit of iterations of the early inliner. This basically bounds diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index c8689c7..98d7fd3 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -390,6 +390,28 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, return inlinable; } +/* Return inlining_insns_single limit for function N */ + +static int +inline_insns_single (cgraph_node *n) +{ + if (opt_for_fn (n->decl, optimize >= 3)) + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE); + else + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE_O2); +} + +/* Return inlining_insns_auto limit for function N */ + +static int +inline_insns_auto (cgraph_node *n) +{ + if (opt_for_fn (n->decl, optimize >= 3)) + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO); + else + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO_O2); +} + /* Decide if we can inline the edge and possibly update inline_failed reason. We check whether inlining is possible at all and whether @@ -532,8 +554,8 @@ can_inline_edge_by_limits_p (struct cgraph_edge *e, bool report, int growth = estimate_edge_growth (e); if (growth > PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SIZE) && (!DECL_DECLARED_INLINE_P (callee->decl) - && growth >= MAX (MAX_INLINE_INSNS_SINGLE, - MAX_INLINE_INSNS_AUTO))) + && growth >= MAX (inline_insns_single (caller), + inline_insns_auto (caller)))) { e->inline_failed = CIF_OPTIMIZATION_MISMATCH; inlinable = false; @@ -745,9 +767,14 @@ big_speedup_p (struct cgraph_edge *e) sreal spec_time = estimate_edge_time (e, &unspec_time); sreal time = compute_uninlined_call_time (e, unspec_time); sreal inlined_time = compute_inlined_call_time (e, spec_time); + cgraph_node *caller = e->caller->global.inlined_to + ? e->caller->global.inlined_to + : e->caller; + int limit = opt_for_fn (caller->decl, optimize) >= 3 + ? PARAM_VALUE (PARAM_INLINE_MIN_SPEEDUP) + : PARAM_VALUE (PARAM_INLINE_MIN_SPEEDUP_O2); - if ((time - inlined_time) * 100 - > (sreal) (time * PARAM_VALUE (PARAM_INLINE_MIN_SPEEDUP))) + if ((time - inlined_time) * 100 > time * limit) return true; return false; } @@ -781,20 +808,29 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && (!e->count.ipa ().initialized_p () || !e->maybe_hot_p ())) && ipa_fn_summaries->get (callee)->min_size - ipa_call_summaries->get (e)->call_stmt_size - > MAX (MAX_INLINE_INSNS_SINGLE, MAX_INLINE_INSNS_AUTO)) + > MAX (inline_insns_single (e->caller), + inline_insns_auto (e->caller))) { - e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; + if (opt_for_fn (e->caller->decl, optimize) >= 3) + e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; + else + e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_O2_LIMIT; want_inline = false; } else if ((DECL_DECLARED_INLINE_P (callee->decl) || e->count.ipa ().nonzero_p ()) && ipa_fn_summaries->get (callee)->min_size - ipa_call_summaries->get (e)->call_stmt_size - > 16 * MAX_INLINE_INSNS_SINGLE) + > 16 * inline_insns_single (e->caller)) { - e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl) - ? CIF_MAX_INLINE_INSNS_SINGLE_LIMIT - : CIF_MAX_INLINE_INSNS_AUTO_LIMIT); + if (opt_for_fn (e->caller->decl, optimize) >= 3) + e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl) + ? CIF_MAX_INLINE_INSNS_SINGLE_LIMIT + : CIF_MAX_INLINE_INSNS_AUTO_LIMIT); + else + e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl) + ? CIF_MAX_INLINE_INSNS_SINGLE_O2_LIMIT + : CIF_MAX_INLINE_INSNS_AUTO_O2_LIMIT); want_inline = false; } else @@ -808,15 +844,18 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) /* Apply MAX_INLINE_INSNS_SINGLE limit. Do not do so when hints suggests that inlining given function is very profitable. */ else if (DECL_DECLARED_INLINE_P (callee->decl) - && growth >= MAX_INLINE_INSNS_SINGLE - && (growth >= MAX_INLINE_INSNS_SINGLE * 16 + && growth >= inline_insns_single (e->caller) + && (growth >= inline_insns_single (e->caller) * 16 || (!(hints & (INLINE_HINT_indirect_call | INLINE_HINT_known_hot | INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride)) && !(big_speedup = big_speedup_p (e))))) { - e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; + if (opt_for_fn (e->caller->decl, optimize) >= 3) + e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; + else + e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_O2_LIMIT; want_inline = false; } else if (!DECL_DECLARED_INLINE_P (callee->decl) @@ -824,12 +863,12 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && growth >= PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SMALL)) { /* growth_likely_positive is expensive, always test it last. */ - if (growth >= MAX_INLINE_INSNS_SINGLE + if (growth >= inline_insns_single (e->caller) || growth_likely_positive (callee, growth)) { - e->inline_failed = CIF_NOT_DECLARED_INLINED; + e->inline_failed = CIF_NOT_DECLARED_INLINED; want_inline = false; - } + } } /* Apply MAX_INLINE_INSNS_AUTO limit for functions not declared inline Upgrade it to MAX_INLINE_INSNS_SINGLE when hints suggests that @@ -839,28 +878,28 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && growth >= ((hints & (INLINE_HINT_indirect_call | INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride)) - ? MAX (MAX_INLINE_INSNS_AUTO, - MAX_INLINE_INSNS_SINGLE) - : MAX_INLINE_INSNS_AUTO) + ? MAX (inline_insns_auto (e->caller), + inline_insns_single (e->caller)) + : inline_insns_auto (e->caller)) && !(big_speedup == -1 ? big_speedup_p (e) : big_speedup)) { /* growth_likely_positive is expensive, always test it last. */ - if (growth >= MAX_INLINE_INSNS_SINGLE + if (growth >= inline_insns_single (e->caller) || growth_likely_positive (callee, growth)) { - e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; + if (opt_for_fn (e->caller->decl, optimize) >= 3) + e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; + else + e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_O2_LIMIT; want_inline = false; - } + } } /* If call is cold, do not inline when function body would grow. */ else if (!e->maybe_hot_p () - && (growth >= MAX_INLINE_INSNS_SINGLE + && (growth >= inline_insns_single (e->caller) || growth_likely_positive (callee, growth))) { - if (e->count.ipa () == profile_count::zero ()) - e->inline_failed = CIF_NEVER_CALL; - else - e->inline_failed = CIF_UNLIKELY_CALL; + e->inline_failed = CIF_UNLIKELY_CALL; want_inline = false; } } @@ -1166,7 +1205,7 @@ edge_badness (struct cgraph_edge *edge, bool dump) && caller_info->inlinable && caller_info->size < (DECL_DECLARED_INLINE_P (caller->decl) - ? MAX_INLINE_INSNS_SINGLE : MAX_INLINE_INSNS_AUTO)) + ? inline_insns_single (caller) : inline_insns_auto (caller))) { if (dump) fprintf (dump_file, diff --git a/gcc/opts.c b/gcc/opts.c index efd75aa..2df0351 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -527,6 +527,7 @@ static const struct default_options default_options_table[] = { OPT_LEVELS_2_PLUS, OPT_ftree_tail_merge, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_ftree_vrp, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_fvect_cost_model_, NULL, VECT_COST_MODEL_CHEAP }, + { OPT_LEVELS_2_PLUS, OPT_finline_functions, NULL, 1 }, /* -O2 and -Os optimizations. */ { OPT_LEVELS_2_PLUS_SPEED_ONLY, OPT_falign_functions, NULL, 1 }, @@ -542,9 +543,6 @@ static const struct default_options default_options_table[] = #endif /* -O3 and -Os optimizations. */ - /* Inlining of functions reducing size is a good idea with -Os - regardless of them being declared inline. */ - { OPT_LEVELS_3_PLUS_AND_SIZE, OPT_finline_functions, NULL, 1 }, /* -O3 optimizations. */ { OPT_LEVELS_3_PLUS, OPT_fgcse_after_reload, NULL, 1 }, diff --git a/gcc/params.def b/gcc/params.def index 0acf29b..80f73b8 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -51,8 +51,13 @@ DEFPARAM (PARAM_PREDICTABLE_BRANCH_OUTCOME, DEFPARAM (PARAM_INLINE_MIN_SPEEDUP, "inline-min-speedup", + "The minimal estimated speedup allowing inliner to ignore inline-insns-single and inline-insns-auto with -O3 and -Ofast.", + 15, 0, 100) + +DEFPARAM (PARAM_INLINE_MIN_SPEEDUP_O2, + "inline-min-speedup-O2", "The minimal estimated speedup allowing inliner to ignore inline-insns-single and inline-insns-auto.", - 15, 0, 0) + 30, 0, 100) /* The single function inlining limit. This is the maximum size of a function counted in internal gcc instructions (not in @@ -67,9 +72,14 @@ DEFPARAM (PARAM_INLINE_MIN_SPEEDUP, gets decreased. */ DEFPARAM (PARAM_MAX_INLINE_INSNS_SINGLE, "max-inline-insns-single", - "The maximum number of instructions in a single function eligible for inlining.", + "The maximum number of instructions in a single function eligible for inlining with -O3 and -Ofast.", 200, 0, 0) +DEFPARAM (PARAM_MAX_INLINE_INSNS_SINGLE_O2, + "max-inline-insns-single-O2", + "The maximum number of instructions in a single function eligible for inlining.", + 30, 0, 0) + /* The single function inlining limit for functions that are inlined by virtue of -finline-functions (-O3). This limit should be chosen to be below or equal to the limit @@ -79,9 +89,14 @@ DEFPARAM (PARAM_MAX_INLINE_INSNS_SINGLE, The default value is 30. */ DEFPARAM (PARAM_MAX_INLINE_INSNS_AUTO, "max-inline-insns-auto", - "The maximum number of instructions when automatically inlining.", + "The maximum number of instructions when automatically inlining with -O3 and -Ofast.", 30, 0, 0) +DEFPARAM (PARAM_MAX_INLINE_INSNS_AUTO_O2, + "max-inline-insns-auto-O2", + "The maximum number of instructions when automatically inlining.", + 15, 0, 0) + DEFPARAM (PARAM_MAX_INLINE_INSNS_SMALL, "max-inline-insns-small", "The maximum number of instructions when automatically inlining small functions.", diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr53844.C b/gcc/testsuite/g++.dg/tree-ssa/pr53844.C index 954cc71..ab9879f 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr53844.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr53844.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-options "-O2 -fdump-tree-optimized-vops" } +// { dg-options "-O2 -fdump-tree-optimized-vops -fno-inline-functions --param max-inline-insns-single-O2=200" } struct VBase; diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp index d62f78c..e9d3c9a 100644 --- a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp @@ -37,7 +37,7 @@ load_lib c-torture.exp torture-init set-torture-options $C_TORTURE_OPTIONS {{}} $LTO_TORTURE_OPTIONS -set additional_flags "-fno-tree-dse -fno-tree-loop-distribute-patterns -fno-tracer -fno-ipa-ra" +set additional_flags "-fno-tree-dse -fno-tree-loop-distribute-patterns -fno-tracer -fno-ipa-ra -fno-inline-functions" if [istarget "powerpc-*-darwin*"] { lappend additional_flags "-Wl,-multiply_defined,suppress" } diff --git a/gcc/testsuite/gcc.dg/ipa/inline-7.c b/gcc/testsuite/gcc.dg/ipa/inline-7.c index 7dabb14..7c64911 100644 --- a/gcc/testsuite/gcc.dg/ipa/inline-7.c +++ b/gcc/testsuite/gcc.dg/ipa/inline-7.c @@ -1,6 +1,6 @@ /* Check that early inliner works out that a is empty of parameter 0. */ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-einline-optimized -fopt-info-inline -fno-partial-inlining" } */ +/* { dg-options "-O2 -fdump-tree-einline-optimized -fopt-info-inline -fno-partial-inlining -fno-inline-functions" } */ void t(void); int a (int b) { diff --git a/gcc/testsuite/gcc.dg/optimize-bswapsi-5.c b/gcc/testsuite/gcc.dg/optimize-bswapsi-5.c index 5819fd7..b4d8b9a 100644 --- a/gcc/testsuite/gcc.dg/optimize-bswapsi-5.c +++ b/gcc/testsuite/gcc.dg/optimize-bswapsi-5.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target bswap } */ -/* { dg-options "-O2 -fdump-tree-bswap" } */ +/* { dg-options "-O2 -fdump-tree-bswap -fno-inline-functions" } */ /* { dg-additional-options "-march=z900" { target s390-*-* } } */ struct L { unsigned int l[2]; }; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c index 1bf79fc..fff731e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-thread2-details -fdump-tree-thread3-details -fdump-tree-thread4-details -fno-finite-loops" } */ +/* { dg-options "-O2 -fdump-tree-thread2-details -fdump-tree-thread3-details -fdump-tree-thread4-details -fno-finite-loops --param early-inlining-insns-O2=14 -fno-inline-functions" } */ /* { dg-final { scan-tree-dump "FSM" "thread2" } } */ /* { dg-final { scan-tree-dump "FSM" "thread3" } } */ /* { dg-final { scan-tree-dump "FSM" "thread4" { xfail *-*-* } } } */ @@ -56,7 +56,7 @@ bmp_iter_and_compl (bitmap_iterator * bi, unsigned *bit_no) } extern int VEC_int_base_length (VEC_int_base *); -static __inline__ bitmap +bitmap compute_idf (bitmap def_blocks, bitmap_head * dfs) { bitmap_iterator bi; diff --git a/gcc/testsuite/gcc.dg/winline-3.c b/gcc/testsuite/gcc.dg/winline-3.c index 7b7c8c5..7043a27 100644 --- a/gcc/testsuite/gcc.dg/winline-3.c +++ b/gcc/testsuite/gcc.dg/winline-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-Winline -O2 --param max-inline-insns-single=1 --param inline-min-speedup=100 -fgnu89-inline" } */ +/* { dg-options "-Winline -O2 --param max-inline-insns-single-O2=1 --param inline-min-speedup-O2=100 -fgnu89-inline" } */ void big (void); inline int q(void) /* { dg-warning "max-inline-insns-single" } */ -- cgit v1.1 From b1fb82e52520bf9be6dff67bbcd6129ae85bc098 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 2 Oct 2019 16:02:16 +0000 Subject: cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT, [...]): New. * cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT, MAX_INLINE_INSNS_AUTO_O2_LIMIT): New. * ipa-inline.c (inline_insns_single, inline_insns_auto): New functions. (can_inline_edge_by_limits_p): Use it. (big_speedup_p): Use PARAM_INLINE_MIN_SPEEDUP_O2. (want_inline_small_function_p): Use O2 bounds. (edge_badness): LIkewise. * opts.c (default_options): Add OPT_finline_functions. * params.def (PARAM_INLINE_MIN_SPEEDUP_O2, PARAM_MAX_INLINE_INSNS_SINGLE_O2, PARAM_MAX_INLINE_INSNS_AUTO_O2): New parameters. * g++.dg/tree-ssa/pr53844.C: Add -fno-inline-functions --param max-inline-insns-single-O2=200. * gcc.c-torture/execute/builtins/builtins.exp: Add -fno-inline-functions to additional_flags. * gcc.dg/ipa/inline-7.c: Add -fno-inline-functions. * gcc.dg/optimize-bswapsi-5.c: Add -fno-inline-functions. * gcc.dg/tree-ssa/ssa-thread-12.c: Add --param early-inlining-insns-O2=14 -fno-inline-functions; revert previous change. * gcc.dg/winline-3.c: Use --param max-inline-insns-single-O2=1 --param inline-min-speedup-O2=100 instead of --param max-inline-insns-single=1 --param inline-min-speedup=100 * invoke.texi (-finline-functions): Update documentation. (max-inline-insns-single-O2, max-inline-insns-auto-O2, inline-min-speedup-O2): Document. (early-inlining-insns-O2): Simplify docs. From-SVN: r276470 --- gcc/ChangeLog | 18 ++++++++++++++++++ gcc/testsuite/ChangeLog | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4f7edd2..5f74d88 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2019-10-02 Jan Hubicka + + * cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT, + MAX_INLINE_INSNS_AUTO_O2_LIMIT): New. + * ipa-inline.c (inline_insns_single, inline_insns_auto): New functions. + (can_inline_edge_by_limits_p): Use it. + (big_speedup_p): Use PARAM_INLINE_MIN_SPEEDUP_O2. + (want_inline_small_function_p): Use O2 bounds. + (edge_badness): LIkewise. + * opts.c (default_options): Add OPT_finline_functions. + * params.def (PARAM_INLINE_MIN_SPEEDUP_O2, + PARAM_MAX_INLINE_INSNS_SINGLE_O2, PARAM_MAX_INLINE_INSNS_AUTO_O2): + New parameters. + * doc/invoke.texi (-finline-functions): Update documentation. + (max-inline-insns-single-O2, max-inline-insns-auto-O2, + inline-min-speedup-O2): Document. + (early-inlining-insns-O2): Simplify docs. + 2019-10-02 Alexander Monakov PR rtl-optimization/87047 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d6cd8ca..d455ce6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,19 @@ +2019-10-02 Jan Hubicka + + * g++.dg/tree-ssa/pr53844.C: Add -fno-inline-functions --param + max-inline-insns-single-O2=200. + * gcc.c-torture/execute/builtins/builtins.exp: Add + -fno-inline-functions to additional_flags. + * gcc.dg/ipa/inline-7.c: Add -fno-inline-functions. + * gcc.dg/optimize-bswapsi-5.c: Add -fno-inline-functions. + * gcc.dg/tree-ssa/ssa-thread-12.c: Add --param + early-inlining-insns-O2=14 -fno-inline-functions; revert previous + change. + * gcc.dg/winline-3.c: Use --param max-inline-insns-single-O2=1 + --param inline-min-speedup-O2=100 + instead of --param max-inline-insns-single=1 --param + inline-min-speedup=100 + 2019-10-02 Alexander Monakov PR rtl-optimization/87047 -- cgit v1.1 From 8b4e5e711d9b2b979dcee445498a7f570ea49e2e Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Wed, 2 Oct 2019 17:01:30 +0000 Subject: re PR fortran/91943 (ICE in gfc_conv_constant_to_tree, at fortran/trans-const.c:370) 2019-10-02 Steven G. Kargl PR fortran/91943 * match.c (gfc_match_call): BOZ cannot be an actual argument in a subroutine reference. * resolve.c (resolve_function): BOZ cannot be an actual argument in a function reference. 2019-10-02 Steven G. Kargl PR fortran/91943 gfortran.dg/pr91943.f90 From-SVN: r276471 --- gcc/fortran/ChangeLog | 8 ++++++++ gcc/fortran/match.c | 10 ++++++++++ gcc/fortran/resolve.c | 15 +++++++++++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/pr91943.f90 | 7 +++++++ 5 files changed, 45 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/pr91943.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 51c393a..f225ff2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,11 @@ +2019-10-02 Steven G. Kargl + + PR fortran/91943 + * match.c (gfc_match_call): BOZ cannot be an actual argument in + a subroutine reference. + * resolve.c (resolve_function): BOZ cannot be an actual argument in + a function reference. + 2019-10-01 Jan Hubicka * module.c (load_commons): Initialize flags to 0 to silecne diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index 83b1189..4a31080 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -4984,6 +4984,16 @@ gfc_match_call (void) goto syntax; } + /* Walk the argument list looking for invalid BOZ. */ + for (a = arglist; a; a = a->next) + if (a->expr && a->expr->ts.type == BT_BOZ) + { + gfc_error ("A BOZ literal constant at %L cannot appear as an actual " + "argument in a subroutine reference", &a->expr->where); + goto cleanup; + } + + /* If any alternate return labels were found, construct a SELECT statement that will jump to the right place. */ diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index e8d0566..a792547 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -3242,6 +3242,21 @@ resolve_function (gfc_expr *expr) if (expr->expr_type != EXPR_FUNCTION) return t; + /* Walk the argument list looking for invalid BOZ. */ + if (expr->value.function.esym) + { + gfc_actual_arglist *a; + + for (a = expr->value.function.actual; a; a = a->next) + if (a->expr && a->expr->ts.type == BT_BOZ) + { + gfc_error ("A BOZ literal constant at %L cannot appear as an " + "actual argument in a function reference", + &a->expr->where); + return false; + } + } + temp = need_full_assumed_size; need_full_assumed_size = 0; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d455ce6..3256a02 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Steven G. Kargl + + PR fortran/91943 + gfortran.dg/pr91943.f90 + 2019-10-02 Jan Hubicka * g++.dg/tree-ssa/pr53844.C: Add -fno-inline-functions --param diff --git a/gcc/testsuite/gfortran.dg/pr91943.f90 b/gcc/testsuite/gfortran.dg/pr91943.f90 new file mode 100644 index 0000000..c2752c5 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91943.f90 @@ -0,0 +1,7 @@ +! { dg-do compile } +! PR fortran/91943 +! Code contributed by Gerhard Steinmetz +program p + print *, f(b'1001') ! { dg-error "cannot appear as an actual argument" } + call sub(b'1001') ! { dg-error "cannot appear as an actual argument" } +end -- cgit v1.1 From 939e9f696b843f2c6472ac0fd541399e2b3faa7e Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Wed, 2 Oct 2019 17:04:57 +0000 Subject: re PR fortran/91942 (ICE in match_vtag, at fortran/io.c:1485) 2019-10-02 Steven G. Kargl PR fortran/91942 * io.c (match_vtag): Check for non-NULL result->symtree. (match_out_tag): Check for invalid constant due to inquiry parameter. (match_filepos): Instead of a syntax error, go to cleanup to get better error messages. 2019-10-02 Steven G. Kargl PR fortran/91942 * gfortran.dg/pr91587.f90: Update dg-error regex. * gfortran.dg/pr91942.f90: New test. From-SVN: r276472 --- gcc/fortran/ChangeLog | 8 ++++++ gcc/fortran/io.c | 48 ++++++++++++++++++++++------------- gcc/testsuite/ChangeLog | 6 +++++ gcc/testsuite/gfortran.dg/pr91587.f90 | 6 ++--- gcc/testsuite/gfortran.dg/pr91942.f90 | 10 ++++++++ 5 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr91942.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f225ff2..476973d 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,13 @@ 2019-10-02 Steven G. Kargl + PR fortran/91942 + * io.c (match_vtag): Check for non-NULL result->symtree. + (match_out_tag): Check for invalid constant due to inquiry parameter. + (match_filepos): Instead of a syntax error, go to cleanup to get better + error messages. + +2019-10-02 Steven G. Kargl + PR fortran/91943 * match.c (gfc_match_call): BOZ cannot be an actual argument in a subroutine reference. diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c index 9ae06b1f..b969a1a 100644 --- a/gcc/fortran/io.c +++ b/gcc/fortran/io.c @@ -1482,24 +1482,29 @@ match_vtag (const io_tag *tag, gfc_expr **v) return MATCH_ERROR; } - if (result->symtree->n.sym->attr.intent == INTENT_IN) + if (result->symtree) { - gfc_error ("Variable %s cannot be INTENT(IN) at %C", tag->name); - gfc_free_expr (result); - return MATCH_ERROR; - } + bool impure; - bool impure = gfc_impure_variable (result->symtree->n.sym); - if (impure && gfc_pure (NULL)) - { - gfc_error ("Variable %s cannot be assigned in PURE procedure at %C", - tag->name); - gfc_free_expr (result); - return MATCH_ERROR; - } + if (result->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error ("Variable %s cannot be INTENT(IN) at %C", tag->name); + gfc_free_expr (result); + return MATCH_ERROR; + } + + impure = gfc_impure_variable (result->symtree->n.sym); + if (impure && gfc_pure (NULL)) + { + gfc_error ("Variable %s cannot be assigned in PURE procedure at %C", + tag->name); + gfc_free_expr (result); + return MATCH_ERROR; + } - if (impure) - gfc_unset_implicit_pure (NULL); + if (impure) + gfc_unset_implicit_pure (NULL); + } *v = result; return MATCH_YES; @@ -1515,7 +1520,16 @@ match_out_tag (const io_tag *tag, gfc_expr **result) m = match_vtag (tag, result); if (m == MATCH_YES) - gfc_check_do_variable ((*result)->symtree); + { + if ((*result)->symtree) + gfc_check_do_variable ((*result)->symtree); + + if ((*result)->expr_type == EXPR_CONSTANT) + { + gfc_error ("Expecting a variable at %L", &(*result)->where); + return MATCH_ERROR; + } + } return m; } @@ -2845,7 +2859,7 @@ match_filepos (gfc_statement st, gfc_exec_op op) m = match_file_element (fp); if (m == MATCH_ERROR) - goto syntax; + goto cleanup; if (m == MATCH_NO) { m = gfc_match_expr (&fp->unit); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3256a02..88e4d326 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2019-10-02 Steven G. Kargl + PR fortran/91942 + * gfortran.dg/pr91587.f90: Update dg-error regex. + * gfortran.dg/pr91942.f90: New test. + +2019-10-02 Steven G. Kargl + PR fortran/91943 gfortran.dg/pr91943.f90 diff --git a/gcc/testsuite/gfortran.dg/pr91587.f90 b/gcc/testsuite/gfortran.dg/pr91587.f90 index c07735d..c304be1 100644 --- a/gcc/testsuite/gfortran.dg/pr91587.f90 +++ b/gcc/testsuite/gfortran.dg/pr91587.f90 @@ -2,9 +2,9 @@ ! PR fortran/91587 ! Code contributed by Gerhard Steinmetz program p - backspace(err=!) ! { dg-error "Syntax error in" } - flush(err=!) ! { dg-error "Syntax error in" } - rewind(err=!) ! { dg-error "Syntax error in" } + backspace(err=!) ! { dg-error "Invalid value for" } + flush(err=!) ! { dg-error "Invalid value for" } + rewind(err=!) ! { dg-error "Invalid value for" } end subroutine bar ! An other matcher runs, and gives a different error. diff --git a/gcc/testsuite/gfortran.dg/pr91942.f90 b/gcc/testsuite/gfortran.dg/pr91942.f90 new file mode 100644 index 0000000..cd237d3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91942.f90 @@ -0,0 +1,10 @@ +! { dg-do compile } +! PR fortran/91942 +! Code contributed by Gerhard Steinmetz +program p + integer :: i + backspace (iostat=i%kind) ! { dg-error "Expecting a variable at" } + endfile (iostat=i%kind) ! { dg-error "Expecting END PROGRAM" } + flush (iostat=i%kind) ! { dg-error "Expecting a variable at" } + rewind (iostat=i%kind) ! { dg-error "Expecting a variable at" } +end -- cgit v1.1 From 307de1007192b12dcf5b21b4444904567a543b2e Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Wed, 2 Oct 2019 17:09:45 +0000 Subject: re PR fortran/91785 (ICE in check_assumed_size_reference, at fortran/resolve.c:1601) 2019-10-02 Steven G. Kargl PR fortran/91785 * primary.c (gfc_match_varspec): Ensure an inquiry parameter has it locus set. 2019-10-02 Steven G. Kargl PR fortran/91785 * gfortran.dg/pr91785.f90: New test. From-SVN: r276473 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/primary.c | 2 ++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/pr91785.f90 | 8 ++++++++ 4 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/pr91785.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 476973d..bf8702f 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,11 @@ 2019-10-02 Steven G. Kargl + PR fortran/91785 + * primary.c (gfc_match_varspec): Ensure an inquiry parameter has + it locus set. + +2019-10-02 Steven G. Kargl + PR fortran/91942 * io.c (match_vtag): Check for non-NULL result->symtree. (match_out_tag): Check for invalid constant due to inquiry parameter. diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c index e94ea82..7c65b2e 100644 --- a/gcc/fortran/primary.c +++ b/gcc/fortran/primary.c @@ -2331,6 +2331,8 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag, if (tmp && tmp->type == REF_INQUIRY) { + if (!primary->where.lb || !primary->where.nextc) + primary->where = gfc_current_locus; gfc_simplify_expr (primary, 0); if (primary->expr_type == EXPR_CONSTANT) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 88e4d326..cdd99ef 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-10-02 Steven G. Kargl + PR fortran/91785 + * gfortran.dg/pr91785.f90: New test. + +2019-10-02 Steven G. Kargl + PR fortran/91942 * gfortran.dg/pr91587.f90: Update dg-error regex. * gfortran.dg/pr91942.f90: New test. diff --git a/gcc/testsuite/gfortran.dg/pr91785.f90 b/gcc/testsuite/gfortran.dg/pr91785.f90 new file mode 100644 index 0000000..fb3d964 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91785.f90 @@ -0,0 +1,8 @@ +! { dg-do compile } +! PR fortran/91785 +! Code contributed by Gerhard Steinmetz +program p + complex :: a(*) ! { dg-error "Assumed size array at" } + real :: b(2) + b = a%im ! { dg-error "upper bound in the last dimension" } +end -- cgit v1.1 From c20a90e0c82f7037f1064693ceb17a58e4682c22 Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Wed, 2 Oct 2019 17:17:55 +0000 Subject: re PR fortran/91784 (ICE in gfc_real2complex, at fortran/arith.c:2208) 2019-10-02 Steven G. Kargl PR fortran/91784 * simplify.c (gfc_convert_constant): Simplify expression if the expres ion type is EXPR_OP. 2019-10-02 Steven G. Kargl PR fortran/91784 * gfortran.dg/pr91784.f90: New test. From-SVN: r276474 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/simplify.c | 6 +++--- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/pr91784.f90 | 9 +++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr91784.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index bf8702f..ea1177f 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,5 +1,11 @@ 2019-10-02 Steven G. Kargl + PR fortran/91784 + * simplify.c (gfc_convert_constant): Simplify expression if the + expression type is EXPR_OP. + +2019-10-02 Steven G. Kargl + PR fortran/91785 * primary.c (gfc_match_varspec): Ensure an inquiry parameter has it locus set. diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c index 3d2fc0d..32ebcc0 100644 --- a/gcc/fortran/simplify.c +++ b/gcc/fortran/simplify.c @@ -8508,10 +8508,10 @@ gfc_convert_constant (gfc_expr *e, bt type, int kind) { if (c->expr->expr_type == EXPR_ARRAY) tmp = gfc_convert_constant (c->expr, type, kind); - else if (c->expr->expr_type == EXPR_OP - && c->expr->value.op.op == INTRINSIC_PARENTHESES) + else if (c->expr->expr_type == EXPR_OP) { - gfc_simplify_expr (c->expr, 1); + if (!gfc_simplify_expr (c->expr, 1)) + return &gfc_bad_expr; tmp = f (c->expr, kind); } else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cdd99ef..0bc13fc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-10-02 Steven G. Kargl + PR fortran/91784 + * gfortran.dg/pr91784.f90: New test. + +2019-10-02 Steven G. Kargl + PR fortran/91785 * gfortran.dg/pr91785.f90: New test. diff --git a/gcc/testsuite/gfortran.dg/pr91784.f90 b/gcc/testsuite/gfortran.dg/pr91784.f90 new file mode 100644 index 0000000..25280e0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91784.f90 @@ -0,0 +1,9 @@ +! { dg-do run } +! PR fortran/91784 +! Code originally contributed by Gerhard Steinmetz +program p + complex :: x(1) + x = (1.0, 2.0) * [real :: -(3.0 + 4.0)] + if (int(real(x(1))) /= -7) stop 1 + if (int(aimag(x(1))) /= -14) stop 2 +end -- cgit v1.1 From c89844e5d30a5235960a2c627abc9369306fda61 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 2 Oct 2019 15:26:47 -0400 Subject: Add some hash_map_safe_* functions like vec_safe_*. gcc/ * hash-map.h (default_hash_map_size): New variable. (create_ggc): Use it as default argument. (hash_map_maybe_create, hash_map_safe_get) (hash_map_safe_get_or_insert, hash_map_safe_put): New fns. gcc/cp/ * constexpr.c (maybe_initialize_fundef_copies_table): Remove. (get_fundef_copy): Use hash_map_safe_get_or_insert. * cp-objcp-common.c (cp_get_debug_type): Use hash_map_safe_*. * decl.c (store_decomp_type): Remove. (cp_finish_decomp): Use hash_map_safe_put. * init.c (get_nsdmi): Use hash_map_safe_*. * pt.c (store_defaulted_ttp, lookup_defaulted_ttp): Remove. (add_defaults_to_ttp): Use hash_map_safe_*. From-SVN: r276484 --- gcc/ChangeLog | 8 ++++++++ gcc/cp/ChangeLog | 12 ++++++++++++ gcc/cp/constexpr.c | 14 ++------------ gcc/cp/cp-objcp-common.c | 6 ++---- gcc/cp/decl.c | 9 +-------- gcc/cp/init.c | 9 ++------- gcc/cp/pt.c | 21 +++------------------ gcc/hash-map.h | 47 +++++++++++++++++++++++++++++++++++++++++++++-- gcc/hash-table.c | 2 +- 9 files changed, 76 insertions(+), 52 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5f74d88..c7773c5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-09-30 Jason Merrill + + Add some hash_map_safe_* functions like vec_safe_*. + * hash-map.h (default_hash_map_size): New variable. + (create_ggc): Use it as default argument. + (hash_map_maybe_create, hash_map_safe_get) + (hash_map_safe_get_or_insert, hash_map_safe_put): New fns. + 2019-10-02 Jan Hubicka * cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bac74fe..baf01e6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2019-09-30 Jason Merrill + + Use hash_map_safe_* functions. + * constexpr.c (maybe_initialize_fundef_copies_table): Remove. + (get_fundef_copy): Use hash_map_safe_get_or_insert. + * cp-objcp-common.c (cp_get_debug_type): Use hash_map_safe_*. + * decl.c (store_decomp_type): Remove. + (cp_finish_decomp): Use hash_map_safe_put. + * init.c (get_nsdmi): Use hash_map_safe_*. + * pt.c (store_defaulted_ttp, lookup_defaulted_ttp): Remove. + (add_defaults_to_ttp): Use hash_map_safe_*. + 2019-10-02 Richard Biener PR c++/91606 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index cb5484f..06672a2 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1098,15 +1098,6 @@ maybe_initialize_constexpr_call_table (void) static GTY(()) hash_map *fundef_copies_table; -/* Initialize FUNDEF_COPIES_TABLE if it's not initialized. */ - -static void -maybe_initialize_fundef_copies_table () -{ - if (fundef_copies_table == NULL) - fundef_copies_table = hash_map::create_ggc (101); -} - /* Reuse a copy or create a new unshared copy of the function FUN. Return this copy. We use a TREE_LIST whose PURPOSE is body, VALUE is parms, TYPE is result. */ @@ -1114,11 +1105,10 @@ maybe_initialize_fundef_copies_table () static tree get_fundef_copy (constexpr_fundef *fundef) { - maybe_initialize_fundef_copies_table (); - tree copy; bool existed; - tree *slot = &fundef_copies_table->get_or_insert (fundef->decl, &existed); + tree *slot = &(hash_map_safe_get_or_insert + (fundef_copies_table, fundef->decl, &existed, 127)); if (!existed) { diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 4369a5b..0a72231 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -145,11 +145,9 @@ cp_get_debug_type (const_tree type) if (dtype) { tree ktype = CONST_CAST_TREE (type); - if (debug_type_map == NULL) - debug_type_map = tree_cache_map::create_ggc (512); - else if (tree *slot = debug_type_map->get (ktype)) + if (tree *slot = hash_map_safe_get (debug_type_map, ktype)) return *slot; - debug_type_map->put (ktype, dtype); + hash_map_safe_put (debug_type_map, ktype, dtype); } return dtype; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c96294f..d6cca65 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7704,13 +7704,6 @@ get_tuple_decomp_init (tree decl, unsigned i) based on the actual type of the variable, so store it in a hash table. */ static GTY((cache)) tree_cache_map *decomp_type_table; -static void -store_decomp_type (tree v, tree t) -{ - if (!decomp_type_table) - decomp_type_table = tree_cache_map::create_ggc (13); - decomp_type_table->put (v, t); -} tree lookup_decomp_type (tree v) @@ -7946,7 +7939,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count) goto error_out; } /* Save the decltype away before reference collapse. */ - store_decomp_type (v[i], eltype); + hash_map_safe_put (decomp_type_table, v[i], eltype); eltype = cp_build_reference_type (eltype, !lvalue_p (init)); TREE_TYPE (v[i]) = eltype; layout_decl (v[i], 0); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 67e0656..76fa030 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -563,10 +563,9 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) init = DECL_INITIAL (DECL_TI_TEMPLATE (member)); location_t expr_loc = cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (member)); - tree *slot; if (TREE_CODE (init) == DEFERRED_PARSE) /* Unparsed. */; - else if (nsdmi_inst && (slot = nsdmi_inst->get (member))) + else if (tree *slot = hash_map_safe_get (nsdmi_inst, member)) init = *slot; /* Check recursive instantiation. */ else if (DECL_INSTANTIATING_NSDMI_P (member)) @@ -611,11 +610,7 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) DECL_INSTANTIATING_NSDMI_P (member) = 0; if (init != error_mark_node) - { - if (!nsdmi_inst) - nsdmi_inst = tree_cache_map::create_ggc (37); - nsdmi_inst->put (member, init); - } + hash_map_safe_put (nsdmi_inst, member, init); if (pushed) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 44b3618..67b3b63 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7357,21 +7357,6 @@ coerce_template_args_for_ttp (tree templ, tree arglist, /* A cache of template template parameters with match-all default arguments. */ static GTY((deletable)) hash_map *defaulted_ttp_cache; -static void -store_defaulted_ttp (tree v, tree t) -{ - if (!defaulted_ttp_cache) - defaulted_ttp_cache = hash_map::create_ggc (13); - defaulted_ttp_cache->put (v, t); -} -static tree -lookup_defaulted_ttp (tree v) -{ - if (defaulted_ttp_cache) - if (tree *p = defaulted_ttp_cache->get (v)) - return *p; - return NULL_TREE; -} /* T is a bound template template-parameter. Copy its arguments into default arguments of the template template-parameter's template parameters. */ @@ -7379,8 +7364,8 @@ lookup_defaulted_ttp (tree v) static tree add_defaults_to_ttp (tree otmpl) { - if (tree c = lookup_defaulted_ttp (otmpl)) - return c; + if (tree *c = hash_map_safe_get (defaulted_ttp_cache, otmpl)) + return *c; tree ntmpl = copy_node (otmpl); @@ -7410,7 +7395,7 @@ add_defaults_to_ttp (tree otmpl) } } - store_defaulted_ttp (otmpl, ntmpl); + hash_map_safe_put (defaulted_ttp_cache, otmpl, ntmpl); return ntmpl; } diff --git a/gcc/hash-map.h b/gcc/hash-map.h index ba20fe7..73ce6a1 100644 --- a/gcc/hash-map.h +++ b/gcc/hash-map.h @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see removed. Objects of hash_map type are copy-constructible but not assignable. */ +const size_t default_hash_map_size = 13; template, Value> */> @@ -129,7 +130,7 @@ class GTY((user)) hash_map }; public: - explicit hash_map (size_t n = 13, bool ggc = false, + explicit hash_map (size_t n = default_hash_map_size, bool ggc = false, bool sanitize_eq_and_hash = true, bool gather_mem_stats = GATHER_STATISTICS CXX_MEM_STAT_INFO) @@ -146,7 +147,7 @@ public: HASH_MAP_ORIGIN PASS_MEM_STAT) {} /* Create a hash_map in ggc memory. */ - static hash_map *create_ggc (size_t size, + static hash_map *create_ggc (size_t size = default_hash_map_size, bool gather_mem_stats = GATHER_STATISTICS CXX_MEM_STAT_INFO) { @@ -326,4 +327,46 @@ gt_pch_nx (hash_map *h, gt_pointer_operator op, void *cookie) op (&h->m_table.m_entries, cookie); } +enum hm_alloc { hm_heap = false, hm_ggc = true }; +template +inline hash_map * +hash_map_maybe_create (hash_map *&h, + size_t size = default_hash_map_size) +{ + if (!h) + { + if (ggc) + h = hash_map::create_ggc (size); + else + h = new hash_map (size); + } + return h; +} + +/* Like h->get, but handles null h. */ +template +inline V* +hash_map_safe_get (hash_map *h, const K& k) +{ + return h ? h->get (k) : NULL; +} + +/* Like h->get, but handles null h. */ +template +inline V& +hash_map_safe_get_or_insert (hash_map *&h, const K& k, bool *e = NULL, + size_t size = default_hash_map_size) +{ + return hash_map_maybe_create (h, size)->get_or_insert (k, e); +} + +/* Like h->put, but handles null h. */ +template +inline bool +hash_map_safe_put (hash_map *&h, const K& k, const V& v, + size_t size = default_hash_map_size) +{ + return hash_map_maybe_create (h, size)->put (k, v); +} + #endif diff --git a/gcc/hash-table.c b/gcc/hash-table.c index e3b5d3d..3520c3b 100644 --- a/gcc/hash-table.c +++ b/gcc/hash-table.c @@ -78,7 +78,7 @@ struct prime_ent const prime_tab[] = { unsigned int hash_table_sanitize_eq_limit; /* The following function returns an index into the above table of the - nearest prime number which is greater than N, and near a power of two. */ + nearest prime number which is at least N, and near a power of two. */ unsigned int hash_table_higher_prime_index (unsigned long n) -- cgit v1.1 From b830c28b56fdc3f4b4555200278218b4b49022d2 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 2 Oct 2019 16:01:42 -0400 Subject: Improve C++ fold caching efficiency. While looking at concepts caching I noticed that we were clearing the caches unnecessarily for non-constant initialization, which shouldn't affect folding. * typeck2.c (store_init_value): Only clear_cv_and_fold_caches if the value is constant. From-SVN: r276487 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/typeck2.c | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index baf01e6..275fc9f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Jason Merrill + + * typeck2.c (store_init_value): Only clear_cv_and_fold_caches if the + value is constant. + 2019-09-30 Jason Merrill Use hash_map_safe_* functions. diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 58fa54f..ec0e6a7 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -907,9 +907,6 @@ store_init_value (tree decl, tree init, vec** cleanups, int flags) /* Handle aggregate NSDMI in non-constant initializers, too. */ value = replace_placeholders (value, decl); - /* DECL may change value; purge caches. */ - clear_cv_and_fold_caches (); - /* If the initializer is not a constant, fill in DECL_INITIAL with the bits that are constant, and then return an expression that will perform the dynamic initialization. */ @@ -918,6 +915,10 @@ store_init_value (tree decl, tree init, vec** cleanups, int flags) || vla_type_p (type) || ! reduced_constant_expression_p (value))) return split_nonconstant_init (decl, value); + + /* DECL may change value; purge caches. */ + clear_cv_and_fold_caches (); + /* If the value is a constant, just put it in DECL_INITIAL. If DECL is an automatic variable, the middle end will turn this into a dynamic initialization later. */ -- cgit v1.1 From b7c41230322051912d979e132c52100158745b73 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 2 Oct 2019 20:11:35 +0000 Subject: runtime: mark go-context.S as no-executable-stack and split-stack supported The .note.GNU-stack section tells the linker that this object does not require an executable stack. The .note.GNU-split-stack section tells the linker that functions in this object can be called directly by split-stack functions, without require a large stack. The .note.GNU-no-split-stack section tells the linker that functions in this object do not have a split-stack prologue. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/198440 From-SVN: r276488 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f7c45ee..54c682a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -07faafda5fbd66a710153814f30d93c91461e7cb +a3aef6b6df932ea6c7094d074695bc0b033a3d17 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From aa29ed6db6d409b54e552830230205a7b4da0d4d Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 2 Oct 2019 21:19:35 +0000 Subject: Fix ALL_REGS thinko in initialisation of function_used_regs My change to the -fipa-ra bookkeeping used ALL_REGS as the supposedly safe default assumption, but ALL_REGS isn't literally all registers, just a close approximation. This caused a bootstrap failure on arm-linux-gnu, where the condition code register isn't in ALL_REGS and so was being masked out of some call-clobbered sets. 2019-10-02 Richard Sandiford gcc/ * cgraph.c (cgraph_node::rtl_info): Use SET_HARD_REG_SET instead of reg_class_contents[ALL_REGS]. From-SVN: r276489 --- gcc/ChangeLog | 5 +++++ gcc/cgraph.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c7773c5..fb0c366 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Richard Sandiford + + * cgraph.c (cgraph_node::rtl_info): Use SET_HARD_REG_SET + instead of reg_class_contents[ALL_REGS]. + 2019-09-30 Jason Merrill Add some hash_map_safe_* functions like vec_safe_*. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 7748cef..0c3c6e7 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1866,7 +1866,7 @@ cgraph_node::rtl_info (const_tree decl) if (node->rtl == NULL) { node->rtl = ggc_cleared_alloc (); - node->rtl->function_used_regs = reg_class_contents[ALL_REGS]; + SET_HARD_REG_SET (node->rtl->function_used_regs); } return node->rtl; } -- cgit v1.1 From d1090a8a805de4e3b33248753e792ab302d3f6db Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 2 Oct 2019 16:00:42 -0600 Subject: PR tree-optimization/80936 - bcmp, bcopy, and bzero not declared nonnull gcc/testsuite/ChangeLog: PR tree-optimization/80936 * gcc.dg/Wnonnull-2.c: New test. * gcc.dg/Wnonnull-3.c: New test. * gcc.dg/nonnull-3.c: Expect more warnings. gcc/ChangeLog: PR tree-optimization/80936 * builtins.def (bcmp, bcopy, bzero): Declare nonnull. From-SVN: r276491 --- gcc/builtins.def | 8 ++--- gcc/testsuite/gcc.dg/Wnonnull-2.c | 55 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Wnonnull-3.c | 71 +++++++++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/nonnull-3.c | 10 +++--- 4 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wnonnull-2.c create mode 100644 gcc/testsuite/gcc.dg/Wnonnull-3.c (limited to 'gcc') diff --git a/gcc/builtins.def b/gcc/builtins.def index 8bb7027..5b9b706 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -687,11 +687,9 @@ DEF_C99_COMPL_BUILTIN (BUILT_IN_CTANHL, "ctanhl", BT_FN_COMPLEX_LONGDOUBL DEF_C99_COMPL_BUILTIN (BUILT_IN_CTANL, "ctanl", BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_MATHFN_FPROUNDING) /* Category: string/memory builtins. */ -/* bcmp, bcopy and bzero have traditionally accepted NULL pointers - when the length parameter is zero, so don't apply attribute "nonnull". */ -DEF_EXT_LIB_BUILTIN (BUILT_IN_BCMP, "bcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_LEAF_LIST) -DEF_EXT_LIB_BUILTIN (BUILT_IN_BCOPY, "bcopy", BT_FN_VOID_CONST_PTR_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST) -DEF_EXT_LIB_BUILTIN (BUILT_IN_BZERO, "bzero", BT_FN_VOID_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST) +DEF_EXT_LIB_BUILTIN (BUILT_IN_BCMP, "bcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF) +DEF_EXT_LIB_BUILTIN (BUILT_IN_BCOPY, "bcopy", BT_FN_VOID_CONST_PTR_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF) +DEF_EXT_LIB_BUILTIN (BUILT_IN_BZERO, "bzero", BT_FN_VOID_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF) DEF_EXT_LIB_BUILTIN (BUILT_IN_INDEX, "index", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF) DEF_LIB_BUILTIN (BUILT_IN_MEMCHR, "memchr", BT_FN_PTR_CONST_PTR_INT_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF) DEF_LIB_BUILTIN (BUILT_IN_MEMCMP, "memcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF) diff --git a/gcc/testsuite/gcc.dg/Wnonnull-2.c b/gcc/testsuite/gcc.dg/Wnonnull-2.c new file mode 100644 index 0000000..d870473 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wnonnull-2.c @@ -0,0 +1,55 @@ +/* PR middle-end/80936 - bcmp, bcopy, and bzero not declared nonnull + Verify that -Wnonnull is issued for calls with constant null pointers + with no optimization. + { dg-do compile } + { dg-options "-O0 -Wall" } */ + +void zero0 (void *p, unsigned n) +{ + __builtin_memset (0, 0, n); // { dg-warning "\\\[-Wnonnull]" } +} + +void zero1 (void *p, unsigned n) +{ + __builtin_bzero (0, n); // { dg-warning "\\\[-Wnonnull]" } +} + +void copy0 (void *p, const void *q, unsigned n) +{ + __builtin_memcpy (0, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +void copy1 (void *p, const void *q, unsigned n) +{ + __builtin_memcpy (0, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +void copy2 (void *p, const void *q, unsigned n) +{ + __builtin_bcopy (q, 0, n); // { dg-warning "\\\[-Wnonnull]" } +} + +void copy3 (void *p, const void *q, unsigned n) +{ + __builtin_bcopy (q, 0, n); // { dg-warning "\\\[-Wnonnull]" } +} + +int cmp0 (const void *p, const void *q, unsigned n) +{ + return __builtin_memcmp (0, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +int cmp1 (const void *p, const void *q, unsigned n) +{ + return __builtin_memcmp (0, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +int cmp2 (const void *p, const void *q, unsigned n) +{ + return __builtin_bcmp (0, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +int cmp3 (const void *p, const void *q, unsigned n) +{ + return __builtin_bcmp (p, 0, n); // { dg-warning "\\\[-Wnonnull]" } +} diff --git a/gcc/testsuite/gcc.dg/Wnonnull-3.c b/gcc/testsuite/gcc.dg/Wnonnull-3.c new file mode 100644 index 0000000..ad016df --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wnonnull-3.c @@ -0,0 +1,71 @@ +/* PR middle-end/80936 - bcmp, bcopy, and bzero not declared nonnull + Verify that with optimization, -Wnonnull is issued for calls with + non-constant arguments determined to be null. + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +#define NOIPA __attribute__ ((noipa)) + +NOIPA void zero0 (void *p, unsigned n) +{ + if (p == 0) + __builtin_memset (p, 0, n); // { dg-warning "\\\[-Wnonnull]" } +} + +NOIPA void zero1 (void *p, unsigned n) +{ + if (p == 0) + __builtin_bzero (p, n); // { dg-warning "\\\[-Wnonnull]" } +} + +NOIPA void copy0 (void *p, const void *q, unsigned n) +{ + if (p == 0) + __builtin_memcpy (p, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +NOIPA void copy1 (void *p, const void *q, unsigned n) +{ + if (q == 0) + __builtin_memcpy (p, q, n); // { dg-warning "\\\[-Wnonnull]" } +} + +NOIPA void copy2 (void *p, const void *q, unsigned n) +{ + if (p == 0) + __builtin_bcopy (q, p, n); // { dg-warning "\\\[-Wnonnull]" } +} + +NOIPA void copy3 (void *p, const void *q, unsigned n) +{ + if (q == 0) + __builtin_bcopy (q, p, n); // { dg-warning "\\\[-Wnonnull]" } +} + +NOIPA int cmp0 (const void *p, const void *q, unsigned n) +{ + if (p == 0) + return __builtin_memcmp (p, q, n); // { dg-warning "\\\[-Wnonnull]" } + return 0; +} + +NOIPA int cmp1 (const void *p, const void *q, unsigned n) +{ + if (q == 0) + return __builtin_memcmp (p, q, n); // { dg-warning "\\\[-Wnonnull]" } + return 0; +} + +NOIPA int cmp2 (const void *p, const void *q, unsigned n) +{ + if (p == 0) + return __builtin_bcmp (p, q, n); // { dg-warning "\\\[-Wnonnull]" } + return 0; +} + +NOIPA int cmp3 (const void *p, const void *q, unsigned n) +{ + if (q == 0) + return __builtin_bcmp (p, q, n); // { dg-warning "\\\[-Wnonnull]" } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/nonnull-3.c b/gcc/testsuite/gcc.dg/nonnull-3.c index 6f7bc4f..c52fe2c 100644 --- a/gcc/testsuite/gcc.dg/nonnull-3.c +++ b/gcc/testsuite/gcc.dg/nonnull-3.c @@ -9,11 +9,11 @@ void foo (void *p, char *s) { - __builtin_bzero (NULL, 0); - __builtin_bcopy (NULL, p, 0); - __builtin_bcopy (p, NULL, 0); - __builtin_bcmp (NULL, p, 0); - __builtin_bcmp (p, NULL, 0); + __builtin_bzero (NULL, 0); /* { dg-warning "null" "pr80936" } */ + __builtin_bcopy (NULL, p, 0); /* { dg-warning "null" "pr80936" } */ + __builtin_bcopy (p, NULL, 0); /* { dg-warning "null" "pr80936" } */ + __builtin_bcmp (NULL, p, 0); /* { dg-warning "null" "pr80936" } */ + __builtin_bcmp (p, NULL, 0); /* { dg-warning "null" "pr80936" } */ __builtin_index (NULL, 16); /* { dg-warning "null" "null pointer check" } */ __builtin_rindex (NULL, 16); /* { dg-warning "null" "null pointer check" } */ -- cgit v1.1 From bead578432b67889c2700c7f0eafa72d74bf197b Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 2 Oct 2019 16:04:00 -0600 Subject: Add changelog entries for r276491. From-SVN: r276492 --- gcc/ChangeLog | 5 +++++ gcc/testsuite/ChangeLog | 7 +++++++ 2 files changed, 12 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fb0c366..371e7bc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-02 Martin Sebor + + PR tree-optimization/80936 + * builtins.def (bcmp, bcopy, bzero): Declare nonnull. + 2019-10-02 Richard Sandiford * cgraph.c (cgraph_node::rtl_info): Use SET_HARD_REG_SET diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0bc13fc..d321861 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-10-02 Martin Sebor + + PR tree-optimization/80936 + * gcc.dg/Wnonnull-2.c: New test. + * gcc.dg/Wnonnull-3.c: New test. + * gcc.dg/nonnull-3.c: Expect more warnings. + 2019-10-02 Steven G. Kargl PR fortran/91784 -- cgit v1.1 From 276a52d5566487fa53bcf34f24290362a10ac316 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 3 Oct 2019 00:31:58 +0200 Subject: constexpr.c (cxx_eval_store_expression): Formatting fix. * constexpr.c (cxx_eval_store_expression): Formatting fix. Handle const_object_being_modified with array type. From-SVN: r276493 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/constexpr.c | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 275fc9f..f2c1aa2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Jakub Jelinek + + * constexpr.c (cxx_eval_store_expression): Formatting fix. Handle + const_object_being_modified with array type. + 2019-10-02 Jason Merrill * typeck2.c (store_init_value): Only clear_cv_and_fold_caches if the diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 06672a2..a6a55b9 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3895,7 +3895,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, bool no_zero_init = true; releasing_vec ctors; - while (!refs->is_empty()) + while (!refs->is_empty ()) { if (*valp == NULL_TREE) { @@ -4036,7 +4036,9 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (const_object_being_modified) { bool fail = false; - if (!CLASS_TYPE_P (TREE_TYPE (const_object_being_modified))) + tree const_objtype + = strip_array_types (TREE_TYPE (const_object_being_modified)); + if (!CLASS_TYPE_P (const_objtype)) fail = true; else { -- cgit v1.1 From 1006c9d4395a939820df76f37c7b085a4a1a003f Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 3 Oct 2019 00:32:56 +0200 Subject: constexpr.c (cxx_eval_constant_expression): If not skipping upon entry to body... * constexpr.c (cxx_eval_constant_expression) : If not skipping upon entry to body, run cleanup with the same *jump_target as it started to run the cleanup even if the body returns, breaks or continues. (potential_constant_expression_1): Allow CLEANUP_STMT. * g++.dg/ext/constexpr-attr-cleanup1.C: New test. From-SVN: r276494 --- gcc/cp/ChangeLog | 6 +++++ gcc/cp/constexpr.c | 27 ++++++++++++++----- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C | 30 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f2c1aa2..7279062 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2019-10-03 Jakub Jelinek + * constexpr.c (cxx_eval_constant_expression) : If + not skipping upon entry to body, run cleanup with the same *jump_target + as it started to run the cleanup even if the body returns, breaks or + continues. + (potential_constant_expression_1): Allow CLEANUP_STMT. + * constexpr.c (cxx_eval_store_expression): Formatting fix. Handle const_object_being_modified with array type. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index a6a55b9..2008793 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4899,14 +4899,21 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; case CLEANUP_STMT: - r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, + { + tree initial_jump_target = jump_target ? *jump_target : NULL_TREE; + r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, + non_constant_p, overflow_p, + jump_target); + if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) + /* Also evaluate the cleanup. If we weren't skipping at the + start of the CLEANUP_BODY, change jump_target temporarily + to &initial_jump_target, so that even a return or break or + continue in the body doesn't skip the cleanup. */ + cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, non_constant_p, overflow_p, - jump_target); - if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) - /* Also evaluate the cleanup. */ - cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, - non_constant_p, overflow_p, - jump_target); + jump_target ? &initial_jump_target + : NULL); + } break; /* These differ from cxx_eval_unary_expression in that this doesn't @@ -6975,6 +6982,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return true; case CLEANUP_STMT: + if (!RECUR (CLEANUP_BODY (t), any)) + return false; + if (!CLEANUP_EH_ONLY (t) && !RECUR (CLEANUP_EXPR (t), any)) + return false; + return true; + case EMPTY_CLASS_EXPR: case PREDICT_EXPR: return false; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d321861..b9fcbb0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-03 Jakub Jelinek + + * g++.dg/ext/constexpr-attr-cleanup1.C: New test. + 2019-10-02 Martin Sebor PR tree-optimization/80936 diff --git a/gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C b/gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C new file mode 100644 index 0000000..2c4f61a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/constexpr-attr-cleanup1.C @@ -0,0 +1,30 @@ +// { dg-do compile { target c++2a } } + +constexpr void +cleanup (int *x) +{ + if (x) + asm (""); // { dg-error "inline assembly is not a constant expression" } +} // { dg-message "only unevaluated inline assembly is allowed in a 'constexpr' function" "" { target *-*-* } .-1 } + +constexpr void +cleanup2 (int *x) +{ +} + +constexpr bool +foo () +{ + int a __attribute__((cleanup (cleanup))) = 1; + return true; +} + +constexpr bool +bar () +{ + int a __attribute__((cleanup (cleanup2))) = 1; + return true; +} + +constexpr auto x = foo (); // { dg-message "in 'constexpr' expansion of" } +constexpr auto y = bar (); -- cgit v1.1 From 775eaa4d83458393a34aa6197ff823b63d6078fd Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 3 Oct 2019 00:33:39 +0200 Subject: re PR rtl-optimization/91976 (RTL check: expected code 'const_int', have 'reg' in emit_block_move_hints, at expr.c:1627) PR rtl-optimization/91976 * expr.c (emit_block_move_hints): Don't call can_move_by_pieces if size is not CONST_INT_P, set pieces_ok to false in that case. Simplify CONST_INT_P (size) && pieces_ok to pieces_ok. Formatting fix. From-SVN: r276495 --- gcc/ChangeLog | 7 +++++++ gcc/expr.c | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 371e7bc..6aff2cd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-03 Jakub Jelinek + + PR rtl-optimization/91976 + * expr.c (emit_block_move_hints): Don't call can_move_by_pieces if + size is not CONST_INT_P, set pieces_ok to false in that case. Simplify + CONST_INT_P (size) && pieces_ok to pieces_ok. Formatting fix. + 2019-10-02 Martin Sebor PR tree-optimization/80936 diff --git a/gcc/expr.c b/gcc/expr.c index bd6a71a..c421054 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1624,16 +1624,18 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, set_mem_size (y, const_size); } - bool pieces_ok = can_move_by_pieces (INTVAL (size), align); + bool pieces_ok = false; + if (CONST_INT_P (size)) + pieces_ok = can_move_by_pieces (INTVAL (size), align); bool pattern_ok = false; - if (!CONST_INT_P (size) || !pieces_ok || might_overlap) + if (!pieces_ok || might_overlap) { - pattern_ok = - emit_block_move_via_pattern (x, y, size, align, - expected_align, expected_size, - min_size, max_size, probable_max_size, - might_overlap); + pattern_ok + = emit_block_move_via_pattern (x, y, size, align, + expected_align, expected_size, + min_size, max_size, probable_max_size, + might_overlap); if (!pattern_ok && might_overlap) { /* Do not try any of the other methods below as they are not safe @@ -1645,7 +1647,7 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, if (pattern_ok) ; - else if (CONST_INT_P (size) && pieces_ok) + else if (pieces_ok) move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN); else if (may_use_call && !might_overlap && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) -- cgit v1.1 From f5fc32e4a38cee21d1935fd04ad19726f76c06a9 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Wed, 2 Oct 2019 23:23:51 +0000 Subject: init.c (build_new): Use cp_expr_loc_or_input_loc in two places. /cp 2019-10-03 Paolo Carlini * init.c (build_new): Use cp_expr_loc_or_input_loc in two places. * name-lookup.c (do_pushdecl): Use DECL_SOURCE_LOCATION. (push_class_level_binding_1): Likewise. (set_decl_namespace): Likewise. /testsuite 2019-10-03 Paolo Carlini * g++.dg/diagnostic/integral-array-size-1.C: New. * g++.dg/cpp0x/alias-decl-1.C: Test location(s) too. * g++.dg/init/new43.C: Likewise. * g++.dg/lookup/friend12.C: Likewise. * g++.dg/lookup/pr79766.C: Likewise. * g++.dg/lookup/pr84375.C: Likewise. * g++.dg/other/new-size-type.C: Likewise. From-SVN: r276496 --- gcc/cp/ChangeLog | 7 + gcc/cp/init.c | 6 +- gcc/cp/name-lookup.c | 14 +- gcc/testsuite/ChangeLog | 10 ++ gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C | 2 +- .../g++.dg/diagnostic/integral-array-size-1.C | 7 + gcc/testsuite/g++.dg/init/new43.C | 178 ++++++++++----------- gcc/testsuite/g++.dg/lookup/friend12.C | 2 +- gcc/testsuite/g++.dg/lookup/pr79766.C | 2 +- gcc/testsuite/g++.dg/lookup/pr84375.C | 2 +- gcc/testsuite/g++.dg/other/new-size-type.C | 2 +- 11 files changed, 130 insertions(+), 102 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/integral-array-size-1.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7279062..bd3592a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2019-10-03 Paolo Carlini + + * init.c (build_new): Use cp_expr_loc_or_input_loc in two places. + * name-lookup.c (do_pushdecl): Use DECL_SOURCE_LOCATION. + (push_class_level_binding_1): Likewise. + (set_decl_namespace): Likewise. + 2019-10-03 Jakub Jelinek * constexpr.c (cxx_eval_constant_expression) : If diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 76fa030..857f360 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3754,7 +3754,8 @@ build_new (vec **placement, tree type, tree nelts, if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false)) { if (complain & tf_error) - permerror (input_location, "size in array new must have integral type"); + permerror (cp_expr_loc_or_input_loc (nelts), + "size in array new must have integral type"); else return error_mark_node; } @@ -3769,7 +3770,8 @@ build_new (vec **placement, tree type, tree nelts, less than zero. ... If the expression is a constant expression, the program is ill-fomed. */ if (TREE_CODE (cst_nelts) == INTEGER_CST - && !valid_array_size_p (input_location, cst_nelts, NULL_TREE, + && !valid_array_size_p (cp_expr_loc_or_input_loc (nelts), + cst_nelts, NULL_TREE, complain & tf_error)) return error_mark_node; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 4d01a54..ff6d5ee 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3080,8 +3080,9 @@ do_pushdecl (tree decl, bool is_friend) /* In a local class, a friend function declaration must find a matching decl in the innermost non-class scope. [class.friend/11] */ - error ("friend declaration %qD in local class without " - "prior local declaration", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "friend declaration %qD in local class without " + "prior local declaration", decl); /* Don't attempt to push it. */ return error_mark_node; } @@ -4451,9 +4452,9 @@ push_class_level_binding_1 (tree name, tree x) tree scope = context_for_name_lookup (x); if (TYPE_P (scope) && same_type_p (scope, current_class_type)) { - error ("%qD has the same name as the class in which it is " - "declared", - x); + error_at (DECL_SOURCE_LOCATION (x), + "%qD has the same name as the class in which it is " + "declared", x); return false; } } @@ -4757,7 +4758,8 @@ set_decl_namespace (tree decl, tree scope, bool friendp) /* Writing "N::i" to declare something directly in "N" is invalid. */ if (CP_DECL_CONTEXT (decl) == current_namespace && at_namespace_scope_p ()) - error ("explicit qualification in declaration of %qD", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "explicit qualification in declaration of %qD", decl); return; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b9fcbb0..27659f4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2019-10-03 Paolo Carlini + + * g++.dg/diagnostic/integral-array-size-1.C: New. + * g++.dg/cpp0x/alias-decl-1.C: Test location(s) too. + * g++.dg/init/new43.C: Likewise. + * g++.dg/lookup/friend12.C: Likewise. + * g++.dg/lookup/pr79766.C: Likewise. + * g++.dg/lookup/pr84375.C: Likewise. + * g++.dg/other/new-size-type.C: Likewise. + 2019-10-03 Jakub Jelinek * g++.dg/ext/constexpr-attr-cleanup1.C: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C index 43284d7..24b0520 100644 --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C @@ -12,5 +12,5 @@ template struct Ptr {}; // { dg-error "specialization" } struct A { using A = int; // { dg-error "11:ISO C\\+\\+ forbids nested type .A." } -// { dg-error "same name as" "" { target c++11 } .-1 } +// { dg-error "11:.using A = int. has the same name as" "" { target c++11 } .-1 } }; diff --git a/gcc/testsuite/g++.dg/diagnostic/integral-array-size-1.C b/gcc/testsuite/g++.dg/diagnostic/integral-array-size-1.C new file mode 100644 index 0000000..31d67c5 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/integral-array-size-1.C @@ -0,0 +1,7 @@ +template +void foo(T a) +{ + new int[a]; // { dg-error "11:size in array new must have integral type" } +} + +template void foo(float); diff --git a/gcc/testsuite/g++.dg/init/new43.C b/gcc/testsuite/g++.dg/init/new43.C index e2ad67d..880e330 100644 --- a/gcc/testsuite/g++.dg/init/new43.C +++ b/gcc/testsuite/g++.dg/init/new43.C @@ -30,36 +30,36 @@ void test_literal () B b; // Verify integer literal. - p = new char [-1]; // { dg-error "size .-1. of array is negative" } - p = new char [2][-3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new char [-4][5]; // { dg-error "size .-4. of array is negative" } - p = new char [-6][-7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) char [-1]; // { dg-error "size .-1. of array is negative" } - p = new (p) char [2][-3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) char [-4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) char [-6][-7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) A [-1]; // { dg-error "size .-1. of array is negative" } - p = new (p) A [2][-3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) A [-4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) A [-6][-7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) B [-1]; // { dg-error "size .-1. of array is negative" } - p = new (p) B [2][-3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) B [-4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) B [-6][-7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (&b) B [-1]; // { dg-error "size .-1. of array is negative" } - p = new (&b) B [2][-3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (&b) B [-4][5]; // { dg-error "size .-4. of array is negative" } - p = new (&b) B [-6][-7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new char [1 - 2]; // { dg-error "size .-1. of array is negative" } - p = new (p) char [2 - 3]; // { dg-error "size .-1. of array is negative" } - p = new A [2 < 1 ? -1 : -2]; // { dg-error "size .-2. of array is negative" } - p = new (p) B [2 - 3 * 2]; // { dg-error "size .-4. of array is negative" } - p = new (&b) B [1][2 - 3 * 2];// { dg-error "size .-4. of array|narrowing conversion" } + p = new char [-1]; // { dg-error "19:size .-1. of array is negative" } + p = new char [2][-3]; // { dg-error "22:size .-3. of array|narrowing conversion" } + p = new char [-4][5]; // { dg-error "19:size .-4. of array is negative" } + p = new char [-6][-7]; // { dg-error "19:size .-6. of array|narrowing conversion" } + // { dg-error "23:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) char [-1]; // { dg-error "23:size .-1. of array is negative" } + p = new (p) char [2][-3]; // { dg-error "26:size .-3. of array|narrowing conversion" } + p = new (p) char [-4][5]; // { dg-error "23:size .-4. of array is negative" } + p = new (p) char [-6][-7]; // { dg-error "23:size .-6. of array|narrowing conversion" } + // { dg-error "27:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) A [-1]; // { dg-error "20:size .-1. of array is negative" } + p = new (p) A [2][-3]; // { dg-error "23:size .-3. of array|narrowing conversion" } + p = new (p) A [-4][5]; // { dg-error "20:size .-4. of array is negative" } + p = new (p) A [-6][-7]; // { dg-error "20:size .-6. of array|narrowing conversion" } + // { dg-error "24:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) B [-1]; // { dg-error "20:size .-1. of array is negative" } + p = new (p) B [2][-3]; // { dg-error "23:size .-3. of array|narrowing conversion" } + p = new (p) B [-4][5]; // { dg-error "20:size .-4. of array is negative" } + p = new (p) B [-6][-7]; // { dg-error "size .-6. of array|narrowing conversion" } + // { dg-error "24:size .-7. of array" "" { target *-*-* } .-1 } + p = new (&b) B [-1]; // { dg-error "21:size .-1. of array is negative" } + p = new (&b) B [2][-3]; // { dg-error "24:size .-3. of array|narrowing conversion" } + p = new (&b) B [-4][5]; // { dg-error "21:size .-4. of array is negative" } + p = new (&b) B [-6][-7]; // { dg-error "21:size .-6. of array|narrowing conversion" } + // { dg-error "25:size .-7. of array" "" { target *-*-* } .-1 } + p = new char [1 - 2]; // { dg-error "21:size .-1. of array is negative" } + p = new (p) char [2 - 3]; // { dg-error "25:size .-1. of array is negative" } + p = new A [2 < 1 ? -1 : -2]; // { dg-error "22:size .-2. of array is negative" } + p = new (p) B [2 - 3 * 2]; // { dg-error "22:size .-4. of array is negative" } + p = new (&b) B [1][2 - 3 * 2];// { dg-error "26:size .-4. of array|narrowing conversion" } } void test_constant_expression () @@ -78,36 +78,36 @@ void test_constant_expression () static const int i7 = -7; // Verify constant expression. - p = new char [i1]; // { dg-error "size .-1. of array is negative" } - p = new char [2][i3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new char [i4][5]; // { dg-error "size .-4. of array is negative" } - p = new char [i6][i7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) char [i1]; // { dg-error "size .-1. of array is negative" } - p = new (p) char [2][i3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) char [i4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) char [i6][i7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) A [i1]; // { dg-error "size .-1. of array is negative" } - p = new (p) A [2][i3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) A [i4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) A [i6][i7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) B [i1]; // { dg-error "size .-1. of array is negative" } - p = new (p) B [2][i3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) B [i4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) B [i6][i7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (&b) B [i1]; // { dg-error "size .-1. of array is negative" } - p = new (&b) B [2][i3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (&b) B [i4][5]; // { dg-error "size .-4. of array is negative" } - p = new (&b) B [i6][i7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new short [i1 - 2]; // { dg-error "size .-3. of array is negative" } - p = new (p) bool [i2 - 3]; // { dg-error "size .-5. of array is negative" } - p = new A [2 < 1 ? i1 : i2]; // { dg-error "size .-2. of array is negative" } - p = new (p) B [2 + i3 * 2]; // { dg-error "size .-4. of array is negative" } - p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size .-7. of array|narrowing conversion" } + p = new char [i1]; // { dg-error "19:size .-1. of array is negative" } + p = new char [2][i3]; // { dg-error "22:size .-3. of array|narrowing conversion" } + p = new char [i4][5]; // { dg-error "19:size .-4. of array is negative" } + p = new char [i6][i7]; // { dg-error "19:size .-6. of array|narrowing conversion" } + // { dg-error "23:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) char [i1]; // { dg-error "23:size .-1. of array is negative" } + p = new (p) char [2][i3]; // { dg-error "26:size .-3. of array|narrowing conversion" } + p = new (p) char [i4][5]; // { dg-error "23:size .-4. of array is negative" } + p = new (p) char [i6][i7]; // { dg-error "23:size .-6. of array|narrowing conversion" } + // { dg-error "27:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) A [i1]; // { dg-error "20:size .-1. of array is negative" } + p = new (p) A [2][i3]; // { dg-error "23:size .-3. of array|narrowing conversion" } + p = new (p) A [i4][5]; // { dg-error "20:size .-4. of array is negative" } + p = new (p) A [i6][i7]; // { dg-error "20:size .-6. of array|narrowing conversion" } + // { dg-error "24:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) B [i1]; // { dg-error "20:size .-1. of array is negative" } + p = new (p) B [2][i3]; // { dg-error "23:size .-3. of array|narrowing conversion" } + p = new (p) B [i4][5]; // { dg-error "20:size .-4. of array is negative" } + p = new (p) B [i6][i7]; // { dg-error "20:size .-6. of array|narrowing conversion" } + // { dg-error "24:size .-7. of array" "" { target *-*-* } .-1 } + p = new (&b) B [i1]; // { dg-error "21:size .-1. of array is negative" } + p = new (&b) B [2][i3]; // { dg-error "24:size .-3. of array|narrowing conversion" } + p = new (&b) B [i4][5]; // { dg-error "21:size .-4. of array is negative" } + p = new (&b) B [i6][i7]; // { dg-error "21:size .-6. of array|narrowing conversion" } + // { dg-error "25:size .-7. of array" "" { target *-*-* } .-1 } + p = new short [i1 - 2]; // { dg-error "23:size .-3. of array is negative" } + p = new (p) bool [i2 - 3]; // { dg-error "26:size .-5. of array is negative" } + p = new A [2 < 1 ? i1 : i2]; // { dg-error "22:size .-2. of array is negative" } + p = new (p) B [2 + i3 * 2]; // { dg-error "22:size .-4. of array is negative" } + p = new (&b) B [1][i1 - 3 * 2];// { dg-error "27:size .-7. of array|narrowing conversion" } } void test_constexpr () @@ -131,36 +131,36 @@ void test_constexpr () #endif // Verify constant expression. - p = new char [s1]; // { dg-error "size .-1. of array is negative" } - p = new char [2][s3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new char [s4][5]; // { dg-error "size .-4. of array is negative" } - p = new char [s6][s7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) char [s1]; // { dg-error "size .-1. of array is negative" } - p = new (p) char [2][s3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) char [s4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) char [s6][s7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) A [s1]; // { dg-error "size .-1. of array is negative" } - p = new (p) A [2][s3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) A [s4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) A [s6][s7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (p) B [s1]; // { dg-error "size .-1. of array is negative" } - p = new (p) B [2][s3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (p) B [s4][5]; // { dg-error "size .-4. of array is negative" } - p = new (p) B [s6][s7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new (&b) B [s1]; // { dg-error "size .-1. of array is negative" } - p = new (&b) B [2][s3]; // { dg-error "size .-3. of array|narrowing conversion" } - p = new (&b) B [s4][5]; // { dg-error "size .-4. of array is negative" } - p = new (&b) B [s6][s7]; // { dg-error "size .-\[67\]. of array|narrowing conversion" } - - p = new int [s1 + s2]; // { dg-error "size .-3. of array is negative" } - p = new (p) long [2 * s3]; // { dg-error "size .-6. of array is negative" } + p = new char [s1]; // { dg-error "19:size .-1. of array is negative" } + p = new char [2][s3]; // { dg-error "22:size .-3. of array|narrowing conversion" } + p = new char [s4][5]; // { dg-error "19:size .-4. of array is negative" } + p = new char [s6][s7]; // { dg-error "19:size .-6. of array|narrowing conversion" } + // { dg-error "23:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) char [s1]; // { dg-error "23:size .-1. of array is negative" } + p = new (p) char [2][s3]; // { dg-error "26:size .-3. of array|narrowing conversion" } + p = new (p) char [s4][5]; // { dg-error "23:size .-4. of array is negative" } + p = new (p) char [s6][s7]; // { dg-error "23:size .-6. of array|narrowing conversion" } + // { dg-error "27:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) A [s1]; // { dg-error "20:size .-1. of array is negative" } + p = new (p) A [2][s3]; // { dg-error "23:size .-3. of array|narrowing conversion" } + p = new (p) A [s4][5]; // { dg-error "20:size .-4. of array is negative" } + p = new (p) A [s6][s7]; // { dg-error "20:size .-6. of array|narrowing conversion" } + // { dg-error "24:size .-7. of array" "" { target *-*-* } .-1 } + p = new (p) B [s1]; // { dg-error "20:size .-1. of array is negative" } + p = new (p) B [2][s3]; // { dg-error "23:size .-3. of array|narrowing conversion" } + p = new (p) B [s4][5]; // { dg-error "20:size .-4. of array is negative" } + p = new (p) B [s6][s7]; // { dg-error "20:size .-6. of array|narrowing conversion" } + // { dg-error "24:size .-7. of array" "" { target *-*-* } .-1 } + p = new (&b) B [s1]; // { dg-error "21:size .-1. of array is negative" } + p = new (&b) B [2][s3]; // { dg-error "24:size .-3. of array|narrowing conversion" } + p = new (&b) B [s4][5]; // { dg-error "21:size .-4. of array is negative" } + p = new (&b) B [s6][s7]; // { dg-error "21:size .-6. of array|narrowing conversion" } + // { dg-error "25:size .-7. of array" "" { target *-*-* } .-1 } + p = new int [s1 + s2]; // { dg-error "21:size .-3. of array is negative" } + p = new (p) long [2 * s3]; // { dg-error "25:size .-6. of array is negative" } p = new A [s2 < s1 ? s1 : s2]; // { dg-error "size .-1. of array is negative" } - p = new (p) B [s7 - s2 * 2]; // { dg-error "size .-3. of array is negative" } - p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size .-2. of array|narrowing conversion" } + p = new (p) B [s7 - s2 * 2]; // { dg-error "23:size .-3. of array is negative" } + p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "27:size .-2. of array|narrowing conversion" } } /* Prune out pedantic warnins (turned into errors via -pedantic-errors). diff --git a/gcc/testsuite/g++.dg/lookup/friend12.C b/gcc/testsuite/g++.dg/lookup/friend12.C index eb61fb5..612b0da 100644 --- a/gcc/testsuite/g++.dg/lookup/friend12.C +++ b/gcc/testsuite/g++.dg/lookup/friend12.C @@ -5,6 +5,6 @@ void foo() extern void bar (int); // not the bar we are looking for struct A { - friend void bar(); // { dg-error "without prior local declaration" } + friend void bar(); // { dg-error "17:friend declaration .void bar\\(\\). in local class without prior local declaration" } }; } diff --git a/gcc/testsuite/g++.dg/lookup/pr79766.C b/gcc/testsuite/g++.dg/lookup/pr79766.C index de9bbb5..09f09fa 100644 --- a/gcc/testsuite/g++.dg/lookup/pr79766.C +++ b/gcc/testsuite/g++.dg/lookup/pr79766.C @@ -24,6 +24,6 @@ void ::R () // OK -> Z::R void S (); -void ::S () // { dg-error "explicit qualification" } +void ::S () // { dg-error "6:explicit qualification" } { } diff --git a/gcc/testsuite/g++.dg/lookup/pr84375.C b/gcc/testsuite/g++.dg/lookup/pr84375.C index 24cdcb2..1b086e1 100644 --- a/gcc/testsuite/g++.dg/lookup/pr84375.C +++ b/gcc/testsuite/g++.dg/lookup/pr84375.C @@ -4,6 +4,6 @@ void foo() { struct A { - friend void A(); // { dg-error "local class without prior local" } + friend void A(); // { dg-error "17:friend declaration .void A\\(\\). in local class without prior local" } }; } diff --git a/gcc/testsuite/g++.dg/other/new-size-type.C b/gcc/testsuite/g++.dg/other/new-size-type.C index a99d747..3411641 100644 --- a/gcc/testsuite/g++.dg/other/new-size-type.C +++ b/gcc/testsuite/g++.dg/other/new-size-type.C @@ -5,5 +5,5 @@ const char* foo() { - return new char[~static_cast(0)];// { dg-error "exceeds maximum object size" } + return new char[~static_cast(0)];// { dg-error "21:exceeds maximum object size" } } -- cgit v1.1 From 202be58655a1964581facd2e514c7d3431258fe8 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 3 Oct 2019 00:50:58 +0100 Subject: Define WIDTH macros for C2x. As part of the integration of TS 18661-1 into C2x, many features became unconditional features not depending on any feature test macro being defined. This patch updates the conditionals on the *_WIDTH macros in limits.h and stdint.h accordingly so that they are defined for C2x. The macro CR_DECIMAL_DIG in float.h does still require __STDC_WANT_IEC_60559_BFP_EXT__ to be defined, and a test for this is added. Bootstrapped with no regressions on x86_64-pc-linux-gnu. gcc: * ginclude/stdint-gcc.h [__STDC_WANT_IEC_60559_BFP_EXT__]: Change condition on WIDTH macros to [__STDC_WANT_IEC_60559_BFP_EXT__ || (__STDC_VERSION__ && __STDC_VERSION__ > 201710L)]. * glimits.h: Likewise. gcc/testsuite: * gcc.dg/cr-decimal-dig-2.c: New test. * gcc.dg/limits-width-2.c: New test. Based on limits-width-1.c. * gcc.dg/stdint-width-2.c: New test. Based on stdint-width-1.c. From-SVN: r276497 --- gcc/ChangeLog | 7 ++ gcc/ginclude/stdint-gcc.h | 5 +- gcc/glimits.h | 5 +- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/gcc.dg/cr-decimal-dig-2.c | 10 ++ gcc/testsuite/gcc.dg/limits-width-2.c | 54 ++++++++++ gcc/testsuite/gcc.dg/stdint-width-2.c | 175 ++++++++++++++++++++++++++++++++ 7 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cr-decimal-dig-2.c create mode 100644 gcc/testsuite/gcc.dg/limits-width-2.c create mode 100644 gcc/testsuite/gcc.dg/stdint-width-2.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6aff2cd..26c5c42 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-02 Joseph Myers + + * ginclude/stdint-gcc.h [__STDC_WANT_IEC_60559_BFP_EXT__]: Change + condition on WIDTH macros to [__STDC_WANT_IEC_60559_BFP_EXT__ || + (__STDC_VERSION__ && __STDC_VERSION__ > 201710L)]. + * glimits.h: Likewise. + 2019-10-03 Jakub Jelinek PR rtl-optimization/91976 diff --git a/gcc/ginclude/stdint-gcc.h b/gcc/ginclude/stdint-gcc.h index 83b03b2..e9dc04e 100644 --- a/gcc/ginclude/stdint-gcc.h +++ b/gcc/ginclude/stdint-gcc.h @@ -260,8 +260,9 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* (!defined __cplusplus || __cplusplus >= 201103L || defined __STDC_CONSTANT_MACROS) */ -#ifdef __STDC_WANT_IEC_60559_BFP_EXT__ -/* TS 18661-1 widths of integer types. */ +#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ \ + || (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L)) +/* TS 18661-1 / C2X widths of integer types. */ #ifdef __INT8_TYPE__ # undef INT8_WIDTH diff --git a/gcc/glimits.h b/gcc/glimits.h index 0cddf0f..1909344 100644 --- a/gcc/glimits.h +++ b/gcc/glimits.h @@ -123,8 +123,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see # define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL) #endif -#ifdef __STDC_WANT_IEC_60559_BFP_EXT__ -/* TS 18661-1 widths of integer types. */ +#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ \ + || (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L)) +/* TS 18661-1 / C2X widths of integer types. */ # undef CHAR_WIDTH # define CHAR_WIDTH __SCHAR_WIDTH__ # undef SCHAR_WIDTH diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 27659f4..e57cc72 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-10-02 Joseph Myers + + * gcc.dg/cr-decimal-dig-2.c: New test. + * gcc.dg/limits-width-2.c: New test. Based on limits-width-1.c. + * gcc.dg/stdint-width-2.c: New test. Based on stdint-width-1.c. + 2019-10-03 Paolo Carlini * g++.dg/diagnostic/integral-array-size-1.C: New. diff --git a/gcc/testsuite/gcc.dg/cr-decimal-dig-2.c b/gcc/testsuite/gcc.dg/cr-decimal-dig-2.c new file mode 100644 index 0000000..42e79d5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cr-decimal-dig-2.c @@ -0,0 +1,10 @@ +/* Test TS 18661-1 CR_DECIMAL_DIG: not in C2X without + __STDC_WANT_IEC_60559_BFP_EXT__ defined. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +#include + +#ifdef CR_DECIMAL_DIG +#error "CR_DECIMAL_DIG defined" +#endif diff --git a/gcc/testsuite/gcc.dg/limits-width-2.c b/gcc/testsuite/gcc.dg/limits-width-2.c new file mode 100644 index 0000000..a3c3895 --- /dev/null +++ b/gcc/testsuite/gcc.dg/limits-width-2.c @@ -0,0 +1,54 @@ +/* Test C2X width macros in . */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +#include + +#define CHECK_WIDTH(TYPE, MAX, WIDTH) \ + _Static_assert ((MAX >> ((TYPE) -1 < 0 ? (WIDTH - 2) : (WIDTH - 1))) == 1, \ + "width must match type") + +#ifndef CHAR_WIDTH +# error "missing CHAR_WIDTH" +#endif +CHECK_WIDTH (char, CHAR_MAX, CHAR_WIDTH); +#ifndef SCHAR_WIDTH +# error "missing SCHAR_WIDTH" +#endif +CHECK_WIDTH (signed char, SCHAR_MAX, SCHAR_WIDTH); +#ifndef UCHAR_WIDTH +# error "missing UCHAR_WIDTH" +#endif +CHECK_WIDTH (unsigned char, UCHAR_MAX, UCHAR_WIDTH); +#ifndef SHRT_WIDTH +# error "missing SHRT_WIDTH" +#endif +CHECK_WIDTH (signed short, SHRT_MAX, SHRT_WIDTH); +#ifndef USHRT_WIDTH +# error "missing USHRT_WIDTH" +#endif +CHECK_WIDTH (unsigned short, USHRT_MAX, USHRT_WIDTH); +#ifndef INT_WIDTH +# error "missing INT_WIDTH" +#endif +CHECK_WIDTH (signed int, INT_MAX, INT_WIDTH); +#ifndef UINT_WIDTH +# error "missing UINT_WIDTH" +#endif +CHECK_WIDTH (unsigned int, UINT_MAX, UINT_WIDTH); +#ifndef LONG_WIDTH +# error "missing LONG_WIDTH" +#endif +CHECK_WIDTH (signed long, LONG_MAX, LONG_WIDTH); +#ifndef ULONG_WIDTH +# error "missing ULONG_WIDTH" +#endif +CHECK_WIDTH (unsigned long, ULONG_MAX, ULONG_WIDTH); +#ifndef LLONG_WIDTH +# error "missing LLONG_WIDTH" +#endif +CHECK_WIDTH (signed long long, LLONG_MAX, LLONG_WIDTH); +#ifndef ULLONG_WIDTH +# error "missing ULLONG_WIDTH" +#endif +CHECK_WIDTH (unsigned long long, ULLONG_MAX, ULLONG_WIDTH); diff --git a/gcc/testsuite/gcc.dg/stdint-width-2.c b/gcc/testsuite/gcc.dg/stdint-width-2.c new file mode 100644 index 0000000..9838cb2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/stdint-width-2.c @@ -0,0 +1,175 @@ +/* Test C2X width macros in . */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -ffreestanding" } */ +/* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ + +#include +#include +#ifndef SIGNAL_SUPPRESS +#include +#endif +typedef __WINT_TYPE__ wint_t; + +#define CHECK_WIDTH(TYPE, MAX, WIDTH) \ + _Static_assert ((MAX >> ((TYPE) -1 < 0 ? (WIDTH - 2) : (WIDTH - 1))) == 1, \ + "width must match type") + +#ifdef INT8_MAX +# ifndef INT8_WIDTH +# error "missing INT8_WIDTH" +# endif +CHECK_WIDTH (int8_t, INT8_MAX, INT8_WIDTH); +#endif +#ifdef INT16_MAX +# ifndef INT16_WIDTH +# error "missing INT16_WIDTH" +# endif +CHECK_WIDTH (int16_t, INT16_MAX, INT16_WIDTH); +#endif +#ifdef INT32_MAX +# ifndef INT32_WIDTH +# error "missing INT32_WIDTH" +# endif +CHECK_WIDTH (int32_t, INT32_MAX, INT32_WIDTH); +#endif +#ifdef INT64_MAX +# ifndef INT64_WIDTH +# error "missing INT64_WIDTH" +# endif +CHECK_WIDTH (int64_t, INT64_MAX, INT64_WIDTH); +#endif +#ifdef UINT8_MAX +# ifndef UINT8_WIDTH +# error "missing UINT8_WIDTH" +# endif +CHECK_WIDTH (uint8_t, UINT8_MAX, UINT8_WIDTH); +#endif +#ifdef UINT16_MAX +# ifndef UINT16_WIDTH +# error "missing UINT16_WIDTH" +# endif +CHECK_WIDTH (uint16_t, UINT16_MAX, UINT16_WIDTH); +#endif +#ifdef UINT32_MAX +# ifndef UINT32_WIDTH +# error "missing UINT32_WIDTH" +# endif +CHECK_WIDTH (uint32_t, UINT32_MAX, UINT32_WIDTH); +#endif +#ifdef UINT64_MAX +# ifndef UINT64_WIDTH +# error "missing UINT64_WIDTH" +# endif +CHECK_WIDTH (uint64_t, UINT64_MAX, UINT64_WIDTH); +#endif + +#ifndef INT_LEAST8_WIDTH +# error "missing INT_LEAST8_WIDTH" +#endif +CHECK_WIDTH (int_least8_t, INT_LEAST8_MAX, INT_LEAST8_WIDTH); +#ifndef INT_LEAST16_WIDTH +# error "missing INT_LEAST16_WIDTH" +#endif +CHECK_WIDTH (int_least16_t, INT_LEAST16_MAX, INT_LEAST16_WIDTH); +#ifndef INT_LEAST32_WIDTH +# error "missing INT_LEAST32_WIDTH" +#endif +CHECK_WIDTH (int_least32_t, INT_LEAST32_MAX, INT_LEAST32_WIDTH); +#ifndef INT_LEAST64_WIDTH +# error "missing INT_LEAST64_WIDTH" +#endif +CHECK_WIDTH (int_least64_t, INT_LEAST64_MAX, INT_LEAST64_WIDTH); +#ifndef INT_LEAST8_WIDTH +# error "missing INT_LEAST8_WIDTH" +#endif +CHECK_WIDTH (uint_least8_t, UINT_LEAST8_MAX, UINT_LEAST8_WIDTH); +#ifndef UINT_LEAST16_WIDTH +# error "missing UINT_LEAST16_WIDTH" +#endif +CHECK_WIDTH (uint_least16_t, UINT_LEAST16_MAX, UINT_LEAST16_WIDTH); +#ifndef UINT_LEAST32_WIDTH +# error "missing UINT_LEAST32_WIDTH" +#endif +CHECK_WIDTH (uint_least32_t, UINT_LEAST32_MAX, UINT_LEAST32_WIDTH); +#ifndef UINT_LEAST64_WIDTH +# error "missing UINT_LEAST64_WIDTH" +#endif +CHECK_WIDTH (uint_least64_t, UINT_LEAST64_MAX, UINT_LEAST64_WIDTH); + +#ifndef INT_FAST8_WIDTH +# error "missing INT_FAST8_WIDTH" +#endif +CHECK_WIDTH (int_fast8_t, INT_FAST8_MAX, INT_FAST8_WIDTH); +#ifndef INT_FAST16_WIDTH +# error "missing INT_FAST16_WIDTH" +#endif +CHECK_WIDTH (int_fast16_t, INT_FAST16_MAX, INT_FAST16_WIDTH); +#ifndef INT_FAST32_WIDTH +# error "missing INT_FAST32_WIDTH" +#endif +CHECK_WIDTH (int_fast32_t, INT_FAST32_MAX, INT_FAST32_WIDTH); +#ifndef INT_FAST64_WIDTH +# error "missing INT_FAST64_WIDTH" +#endif +CHECK_WIDTH (int_fast64_t, INT_FAST64_MAX, INT_FAST64_WIDTH); +#ifndef INT_FAST8_WIDTH +# error "missing INT_FAST8_WIDTH" +#endif +CHECK_WIDTH (uint_fast8_t, UINT_FAST8_MAX, UINT_FAST8_WIDTH); +#ifndef UINT_FAST16_WIDTH +# error "missing UINT_FAST16_WIDTH" +#endif +CHECK_WIDTH (uint_fast16_t, UINT_FAST16_MAX, UINT_FAST16_WIDTH); +#ifndef UINT_FAST32_WIDTH +# error "missing UINT_FAST32_WIDTH" +#endif +CHECK_WIDTH (uint_fast32_t, UINT_FAST32_MAX, UINT_FAST32_WIDTH); +#ifndef UINT_FAST64_WIDTH +# error "missing UINT_FAST64_WIDTH" +#endif +CHECK_WIDTH (uint_fast64_t, UINT_FAST64_MAX, UINT_FAST64_WIDTH); + +#ifdef INTPTR_MAX +# ifndef INTPTR_WIDTH +# error "missing INTPTR_WIDTH" +# endif +CHECK_WIDTH (intptr_t, INTPTR_MAX, INTPTR_WIDTH); +#endif +#ifdef UINTPTR_MAX +# ifndef UINTPTR_WIDTH +# error "missing UINTPTR_WIDTH" +# endif +CHECK_WIDTH (uintptr_t, UINTPTR_MAX, UINTPTR_WIDTH); +#endif + +#ifndef INTMAX_WIDTH +# error "missing INTMAX_WIDTH" +#endif +CHECK_WIDTH (intmax_t, INTMAX_MAX, INTMAX_WIDTH); +#ifndef UINTMAX_WIDTH +# error "missing UINTMAX_WIDTH" +#endif +CHECK_WIDTH (uintmax_t, UINTMAX_MAX, UINTMAX_WIDTH); + +#ifndef PTRDIFF_WIDTH +# error "missing PTRDIFF_WIDTH" +#endif +CHECK_WIDTH (ptrdiff_t, PTRDIFF_MAX, PTRDIFF_WIDTH); +#ifndef SIGNAL_SUPPRESS +# ifndef SIG_ATOMIC_WIDTH +# error "missing SIG_ATOMIC_WIDTH" +# endif +CHECK_WIDTH (sig_atomic_t, SIG_ATOMIC_MAX, SIG_ATOMIC_WIDTH); +#endif +#ifndef SIZE_WIDTH +# error "missing SIZE_WIDTH" +#endif +CHECK_WIDTH (size_t, SIZE_MAX, SIZE_WIDTH); +#ifndef WCHAR_WIDTH +# error "missing WCHAR_WIDTH" +#endif +CHECK_WIDTH (wchar_t, WCHAR_MAX, WCHAR_WIDTH); +#ifndef WINT_WIDTH +# error "missing WINT_WIDTH" +#endif +CHECK_WIDTH (wint_t, WINT_MAX, WINT_WIDTH); -- cgit v1.1 From e5ec901cec9de5295bb323f538d6addd479bac46 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Thu, 3 Oct 2019 00:13:40 +0000 Subject: Use the SIGNED_16BIT_OFFSET_EXTRA_P macro for 16-bit signed tests. 2019-10-02 Michael Meissner * config/rs6000/rs6000.c (mem_operand_gpr): Use SIGNED_16BIT_OFFSET_EXTRA_P. (mem_operand_ds_form): Use SIGNED_16BIT_OFFSET_EXTRA_P. (rs6000_mode_dependent_address): Use SIGNED_16BIT_OFFSET_EXTRA_P. From-SVN: r276498 --- gcc/ChangeLog | 8 ++++++++ gcc/config/rs6000/predicates.md | 3 ++- gcc/config/rs6000/rs6000.c | 12 ++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26c5c42..2d6bdba 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-10-02 Michael Meissner + + * config/rs6000/rs6000.c (mem_operand_gpr): Use + SIGNED_16BIT_OFFSET_EXTRA_P macro. + (mem_operand_ds_form): Use SIGNED_16BIT_OFFSET_EXTRA_P macro. + (rs6000_mode_dependent_address): Use SIGNED_16BIT_OFFSET_EXTRA_P + macro. + 2019-10-02 Joseph Myers * ginclude/stdint-gcc.h [__STDC_WANT_IEC_60559_BFP_EXT__]: Change diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 345d9c3..2e13a7e 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -851,7 +851,8 @@ ;; Return 1 if OP is a constant but not a valid add_operand. (define_predicate "non_add_cint_operand" (and (match_code "const_int") - (not (match_operand 0 "add_operand")))) + (match_test "!satisfies_constraint_I (op) + && !satisfies_constraint_L (op)"))) ;; Return 1 if the operand is a constant that can be used as the operand ;; of an AND, OR or XOR. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 330e249..a4a3882 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -7372,7 +7372,7 @@ mem_operand_gpr (rtx op, machine_mode mode) causes a wrap, so test only the low 16 bits. */ offset = ((offset & 0xffff) ^ 0x8000) - 0x8000; - return offset + 0x8000 < 0x10000u - extra; + return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra); } /* As above, but for DS-FORM VSX insns. Unlike mem_operand_gpr, @@ -7405,7 +7405,7 @@ mem_operand_ds_form (rtx op, machine_mode mode) causes a wrap, so test only the low 16 bits. */ offset = ((offset & 0xffff) ^ 0x8000) - 0x8000; - return offset + 0x8000 < 0x10000u - extra; + return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra); } /* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address_p. */ @@ -7754,8 +7754,7 @@ rs6000_legitimate_offset_address_p (machine_mode mode, rtx x, break; } - offset += 0x8000; - return offset < 0x10000 - extra; + return SIGNED_16BIT_OFFSET_EXTRA_P (offset, extra); } bool @@ -8772,8 +8771,9 @@ rs6000_mode_dependent_address (const_rtx addr) && XEXP (addr, 0) != arg_pointer_rtx && CONST_INT_P (XEXP (addr, 1))) { - unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1)); - return val + 0x8000 >= 0x10000 - (TARGET_POWERPC64 ? 8 : 12); + HOST_WIDE_INT val = INTVAL (XEXP (addr, 1)); + HOST_WIDE_INT extra = TARGET_POWERPC64 ? 8 : 12; + return !SIGNED_16BIT_OFFSET_EXTRA_P (val, extra); } break; -- cgit v1.1 From e6f53878db8cb0e9c96b1393099d7296d6f23329 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 3 Oct 2019 00:16:19 +0000 Subject: Daily bump. From-SVN: r276502 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 11b6d83..e0a8c09 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20191002 +20191003 -- cgit v1.1 From 0a8c8f4d6578fac21adc0e156861c4b47bed4418 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Thu, 3 Oct 2019 00:17:56 +0000 Subject: Undo unintended change to predicates.md in subversion id 276498 From-SVN: r276503 --- gcc/config/rs6000/predicates.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 2e13a7e..345d9c3 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -851,8 +851,7 @@ ;; Return 1 if OP is a constant but not a valid add_operand. (define_predicate "non_add_cint_operand" (and (match_code "const_int") - (match_test "!satisfies_constraint_I (op) - && !satisfies_constraint_L (op)"))) + (not (match_operand 0 "add_operand")))) ;; Return 1 if the operand is a constant that can be used as the operand ;; of an AND, OR or XOR. -- cgit v1.1 From 38a734350fd787da1b4bcf9b4e0a99ed2adb5eae Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 3 Oct 2019 08:08:50 +0000 Subject: Makefile.in (OBJS): Add range.o and range-op.o. * Makefile.in (OBJS): Add range.o and range-op.o. Remove wide-int-range.o. * function-tests.c (test_ranges): New. (function_tests_c_tests): Call test_ranges. * ipa-cp.c (ipa_vr_operation_and_type_effects): Call range_fold_unary_expr instead of extract_range_from_unary_expr. * ipa-prop.c (ipa_compute_jump_functions_for_edge): Same. * range-op.cc: New file. * range-op.h: New file. * range.cc: New file. * range.h: New file. * selftest.h (range_tests): New prototype. * ssa.h: Include range.h. * tree-vrp.c (value_range_base::value_range_base): New constructors. (value_range_base::singleton_p): Do not call ranges_from_anti_range until sure we will need to. (value_range_base::type): Rename gcc_assert to gcc_checking_assert. (vrp_val_is_max): New argument. (vrp_val_is_min): Same. (wide_int_range_set_zero_nonzero_bits): Move from wide-int-range.cc. (extract_range_into_wide_ints): Remove. (extract_range_from_multiplicative_op): Remove. (extract_range_from_pointer_plus_expr): Abstract POINTER_PLUS code from extract_range_from_binary_expr. (extract_range_from_plus_minus_expr): Abstract PLUS/MINUS code from extract_range_from_binary_expr. (extract_range_from_binary_expr): Remove. (normalize_for_range_ops): New. (range_fold_binary_expr): New. (range_fold_unary_expr): New. (value_range_base::num_pairs): New. (value_range_base::lower_bound): New. (value_range_base::upper_bound): New. (value_range_base::upper_bound): New. (value_range_base::contains_p): New. (value_range_base::invert): New. (value_range_base::union_): New. (value_range_base::intersect): New. (range_compatible_p): New. (value_range_base::operator==): New. (determine_value_range_1): Call range_fold_*expr instead of extract_range_from_*expr. * tree-vrp.h (class value_range_base): Add new constructors. Add methods for union_, intersect, operator==, contains_p, num_pairs, lower_bound, upper_bound, invert. (vrp_val_is_min): Add handle_pointers argument. (vrp_val_is_max): Same. (extract_range_from_unary_expr): Remove. (extract_range_from_binary_expr): Remove. (range_fold_unary_expr): New. (range_fold_binary_expr): New. * vr-values.c (vr_values::extract_range_from_binary_expr): Call range_fold_binary_expr instead of extract_range_from_binary_expr. (vr_values::extract_range_basic): Same. (vr_values::extract_range_from_unary_expr): Call range_fold_unary_expr instead of extract_range_from_unary_expr. * wide-int-range.cc: Remove. * wide-int-range.h: Remove. From-SVN: r276504 --- gcc/ChangeLog | 64 + gcc/Makefile.in | 3 +- gcc/function-tests.c | 14 + gcc/ipa-cp.c | 3 +- gcc/ipa-prop.c | 4 +- gcc/range-op.cc | 3260 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/range-op.h | 88 ++ gcc/range.cc | 89 ++ gcc/range.h | 33 + gcc/selftest.h | 4 + gcc/ssa.h | 1 + gcc/tree-vrp.c | 1226 ++++++++----------- gcc/tree-vrp.h | 37 +- gcc/vr-values.c | 13 +- gcc/wide-int-range.cc | 865 ------------- gcc/wide-int-range.h | 188 --- 16 files changed, 4116 insertions(+), 1776 deletions(-) create mode 100644 gcc/range-op.cc create mode 100644 gcc/range-op.h create mode 100644 gcc/range.cc create mode 100644 gcc/range.h delete mode 100644 gcc/wide-int-range.cc delete mode 100644 gcc/wide-int-range.h (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2d6bdba..991949b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,67 @@ +2019-10-03 Aldy Hernandez + + * Makefile.in (OBJS): Add range.o and range-op.o. + Remove wide-int-range.o. + * function-tests.c (test_ranges): New. + (function_tests_c_tests): Call test_ranges. + * ipa-cp.c (ipa_vr_operation_and_type_effects): Call + range_fold_unary_expr instead of extract_range_from_unary_expr. + * ipa-prop.c (ipa_compute_jump_functions_for_edge): Same. + * range-op.cc: New file. + * range-op.h: New file. + * range.cc: New file. + * range.h: New file. + * selftest.h (range_tests): New prototype. + * ssa.h: Include range.h. + * tree-vrp.c (value_range_base::value_range_base): New + constructors. + (value_range_base::singleton_p): Do not call + ranges_from_anti_range until sure we will need to. + (value_range_base::type): Rename gcc_assert to + gcc_checking_assert. + (vrp_val_is_max): New argument. + (vrp_val_is_min): Same. + (wide_int_range_set_zero_nonzero_bits): Move from + wide-int-range.cc. + (extract_range_into_wide_ints): Remove. + (extract_range_from_multiplicative_op): Remove. + (extract_range_from_pointer_plus_expr): Abstract POINTER_PLUS code + from extract_range_from_binary_expr. + (extract_range_from_plus_minus_expr): Abstract PLUS/MINUS code + from extract_range_from_binary_expr. + (extract_range_from_binary_expr): Remove. + (normalize_for_range_ops): New. + (range_fold_binary_expr): New. + (range_fold_unary_expr): New. + (value_range_base::num_pairs): New. + (value_range_base::lower_bound): New. + (value_range_base::upper_bound): New. + (value_range_base::upper_bound): New. + (value_range_base::contains_p): New. + (value_range_base::invert): New. + (value_range_base::union_): New. + (value_range_base::intersect): New. + (range_compatible_p): New. + (value_range_base::operator==): New. + (determine_value_range_1): Call range_fold_*expr instead of + extract_range_from_*expr. + * tree-vrp.h (class value_range_base): Add new constructors. + Add methods for union_, intersect, operator==, contains_p, + num_pairs, lower_bound, upper_bound, invert. + (vrp_val_is_min): Add handle_pointers argument. + (vrp_val_is_max): Same. + (extract_range_from_unary_expr): Remove. + (extract_range_from_binary_expr): Remove. + (range_fold_unary_expr): New. + (range_fold_binary_expr): New. + * vr-values.c (vr_values::extract_range_from_binary_expr): Call + range_fold_binary_expr instead of extract_range_from_binary_expr. + (vr_values::extract_range_basic): Same. + (vr_values::extract_range_from_unary_expr): Call + range_fold_unary_expr instead of extract_range_from_unary_expr. + * wide-int-range.cc: Remove. + * wide-int-range.h: Remove. + 2019-10-02 Michael Meissner * config/rs6000/rs6000.c (mem_operand_gpr): Use diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ca03cfd..59adfaa 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1453,6 +1453,8 @@ OBJS = \ print-tree.o \ profile.o \ profile-count.o \ + range.o \ + range-op.o \ read-md.o \ read-rtl.o \ read-rtl-function.o \ @@ -1611,7 +1613,6 @@ OBJS = \ web.o \ wide-int.o \ wide-int-print.o \ - wide-int-range.o \ xcoffout.o \ $(out_object_file) \ $(EXTRA_OBJS) \ diff --git a/gcc/function-tests.c b/gcc/function-tests.c index f1e29e4..2440dd6 100644 --- a/gcc/function-tests.c +++ b/gcc/function-tests.c @@ -570,6 +570,19 @@ test_conversion_to_ssa () ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt))); } +/* Test range folding. We must start this here because we need cfun + set. */ + +static void +test_ranges () +{ + tree fndecl = build_trivial_high_gimple_function (); + function *fun = DECL_STRUCT_FUNCTION (fndecl); + push_cfun (fun); + range_tests (); + pop_cfun (); +} + /* Test of expansion from gimple-ssa to RTL. */ static void @@ -674,6 +687,7 @@ function_tests_c_tests () test_gimplification (); test_building_cfg (); test_conversion_to_ssa (); + test_ranges (); test_expansion_to_rtl (); } diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index b4fb74e..67664ec 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -1944,8 +1944,7 @@ ipa_vr_operation_and_type_effects (value_range_base *dst_vr, enum tree_code operation, tree dst_type, tree src_type) { - extract_range_from_unary_expr (dst_vr, operation, dst_type, - src_vr, src_type); + range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type); if (dst_vr->varying_p () || dst_vr->undefined_p ()) return false; return true; diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 2f2b070..25a108d 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -1921,8 +1921,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi, value_range_base tmpvr (type, wide_int_to_tree (TREE_TYPE (arg), min), wide_int_to_tree (TREE_TYPE (arg), max)); - extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type, - &tmpvr, TREE_TYPE (arg)); + range_fold_unary_expr (&resvr, NOP_EXPR, param_type, + &tmpvr, TREE_TYPE (arg)); if (!resvr.undefined_p () && !resvr.varying_p ()) ipa_set_jfunc_vr (jfunc, &resvr); else diff --git a/gcc/range-op.cc b/gcc/range-op.cc new file mode 100644 index 0000000..b538b00 --- /dev/null +++ b/gcc/range-op.cc @@ -0,0 +1,3260 @@ +/* Code for range operators. + Copyright (C) 2017-2019 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + and Aldy Hernandez . + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "insn-codes.h" +#include "rtl.h" +#include "tree.h" +#include "gimple.h" +#include "cfghooks.h" +#include "tree-pass.h" +#include "ssa.h" +#include "optabs-tree.h" +#include "gimple-pretty-print.h" +#include "diagnostic-core.h" +#include "flags.h" +#include "fold-const.h" +#include "stor-layout.h" +#include "calls.h" +#include "cfganal.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "tree-cfg.h" +#include "wide-int.h" +#include "range-op.h" + +// Return the upper limit for a type. + +static inline wide_int +max_limit (const_tree type) +{ + return wi::max_value (TYPE_PRECISION (type) , TYPE_SIGN (type)); +} + +// Return the lower limit for a type. + +static inline wide_int +min_limit (const_tree type) +{ + return wi::min_value (TYPE_PRECISION (type) , TYPE_SIGN (type)); +} + +// If the range of either op1 or op2 is undefined, set the result to +// undefined and return TRUE. + +inline bool +empty_range_check (value_range_base &r, + const value_range_base &op1, + const value_range_base & op2) +{ + if (op1.undefined_p () || op2.undefined_p ()) + { + r.set_undefined (); + return true; + } + else + return false; +} + +// Return TRUE if shifting by OP is undefined behavior, and set R to +// the appropriate range. + +static inline bool +undefined_shift_range_check (value_range_base &r, tree type, + value_range_base op) +{ + if (op.undefined_p ()) + { + r = value_range_base (); + return true; + } + + // Shifting by any values outside [0..prec-1], gets undefined + // behavior from the shift operation. We cannot even trust + // SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl + // shifts, and the operation at the tree level may be widened. + if (wi::lt_p (op.lower_bound (), 0, TYPE_SIGN (op.type ())) + || wi::ge_p (op.upper_bound (), + TYPE_PRECISION (type), TYPE_SIGN (op.type ()))) + { + r = value_range_base (type); + return true; + } + return false; +} + +// Return TRUE if 0 is within [WMIN, WMAX]. + +static inline bool +wi_includes_zero_p (tree type, const wide_int &wmin, const wide_int &wmax) +{ + signop sign = TYPE_SIGN (type); + return wi::le_p (wmin, 0, sign) && wi::ge_p (wmax, 0, sign); +} + +// Return TRUE if [WMIN, WMAX] is the singleton 0. + +static inline bool +wi_zero_p (tree type, const wide_int &wmin, const wide_int &wmax) +{ + unsigned prec = TYPE_PRECISION (type); + return wmin == wmax && wi::eq_p (wmin, wi::zero (prec)); +} + +// Default wide_int fold operation returns [MIN, MAX]. + +value_range_base +range_operator::wi_fold (tree type, + const wide_int &lh_lb ATTRIBUTE_UNUSED, + const wide_int &lh_ub ATTRIBUTE_UNUSED, + const wide_int &rh_lb ATTRIBUTE_UNUSED, + const wide_int &rh_ub ATTRIBUTE_UNUSED) const +{ + return value_range_base (type); +} + +// The default for fold is to break all ranges into sub-ranges and +// invoke the wi_fold method on each sub-range pair. + +value_range_base +range_operator::fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + for (unsigned x = 0; x < lh.num_pairs (); ++x) + for (unsigned y = 0; y < rh.num_pairs (); ++y) + { + wide_int lh_lb = lh.lower_bound (x); + wide_int lh_ub = lh.upper_bound (x); + wide_int rh_lb = rh.lower_bound (y); + wide_int rh_ub = rh.upper_bound (y); + r.union_ (wi_fold (type, lh_lb, lh_ub, rh_lb, rh_ub)); + if (r.varying_p ()) + return r; + } + return r; +} + +// The default for op1_range is to return false. + +bool +range_operator::op1_range (value_range_base &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const value_range_base &lhs ATTRIBUTE_UNUSED, + const value_range_base &op2 ATTRIBUTE_UNUSED) const +{ + return false; +} + +// The default for op2_range is to return false. + +bool +range_operator::op2_range (value_range_base &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const value_range_base &lhs ATTRIBUTE_UNUSED, + const value_range_base &op1 ATTRIBUTE_UNUSED) const +{ + return false; +} + + +// Called when there is either an overflow OR an underflow... which +// means an anti range must be created to compensate. This does not +// cover the case where there are 2 possible overflows, or none. + +static value_range_base +adjust_overflow_bound (tree type, const wide_int &wmin, const wide_int &wmax) +{ + const signop sgn = TYPE_SIGN (type); + const unsigned int prec = TYPE_PRECISION (type); + + wide_int tmin = wide_int::from (wmin, prec, sgn); + wide_int tmax = wide_int::from (wmax, prec, sgn); + + bool covers = false; + wide_int tem = tmin; + tmin = tmax + 1; + if (wi::cmp (tmin, tmax, sgn) < 0) + covers = true; + tmax = tem - 1; + if (wi::cmp (tmax, tem, sgn) > 0) + covers = true; + + // If the anti-range would cover nothing, drop to varying. + // Likewise if the anti-range bounds are outside of the types + // values. + if (covers || wi::cmp (tmin, tmax, sgn) > 0) + return value_range_base (type); + + return value_range_base (VR_ANTI_RANGE, type, tmin, tmax); +} + +// Given a newly calculated lbound and ubound, examine their +// respective overflow bits to determine how to create a range. +// Return said range. + +static value_range_base +create_range_with_overflow (tree type, + const wide_int &wmin, const wide_int &wmax, + wi::overflow_type min_ovf = wi::OVF_NONE, + wi::overflow_type max_ovf = wi::OVF_NONE) +{ + const signop sgn = TYPE_SIGN (type); + const unsigned int prec = TYPE_PRECISION (type); + const bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type); + + // For one bit precision if max != min, then the range covers all + // values. + if (prec == 1 && wi::ne_p (wmax, wmin)) + return value_range_base (type); + + if (overflow_wraps) + { + // If overflow wraps, truncate the values and adjust the range, + // kind, and bounds appropriately. + if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE)) + { + wide_int tmin = wide_int::from (wmin, prec, sgn); + wide_int tmax = wide_int::from (wmax, prec, sgn); + // If the limits are swapped, we wrapped around and cover + // the entire range. + if (wi::gt_p (tmin, tmax, sgn)) + return value_range_base (type); + + // No overflow or both overflow or underflow. The range + // kind stays normal. + return value_range_base (type, tmin, tmax); + } + + if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE) + || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE)) + return adjust_overflow_bound (type, wmin, wmax); + + // Other underflow and/or overflow, drop to VR_VARYING. + return value_range_base (type); + } + else + { + // If overflow does not wrap, saturate to [MIN, MAX]. + wide_int new_lb, new_ub; + if (min_ovf == wi::OVF_UNDERFLOW) + new_lb = wi::min_value (prec, sgn); + else if (min_ovf == wi::OVF_OVERFLOW) + new_lb = wi::max_value (prec, sgn); + else + new_lb = wmin; + + if (max_ovf == wi::OVF_UNDERFLOW) + new_ub = wi::min_value (prec, sgn); + else if (max_ovf == wi::OVF_OVERFLOW) + new_ub = wi::max_value (prec, sgn); + else + new_ub = wmax; + + return value_range_base (type, new_lb, new_ub); + } +} + +// Like above, but canonicalize the case where the bounds are swapped +// and overflow may wrap. In which case, we transform [10,5] into +// [MIN,5][10,MAX]. + +static inline value_range_base +create_possibly_reversed_range (tree type, + const wide_int &new_lb, const wide_int &new_ub) +{ + signop s = TYPE_SIGN (type); + // If the bounds are swapped, treat the result as if an overflow occured. + if (wi::gt_p (new_lb, new_ub, s)) + return adjust_overflow_bound (type, new_lb, new_ub); + + // Otherwise its just a normal range. + return value_range_base (type, new_lb, new_ub); +} + +// Return a value_range_base instance that is a boolean TRUE. + +static inline value_range_base +range_true (tree type) +{ + unsigned prec = TYPE_PRECISION (type); + return value_range_base (type, wi::one (prec), wi::one (prec)); +} + +// Return a value_range_base instance that is a boolean FALSE. + +static inline value_range_base +range_false (tree type) +{ + unsigned prec = TYPE_PRECISION (type); + return value_range_base (type, wi::zero (prec), wi::zero (prec)); +} + +// Return a value_range_base that covers both true and false. + +static inline value_range_base +range_true_and_false (tree type) +{ + unsigned prec = TYPE_PRECISION (type); + return value_range_base (type, wi::zero (prec), wi::one (prec)); +} + +enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL }; + +// Return the summary information about boolean range LHS. Return an +// "interesting" range in R. For EMPTY or FULL, return the equivalent +// range for TYPE, for BRS_TRUE and BRS false, return the negation of +// the bool range. + +static bool_range_state +get_bool_state (value_range_base &r, + const value_range_base &lhs, tree val_type) +{ + // If there is no result, then this is unexecutable. + if (lhs.undefined_p ()) + { + r.set_undefined (); + return BRS_EMPTY; + } + + // If the bounds aren't the same, then it's not a constant. + if (!wi::eq_p (lhs.upper_bound (), lhs.lower_bound ())) + { + r.set_varying (val_type); + return BRS_FULL; + } + + if (lhs.zero_p ()) + return BRS_FALSE; + + return BRS_TRUE; +} + + +class operator_equal : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &val) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &val) const; +} op_equal; + +value_range_base +operator_equal::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (empty_range_check (r, op1, op2)) + return r; + + // We can be sure the values are always equal or not if both ranges + // consist of a single value, and then compare them. + if (wi::eq_p (op1.lower_bound (), op1.upper_bound ()) + && wi::eq_p (op2.lower_bound (), op2.upper_bound ())) + { + if (wi::eq_p (op1.lower_bound (), op2.upper_bound())) + r = range_true (type); + else + r = range_false (type); + } + else + { + // If ranges do not intersect, we know the range is not equal, + // otherwise we don't know anything for sure. + r = range_intersect (op1, op2); + if (r.undefined_p ()) + r = range_false (type); + else + r = range_true_and_false (type); + } + + return r; +} + +bool +operator_equal::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_FALSE: + // If the result is false, the only time we know anything is + // if OP2 is a constant. + if (wi::eq_p (op2.lower_bound(), op2.upper_bound())) + r = range_invert (op2); + else + r.set_varying (type); + break; + + case BRS_TRUE: + // If it's true, the result is the same as OP2. + r = op2; + break; + + default: + break; + } + return true; +} + +bool +operator_equal::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + return operator_equal::op1_range (r, type, lhs, op1); +} + + +class operator_not_equal : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_not_equal; + +value_range_base +operator_not_equal::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (empty_range_check (r, op1, op2)) + return r; + + // We can be sure the values are always equal or not if both ranges + // consist of a single value, and then compare them. + if (wi::eq_p (op1.lower_bound (), op1.upper_bound ()) + && wi::eq_p (op2.lower_bound (), op2.upper_bound ())) + { + if (wi::ne_p (op1.lower_bound (), op2.upper_bound())) + r = range_true (type); + else + r = range_false (type); + } + else + { + // If ranges do not intersect, we know the range is not equal, + // otherwise we don't know anything for sure. + r = range_intersect (op1, op2); + if (r.undefined_p ()) + r = range_true (type); + else + r = range_true_and_false (type); + } + + return r; +} + +bool +operator_not_equal::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + // If the result is true, the only time we know anything is if + // OP2 is a constant. + if (wi::eq_p (op2.lower_bound(), op2.upper_bound())) + r = range_invert (op2); + else + r.set_varying (type); + break; + + case BRS_FALSE: + // If its true, the result is the same as OP2. + r = op2; + break; + + default: + break; + } + return true; +} + + +bool +operator_not_equal::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + return operator_not_equal::op1_range (r, type, lhs, op1); +} + +// (X < VAL) produces the range of [MIN, VAL - 1]. + +static void +build_lt (value_range_base &r, tree type, const wide_int &val) +{ + wi::overflow_type ov; + wide_int lim = wi::sub (val, 1, TYPE_SIGN (type), &ov); + + // If val - 1 underflows, check if X < MIN, which is an empty range. + if (ov) + r.set_undefined (); + else + r = value_range_base (type, min_limit (type), lim); +} + +// (X <= VAL) produces the range of [MIN, VAL]. + +static void +build_le (value_range_base &r, tree type, const wide_int &val) +{ + r = value_range_base (type, min_limit (type), val); +} + +// (X > VAL) produces the range of [VAL + 1, MAX]. + +static void +build_gt (value_range_base &r, tree type, const wide_int &val) +{ + wi::overflow_type ov; + wide_int lim = wi::add (val, 1, TYPE_SIGN (type), &ov); + // If val + 1 overflows, check is for X > MAX, which is an empty range. + if (ov) + r.set_undefined (); + else + r = value_range_base (type, lim, max_limit (type)); +} + +// (X >= val) produces the range of [VAL, MAX]. + +static void +build_ge (value_range_base &r, tree type, const wide_int &val) +{ + r = value_range_base (type, val, max_limit (type)); +} + + +class operator_lt : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_lt; + +value_range_base +operator_lt::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (empty_range_check (r, op1, op2)) + return r; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::lt_p (op1.upper_bound (), op2.lower_bound (), sign)) + r = range_true (type); + else if (!wi::lt_p (op1.lower_bound (), op2.upper_bound (), sign)) + r = range_false (type); + else + r = range_true_and_false (type); + return r; +} + +bool +operator_lt::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_lt (r, type, op2.upper_bound ()); + break; + + case BRS_FALSE: + build_ge (r, type, op2.lower_bound ()); + break; + + default: + break; + } + return true; +} + +bool +operator_lt::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_FALSE: + build_le (r, type, op1.upper_bound ()); + break; + + case BRS_TRUE: + build_gt (r, type, op1.lower_bound ()); + break; + + default: + break; + } + return true; +} + + +class operator_le : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_le; + +value_range_base +operator_le::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (empty_range_check (r, op1, op2)) + return r; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::le_p (op1.upper_bound (), op2.lower_bound (), sign)) + r = range_true (type); + else if (!wi::le_p (op1.lower_bound (), op2.upper_bound (), sign)) + r = range_false (type); + else + r = range_true_and_false (type); + return r; +} + +bool +operator_le::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_le (r, type, op2.upper_bound ()); + break; + + case BRS_FALSE: + build_gt (r, type, op2.lower_bound ()); + break; + + default: + break; + } + return true; +} + +bool +operator_le::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_FALSE: + build_lt (r, type, op1.upper_bound ()); + break; + + case BRS_TRUE: + build_ge (r, type, op1.lower_bound ()); + break; + + default: + break; + } + return true; +} + + +class operator_gt : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_gt; + +value_range_base +operator_gt::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (empty_range_check (r, op1, op2)) + return r; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::gt_p (op1.lower_bound (), op2.upper_bound (), sign)) + r = range_true (type); + else if (!wi::gt_p (op1.upper_bound (), op2.lower_bound (), sign)) + r = range_false (type); + else + r = range_true_and_false (type); + return r; +} + +bool +operator_gt::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_gt (r, type, op2.lower_bound ()); + break; + + case BRS_FALSE: + build_le (r, type, op2.upper_bound ()); + break; + + default: + break; + } + return true; +} + +bool +operator_gt::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_FALSE: + build_ge (r, type, op1.lower_bound ()); + break; + + case BRS_TRUE: + build_lt (r, type, op1.upper_bound ()); + break; + + default: + break; + } + return true; +} + + +class operator_ge : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_ge; + +value_range_base +operator_ge::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (empty_range_check (r, op1, op2)) + return r; + + signop sign = TYPE_SIGN (op1.type ()); + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); + + if (wi::ge_p (op1.lower_bound (), op2.upper_bound (), sign)) + r = range_true (type); + else if (!wi::ge_p (op1.upper_bound (), op2.lower_bound (), sign)) + r = range_false (type); + else + r = range_true_and_false (type); + return r; +} + +bool +operator_ge::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_ge (r, type, op2.lower_bound ()); + break; + + case BRS_FALSE: + build_lt (r, type, op2.upper_bound ()); + break; + + default: + break; + } + return true; +} + +bool +operator_ge::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_FALSE: + build_gt (r, type, op1.lower_bound ()); + break; + + case BRS_TRUE: + build_le (r, type, op1.upper_bound ()); + break; + + default: + break; + } + return true; +} + + +class operator_plus : public range_operator +{ +public: + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_plus; + +value_range_base +operator_plus::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + wi::overflow_type ov_lb, ov_ub; + signop s = TYPE_SIGN (type); + wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb); + wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub); + return create_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); +} + +bool +operator_plus::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + r = range_op_handler (MINUS_EXPR, type)->fold_range (type, lhs, op2); + return true; +} + +bool +operator_plus::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + r = range_op_handler (MINUS_EXPR, type)->fold_range (type, lhs, op1); + return true; +} + + +class operator_minus : public range_operator +{ +public: + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_minus; + +value_range_base +operator_minus::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + wi::overflow_type ov_lb, ov_ub; + signop s = TYPE_SIGN (type); + wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb); + wide_int new_ub = wi::sub (lh_ub, rh_lb, s, &ov_ub); + return create_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); +} + +bool +operator_minus::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + r = range_op_handler (PLUS_EXPR, type)->fold_range (type, lhs, op2); + return true; +} + +bool +operator_minus::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + r = fold_range (type, op1, lhs); + return true; +} + + +class operator_min : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_min; + +value_range_base +operator_min::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + signop s = TYPE_SIGN (type); + wide_int new_lb = wi::min (lh_lb, rh_lb, s); + wide_int new_ub = wi::min (lh_ub, rh_ub, s); + return create_range_with_overflow (type, new_lb, new_ub); +} + + +class operator_max : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_max; + +value_range_base +operator_max::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + signop s = TYPE_SIGN (type); + wide_int new_lb = wi::max (lh_lb, rh_lb, s); + wide_int new_ub = wi::max (lh_ub, rh_ub, s); + return create_range_with_overflow (type, new_lb, new_ub); +} + + +class cross_product_operator : public range_operator +{ +public: + // Perform an operation between two wide-ints and place the result + // in R. Return true if the operation overflowed. + virtual bool wi_op_overflows (wide_int &r, + tree type, + const wide_int &, + const wide_int &) const = 0; + + // Calculate the cross product of two sets of sub-ranges and return it. + value_range_base wi_cross_product (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +}; + +// Calculate the cross product of two sets of ranges and return it. +// +// Multiplications, divisions and shifts are a bit tricky to handle, +// depending on the mix of signs we have in the two ranges, we need to +// operate on different values to get the minimum and maximum values +// for the new range. One approach is to figure out all the +// variations of range combinations and do the operations. +// +// However, this involves several calls to compare_values and it is +// pretty convoluted. It's simpler to do the 4 operations (MIN0 OP +// MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP MAX1) and then +// figure the smallest and largest values to form the new range. + +value_range_base +cross_product_operator::wi_cross_product (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + wide_int cp1, cp2, cp3, cp4; + + // Compute the 4 cross operations, bailing if we get an overflow we + // can't handle. + if (wi_op_overflows (cp1, type, lh_lb, rh_lb)) + return value_range_base (type); + if (wi::eq_p (lh_lb, lh_ub)) + cp3 = cp1; + else if (wi_op_overflows (cp3, type, lh_ub, rh_lb)) + return value_range_base (type); + if (wi::eq_p (rh_lb, rh_ub)) + cp2 = cp1; + else if (wi_op_overflows (cp2, type, lh_lb, rh_ub)) + return value_range_base (type); + if (wi::eq_p (lh_lb, lh_ub)) + cp4 = cp2; + else if (wi_op_overflows (cp4, type, lh_ub, rh_ub)) + return value_range_base (type); + + // Order pairs. + signop sign = TYPE_SIGN (type); + if (wi::gt_p (cp1, cp2, sign)) + std::swap (cp1, cp2); + if (wi::gt_p (cp3, cp4, sign)) + std::swap (cp3, cp4); + + // Choose min and max from the ordered pairs. + wide_int res_lb = wi::min (cp1, cp3, sign); + wide_int res_ub = wi::max (cp2, cp4, sign); + return create_range_with_overflow (type, res_lb, res_ub); +} + + +class operator_mult : public cross_product_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; + virtual bool wi_op_overflows (wide_int &res, + tree type, + const wide_int &w0, + const wide_int &w1) const; +} op_mult; + +bool +operator_mult::wi_op_overflows (wide_int &res, + tree type, + const wide_int &w0, + const wide_int &w1) const +{ + wi::overflow_type overflow = wi::OVF_NONE; + signop sign = TYPE_SIGN (type); + res = wi::mul (w0, w1, sign, &overflow); + if (overflow && TYPE_OVERFLOW_UNDEFINED (type)) + { + // For multiplication, the sign of the overflow is given + // by the comparison of the signs of the operands. + if (sign == UNSIGNED || w0.sign_mask () == w1.sign_mask ()) + res = wi::max_value (w0.get_precision (), sign); + else + res = wi::min_value (w0.get_precision (), sign); + return false; + } + return overflow; +} + +value_range_base +operator_mult::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + if (TYPE_OVERFLOW_UNDEFINED (type)) + return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub); + + // Multiply the ranges when overflow wraps. This is basically fancy + // code so we don't drop to varying with an unsigned + // [-3,-1]*[-3,-1]. + // + // This test requires 2*prec bits if both operands are signed and + // 2*prec + 2 bits if either is not. Therefore, extend the values + // using the sign of the result to PREC2. From here on out, + // everthing is just signed math no matter what the input types + // were. + + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + widest2_int min0 = widest2_int::from (lh_lb, sign); + widest2_int max0 = widest2_int::from (lh_ub, sign); + widest2_int min1 = widest2_int::from (rh_lb, sign); + widest2_int max1 = widest2_int::from (rh_ub, sign); + widest2_int sizem1 = wi::mask (prec, false); + widest2_int size = sizem1 + 1; + + // Canonicalize the intervals. + if (sign == UNSIGNED) + { + if (wi::ltu_p (size, min0 + max0)) + { + min0 -= size; + max0 -= size; + } + if (wi::ltu_p (size, min1 + max1)) + { + min1 -= size; + max1 -= size; + } + } + + // Sort the 4 products so that min is in prod0 and max is in + // prod3. + widest2_int prod0 = min0 * min1; + widest2_int prod1 = min0 * max1; + widest2_int prod2 = max0 * min1; + widest2_int prod3 = max0 * max1; + + // min0min1 > max0max1 + if (prod0 > prod3) + std::swap (prod0, prod3); + + // min0max1 > max0min1 + if (prod1 > prod2) + std::swap (prod1, prod2); + + if (prod0 > prod1) + std::swap (prod0, prod1); + + if (prod2 > prod3) + std::swap (prod2, prod3); + + // diff = max - min + prod2 = prod3 - prod0; + if (wi::geu_p (prod2, sizem1)) + // The range covers all values. + return value_range_base (type); + + wide_int new_lb = wide_int::from (prod0, prec, sign); + wide_int new_ub = wide_int::from (prod3, prec, sign); + return create_possibly_reversed_range (type, new_lb, new_ub); +} + + +class operator_div : public cross_product_operator +{ +public: + operator_div (enum tree_code c) { code = c; } + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; + virtual bool wi_op_overflows (wide_int &res, + tree type, + const wide_int &, + const wide_int &) const; +private: + enum tree_code code; +}; + +bool +operator_div::wi_op_overflows (wide_int &res, + tree type, + const wide_int &w0, + const wide_int &w1) const +{ + if (w1 == 0) + return true; + + wi::overflow_type overflow = wi::OVF_NONE; + signop sign = TYPE_SIGN (type); + + switch (code) + { + case EXACT_DIV_EXPR: + // EXACT_DIV_EXPR is implemented as TRUNC_DIV_EXPR in + // operator_exact_divide. No need to handle it here. + gcc_unreachable (); + break; + case TRUNC_DIV_EXPR: + res = wi::div_trunc (w0, w1, sign, &overflow); + break; + case FLOOR_DIV_EXPR: + res = wi::div_floor (w0, w1, sign, &overflow); + break; + case ROUND_DIV_EXPR: + res = wi::div_round (w0, w1, sign, &overflow); + break; + case CEIL_DIV_EXPR: + res = wi::div_ceil (w0, w1, sign, &overflow); + break; + default: + gcc_unreachable (); + } + + if (overflow && TYPE_OVERFLOW_UNDEFINED (type)) + { + // For division, the only case is -INF / -1 = +INF. + res = wi::max_value (w0.get_precision (), sign); + return false; + } + return overflow; +} + +value_range_base +operator_div::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + // If we know we will divide by zero, return undefined. + if (rh_lb == 0 && rh_ub == 0) + return value_range_base (); + + const wide_int dividend_min = lh_lb; + const wide_int dividend_max = lh_ub; + const wide_int divisor_min = rh_lb; + const wide_int divisor_max = rh_ub; + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + wide_int extra_min, extra_max; + + // If we know we won't divide by zero, just do the division. + if (!wi_includes_zero_p (type, divisor_min, divisor_max)) + return wi_cross_product (type, dividend_min, dividend_max, + divisor_min, divisor_max); + + // If flag_non_call_exceptions, we must not eliminate a division by zero. + if (cfun->can_throw_non_call_exceptions) + return value_range_base (type); + + // If we're definitely dividing by zero, there's nothing to do. + if (wi_zero_p (type, divisor_min, divisor_max)) + return value_range_base (); + + // Perform the division in 2 parts, [LB, -1] and [1, UB], which will + // skip any division by zero. + + // First divide by the negative numbers, if any. + value_range_base r; + if (wi::neg_p (divisor_min, sign)) + r = wi_cross_product (type, dividend_min, dividend_max, + divisor_min, wi::minus_one (prec)); + // Then divide by the non-zero positive numbers, if any. + if (wi::gt_p (divisor_max, wi::zero (prec), sign)) + { + value_range_base tmp; + tmp = wi_cross_product (type, dividend_min, dividend_max, + wi::one (prec), divisor_max); + r.union_ (tmp); + } + return r; +} + +operator_div op_trunc_div (TRUNC_DIV_EXPR); +operator_div op_floor_div(FLOOR_DIV_EXPR); +operator_div op_round_div (ROUND_DIV_EXPR); +operator_div op_ceil_div (CEIL_DIV_EXPR); + + +class operator_exact_divide : public operator_div +{ +public: + operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { } + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + +} op_exact_div; + +bool +operator_exact_divide::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + tree offset; + // [2, 4] = op1 / [3,3] since its exact divide, no need to worry about + // remainders in the endpoints, so op1 = [2,4] * [3,3] = [6,12]. + // We wont bother trying to enumerate all the in between stuff :-P + // TRUE accuraacy is [6,6][9,9][12,12]. This is unlikely to matter most of + // the time however. + // If op2 is a multiple of 2, we would be able to set some non-zero bits. + if (op2.singleton_p (&offset) + && !integer_zerop (offset)) + { + r = range_op_handler (MULT_EXPR, type)->fold_range (type, lhs, op2); + return true; + } + return false; +} + + +class operator_lshift : public cross_product_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; + virtual bool wi_op_overflows (wide_int &res, + tree type, + const wide_int &, + const wide_int &) const; +} op_lshift; + +value_range_base +operator_lshift::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (undefined_shift_range_check (r, type, op2)) + return r; + + // Transform left shifts by constants into multiplies. + if (op2.singleton_p ()) + { + unsigned shift = op2.lower_bound ().to_uhwi (); + wide_int tmp = wi::set_bit_in_zero (shift, TYPE_PRECISION (type)); + value_range_base mult (type, tmp, tmp); + + // Force wrapping multiplication. + bool saved_flag_wrapv = flag_wrapv; + bool saved_flag_wrapv_pointer = flag_wrapv_pointer; + flag_wrapv = 1; + flag_wrapv_pointer = 1; + r = range_op_handler (MULT_EXPR, type)->fold_range (type, op1, mult); + flag_wrapv = saved_flag_wrapv; + flag_wrapv_pointer = saved_flag_wrapv_pointer; + return r; + } + + // Otherwise, invoke the generic fold routine. + return range_operator::fold_range (type, op1, op2); +} + +value_range_base +operator_lshift::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + int overflow_pos = sign == SIGNED ? prec - 1 : prec; + int bound_shift = overflow_pos - rh_ub.to_shwi (); + // If bound_shift == HOST_BITS_PER_WIDE_INT, the llshift can + // overflow. However, for that to happen, rh.max needs to be zero, + // which means rh is a singleton range of zero, which means it + // should be handled by the lshift fold_range above. + wide_int bound = wi::set_bit_in_zero (bound_shift, prec); + wide_int complement = ~(bound - 1); + wide_int low_bound, high_bound; + bool in_bounds = false; + + if (sign == UNSIGNED) + { + low_bound = bound; + high_bound = complement; + if (wi::ltu_p (lh_ub, low_bound)) + { + // [5, 6] << [1, 2] == [10, 24]. + // We're shifting out only zeroes, the value increases + // monotonically. + in_bounds = true; + } + else if (wi::ltu_p (high_bound, lh_lb)) + { + // [0xffffff00, 0xffffffff] << [1, 2] + // == [0xfffffc00, 0xfffffffe]. + // We're shifting out only ones, the value decreases + // monotonically. + in_bounds = true; + } + } + else + { + // [-1, 1] << [1, 2] == [-4, 4] + low_bound = complement; + high_bound = bound; + if (wi::lts_p (lh_ub, high_bound) + && wi::lts_p (low_bound, lh_lb)) + { + // For non-negative numbers, we're shifting out only zeroes, + // the value increases monotonically. For negative numbers, + // we're shifting out only ones, the value decreases + // monotonically. + in_bounds = true; + } + } + + if (in_bounds) + return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub); + + return value_range_base (type); +} + +bool +operator_lshift::wi_op_overflows (wide_int &res, + tree type, + const wide_int &w0, + const wide_int &w1) const +{ + signop sign = TYPE_SIGN (type); + if (wi::neg_p (w1)) + { + // It's unclear from the C standard whether shifts can overflow. + // The following code ignores overflow; perhaps a C standard + // interpretation ruling is needed. + res = wi::rshift (w0, -w1, sign); + } + else + res = wi::lshift (w0, w1); + return false; +} + + +class operator_rshift : public cross_product_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; + virtual bool wi_op_overflows (wide_int &res, + tree type, + const wide_int &w0, + const wide_int &w1) const; +} op_rshift; + +bool +operator_rshift::wi_op_overflows (wide_int &res, + tree type, + const wide_int &w0, + const wide_int &w1) const +{ + signop sign = TYPE_SIGN (type); + if (wi::neg_p (w1)) + res = wi::lshift (w0, -w1); + else + { + // It's unclear from the C standard whether shifts can overflow. + // The following code ignores overflow; perhaps a C standard + // interpretation ruling is needed. + res = wi::rshift (w0, w1, sign); + } + return false; +} + +value_range_base +operator_rshift::fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const +{ + value_range_base r; + if (undefined_shift_range_check (r, type, op2)) + return r; + + // Otherwise, invoke the generic fold routine. + return range_operator::fold_range (type, op1, op2); +} + +value_range_base +operator_rshift::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const +{ + return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub); +} + + +class operator_cast: public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + +} op_convert; + +value_range_base +operator_cast::fold_range (tree type ATTRIBUTE_UNUSED, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + tree inner = lh.type (); + tree outer = rh.type (); + gcc_checking_assert (rh.varying_p ()); + gcc_checking_assert (types_compatible_p (outer, type)); + signop inner_sign = TYPE_SIGN (inner); + signop outer_sign = TYPE_SIGN (outer); + unsigned inner_prec = TYPE_PRECISION (inner); + unsigned outer_prec = TYPE_PRECISION (outer); + + for (unsigned x = 0; x < lh.num_pairs (); ++x) + { + wide_int lh_lb = lh.lower_bound (x); + wide_int lh_ub = lh.upper_bound (x); + + // If the conversion is not truncating we can convert the min + // and max values and canonicalize the resulting range. + // Otherwise, we can do the conversion if the size of the range + // is less than what the precision of the target type can + // represent. + if (outer_prec >= inner_prec + || wi::rshift (wi::sub (lh_ub, lh_lb), + wi::uhwi (outer_prec, inner_prec), + inner_sign) == 0) + { + wide_int min = wide_int::from (lh_lb, outer_prec, inner_sign); + wide_int max = wide_int::from (lh_ub, outer_prec, inner_sign); + if (!wi::eq_p (min, wi::min_value (outer_prec, outer_sign)) + || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign))) + { + value_range_base tmp; + tmp = create_possibly_reversed_range (type, min, max); + r.union_ (tmp); + continue; + } + } + return value_range_base (type); + } + return r; +} + +bool +operator_cast::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + tree lhs_type = lhs.type (); + gcc_checking_assert (types_compatible_p (op2.type(), type)); + + // If the precision of the LHS is smaller than the precision of the + // RHS, then there would be truncation of the value on the RHS, and + // so we can tell nothing about it. + if (TYPE_PRECISION (lhs_type) < TYPE_PRECISION (type)) + { + // If we've been passed an actual value for the RHS rather than + // the type, see if it fits the LHS, and if so, then we can allow + // it. + r = op2; + r = fold_range (lhs_type, r, value_range_base (lhs_type)); + r = fold_range (type, r, value_range_base (type)); + if (r == op2) + { + // We know the value of the RHS fits in the LHS type, so + // convert the LHS and remove any values that arent in OP2. + r = lhs; + r = fold_range (type, r, value_range_base (type)); + r.intersect (op2); + return true; + } + // Special case if the LHS is a boolean. A 0 means the RHS is + // zero, and a 1 means the RHS is non-zero. + if (TREE_CODE (lhs_type) == BOOLEAN_TYPE) + { + // If the LHS is unknown, the result is whatever op2 already is. + if (!lhs.singleton_p ()) + { + r = op2; + return true; + } + // Boolean casts are weird in GCC. It's actually an implied + // mask with 0x01, so all that is known is whether the + // rightmost bit is 0 or 1, which implies the only value + // *not* in the RHS is 0 or -1. + unsigned prec = TYPE_PRECISION (type); + if (lhs.zero_p ()) + r = value_range_base (VR_ANTI_RANGE, type, + wi::minus_one (prec), wi::minus_one (prec)); + else + r = value_range_base (VR_ANTI_RANGE, type, + wi::zero (prec), wi::zero (prec)); + // And intersect it with what we know about op2. + r.intersect (op2); + } + else + // Otherwise we'll have to assume it's whatever we know about op2. + r = op2; + return true; + } + + // If the LHS precision is greater than the rhs precision, the LHS + // range is restricted to the range of the RHS by this + // assignment. + if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (type)) + { + // Cast the range of the RHS to the type of the LHS. + value_range_base op_type (type); + op_type = fold_range (lhs_type, op_type, value_range_base (lhs_type)); + + // Intersect this with the LHS range will produce the RHS range. + r = range_intersect (lhs, op_type); + } + else + r = lhs; + + // Cast the calculated range to the type of the RHS. + r = fold_range (type, r, value_range_base (type)); + return true; +} + + +class operator_logical_and : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_logical_and; + + +value_range_base +operator_logical_and::fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + // 0 && anything is 0. + if ((wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (lh.upper_bound (), 0)) + || (wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (rh.upper_bound (), 0))) + return range_false (type); + + // To reach this point, there must be a logical 1 on each side, and + // the only remaining question is whether there is a zero or not. + if (lh.contains_p (build_zero_cst (lh.type ())) + || rh.contains_p (build_zero_cst (rh.type ()))) + return range_true_and_false (type); + + return range_true (type); +} + +bool +operator_logical_and::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2 ATTRIBUTE_UNUSED) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + // A true result means both sides of the AND must be true. + r = range_true (type); + break; + default: + // Any other result means only one side has to be false, the + // other side can be anything. So we cannott be sure of any + // result here. + r = range_true_and_false (type); + break; + } + return true; +} + +bool +operator_logical_and::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + return operator_logical_and::op1_range (r, type, lhs, op1); +} + + +class operator_bitwise_and : public range_operator +{ +public: + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_bitwise_and; + +// Optimize BIT_AND_EXPR and BIT_IOR_EXPR in terms of a mask if +// possible. Basically, see if we can optimize: +// +// [LB, UB] op Z +// into: +// [LB op Z, UB op Z] +// +// If the optimization was successful, accumulate the range in R and +// return TRUE. + +static bool +wi_optimize_and_or (value_range_base &r, + enum tree_code code, + tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) +{ + // Calculate the singleton mask among the ranges, if any. + wide_int lower_bound, upper_bound, mask; + if (wi::eq_p (rh_lb, rh_ub)) + { + mask = rh_lb; + lower_bound = lh_lb; + upper_bound = lh_ub; + } + else if (wi::eq_p (lh_lb, lh_ub)) + { + mask = lh_lb; + lower_bound = rh_lb; + upper_bound = rh_ub; + } + else + return false; + + // If Z is a constant which (for op | its bitwise not) has n + // consecutive least significant bits cleared followed by m 1 + // consecutive bits set immediately above it and either + // m + n == precision, or (x >> (m + n)) == (y >> (m + n)). + // + // The least significant n bits of all the values in the range are + // cleared or set, the m bits above it are preserved and any bits + // above these are required to be the same for all values in the + // range. + wide_int w = mask; + int m = 0, n = 0; + if (code == BIT_IOR_EXPR) + w = ~w; + if (wi::eq_p (w, 0)) + n = w.get_precision (); + else + { + n = wi::ctz (w); + w = ~(w | wi::mask (n, false, w.get_precision ())); + if (wi::eq_p (w, 0)) + m = w.get_precision () - n; + else + m = wi::ctz (w) - n; + } + wide_int new_mask = wi::mask (m + n, true, w.get_precision ()); + if ((new_mask & lower_bound) != (new_mask & upper_bound)) + return false; + + wide_int res_lb, res_ub; + if (code == BIT_AND_EXPR) + { + res_lb = wi::bit_and (lower_bound, mask); + res_ub = wi::bit_and (upper_bound, mask); + } + else if (code == BIT_IOR_EXPR) + { + res_lb = wi::bit_or (lower_bound, mask); + res_ub = wi::bit_or (upper_bound, mask); + } + else + gcc_unreachable (); + r = create_range_with_overflow (type, res_lb, res_ub); + return true; +} + +// For range [LB, UB] compute two wide_int bit masks. +// +// In the MAYBE_NONZERO bit mask, if some bit is unset, it means that +// for all numbers in the range the bit is 0, otherwise it might be 0 +// or 1. +// +// In the MUSTBE_NONZERO bit mask, if some bit is set, it means that +// for all numbers in the range the bit is 1, otherwise it might be 0 +// or 1. + +static void +wi_set_zero_nonzero_bits (tree type, + const wide_int &lb, const wide_int &ub, + wide_int &maybe_nonzero, + wide_int &mustbe_nonzero) +{ + signop sign = TYPE_SIGN (type); + + if (wi::eq_p (lb, ub)) + maybe_nonzero = mustbe_nonzero = lb; + else if (wi::ge_p (lb, 0, sign) || wi::lt_p (ub, 0, sign)) + { + wide_int xor_mask = lb ^ ub; + maybe_nonzero = lb | ub; + mustbe_nonzero = lb & ub; + if (xor_mask != 0) + { + wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false, + maybe_nonzero.get_precision ()); + maybe_nonzero = maybe_nonzero | mask; + mustbe_nonzero = wi::bit_and_not (mustbe_nonzero, mask); + } + } + else + { + maybe_nonzero = wi::minus_one (lb.get_precision ()); + mustbe_nonzero = wi::zero (lb.get_precision ()); + } +} + +value_range_base +operator_bitwise_and::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + value_range_base r; + if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub)) + return r; + + wide_int maybe_nonzero_lh, mustbe_nonzero_lh; + wide_int maybe_nonzero_rh, mustbe_nonzero_rh; + wi_set_zero_nonzero_bits (type, lh_lb, lh_ub, + maybe_nonzero_lh, mustbe_nonzero_lh); + wi_set_zero_nonzero_bits (type, rh_lb, rh_ub, + maybe_nonzero_rh, mustbe_nonzero_rh); + + wide_int new_lb = mustbe_nonzero_lh & mustbe_nonzero_rh; + wide_int new_ub = maybe_nonzero_lh & maybe_nonzero_rh; + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + // If both input ranges contain only negative values, we can + // truncate the result range maximum to the minimum of the + // input range maxima. + if (wi::lt_p (lh_ub, 0, sign) && wi::lt_p (rh_ub, 0, sign)) + { + new_ub = wi::min (new_ub, lh_ub, sign); + new_ub = wi::min (new_ub, rh_ub, sign); + } + // If either input range contains only non-negative values + // we can truncate the result range maximum to the respective + // maximum of the input range. + if (wi::ge_p (lh_lb, 0, sign)) + new_ub = wi::min (new_ub, lh_ub, sign); + if (wi::ge_p (rh_lb, 0, sign)) + new_ub = wi::min (new_ub, rh_ub, sign); + // PR68217: In case of signed & sign-bit-CST should + // result in [-INF, 0] instead of [-INF, INF]. + if (wi::gt_p (new_lb, new_ub, sign)) + { + wide_int sign_bit = wi::set_bit_in_zero (prec - 1, prec); + if (sign == SIGNED + && ((wi::eq_p (lh_lb, lh_ub) + && !wi::cmps (lh_lb, sign_bit)) + || (wi::eq_p (rh_lb, rh_ub) + && !wi::cmps (rh_lb, sign_bit)))) + { + new_lb = wi::min_value (prec, sign); + new_ub = wi::zero (prec); + } + } + // If the limits got swapped around, return varying. + if (wi::gt_p (new_lb, new_ub,sign)) + return value_range_base (type); + + return create_range_with_overflow (type, new_lb, new_ub); +} + +bool +operator_bitwise_and::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + // If this is really a logical wi_fold, call that. + if (types_compatible_p (type, boolean_type_node)) + return op_logical_and.op1_range (r, type, lhs, op2); + + // For now do nothing with bitwise AND of value_range's. + r.set_varying (type); + return true; +} + +bool +operator_bitwise_and::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + return operator_bitwise_and::op1_range (r, type, lhs, op1); +} + + +class operator_logical_or : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; +} op_logical_or; + +value_range_base +operator_logical_or::fold_range (tree type ATTRIBUTE_UNUSED, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + return range_union (lh, rh); +} + +bool +operator_logical_or::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2 ATTRIBUTE_UNUSED) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_FALSE: + // A false result means both sides of the OR must be false. + r = range_false (type); + break; + default: + // Any other result means only one side has to be true, the + // other side can be anything. so we can't be sure of any result + // here. + r = range_true_and_false (type); + break; + } + return true; +} + +bool +operator_logical_or::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + return operator_logical_or::op1_range (r, type, lhs, op1); +} + + +class operator_bitwise_or : public range_operator +{ +public: + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_bitwise_or; + +value_range_base +operator_bitwise_or::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + value_range_base r; + if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub)) + return r; + + wide_int maybe_nonzero_lh, mustbe_nonzero_lh; + wide_int maybe_nonzero_rh, mustbe_nonzero_rh; + wi_set_zero_nonzero_bits (type, lh_lb, lh_ub, + maybe_nonzero_lh, mustbe_nonzero_lh); + wi_set_zero_nonzero_bits (type, rh_lb, rh_ub, + maybe_nonzero_rh, mustbe_nonzero_rh); + wide_int new_lb = mustbe_nonzero_lh | mustbe_nonzero_rh; + wide_int new_ub = maybe_nonzero_lh | maybe_nonzero_rh; + signop sign = TYPE_SIGN (type); + // If the input ranges contain only positive values we can + // truncate the minimum of the result range to the maximum + // of the input range minima. + if (wi::ge_p (lh_lb, 0, sign) + && wi::ge_p (rh_lb, 0, sign)) + { + new_lb = wi::max (new_lb, lh_lb, sign); + new_lb = wi::max (new_lb, rh_lb, sign); + } + // If either input range contains only negative values + // we can truncate the minimum of the result range to the + // respective minimum range. + if (wi::lt_p (lh_ub, 0, sign)) + new_lb = wi::max (new_lb, lh_lb, sign); + if (wi::lt_p (rh_ub, 0, sign)) + new_lb = wi::max (new_lb, rh_lb, sign); + // If the limits got swapped around, return varying. + if (wi::gt_p (new_lb, new_ub,sign)) + return value_range_base (type); + + return create_range_with_overflow (type, new_lb, new_ub); +} + +bool +operator_bitwise_or::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + // If this is really a logical wi_fold, call that. + if (types_compatible_p (type, boolean_type_node)) + return op_logical_or.op1_range (r, type, lhs, op2); + + // For now do nothing with bitwise OR of value_range's. + r.set_varying (type); + return true; +} + +bool +operator_bitwise_or::op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const +{ + return operator_bitwise_or::op1_range (r, type, lhs, op1); +} + + +class operator_bitwise_xor : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_bitwise_xor; + +value_range_base +operator_bitwise_xor::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + signop sign = TYPE_SIGN (type); + wide_int maybe_nonzero_lh, mustbe_nonzero_lh; + wide_int maybe_nonzero_rh, mustbe_nonzero_rh; + wi_set_zero_nonzero_bits (type, lh_lb, lh_ub, + maybe_nonzero_lh, mustbe_nonzero_lh); + wi_set_zero_nonzero_bits (type, rh_lb, rh_ub, + maybe_nonzero_rh, mustbe_nonzero_rh); + + wide_int result_zero_bits = ((mustbe_nonzero_lh & mustbe_nonzero_rh) + | ~(maybe_nonzero_lh | maybe_nonzero_rh)); + wide_int result_one_bits + = (wi::bit_and_not (mustbe_nonzero_lh, maybe_nonzero_rh) + | wi::bit_and_not (mustbe_nonzero_rh, maybe_nonzero_lh)); + wide_int new_ub = ~result_zero_bits; + wide_int new_lb = result_one_bits; + + // If the range has all positive or all negative values, the result + // is better than VARYING. + if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign)) + return create_range_with_overflow (type, new_lb, new_ub); + + return value_range_base (type); +} + + +class operator_trunc_mod : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +} op_trunc_mod; + +value_range_base +operator_trunc_mod::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + wide_int new_lb, new_ub, tmp; + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + + // Mod 0 is undefined. Return undefined. + if (wi_zero_p (type, rh_lb, rh_ub)) + return value_range_base (); + + // ABS (A % B) < ABS (B) and either 0 <= A % B <= A or A <= A % B <= 0. + new_ub = rh_ub - 1; + if (sign == SIGNED) + { + tmp = -1 - rh_lb; + new_ub = wi::smax (new_ub, tmp); + } + + if (sign == UNSIGNED) + new_lb = wi::zero (prec); + else + { + new_lb = -new_ub; + tmp = lh_lb; + if (wi::gts_p (tmp, 0)) + tmp = wi::zero (prec); + new_lb = wi::smax (new_lb, tmp); + } + tmp = lh_ub; + if (sign == SIGNED && wi::neg_p (tmp)) + tmp = wi::zero (prec); + new_ub = wi::min (new_ub, tmp, sign); + + return create_range_with_overflow (type, new_lb, new_ub); +} + + +class operator_logical_not : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; +} op_logical_not; + +// Folding a logical NOT, oddly enough, involves doing nothing on the +// forward pass through. During the initial walk backwards, the +// logical NOT reversed the desired outcome on the way back, so on the +// way forward all we do is pass the range forward. +// +// b_2 = x_1 < 20 +// b_3 = !b_2 +// if (b_3) +// to determine the TRUE branch, walking backward +// if (b_3) if ([1,1]) +// b_3 = !b_2 [1,1] = ![0,0] +// b_2 = x_1 < 20 [0,0] = x_1 < 20, false, so x_1 == [20, 255] +// which is the result we are looking for.. so.. pass it through. + +value_range_base +operator_logical_not::fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh ATTRIBUTE_UNUSED) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + if (lh.varying_p () || lh.undefined_p ()) + r = lh; + else + r = range_invert (lh); + gcc_checking_assert (lh.type() == type); + return r; +} + +bool +operator_logical_not::op1_range (value_range_base &r, + tree type ATTRIBUTE_UNUSED, + const value_range_base &lhs, + const value_range_base &op2 ATTRIBUTE_UNUSED) const +{ + if (lhs.varying_p () || lhs.undefined_p ()) + r = lhs; + else + r = range_invert (lhs); + return true; +} + + +class operator_bitwise_not : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; +} op_bitwise_not; + +value_range_base +operator_bitwise_not::fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + // ~X is simply -1 - X. + value_range_base minusone (type, + wi::minus_one (TYPE_PRECISION (type)), + wi::minus_one (TYPE_PRECISION (type))); + r = range_op_handler (MINUS_EXPR, type)->fold_range (type, minusone, lh); + return r; +} + +bool +operator_bitwise_not::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + // ~X is -1 - X and since bitwise NOT is involutary...do it again. + r = fold_range (type, lhs, op2); + return true; +} + + +class operator_cst : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; +} op_integer_cst; + +value_range_base +operator_cst::fold_range (tree type ATTRIBUTE_UNUSED, + const value_range_base &lh, + const value_range_base &rh ATTRIBUTE_UNUSED) const +{ + return lh; +} + + +class operator_identity : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; +} op_identity; + +value_range_base +operator_identity::fold_range (tree type ATTRIBUTE_UNUSED, + const value_range_base &lh, + const value_range_base &rh ATTRIBUTE_UNUSED) const +{ + return lh; +} + +bool +operator_identity::op1_range (value_range_base &r, tree type ATTRIBUTE_UNUSED, + const value_range_base &lhs, + const value_range_base &op2 ATTRIBUTE_UNUSED) const +{ + r = lhs; + return true; +} + + +class operator_abs : public range_operator +{ + public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; +} op_abs; + +value_range_base +operator_abs::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb ATTRIBUTE_UNUSED, + const wide_int &rh_ub ATTRIBUTE_UNUSED) const +{ + wide_int min, max; + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + + // Pass through LH for the easy cases. + if (sign == UNSIGNED || wi::ge_p (lh_lb, 0, sign)) + return value_range_base (type, lh_lb, lh_ub); + + // -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get + // a useful range. + wide_int min_value = wi::min_value (prec, sign); + wide_int max_value = wi::max_value (prec, sign); + if (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lh_lb, min_value)) + return value_range_base (type); + + // ABS_EXPR may flip the range around, if the original range + // included negative values. + if (wi::eq_p (lh_lb, min_value)) + min = max_value; + else + min = wi::abs (lh_lb); + if (wi::eq_p (lh_ub, min_value)) + max = max_value; + else + max = wi::abs (lh_ub); + + // If the range contains zero then we know that the minimum value in the + // range will be zero. + if (wi::le_p (lh_lb, 0, sign) && wi::ge_p (lh_ub, 0, sign)) + { + if (wi::gt_p (min, max, sign)) + max = min; + min = wi::zero (prec); + } + else + { + // If the range was reversed, swap MIN and MAX. + if (wi::gt_p (min, max, sign)) + std::swap (min, max); + } + + // If the new range has its limits swapped around (MIN > MAX), then + // the operation caused one of them to wrap around. The only thing + // we know is that the result is positive. + if (wi::gt_p (min, max, sign)) + { + min = wi::zero (prec); + max = max_value; + } + return value_range_base (type, min, max); +} + +bool +operator_abs::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + if (empty_range_check (r, lhs, op2)) + return true; + if (TYPE_UNSIGNED (type)) + { + r = lhs; + return true; + } + // Start with the positives because negatives are an impossible result. + value_range_base positives = range_positives (type); + positives.intersect (lhs); + r = positives; + // Then add the negative of each pair: + // ABS(op1) = [5,20] would yield op1 => [-20,-5][5,20]. + for (unsigned i = 0; i < positives.num_pairs (); ++i) + r.union_ (value_range_base (type, + -positives.upper_bound (i), + -positives.lower_bound (i))); + return true; +} + + +class operator_absu : public range_operator +{ + public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; +} op_absu; + +value_range_base +operator_absu::wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb ATTRIBUTE_UNUSED, + const wide_int &rh_ub ATTRIBUTE_UNUSED) const +{ + wide_int new_lb, new_ub; + + // Pass through VR0 the easy cases. + if (wi::ges_p (lh_lb, 0)) + { + new_lb = lh_lb; + new_ub = lh_ub; + } + else + { + new_lb = wi::abs (lh_lb); + new_ub = wi::abs (lh_ub); + + // If the range contains zero then we know that the minimum + // value in the range will be zero. + if (wi::ges_p (lh_ub, 0)) + { + if (wi::gtu_p (new_lb, new_ub)) + new_ub = new_lb; + new_lb = wi::zero (TYPE_PRECISION (type)); + } + else + std::swap (new_lb, new_ub); + } + + gcc_checking_assert (TYPE_UNSIGNED (type)); + return value_range_base (type, new_lb, new_ub); +} + + +class operator_negate : public range_operator +{ + public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; +} op_negate; + +value_range_base +operator_negate::fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + // -X is simply 0 - X. + return + range_op_handler (MINUS_EXPR, type)->fold_range (type, + range_zero (type), lh); +} + +bool +operator_negate::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + // NEGATE is involutory. + r = fold_range (type, lhs, op2); + return true; +} + + +class operator_addr_expr : public range_operator +{ +public: + virtual value_range_base fold_range (tree type, + const value_range_base &op1, + const value_range_base &op2) const; + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; +} op_addr; + +value_range_base +operator_addr_expr::fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const +{ + value_range_base r; + if (empty_range_check (r, lh, rh)) + return r; + + // Return a non-null pointer of the LHS type (passed in op2). + if (lh.zero_p ()) + return range_zero (type); + if (!lh.contains_p (build_zero_cst (lh.type ()))) + return range_nonzero (type); + return value_range_base (type); +} + +bool +operator_addr_expr::op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const +{ + r = operator_addr_expr::fold_range (type, lhs, op2); + return true; +} + + +class pointer_plus_operator : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; +} op_pointer_plus; + +value_range_base +pointer_plus_operator::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + // For pointer types, we are really only interested in asserting + // whether the expression evaluates to non-NULL. + // + // With -fno-delete-null-pointer-checks we need to be more + // conservative. As some object might reside at address 0, + // then some offset could be added to it and the same offset + // subtracted again and the result would be NULL. + // E.g. + // static int a[12]; where &a[0] is NULL and + // ptr = &a[6]; + // ptr -= 6; + // ptr will be NULL here, even when there is POINTER_PLUS_EXPR + // where the first range doesn't include zero and the second one + // doesn't either. As the second operand is sizetype (unsigned), + // consider all ranges where the MSB could be set as possible + // subtractions where the result might be NULL. + if ((!wi_includes_zero_p (type, lh_lb, lh_ub) + || !wi_includes_zero_p (type, rh_lb, rh_ub)) + && !TYPE_OVERFLOW_WRAPS (type) + && (flag_delete_null_pointer_checks + || !wi::sign_mask (rh_ub))) + return range_nonzero (type); + if (lh_lb == lh_ub && lh_lb == 0 + && rh_lb == rh_ub && rh_lb == 0) + return range_zero (type); + return value_range_base (type); +} + + +class pointer_min_max_operator : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; +} op_ptr_min_max; + +value_range_base +pointer_min_max_operator::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + // For MIN/MAX expressions with pointers, we only care about + // nullness. If both are non null, then the result is nonnull. + // If both are null, then the result is null. Otherwise they + // are varying. + if (!wi_includes_zero_p (type, lh_lb, lh_ub) + && !wi_includes_zero_p (type, rh_lb, rh_ub)) + return range_nonzero (type); + if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) + return range_zero (type); + return value_range_base (type); +} + + +class pointer_and_operator : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; +} op_pointer_and; + +value_range_base +pointer_and_operator::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb ATTRIBUTE_UNUSED, + const wide_int &rh_ub ATTRIBUTE_UNUSED) const +{ + // For pointer types, we are really only interested in asserting + // whether the expression evaluates to non-NULL. + if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub)) + return range_zero (type); + + return value_range_base (type); +} + + +class pointer_or_operator : public range_operator +{ +public: + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, const wide_int &lh_ub, + const wide_int &rh_lb, const wide_int &rh_ub) const; +} op_pointer_or; + +value_range_base +pointer_or_operator::wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const +{ + // For pointer types, we are really only interested in asserting + // whether the expression evaluates to non-NULL. + if (!wi_includes_zero_p (type, lh_lb, lh_ub) + && !wi_includes_zero_p (type, rh_lb, rh_ub)) + return range_nonzero (type); + if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) + return range_zero (type); + return value_range_base (type); +} + +// This implements the range operator tables as local objects in this file. + +class range_op_table +{ +public: + inline range_operator *operator[] (enum tree_code code); +protected: + void set (enum tree_code code, range_operator &op); +private: + range_operator *m_range_tree[MAX_TREE_CODES]; +}; + +// Return a pointer to the range_operator instance, if there is one +// associated with tree_code CODE. + +range_operator * +range_op_table::operator[] (enum tree_code code) +{ + gcc_checking_assert (code > 0 && code < MAX_TREE_CODES); + return m_range_tree[code]; +} + +// Add OP to the handler table for CODE. + +void +range_op_table::set (enum tree_code code, range_operator &op) +{ + gcc_checking_assert (m_range_tree[code] == NULL); + m_range_tree[code] = &op; +} + +// Instantiate a range op table for integral operations. + +class integral_table : public range_op_table +{ +public: + integral_table (); +} integral_tree_table; + +integral_table::integral_table () +{ + set (EQ_EXPR, op_equal); + set (NE_EXPR, op_not_equal); + set (LT_EXPR, op_lt); + set (LE_EXPR, op_le); + set (GT_EXPR, op_gt); + set (GE_EXPR, op_ge); + set (PLUS_EXPR, op_plus); + set (MINUS_EXPR, op_minus); + set (MIN_EXPR, op_min); + set (MAX_EXPR, op_max); + set (MULT_EXPR, op_mult); + set (TRUNC_DIV_EXPR, op_trunc_div); + set (FLOOR_DIV_EXPR, op_floor_div); + set (ROUND_DIV_EXPR, op_round_div); + set (CEIL_DIV_EXPR, op_ceil_div); + set (EXACT_DIV_EXPR, op_exact_div); + set (LSHIFT_EXPR, op_lshift); + set (RSHIFT_EXPR, op_rshift); + set (NOP_EXPR, op_convert); + set (CONVERT_EXPR, op_convert); + set (TRUTH_AND_EXPR, op_logical_and); + set (BIT_AND_EXPR, op_bitwise_and); + set (TRUTH_OR_EXPR, op_logical_or); + set (BIT_IOR_EXPR, op_bitwise_or); + set (BIT_XOR_EXPR, op_bitwise_xor); + set (TRUNC_MOD_EXPR, op_trunc_mod); + set (TRUTH_NOT_EXPR, op_logical_not); + set (BIT_NOT_EXPR, op_bitwise_not); + set (INTEGER_CST, op_integer_cst); + set (SSA_NAME, op_identity); + set (PAREN_EXPR, op_identity); + set (OBJ_TYPE_REF, op_identity); + set (ABS_EXPR, op_abs); + set (ABSU_EXPR, op_absu); + set (NEGATE_EXPR, op_negate); + set (ADDR_EXPR, op_addr); +} + +// Instantiate a range op table for pointer operations. + +class pointer_table : public range_op_table +{ +public: + pointer_table (); +} pointer_tree_table; + +pointer_table::pointer_table () +{ + set (BIT_AND_EXPR, op_pointer_and); + set (BIT_IOR_EXPR, op_pointer_or); + set (MIN_EXPR, op_ptr_min_max); + set (MAX_EXPR, op_ptr_min_max); + set (POINTER_PLUS_EXPR, op_pointer_plus); + + set (EQ_EXPR, op_equal); + set (NE_EXPR, op_not_equal); + set (LT_EXPR, op_lt); + set (LE_EXPR, op_le); + set (GT_EXPR, op_gt); + set (GE_EXPR, op_ge); + set (SSA_NAME, op_identity); + set (ADDR_EXPR, op_addr); + set (NOP_EXPR, op_convert); + set (CONVERT_EXPR, op_convert); + + set (BIT_NOT_EXPR, op_bitwise_not); + set (BIT_XOR_EXPR, op_bitwise_xor); +} + +// The tables are hidden and accessed via a simple extern function. + +range_operator * +range_op_handler (enum tree_code code, tree type) +{ + // First check if there is apointer specialization. + if (POINTER_TYPE_P (type)) + return pointer_tree_table[code]; + return integral_tree_table[code]; +} + +// Cast the range in R to TYPE. + +void +range_cast (value_range_base &r, tree type) +{ + range_operator *op = range_op_handler (CONVERT_EXPR, type); + r = op->fold_range (type, r, value_range_base (type)); +} + +#if CHECKING_P +#include "selftest.h" +#include "stor-layout.h" + +// Ideally this should go in namespace selftest, but range_tests +// needs to be a friend of class value_range_base so it can access +// value_range_base::m_max_pairs. + +#define INT(N) build_int_cst (integer_type_node, (N)) +#define UINT(N) build_int_cstu (unsigned_type_node, (N)) +#define INT16(N) build_int_cst (short_integer_type_node, (N)) +#define UINT16(N) build_int_cstu (short_unsigned_type_node, (N)) +#define INT64(N) build_int_cstu (long_long_integer_type_node, (N)) +#define UINT64(N) build_int_cstu (long_long_unsigned_type_node, (N)) +#define UINT128(N) build_int_cstu (u128_type, (N)) +#define UCHAR(N) build_int_cstu (unsigned_char_type_node, (N)) +#define SCHAR(N) build_int_cst (signed_char_type_node, (N)) + +#define RANGE3(A,B,C,D,E,F) \ +( i1 = value_range_base (INT (A), INT (B)), \ + i2 = value_range_base (INT (C), INT (D)), \ + i3 = value_range_base (INT (E), INT (F)), \ + i1.union_ (i2), \ + i1.union_ (i3), \ + i1 ) + +// Run all of the selftests within this file. + +void +range_tests () +{ + tree u128_type = build_nonstandard_integer_type (128, /*unsigned=*/1); + value_range_base i1, i2, i3; + value_range_base r0, r1, rold; + + // Test that NOT(255) is [0..254] in 8-bit land. + value_range_base not_255 (VR_ANTI_RANGE, UCHAR (255), UCHAR (255)); + ASSERT_TRUE (not_255 == value_range_base (UCHAR (0), UCHAR (254))); + + // Test that NOT(0) is [1..255] in 8-bit land. + value_range_base not_zero = range_nonzero (unsigned_char_type_node); + ASSERT_TRUE (not_zero == value_range_base (UCHAR (1), UCHAR (255))); + + // Check that [0,127][0x..ffffff80,0x..ffffff] + // => ~[128, 0x..ffffff7f]. + r0 = value_range_base (UINT128 (0), UINT128 (127)); + tree high = build_minus_one_cst (u128_type); + // low = -1 - 127 => 0x..ffffff80. + tree low = fold_build2 (MINUS_EXPR, u128_type, high, UINT128(127)); + r1 = value_range_base (low, high); // [0x..ffffff80, 0x..ffffffff] + // r0 = [0,127][0x..ffffff80,0x..fffffff]. + r0.union_ (r1); + // r1 = [128, 0x..ffffff7f]. + r1 = value_range_base (UINT128(128), + fold_build2 (MINUS_EXPR, u128_type, + build_minus_one_cst (u128_type), + UINT128(128))); + r0.invert (); + ASSERT_TRUE (r0 == r1); + + r0.set_varying (integer_type_node); + tree minint = wide_int_to_tree (integer_type_node, r0.lower_bound ()); + tree maxint = wide_int_to_tree (integer_type_node, r0.upper_bound ()); + + r0.set_varying (short_integer_type_node); + tree minshort = wide_int_to_tree (short_integer_type_node, r0.lower_bound ()); + tree maxshort = wide_int_to_tree (short_integer_type_node, r0.upper_bound ()); + + r0.set_varying (unsigned_type_node); + tree maxuint = wide_int_to_tree (unsigned_type_node, r0.upper_bound ()); + + // Check that ~[0,5] => [6,MAX] for unsigned int. + r0 = value_range_base (UINT (0), UINT (5)); + r0.invert (); + ASSERT_TRUE (r0 == value_range_base (UINT(6), maxuint)); + + // Check that ~[10,MAX] => [0,9] for unsigned int. + r0 = value_range_base (VR_RANGE, UINT(10), maxuint); + r0.invert (); + ASSERT_TRUE (r0 == value_range_base (UINT (0), UINT (9))); + + // Check that ~[0,5] => [6,MAX] for unsigned 128-bit numbers. + r0 = value_range_base (VR_ANTI_RANGE, UINT128 (0), UINT128 (5)); + r1 = value_range_base (UINT128(6), build_minus_one_cst (u128_type)); + ASSERT_TRUE (r0 == r1); + + // Check that [~5] is really [-MIN,4][6,MAX]. + r0 = value_range_base (VR_ANTI_RANGE, INT (5), INT (5)); + r1 = value_range_base (minint, INT (4)); + r1.union_ (value_range_base (INT (6), maxint)); + ASSERT_FALSE (r1.undefined_p ()); + ASSERT_TRUE (r0 == r1); + + r1 = value_range_base (INT (5), INT (5)); + r1.check (); + value_range_base r2 (r1); + ASSERT_TRUE (r1 == r2); + + r1 = value_range_base (INT (5), INT (10)); + r1.check (); + + r1 = value_range_base (integer_type_node, + wi::to_wide (INT (5)), wi::to_wide (INT (10))); + r1.check (); + ASSERT_TRUE (r1.contains_p (INT (7))); + + r1 = value_range_base (SCHAR (0), SCHAR (20)); + ASSERT_TRUE (r1.contains_p (SCHAR(15))); + ASSERT_FALSE (r1.contains_p (SCHAR(300))); + + // If a range is in any way outside of the range for the converted + // to range, default to the range for the new type. + r1 = value_range_base (integer_zero_node, maxint); + range_cast (r1, short_integer_type_node); + ASSERT_TRUE (r1.lower_bound () == wi::to_wide (minshort) + && r1.upper_bound() == wi::to_wide (maxshort)); + + // (unsigned char)[-5,-1] => [251,255]. + r0 = rold = value_range_base (SCHAR (-5), SCHAR (-1)); + range_cast (r0, unsigned_char_type_node); + ASSERT_TRUE (r0 == value_range_base (UCHAR (251), UCHAR (255))); + range_cast (r0, signed_char_type_node); + ASSERT_TRUE (r0 == rold); + + // (signed char)[15, 150] => [-128,-106][15,127]. + r0 = rold = value_range_base (UCHAR (15), UCHAR (150)); + range_cast (r0, signed_char_type_node); + r1 = value_range_base (SCHAR (15), SCHAR (127)); + r2 = value_range_base (SCHAR (-128), SCHAR (-106)); + r1.union_ (r2); + ASSERT_TRUE (r1 == r0); + range_cast (r0, unsigned_char_type_node); + ASSERT_TRUE (r0 == rold); + + // (unsigned char)[-5, 5] => [0,5][251,255]. + r0 = rold = value_range_base (SCHAR (-5), SCHAR (5)); + range_cast (r0, unsigned_char_type_node); + r1 = value_range_base (UCHAR (251), UCHAR (255)); + r2 = value_range_base (UCHAR (0), UCHAR (5)); + r1.union_ (r2); + ASSERT_TRUE (r0 == r1); + range_cast (r0, signed_char_type_node); + ASSERT_TRUE (r0 == rold); + + // (unsigned char)[-5,5] => [0,5][251,255]. + r0 = value_range_base (INT (-5), INT (5)); + range_cast (r0, unsigned_char_type_node); + r1 = value_range_base (UCHAR (0), UCHAR (5)); + r1.union_ (value_range_base (UCHAR (251), UCHAR (255))); + ASSERT_TRUE (r0 == r1); + + // (unsigned char)[5U,1974U] => [0,255]. + r0 = value_range_base (UINT (5), UINT (1974)); + range_cast (r0, unsigned_char_type_node); + ASSERT_TRUE (r0 == value_range_base (UCHAR (0), UCHAR (255))); + range_cast (r0, integer_type_node); + // Going to a wider range should not sign extend. + ASSERT_TRUE (r0 == value_range_base (INT (0), INT (255))); + + // (unsigned char)[-350,15] => [0,255]. + r0 = value_range_base (INT (-350), INT (15)); + range_cast (r0, unsigned_char_type_node); + ASSERT_TRUE (r0 == (value_range_base + (TYPE_MIN_VALUE (unsigned_char_type_node), + TYPE_MAX_VALUE (unsigned_char_type_node)))); + + // Casting [-120,20] from signed char to unsigned short. + // => [0, 20][0xff88, 0xffff]. + r0 = value_range_base (SCHAR (-120), SCHAR (20)); + range_cast (r0, short_unsigned_type_node); + r1 = value_range_base (UINT16 (0), UINT16 (20)); + r2 = value_range_base (UINT16 (0xff88), UINT16 (0xffff)); + r1.union_ (r2); + ASSERT_TRUE (r0 == r1); + // A truncating cast back to signed char will work because [-120, 20] + // is representable in signed char. + range_cast (r0, signed_char_type_node); + ASSERT_TRUE (r0 == value_range_base (SCHAR (-120), SCHAR (20))); + + // unsigned char -> signed short + // (signed short)[(unsigned char)25, (unsigned char)250] + // => [(signed short)25, (signed short)250] + r0 = rold = value_range_base (UCHAR (25), UCHAR (250)); + range_cast (r0, short_integer_type_node); + r1 = value_range_base (INT16 (25), INT16 (250)); + ASSERT_TRUE (r0 == r1); + range_cast (r0, unsigned_char_type_node); + ASSERT_TRUE (r0 == rold); + + // Test casting a wider signed [-MIN,MAX] to a nar`rower unsigned. + r0 = value_range_base (TYPE_MIN_VALUE (long_long_integer_type_node), + TYPE_MAX_VALUE (long_long_integer_type_node)); + range_cast (r0, short_unsigned_type_node); + r1 = value_range_base (TYPE_MIN_VALUE (short_unsigned_type_node), + TYPE_MAX_VALUE (short_unsigned_type_node)); + ASSERT_TRUE (r0 == r1); + + // NOT([10,20]) ==> [-MIN,9][21,MAX]. + r0 = r1 = value_range_base (INT (10), INT (20)); + r2 = value_range_base (minint, INT(9)); + r2.union_ (value_range_base (INT(21), maxint)); + ASSERT_FALSE (r2.undefined_p ()); + r1.invert (); + ASSERT_TRUE (r1 == r2); + // Test that NOT(NOT(x)) == x. + r2.invert (); + ASSERT_TRUE (r0 == r2); + + // Test that booleans and their inverse work as expected. + r0 = range_zero (boolean_type_node); + ASSERT_TRUE (r0 == value_range_base (build_zero_cst (boolean_type_node), + build_zero_cst (boolean_type_node))); + r0.invert (); + ASSERT_TRUE (r0 == value_range_base (build_one_cst (boolean_type_node), + build_one_cst (boolean_type_node))); + + // Casting NONZERO to a narrower type will wrap/overflow so + // it's just the entire range for the narrower type. + // + // "NOT 0 at signed 32-bits" ==> [-MIN_32,-1][1, +MAX_32]. This is + // is outside of the range of a smaller range, return the full + // smaller range. + r0 = range_nonzero (integer_type_node); + range_cast (r0, short_integer_type_node); + r1 = value_range_base (TYPE_MIN_VALUE (short_integer_type_node), + TYPE_MAX_VALUE (short_integer_type_node)); + ASSERT_TRUE (r0 == r1); + + // Casting NONZERO from a narrower signed to a wider signed. + // + // NONZERO signed 16-bits is [-MIN_16,-1][1, +MAX_16]. + // Converting this to 32-bits signed is [-MIN_16,-1][1, +MAX_16]. + r0 = range_nonzero (short_integer_type_node); + range_cast (r0, integer_type_node); + r1 = value_range_base (INT (-32768), INT (-1)); + r2 = value_range_base (INT (1), INT (32767)); + r1.union_ (r2); + ASSERT_TRUE (r0 == r1); + + if (value_range_base::m_max_pairs > 2) + { + // ([10,20] U [5,8]) U [1,3] ==> [1,3][5,8][10,20]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (5), INT (8)); + r0.union_ (r1); + r1 = value_range_base (INT (1), INT (3)); + r0.union_ (r1); + ASSERT_TRUE (r0 == RANGE3 (1, 3, 5, 8, 10, 20)); + + // [1,3][5,8][10,20] U [-5,0] => [-5,3][5,8][10,20]. + r1 = value_range_base (INT (-5), INT (0)); + r0.union_ (r1); + ASSERT_TRUE (r0 == RANGE3 (-5, 3, 5, 8, 10, 20)); + } + + // [10,20] U [30,40] ==> [10,20][30,40]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (30), INT (40)); + r0.union_ (r1); + ASSERT_TRUE (r0 == range_union (value_range_base (INT (10), INT (20)), + value_range_base (INT (30), INT (40)))); + if (value_range_base::m_max_pairs > 2) + { + // [10,20][30,40] U [50,60] ==> [10,20][30,40][50,60]. + r1 = value_range_base (INT (50), INT (60)); + r0.union_ (r1); + ASSERT_TRUE (r0 == RANGE3 (10, 20, 30, 40, 50, 60)); + // [10,20][30,40][50,60] U [70, 80] ==> [10,20][30,40][50,60][70,80]. + r1 = value_range_base (INT (70), INT (80)); + r0.union_ (r1); + + r2 = RANGE3 (10, 20, 30, 40, 50, 60); + r2.union_ (value_range_base (INT (70), INT (80))); + ASSERT_TRUE (r0 == r2); + } + + // Make sure NULL and non-NULL of pointer types work, and that + // inverses of them are consistent. + tree voidp = build_pointer_type (void_type_node); + r0 = range_zero (voidp); + r1 = r0; + r0.invert (); + r0.invert (); + ASSERT_TRUE (r0 == r1); + + if (value_range_base::m_max_pairs > 2) + { + // [10,20][30,40][50,60] U [6,35] => [6,40][50,60]. + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = value_range_base (INT (6), INT (35)); + r0.union_ (r1); + ASSERT_TRUE (r0 == range_union (value_range_base (INT (6), INT (40)), + value_range_base (INT (50), INT (60)))); + + // [10,20][30,40][50,60] U [6,60] => [6,60]. + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = value_range_base (INT (6), INT (60)); + r0.union_ (r1); + ASSERT_TRUE (r0 == value_range_base (INT (6), INT (60))); + + // [10,20][30,40][50,60] U [6,70] => [6,70]. + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = value_range_base (INT (6), INT (70)); + r0.union_ (r1); + ASSERT_TRUE (r0 == value_range_base (INT (6), INT (70))); + + // [10,20][30,40][50,60] U [35,70] => [10,20][30,70]. + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = value_range_base (INT (35), INT (70)); + r0.union_ (r1); + ASSERT_TRUE (r0 == range_union (value_range_base (INT (10), INT (20)), + value_range_base (INT (30), INT (70)))); + } + + // [10,20][30,40] U [25,70] => [10,70]. + r0 = range_union (value_range_base (INT (10), INT (20)), + value_range_base (INT (30), INT (40))); + r1 = value_range_base (INT (25), INT (70)); + r0.union_ (r1); + ASSERT_TRUE (r0 == range_union (value_range_base (INT (10), INT (20)), + value_range_base (INT (25), INT (70)))); + + if (value_range_base::m_max_pairs > 2) + { + // [10,20][30,40][50,60] U [15,35] => [10,40][50,60]. + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = value_range_base (INT (15), INT (35)); + r0.union_ (r1); + ASSERT_TRUE (r0 == range_union (value_range_base (INT (10), INT (40)), + value_range_base (INT (50), INT (60)))); + } + + // [10,20] U [15, 30] => [10, 30]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (15), INT (30)); + r0.union_ (r1); + ASSERT_TRUE (r0 == value_range_base (INT (10), INT (30))); + + // [10,20] U [25,25] => [10,20][25,25]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (25), INT (25)); + r0.union_ (r1); + ASSERT_TRUE (r0 == range_union (value_range_base (INT (10), INT (20)), + value_range_base (INT (25), INT (25)))); + + if (value_range_base::m_max_pairs > 2) + { + // [10,20][30,40][50,60] U [35,35] => [10,20][30,40][50,60]. + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = value_range_base (INT (35), INT (35)); + r0.union_ (r1); + ASSERT_TRUE (r0 == RANGE3 (10, 20, 30, 40, 50, 60)); + } + + // [15,40] U [] => [15,40]. + r0 = value_range_base (INT (15), INT (40)); + r1.set_undefined (); + r0.union_ (r1); + ASSERT_TRUE (r0 == value_range_base (INT (15), INT (40))); + + // [10,20] U [10,10] => [10,20]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (10), INT (10)); + r0.union_ (r1); + ASSERT_TRUE (r0 == value_range_base (INT (10), INT (20))); + + // [10,20] U [9,9] => [9,20]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (9), INT (9)); + r0.union_ (r1); + ASSERT_TRUE (r0 == value_range_base (INT (9), INT (20))); + + if (value_range_base::m_max_pairs > 2) + { + // [10,10][12,12][20,100] ^ [15,200]. + r0 = RANGE3 (10, 10, 12, 12, 20, 100); + r1 = value_range_base (INT (15), INT (200)); + r0.intersect (r1); + ASSERT_TRUE (r0 == value_range_base (INT (20), INT (100))); + + // [10,20][30,40][50,60] ^ [15,25][38,51][55,70] + // => [15,20][38,40][50,51][55,60] + r0 = RANGE3 (10, 20, 30, 40, 50, 60); + r1 = RANGE3 (15, 25, 38, 51, 55, 70); + r0.intersect (r1); + if (value_range_base::m_max_pairs == 3) + { + // When pairs==3, we don't have enough space, so + // conservatively handle things. Thus, the ...[50,60]. + ASSERT_TRUE (r0 == RANGE3 (15, 20, 38, 40, 50, 60)); + } + else + { + r2 = RANGE3 (15, 20, 38, 40, 50, 51); + r2.union_ (value_range_base (INT (55), INT (60))); + ASSERT_TRUE (r0 == r2); + } + + // [15,20][30,40][50,60] ^ [15,35][40,90][100,200] + // => [15,20][30,35][40,60] + r0 = RANGE3 (15, 20, 30, 40, 50, 60); + r1 = RANGE3 (15, 35, 40, 90, 100, 200); + r0.intersect (r1); + if (value_range_base::m_max_pairs == 3) + { + // When pairs==3, we don't have enough space, so + // conservatively handle things. + ASSERT_TRUE (r0 == RANGE3 (15, 20, 30, 35, 40, 60)); + } + else + { + r2 = RANGE3 (15, 20, 30, 35, 40, 40); + r2.union_ (value_range_base (INT (50), INT (60))); + ASSERT_TRUE (r0 == r2); + } + + // Test cases where a union inserts a sub-range inside a larger + // range. + // + // [8,10][135,255] U [14,14] => [8,10][14,14][135,255] + r0 = range_union (value_range_base (INT (8), INT (10)), + value_range_base (INT (135), INT (255))); + r1 = value_range_base (INT (14), INT (14)); + r0.union_ (r1); + ASSERT_TRUE (r0 == RANGE3 (8, 10, 14, 14, 135, 255)); + } + + // [10,20] ^ [15,30] => [15,20]. + r0 = value_range_base (INT (10), INT (20)); + r1 = value_range_base (INT (15), INT (30)); + r0.intersect (r1); + ASSERT_TRUE (r0 == value_range_base (INT (15), INT (20))); + + // [10,20][30,40] ^ [40,50] => [40,40]. + r0 = range_union (value_range_base (INT (10), INT (20)), + value_range_base (INT (30), INT (40))); + r1 = value_range_base (INT (40), INT (50)); + r0.intersect (r1); + ASSERT_TRUE (r0 == value_range_base (INT (40), INT (40))); + + // Test non-destructive intersection. + r0 = rold = value_range_base (INT (10), INT (20)); + ASSERT_FALSE (range_intersect (r0, value_range_base (INT (15), + INT (30))).undefined_p ()); + ASSERT_TRUE (r0 == rold); + + // Test the internal sanity of wide_int's wrt HWIs. + ASSERT_TRUE (wi::max_value (TYPE_PRECISION (boolean_type_node), + TYPE_SIGN (boolean_type_node)) + == wi::uhwi (1, TYPE_PRECISION (boolean_type_node))); + + // Test zero_p(). + r0 = value_range_base (INT (0), INT (0)); + ASSERT_TRUE (r0.zero_p ()); + + // Test nonzero_p(). + r0 = value_range_base (INT (0), INT (0)); + r0.invert (); + ASSERT_TRUE (r0.nonzero_p ()); +} +#endif // CHECKING_P diff --git a/gcc/range-op.h b/gcc/range-op.h new file mode 100644 index 0000000..f651075 --- /dev/null +++ b/gcc/range-op.h @@ -0,0 +1,88 @@ +/* Header file for range operator class. + Copyright (C) 2017-2019 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + and Aldy Hernandez . + +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 +. */ + +#ifndef GCC_RANGE_OP_H +#define GCC_RANGE_OP_H + +// This class is implemented for each kind of operator supported by +// the range generator. It serves various purposes. +// +// 1 - Generates range information for the specific operation between +// two ranges. This provides the ability to fold ranges for an +// expression. +// +// 2 - Performs range algebra on the expression such that a range can be +// adjusted in terms of one of the operands: +// +// def = op1 + op2 +// +// Given a range for def, we can adjust the range so that it is in +// terms of either operand. +// +// op1_range (def_range, op2) will adjust the range in place so it +// is in terms of op1. Since op1 = def - op2, it will subtract +// op2 from each element of the range. +// +// 3 - Creates a range for an operand based on whether the result is 0 or +// non-zero. This is mostly for logical true false, but can serve other +// purposes. +// ie 0 = op1 - op2 implies op2 has the same range as op1. + +class range_operator +{ +public: + // Perform an operation between 2 ranges and return it. + virtual value_range_base fold_range (tree type, + const value_range_base &lh, + const value_range_base &rh) const; + + // Return the range for op[12] in the general case. LHS is the range for + // the LHS of the expression, OP[12]is the range for the other + // + // The operand and the result is returned in R. + // + // TYPE is the expected type of the range. + // + // Return TRUE if the operation is performed and a valid range is available. + // + // i.e. [LHS] = ??? + OP2 + // is re-formed as R = [LHS] - OP2. + virtual bool op1_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op2) const; + virtual bool op2_range (value_range_base &r, tree type, + const value_range_base &lhs, + const value_range_base &op1) const; + +protected: + // Perform an operation between 2 sub-ranges and return it. + virtual value_range_base wi_fold (tree type, + const wide_int &lh_lb, + const wide_int &lh_ub, + const wide_int &rh_lb, + const wide_int &rh_ub) const; +}; + +extern range_operator *range_op_handler (enum tree_code code, tree type); + +extern void range_cast (value_range_base &, tree type); + +#endif // GCC_RANGE_OP_H diff --git a/gcc/range.cc b/gcc/range.cc new file mode 100644 index 0000000..5e4d904 --- /dev/null +++ b/gcc/range.cc @@ -0,0 +1,89 @@ +/* Misc range functions. + Copyright (C) 2017-2019 Free Software Foundation, Inc. + Contributed by Aldy Hernandez . + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "gimple-pretty-print.h" +#include "fold-const.h" +#include "ssa.h" +#include "range.h" + +value_range_base +range_intersect (const value_range_base &r1, const value_range_base &r2) +{ + value_range_base tmp (r1); + tmp.intersect (r2); + return tmp; +} + +value_range_base +range_invert (const value_range_base &r1) +{ + value_range_base tmp (r1); + tmp.invert (); + return tmp; +} + +value_range_base +range_union (const value_range_base &r1, const value_range_base &r2) +{ + value_range_base tmp (r1); + tmp.union_ (r2); + return tmp; +} + +value_range_base +range_zero (tree type) +{ + return value_range_base (build_zero_cst (type), build_zero_cst (type)); +} + +value_range_base +range_nonzero (tree type) +{ + return value_range_base (VR_ANTI_RANGE, + build_zero_cst (type), build_zero_cst (type)); +} + +value_range_base +range_positives (tree type) +{ + unsigned prec = TYPE_PRECISION (type); + signop sign = TYPE_SIGN (type); + return value_range_base (type, wi::zero (prec), wi::max_value (prec, sign)); +} + +value_range_base +range_negatives (tree type) +{ + unsigned prec = TYPE_PRECISION (type); + signop sign = TYPE_SIGN (type); + value_range_base r; + if (sign == UNSIGNED) + r.set_undefined (); + else + r = value_range_base (type, wi::min_value (prec, sign), + wi::minus_one (prec)); + return r; +} diff --git a/gcc/range.h b/gcc/range.h new file mode 100644 index 0000000..3983171 --- /dev/null +++ b/gcc/range.h @@ -0,0 +1,33 @@ +/* Header file for misc range functions. -*- C++ -*- + Copyright (C) 2017-2019 Free Software Foundation, Inc. + Contributed by Aldy Hernandez . + +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 +. */ + +#ifndef GCC_RANGE_H +#define GCC_RANGE_H + +value_range_base range_zero (tree type); +value_range_base range_nonzero (tree type); +value_range_base range_intersect (const value_range_base &, + const value_range_base &); +value_range_base range_union (const value_range_base &, + const value_range_base &); +value_range_base range_invert (const value_range_base &); +value_range_base range_positives (tree type); +value_range_base range_negatives (tree type); +#endif // GCC_RANGE_H diff --git a/gcc/selftest.h b/gcc/selftest.h index 75b2cd8..6f2c2af 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -259,6 +259,10 @@ extern int num_passes; } /* end of namespace selftest. */ +/* This is outside of the selftest namespace because it's a friend of + value_range_base. */ +extern void range_tests (); + /* Macros for writing tests. */ /* Evaluate EXPR and coerce to bool, calling diff --git a/gcc/ssa.h b/gcc/ssa.h index 56a8d10..2fe4add 100644 --- a/gcc/ssa.h +++ b/gcc/ssa.h @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "gimple-ssa.h" #include "tree-vrp.h" +#include "range.h" #include "tree-ssanames.h" #include "tree-phinodes.h" #include "ssa-iterators.h" diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 0a7e7c7..a2ab4a2 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -67,7 +67,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "vr-values.h" #include "builtins.h" -#include "wide-int-range.h" +#include "range-op.h" static bool ranges_from_anti_range (const value_range_base *ar, @@ -131,6 +131,36 @@ value_range::value_range (const value_range_base &other) set (other.kind (), other.min(), other.max (), NULL); } +value_range_base::value_range_base (tree type) +{ + set_varying (type); +} + +value_range_base::value_range_base (enum value_range_kind kind, + tree type, + const wide_int &wmin, + const wide_int &wmax) +{ + tree min = wide_int_to_tree (type, wmin); + tree max = wide_int_to_tree (type, wmax); + gcc_checking_assert (kind == VR_RANGE || kind == VR_ANTI_RANGE); + set (kind, min, max); +} + +value_range_base::value_range_base (tree type, + const wide_int &wmin, + const wide_int &wmax) +{ + tree min = wide_int_to_tree (type, wmin); + tree max = wide_int_to_tree (type, wmax); + set (VR_RANGE, min, max); +} + +value_range_base::value_range_base (tree min, tree max) +{ + set (VR_RANGE, min, max); +} + /* Like set, but keep the equivalences in place. */ void @@ -350,10 +380,14 @@ value_range_base::singleton_p (tree *result) const return false; } - value_range_base vr0, vr1; - return (ranges_from_anti_range (this, &vr0, &vr1, true) - && vr1.undefined_p () - && vr0.singleton_p (result)); + /* An anti-range that includes an extreme, is just a range with + one sub-range. Use the one sub-range. */ + if (vrp_val_is_min (m_min, true) || vrp_val_is_max (m_max, true)) + { + value_range_base vr0, vr1; + ranges_from_anti_range (this, &vr0, &vr1, true); + return vr0.singleton_p (result); + } } if (m_kind == VR_RANGE && vrp_operand_equal_p (min (), max ()) @@ -369,7 +403,7 @@ value_range_base::singleton_p (tree *result) const tree value_range_base::type () const { - gcc_assert (m_min); + gcc_checking_assert (m_min); return TREE_TYPE (min ()); } @@ -573,9 +607,9 @@ vrp_val_min (const_tree type, bool handle_pointers) is not == to the integer constant with the same value in the type. */ bool -vrp_val_is_max (const_tree val) +vrp_val_is_max (const_tree val, bool handle_pointers) { - tree type_max = vrp_val_max (TREE_TYPE (val)); + tree type_max = vrp_val_max (TREE_TYPE (val), handle_pointers); return (val == type_max || (type_max != NULL_TREE && operand_equal_p (val, type_max, 0))); @@ -584,9 +618,9 @@ vrp_val_is_max (const_tree val) /* Return whether VAL is equal to the minimum value of its type. */ bool -vrp_val_is_min (const_tree val) +vrp_val_is_min (const_tree val, bool handle_pointers) { - tree type_min = vrp_val_min (TREE_TYPE (val)); + tree type_min = vrp_val_min (TREE_TYPE (val), handle_pointers); return (val == type_min || (type_min != NULL_TREE && operand_equal_p (val, type_min, 0))); @@ -1220,9 +1254,46 @@ value_range_base::value_inside_range (tree val) const return !!cmp2; } -/* Value range wrapper for wide_int_range_set_zero_nonzero_bits. +/* For range [LB, UB] compute two wide_int bit masks. + + In the MAY_BE_NONZERO bit mask, if some bit is unset, it means that + for all numbers in the range the bit is 0, otherwise it might be 0 + or 1. + + In the MUST_BE_NONZERO bit mask, if some bit is set, it means that + for all numbers in the range the bit is 1, otherwise it might be 0 + or 1. */ + +static inline void +wide_int_range_set_zero_nonzero_bits (signop sign, + const wide_int &lb, const wide_int &ub, + wide_int &may_be_nonzero, + wide_int &must_be_nonzero) +{ + may_be_nonzero = wi::minus_one (lb.get_precision ()); + must_be_nonzero = wi::zero (lb.get_precision ()); + + if (wi::eq_p (lb, ub)) + { + may_be_nonzero = lb; + must_be_nonzero = may_be_nonzero; + } + else if (wi::ge_p (lb, 0, sign) || wi::lt_p (ub, 0, sign)) + { + wide_int xor_mask = lb ^ ub; + may_be_nonzero = lb | ub; + must_be_nonzero = lb & ub; + if (xor_mask != 0) + { + wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false, + may_be_nonzero.get_precision ()); + may_be_nonzero = may_be_nonzero | mask; + must_be_nonzero = wi::bit_and_not (must_be_nonzero, mask); + } + } +} - Compute MAY_BE_NONZERO and MUST_BE_NONZERO bit masks for range in VR. +/* value_range wrapper for wide_int_range_set_zero_nonzero_bits above. Return TRUE if VR was a constant range and we were able to compute the bit masks. */ @@ -1288,87 +1359,6 @@ ranges_from_anti_range (const value_range_base *ar, return !vr0->undefined_p (); } -/* Extract the components of a value range into a pair of wide ints in - [WMIN, WMAX], after having normalized any symbolics from the input. */ - -static void inline -extract_range_into_wide_ints (const value_range_base *vr_, - tree type, wide_int &wmin, wide_int &wmax) -{ - signop sign = TYPE_SIGN (type); - unsigned int prec = TYPE_PRECISION (type); - gcc_assert (vr_->kind () != VR_ANTI_RANGE || vr_->symbolic_p ()); - value_range vr = vr_->normalize_symbolics (); - if (range_int_cst_p (&vr)) - { - wmin = wi::to_wide (vr.min ()); - wmax = wi::to_wide (vr.max ()); - } - else - { - wmin = wi::min_value (prec, sign); - wmax = wi::max_value (prec, sign); - } -} - -/* Value range wrapper for wide_int_range_multiplicative_op: - - *VR = *VR0 .CODE. *VR1. */ - -static void -extract_range_from_multiplicative_op (value_range_base *vr, - enum tree_code code, tree type, - const value_range_base *vr0, - const value_range_base *vr1) -{ - gcc_assert (code == MULT_EXPR - || code == TRUNC_DIV_EXPR - || code == FLOOR_DIV_EXPR - || code == CEIL_DIV_EXPR - || code == EXACT_DIV_EXPR - || code == ROUND_DIV_EXPR - || code == RSHIFT_EXPR - || code == LSHIFT_EXPR); - if (!range_int_cst_p (vr1)) - { - vr->set_varying (type); - return; - } - - /* Even if vr0 is VARYING or otherwise not usable, we can derive - useful ranges just from the shift count. E.g. - x >> 63 for signed 64-bit x is always [-1, 0]. */ - value_range_base tem = vr0->normalize_symbolics (); - tree vr0_min, vr0_max; - if (tem.kind () == VR_RANGE) - { - vr0_min = tem.min (); - vr0_max = tem.max (); - } - else - { - vr0_min = vrp_val_min (type); - vr0_max = vrp_val_max (type); - } - - wide_int res_lb, res_ub; - wide_int vr0_lb = wi::to_wide (vr0_min); - wide_int vr0_ub = wi::to_wide (vr0_max); - wide_int vr1_lb = wi::to_wide (vr1->min ()); - wide_int vr1_ub = wi::to_wide (vr1->max ()); - bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type); - unsigned prec = TYPE_PRECISION (type); - - if (wide_int_range_multiplicative_op (res_lb, res_ub, - code, TYPE_SIGN (type), prec, - vr0_lb, vr0_ub, vr1_lb, vr1_ub, - overflow_undefined)) - vr->set (VR_RANGE, wide_int_to_tree (type, res_lb), - wide_int_to_tree (type, res_ub)); - else - vr->set_varying (type); -} - /* If BOUND will include a symbolic bound, adjust it accordingly, otherwise leave it as is. @@ -1484,8 +1474,7 @@ set_value_range_with_overflow (value_range_kind &kind, tree &min, tree &max, if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE)) { /* If the limits are swapped, we wrapped around and cover - the entire range. We have a similar check at the end of - extract_range_from_binary_expr. */ + the entire range. */ if (wi::gt_p (tmin, tmax, sgn)) kind = VR_VARYING; else @@ -1554,91 +1543,71 @@ set_value_range_with_overflow (value_range_kind &kind, tree &min, tree &max, } } -/* Extract range information from a binary operation CODE based on - the ranges of each of its operands *VR0 and *VR1 with resulting - type EXPR_TYPE. The resulting range is stored in *VR. */ +/* Fold two value range's of a POINTER_PLUS_EXPR into VR. */ -void -extract_range_from_binary_expr (value_range_base *vr, - enum tree_code code, tree expr_type, - const value_range_base *vr0_, - const value_range_base *vr1_) +static void +extract_range_from_pointer_plus_expr (value_range_base *vr, + enum tree_code code, + tree expr_type, + const value_range_base *vr0, + const value_range_base *vr1) { - signop sign = TYPE_SIGN (expr_type); - unsigned int prec = TYPE_PRECISION (expr_type); - value_range_base vr0 = *vr0_, vr1 = *vr1_; - value_range_base vrtem0, vrtem1; - enum value_range_kind type; - tree min = NULL_TREE, max = NULL_TREE; - int cmp; - - if (!INTEGRAL_TYPE_P (expr_type) - && !POINTER_TYPE_P (expr_type)) - { - vr->set_varying (expr_type); - return; - } + gcc_checking_assert (POINTER_TYPE_P (expr_type) + && code == POINTER_PLUS_EXPR); + /* For pointer types, we are really only interested in asserting + whether the expression evaluates to non-NULL. + With -fno-delete-null-pointer-checks we need to be more + conservative. As some object might reside at address 0, + then some offset could be added to it and the same offset + subtracted again and the result would be NULL. + E.g. + static int a[12]; where &a[0] is NULL and + ptr = &a[6]; + ptr -= 6; + ptr will be NULL here, even when there is POINTER_PLUS_EXPR + where the first range doesn't include zero and the second one + doesn't either. As the second operand is sizetype (unsigned), + consider all ranges where the MSB could be set as possible + subtractions where the result might be NULL. */ + if ((!range_includes_zero_p (vr0) + || !range_includes_zero_p (vr1)) + && !TYPE_OVERFLOW_WRAPS (expr_type) + && (flag_delete_null_pointer_checks + || (range_int_cst_p (vr1) + && !tree_int_cst_sign_bit (vr1->max ())))) + vr->set_nonzero (expr_type); + else if (vr0->zero_p () && vr1->zero_p ()) + vr->set_zero (expr_type); + else + vr->set_varying (expr_type); +} - /* Not all binary expressions can be applied to ranges in a - meaningful way. Handle only arithmetic operations. */ - if (code != PLUS_EXPR - && code != MINUS_EXPR - && code != POINTER_PLUS_EXPR - && code != MULT_EXPR - && code != TRUNC_DIV_EXPR - && code != FLOOR_DIV_EXPR - && code != CEIL_DIV_EXPR - && code != EXACT_DIV_EXPR - && code != ROUND_DIV_EXPR - && code != TRUNC_MOD_EXPR - && code != RSHIFT_EXPR - && code != LSHIFT_EXPR - && code != MIN_EXPR - && code != MAX_EXPR - && code != BIT_AND_EXPR - && code != BIT_IOR_EXPR - && code != BIT_XOR_EXPR) - { - vr->set_varying (expr_type); - return; - } +/* Extract range information from a PLUS/MINUS_EXPR and store the + result in *VR. */ - /* If both ranges are UNDEFINED, so is the result. */ - if (vr0.undefined_p () && vr1.undefined_p ()) - { - vr->set_undefined (); - return; - } - /* If one of the ranges is UNDEFINED drop it to VARYING for the following - code. At some point we may want to special-case operations that - have UNDEFINED result for all or some value-ranges of the not UNDEFINED - operand. */ - else if (vr0.undefined_p ()) - vr0.set_varying (expr_type); - else if (vr1.undefined_p ()) - vr1.set_varying (expr_type); +static void +extract_range_from_plus_minus_expr (value_range_base *vr, + enum tree_code code, + tree expr_type, + const value_range_base *vr0_, + const value_range_base *vr1_) +{ + gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR); - /* We get imprecise results from ranges_from_anti_range when - code is EXACT_DIV_EXPR. We could mask out bits in the resulting - range, but then we also need to hack up vrp_union. It's just - easier to special case when vr0 is ~[0,0] for EXACT_DIV_EXPR. */ - if (code == EXACT_DIV_EXPR && vr0.nonzero_p ()) - { - vr->set_nonzero (expr_type); - return; - } + value_range_base vr0 = *vr0_, vr1 = *vr1_; + value_range_base vrtem0, vrtem1; /* Now canonicalize anti-ranges to ranges when they are not symbolic and express ~[] op X as ([]' op X) U ([]'' op X). */ if (vr0.kind () == VR_ANTI_RANGE && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1)) { - extract_range_from_binary_expr (vr, code, expr_type, &vrtem0, vr1_); + extract_range_from_plus_minus_expr (vr, code, expr_type, &vrtem0, vr1_); if (!vrtem1.undefined_p ()) { value_range_base vrres; - extract_range_from_binary_expr (&vrres, code, expr_type, - &vrtem1, vr1_); + extract_range_from_plus_minus_expr (&vrres, code, expr_type, + &vrtem1, vr1_); vr->union_ (&vrres); } return; @@ -1647,422 +1616,129 @@ extract_range_from_binary_expr (value_range_base *vr, if (vr1.kind () == VR_ANTI_RANGE && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1)) { - extract_range_from_binary_expr (vr, code, expr_type, vr0_, &vrtem0); + extract_range_from_plus_minus_expr (vr, code, expr_type, vr0_, &vrtem0); if (!vrtem1.undefined_p ()) { value_range_base vrres; - extract_range_from_binary_expr (&vrres, code, expr_type, - vr0_, &vrtem1); + extract_range_from_plus_minus_expr (&vrres, code, expr_type, + vr0_, &vrtem1); vr->union_ (&vrres); } return; } - /* The type of the resulting value range defaults to VR0.TYPE. */ - type = vr0.kind (); - - /* Refuse to operate on VARYING ranges, ranges of different kinds - and symbolic ranges. As an exception, we allow BIT_{AND,IOR} - because we may be able to derive a useful range even if one of - the operands is VR_VARYING or symbolic range. Similarly for - divisions, MIN/MAX and PLUS/MINUS. - - TODO, we may be able to derive anti-ranges in some cases. */ - if (code != BIT_AND_EXPR - && code != BIT_IOR_EXPR - && code != TRUNC_DIV_EXPR - && code != FLOOR_DIV_EXPR - && code != CEIL_DIV_EXPR - && code != EXACT_DIV_EXPR - && code != ROUND_DIV_EXPR - && code != TRUNC_MOD_EXPR - && code != MIN_EXPR - && code != MAX_EXPR - && code != PLUS_EXPR - && code != MINUS_EXPR - && code != RSHIFT_EXPR - && code != POINTER_PLUS_EXPR - && (vr0.varying_p () - || vr1.varying_p () - || vr0.kind () != vr1.kind () - || vr0.symbolic_p () - || vr1.symbolic_p ())) - { - vr->set_varying (expr_type); - return; - } - - /* Now evaluate the expression to determine the new range. */ - if (POINTER_TYPE_P (expr_type)) + value_range_kind kind; + value_range_kind vr0_kind = vr0.kind (), vr1_kind = vr1.kind (); + tree vr0_min = vr0.min (), vr0_max = vr0.max (); + tree vr1_min = vr1.min (), vr1_max = vr1.max (); + tree min = NULL, max = NULL; + + /* This will normalize things such that calculating + [0,0] - VR_VARYING is not dropped to varying, but is + calculated as [MIN+1, MAX]. */ + if (vr0.varying_p ()) + { + vr0_kind = VR_RANGE; + vr0_min = vrp_val_min (expr_type); + vr0_max = vrp_val_max (expr_type); + } + if (vr1.varying_p ()) + { + vr1_kind = VR_RANGE; + vr1_min = vrp_val_min (expr_type); + vr1_max = vrp_val_max (expr_type); + } + + const bool minus_p = (code == MINUS_EXPR); + tree min_op0 = vr0_min; + tree min_op1 = minus_p ? vr1_max : vr1_min; + tree max_op0 = vr0_max; + tree max_op1 = minus_p ? vr1_min : vr1_max; + tree sym_min_op0 = NULL_TREE; + tree sym_min_op1 = NULL_TREE; + tree sym_max_op0 = NULL_TREE; + tree sym_max_op1 = NULL_TREE; + bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1; + + neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false; + + /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or + single-symbolic ranges, try to compute the precise resulting range, + but only if we know that this resulting range will also be constant + or single-symbolic. */ + if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE + && (TREE_CODE (min_op0) == INTEGER_CST + || (sym_min_op0 + = get_single_symbol (min_op0, &neg_min_op0, &min_op0))) + && (TREE_CODE (min_op1) == INTEGER_CST + || (sym_min_op1 + = get_single_symbol (min_op1, &neg_min_op1, &min_op1))) + && (!(sym_min_op0 && sym_min_op1) + || (sym_min_op0 == sym_min_op1 + && neg_min_op0 == (minus_p ? neg_min_op1 : !neg_min_op1))) + && (TREE_CODE (max_op0) == INTEGER_CST + || (sym_max_op0 + = get_single_symbol (max_op0, &neg_max_op0, &max_op0))) + && (TREE_CODE (max_op1) == INTEGER_CST + || (sym_max_op1 + = get_single_symbol (max_op1, &neg_max_op1, &max_op1))) + && (!(sym_max_op0 && sym_max_op1) + || (sym_max_op0 == sym_max_op1 + && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1)))) { - if (code == MIN_EXPR || code == MAX_EXPR) - { - /* For MIN/MAX expressions with pointers, we only care about - nullness, if both are non null, then the result is nonnull. - If both are null, then the result is null. Otherwise they - are varying. */ - if (!range_includes_zero_p (&vr0) && !range_includes_zero_p (&vr1)) - vr->set_nonzero (expr_type); - else if (vr0.zero_p () && vr1.zero_p ()) - vr->set_zero (expr_type); - else - vr->set_varying (expr_type); - } - else if (code == POINTER_PLUS_EXPR) - { - /* For pointer types, we are really only interested in asserting - whether the expression evaluates to non-NULL. - With -fno-delete-null-pointer-checks we need to be more - conservative. As some object might reside at address 0, - then some offset could be added to it and the same offset - subtracted again and the result would be NULL. - E.g. - static int a[12]; where &a[0] is NULL and - ptr = &a[6]; - ptr -= 6; - ptr will be NULL here, even when there is POINTER_PLUS_EXPR - where the first range doesn't include zero and the second one - doesn't either. As the second operand is sizetype (unsigned), - consider all ranges where the MSB could be set as possible - subtractions where the result might be NULL. */ - if ((!range_includes_zero_p (&vr0) - || !range_includes_zero_p (&vr1)) - && !TYPE_OVERFLOW_WRAPS (expr_type) - && (flag_delete_null_pointer_checks - || (range_int_cst_p (&vr1) - && !tree_int_cst_sign_bit (vr1.max ())))) - vr->set_nonzero (expr_type); - else if (vr0.zero_p () && vr1.zero_p ()) - vr->set_zero (expr_type); - else - vr->set_varying (expr_type); - } - else if (code == BIT_AND_EXPR) - { - /* For pointer types, we are really only interested in asserting - whether the expression evaluates to non-NULL. */ - if (vr0.zero_p () || vr1.zero_p ()) - vr->set_zero (expr_type); - else - vr->set_varying (expr_type); - } - else - vr->set_varying (expr_type); - - return; - } - - /* For integer ranges, apply the operation to each end of the - range and see what we end up with. */ - if (code == PLUS_EXPR || code == MINUS_EXPR) - { - value_range_kind vr0_kind = vr0.kind (), vr1_kind = vr1.kind (); - tree vr0_min = vr0.min (), vr0_max = vr0.max (); - tree vr1_min = vr1.min (), vr1_max = vr1.max (); - /* This will normalize things such that calculating - [0,0] - VR_VARYING is not dropped to varying, but is - calculated as [MIN+1, MAX]. */ - if (vr0.varying_p ()) - { - vr0_kind = VR_RANGE; - vr0_min = vrp_val_min (expr_type); - vr0_max = vrp_val_max (expr_type); - } - if (vr1.varying_p ()) - { - vr1_kind = VR_RANGE; - vr1_min = vrp_val_min (expr_type); - vr1_max = vrp_val_max (expr_type); - } - - const bool minus_p = (code == MINUS_EXPR); - tree min_op0 = vr0_min; - tree min_op1 = minus_p ? vr1_max : vr1_min; - tree max_op0 = vr0_max; - tree max_op1 = minus_p ? vr1_min : vr1_max; - tree sym_min_op0 = NULL_TREE; - tree sym_min_op1 = NULL_TREE; - tree sym_max_op0 = NULL_TREE; - tree sym_max_op1 = NULL_TREE; - bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1; - - neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false; - - /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or - single-symbolic ranges, try to compute the precise resulting range, - but only if we know that this resulting range will also be constant - or single-symbolic. */ - if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE - && (TREE_CODE (min_op0) == INTEGER_CST - || (sym_min_op0 - = get_single_symbol (min_op0, &neg_min_op0, &min_op0))) - && (TREE_CODE (min_op1) == INTEGER_CST - || (sym_min_op1 - = get_single_symbol (min_op1, &neg_min_op1, &min_op1))) - && (!(sym_min_op0 && sym_min_op1) - || (sym_min_op0 == sym_min_op1 - && neg_min_op0 == (minus_p ? neg_min_op1 : !neg_min_op1))) - && (TREE_CODE (max_op0) == INTEGER_CST - || (sym_max_op0 - = get_single_symbol (max_op0, &neg_max_op0, &max_op0))) - && (TREE_CODE (max_op1) == INTEGER_CST - || (sym_max_op1 - = get_single_symbol (max_op1, &neg_max_op1, &max_op1))) - && (!(sym_max_op0 && sym_max_op1) - || (sym_max_op0 == sym_max_op1 - && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1)))) - { - wide_int wmin, wmax; - wi::overflow_type min_ovf = wi::OVF_NONE; - wi::overflow_type max_ovf = wi::OVF_NONE; - - /* Build the bounds. */ - combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1); - combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1); - - /* If we have overflow for the constant part and the resulting - range will be symbolic, drop to VR_VARYING. */ - if (((bool)min_ovf && sym_min_op0 != sym_min_op1) - || ((bool)max_ovf && sym_max_op0 != sym_max_op1)) - { - vr->set_varying (expr_type); - return; - } + wide_int wmin, wmax; + wi::overflow_type min_ovf = wi::OVF_NONE; + wi::overflow_type max_ovf = wi::OVF_NONE; - /* Adjust the range for possible overflow. */ - min = NULL_TREE; - max = NULL_TREE; - set_value_range_with_overflow (type, min, max, expr_type, - wmin, wmax, min_ovf, max_ovf); - if (type == VR_VARYING) - { - vr->set_varying (expr_type); - return; - } + /* Build the bounds. */ + combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1); + combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1); - /* Build the symbolic bounds if needed. */ - adjust_symbolic_bound (min, code, expr_type, - sym_min_op0, sym_min_op1, - neg_min_op0, neg_min_op1); - adjust_symbolic_bound (max, code, expr_type, - sym_max_op0, sym_max_op1, - neg_max_op0, neg_max_op1); - } - else + /* If we have overflow for the constant part and the resulting + range will be symbolic, drop to VR_VARYING. */ + if (((bool)min_ovf && sym_min_op0 != sym_min_op1) + || ((bool)max_ovf && sym_max_op0 != sym_max_op1)) { - /* For other cases, for example if we have a PLUS_EXPR with two - VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort - to compute a precise range for such a case. - ??? General even mixed range kind operations can be expressed - by for example transforming ~[3, 5] + [1, 2] to range-only - operations and a union primitive: - [-INF, 2] + [1, 2] U [5, +INF] + [1, 2] - [-INF+1, 4] U [6, +INF(OVF)] - though usually the union is not exactly representable with - a single range or anti-range as the above is - [-INF+1, +INF(OVF)] intersected with ~[5, 5] - but one could use a scheme similar to equivalences for this. */ vr->set_varying (expr_type); return; } - } - else if (code == MIN_EXPR - || code == MAX_EXPR) - { - wide_int wmin, wmax; - wide_int vr0_min, vr0_max; - wide_int vr1_min, vr1_max; - extract_range_into_wide_ints (&vr0, expr_type, vr0_min, vr0_max); - extract_range_into_wide_ints (&vr1, expr_type, vr1_min, vr1_max); - if (wide_int_range_min_max (wmin, wmax, code, sign, prec, - vr0_min, vr0_max, vr1_min, vr1_max)) - vr->set (VR_RANGE, wide_int_to_tree (expr_type, wmin), - wide_int_to_tree (expr_type, wmax)); - else - vr->set_varying (expr_type); - return; - } - else if (code == MULT_EXPR) - { - if (!range_int_cst_p (&vr0) - || !range_int_cst_p (&vr1)) - { - vr->set_varying (expr_type); - return; - } - extract_range_from_multiplicative_op (vr, code, expr_type, &vr0, &vr1); - return; - } - else if (code == RSHIFT_EXPR - || code == LSHIFT_EXPR) - { - if (range_int_cst_p (&vr1) - && !wide_int_range_shift_undefined_p - (TYPE_SIGN (TREE_TYPE (vr1.min ())), - prec, - wi::to_wide (vr1.min ()), - wi::to_wide (vr1.max ()))) - { - if (code == RSHIFT_EXPR) - { - extract_range_from_multiplicative_op (vr, code, expr_type, - &vr0, &vr1); - return; - } - else if (code == LSHIFT_EXPR - && range_int_cst_p (&vr0)) - { - wide_int res_lb, res_ub; - if (wide_int_range_lshift (res_lb, res_ub, sign, prec, - wi::to_wide (vr0.min ()), - wi::to_wide (vr0.max ()), - wi::to_wide (vr1.min ()), - wi::to_wide (vr1.max ()), - TYPE_OVERFLOW_UNDEFINED (expr_type))) - { - min = wide_int_to_tree (expr_type, res_lb); - max = wide_int_to_tree (expr_type, res_ub); - vr->set (VR_RANGE, min, max); - return; - } - } - } - vr->set_varying (expr_type); - return; - } - else if (code == TRUNC_DIV_EXPR - || code == FLOOR_DIV_EXPR - || code == CEIL_DIV_EXPR - || code == EXACT_DIV_EXPR - || code == ROUND_DIV_EXPR) - { - wide_int dividend_min, dividend_max, divisor_min, divisor_max; - wide_int wmin, wmax, extra_min, extra_max; - bool extra_range_p; - - /* Special case explicit division by zero as undefined. */ - if (vr1.zero_p ()) - { - vr->set_undefined (); - return; - } - /* First, normalize ranges into constants we can handle. Note - that VR_ANTI_RANGE's of constants were already normalized - before arriving here. - - NOTE: As a future improvement, we may be able to do better - with mixed symbolic (anti-)ranges like [0, A]. See note in - ranges_from_anti_range. */ - extract_range_into_wide_ints (&vr0, expr_type, - dividend_min, dividend_max); - extract_range_into_wide_ints (&vr1, expr_type, - divisor_min, divisor_max); - if (!wide_int_range_div (wmin, wmax, code, sign, prec, - dividend_min, dividend_max, - divisor_min, divisor_max, - TYPE_OVERFLOW_UNDEFINED (expr_type), - extra_range_p, extra_min, extra_max)) + /* Adjust the range for possible overflow. */ + min = NULL_TREE; + max = NULL_TREE; + set_value_range_with_overflow (kind, min, max, expr_type, + wmin, wmax, min_ovf, max_ovf); + if (kind == VR_VARYING) { vr->set_varying (expr_type); return; } - vr->set (VR_RANGE, wide_int_to_tree (expr_type, wmin), - wide_int_to_tree (expr_type, wmax)); - if (extra_range_p) - { - value_range_base - extra_range (VR_RANGE, wide_int_to_tree (expr_type, extra_min), - wide_int_to_tree (expr_type, extra_max)); - vr->union_ (&extra_range); - } - return; + + /* Build the symbolic bounds if needed. */ + adjust_symbolic_bound (min, code, expr_type, + sym_min_op0, sym_min_op1, + neg_min_op0, neg_min_op1); + adjust_symbolic_bound (max, code, expr_type, + sym_max_op0, sym_max_op1, + neg_max_op0, neg_max_op1); } - else if (code == TRUNC_MOD_EXPR) + else { - if (vr1.zero_p ()) - { - vr->set_undefined (); - return; - } - wide_int wmin, wmax, tmp; - wide_int vr0_min, vr0_max, vr1_min, vr1_max; - extract_range_into_wide_ints (&vr0, expr_type, vr0_min, vr0_max); - extract_range_into_wide_ints (&vr1, expr_type, vr1_min, vr1_max); - wide_int_range_trunc_mod (wmin, wmax, sign, prec, - vr0_min, vr0_max, vr1_min, vr1_max); - min = wide_int_to_tree (expr_type, wmin); - max = wide_int_to_tree (expr_type, wmax); - vr->set (VR_RANGE, min, max); + /* For other cases, for example if we have a PLUS_EXPR with two + VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort + to compute a precise range for such a case. + ??? General even mixed range kind operations can be expressed + by for example transforming ~[3, 5] + [1, 2] to range-only + operations and a union primitive: + [-INF, 2] + [1, 2] U [5, +INF] + [1, 2] + [-INF+1, 4] U [6, +INF(OVF)] + though usually the union is not exactly representable with + a single range or anti-range as the above is + [-INF+1, +INF(OVF)] intersected with ~[5, 5] + but one could use a scheme similar to equivalences for this. */ + vr->set_varying (expr_type); return; } - else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR) - { - wide_int may_be_nonzero0, may_be_nonzero1; - wide_int must_be_nonzero0, must_be_nonzero1; - wide_int wmin, wmax; - wide_int vr0_min, vr0_max, vr1_min, vr1_max; - vrp_set_zero_nonzero_bits (expr_type, &vr0, - &may_be_nonzero0, &must_be_nonzero0); - vrp_set_zero_nonzero_bits (expr_type, &vr1, - &may_be_nonzero1, &must_be_nonzero1); - extract_range_into_wide_ints (&vr0, expr_type, vr0_min, vr0_max); - extract_range_into_wide_ints (&vr1, expr_type, vr1_min, vr1_max); - if (code == BIT_AND_EXPR) - { - if (wide_int_range_bit_and (wmin, wmax, sign, prec, - vr0_min, vr0_max, - vr1_min, vr1_max, - must_be_nonzero0, - may_be_nonzero0, - must_be_nonzero1, - may_be_nonzero1)) - { - min = wide_int_to_tree (expr_type, wmin); - max = wide_int_to_tree (expr_type, wmax); - vr->set (VR_RANGE, min, max); - } - else - vr->set_varying (expr_type); - return; - } - else if (code == BIT_IOR_EXPR) - { - if (wide_int_range_bit_ior (wmin, wmax, sign, - vr0_min, vr0_max, - vr1_min, vr1_max, - must_be_nonzero0, - may_be_nonzero0, - must_be_nonzero1, - may_be_nonzero1)) - { - min = wide_int_to_tree (expr_type, wmin); - max = wide_int_to_tree (expr_type, wmax); - vr->set (VR_RANGE, min, max); - } - else - vr->set_varying (expr_type); - return; - } - else if (code == BIT_XOR_EXPR) - { - if (wide_int_range_bit_xor (wmin, wmax, sign, prec, - must_be_nonzero0, - may_be_nonzero0, - must_be_nonzero1, - may_be_nonzero1)) - { - min = wide_int_to_tree (expr_type, wmin); - max = wide_int_to_tree (expr_type, wmax); - vr->set (VR_RANGE, min, max); - } - else - vr->set_varying (expr_type); - return; - } - } - else - gcc_unreachable (); /* If either MIN or MAX overflowed, then set the resulting range to VARYING. */ @@ -2075,16 +1751,7 @@ extract_range_from_binary_expr (value_range_base *vr, return; } - /* We punt for [-INF, +INF]. - We learn nothing when we have INF on both sides. - Note that we do accept [-INF, -INF] and [+INF, +INF]. */ - if (vrp_val_is_min (min) && vrp_val_is_max (max)) - { - vr->set_varying (expr_type); - return; - } - - cmp = compare_values (min, max); + int cmp = compare_values (min, max); if (cmp == -2 || cmp == 1) { /* If the new range has its limits swapped around (MIN > MAX), @@ -2093,166 +1760,162 @@ extract_range_from_binary_expr (value_range_base *vr, vr->set_varying (expr_type); } else - vr->set (type, min, max); + vr->set (kind, min, max); } -/* Extract range information from a unary operation CODE based on - the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE. - The resulting range is stored in *VR. */ +/* Normalize a value_range for use in range_ops and return it. */ -void -extract_range_from_unary_expr (value_range_base *vr, - enum tree_code code, tree type, - const value_range_base *vr0_, tree op0_type) +static value_range_base +normalize_for_range_ops (const value_range_base &vr) { - signop sign = TYPE_SIGN (type); - unsigned int prec = TYPE_PRECISION (type); - value_range_base vr0 = *vr0_; - value_range_base vrtem0, vrtem1; + tree type = vr.type (); - /* VRP only operates on integral and pointer types. */ - if (!(INTEGRAL_TYPE_P (op0_type) - || POINTER_TYPE_P (op0_type)) - || !(INTEGRAL_TYPE_P (type) - || POINTER_TYPE_P (type))) + /* This will return ~[0,0] for [&var, &var]. */ + if (POINTER_TYPE_P (type) && !range_includes_zero_p (&vr)) { - vr->set_varying (type); - return; + value_range_base temp; + temp.set_nonzero (type); + return temp; } + if (vr.symbolic_p ()) + return normalize_for_range_ops (vr.normalize_symbolics ()); + if (TREE_CODE (vr.min ()) == INTEGER_CST + && TREE_CODE (vr.max ()) == INTEGER_CST) + return vr; + /* Anything not strictly numeric at this point becomes varying. */ + return value_range_base (vr.type ()); +} - /* If VR0 is UNDEFINED, so is the result. */ - if (vr0.undefined_p ()) - { - vr->set_undefined (); - return; - } +/* Fold a binary expression of two value_range's with range-ops. */ - /* Handle operations that we express in terms of others. */ - if (code == PAREN_EXPR) +void +range_fold_binary_expr (value_range_base *vr, + enum tree_code code, + tree expr_type, + const value_range_base *vr0_, + const value_range_base *vr1_) +{ + if (!value_range_base::supports_type_p (expr_type) + || (!vr0_->undefined_p () + && !value_range_base::supports_type_p (vr0_->type ())) + || (!vr1_->undefined_p () + && !value_range_base::supports_type_p (vr1_->type ()))) { - /* PAREN_EXPR and OBJ_TYPE_REF are simple copies. */ - *vr = vr0; + vr->set_varying (expr_type); return; } - else if (code == NEGATE_EXPR) + if (vr0_->undefined_p () && vr1_->undefined_p ()) { - /* -X is simply 0 - X, so re-use existing code that also handles - anti-ranges fine. */ - value_range_base zero; - zero.set (build_int_cst (type, 0)); - extract_range_from_binary_expr (vr, MINUS_EXPR, type, &zero, &vr0); + vr->set_undefined (); return; } - else if (code == BIT_NOT_EXPR) + range_operator *op = range_op_handler (code, expr_type); + if (!op) { - /* ~X is simply -1 - X, so re-use existing code that also handles - anti-ranges fine. */ - value_range_base minusone; - minusone.set (build_int_cst (type, -1)); - extract_range_from_binary_expr (vr, MINUS_EXPR, type, &minusone, &vr0); + vr->set_varying (expr_type); return; } - /* Now canonicalize anti-ranges to ranges when they are not symbolic - and express op ~[] as (op []') U (op []''). */ - if (vr0.kind () == VR_ANTI_RANGE - && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1)) + /* Mimic any behavior users of extract_range_from_binary_expr may + expect. */ + value_range_base vr0 = *vr0_, vr1 = *vr1_; + if (vr0.undefined_p ()) + vr0.set_varying (expr_type); + else if (vr1.undefined_p ()) + vr1.set_varying (expr_type); + + /* Handle symbolics. */ + if (vr0.symbolic_p () || vr1.symbolic_p ()) { - extract_range_from_unary_expr (vr, code, type, &vrtem0, op0_type); - if (!vrtem1.undefined_p ()) + if ((code == PLUS_EXPR || code == MINUS_EXPR)) { - value_range_base vrres; - extract_range_from_unary_expr (&vrres, code, type, - &vrtem1, op0_type); - vr->union_ (&vrres); + extract_range_from_plus_minus_expr (vr, code, expr_type, + &vr0, &vr1); + return; + } + if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR) + { + extract_range_from_pointer_plus_expr (vr, code, expr_type, + &vr0, &vr1); + return; } - return; } - if (CONVERT_EXPR_CODE_P (code)) - { - tree inner_type = op0_type; - tree outer_type = type; + /* Do the range-ops dance. */ + value_range_base n0 = normalize_for_range_ops (vr0); + value_range_base n1 = normalize_for_range_ops (vr1); + *vr = op->fold_range (expr_type, n0, n1); +} - /* If the expression involves a pointer, we are only interested in - determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). +/* Fold a unary expression of a value_range with range-ops. */ - This may lose precision when converting (char *)~[0,2] to - int, because we'll forget that the pointer can also not be 1 - or 2. In practice we don't care, as this is some idiot - storing a magic constant to a pointer. */ - if (POINTER_TYPE_P (type) || POINTER_TYPE_P (op0_type)) +void +range_fold_unary_expr (value_range_base *vr, + enum tree_code code, tree expr_type, + const value_range_base *vr0, + tree vr0_type) +{ + /* Mimic any behavior users of extract_range_from_unary_expr may + expect. */ + if (!value_range_base::supports_type_p (expr_type) + || !value_range_base::supports_type_p (vr0_type)) + { + vr->set_varying (expr_type); + return; + } + if (vr0->undefined_p ()) + { + vr->set_undefined (); + return; + } + range_operator *op = range_op_handler (code, expr_type); + if (!op) + { + vr->set_varying (expr_type); + return; + } + + /* Handle symbolics. */ + if (vr0->symbolic_p ()) + { + if (code == NEGATE_EXPR) { - if (!range_includes_zero_p (&vr0)) - vr->set_nonzero (type); - else if (vr0.zero_p ()) - vr->set_zero (type); - else - vr->set_varying (type); + /* -X is simply 0 - X. */ + value_range_base zero; + zero.set_zero (vr0->type ()); + range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0); return; } - - /* The POINTER_TYPE_P code above will have dealt with all - pointer anti-ranges. Any remaining anti-ranges at this point - will be integer conversions from SSA names that will be - normalized into VARYING. For instance: ~[x_55, x_55]. */ - gcc_assert (vr0.kind () != VR_ANTI_RANGE - || TREE_CODE (vr0.min ()) != INTEGER_CST); - - /* NOTES: Previously we were returning VARYING for all symbolics, but - we can do better by treating them as [-MIN, +MAX]. For - example, converting [SYM, SYM] from INT to LONG UNSIGNED, - we can return: ~[0x8000000, 0xffffffff7fffffff]. - - We were also failing to convert ~[0,0] from char* to unsigned, - instead choosing to return VR_VARYING. Now we return ~[0,0]. */ - wide_int vr0_min, vr0_max, wmin, wmax; - signop inner_sign = TYPE_SIGN (inner_type); - signop outer_sign = TYPE_SIGN (outer_type); - unsigned inner_prec = TYPE_PRECISION (inner_type); - unsigned outer_prec = TYPE_PRECISION (outer_type); - extract_range_into_wide_ints (&vr0, inner_type, vr0_min, vr0_max); - if (wide_int_range_convert (wmin, wmax, - inner_sign, inner_prec, - outer_sign, outer_prec, - vr0_min, vr0_max)) + if (code == BIT_NOT_EXPR) { - tree min = wide_int_to_tree (outer_type, wmin); - tree max = wide_int_to_tree (outer_type, wmax); - vr->set (VR_RANGE, min, max); + /* ~X is simply -1 - X. */ + value_range_base minusone; + minusone.set (build_int_cst (vr0->type (), -1)); + range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0); + return; } - else - vr->set_varying (outer_type); + *vr = op->fold_range (expr_type, + normalize_for_range_ops (*vr0), + value_range_base (expr_type)); return; } - else if (code == ABS_EXPR) + if (CONVERT_EXPR_CODE_P (code) && (POINTER_TYPE_P (expr_type) + || POINTER_TYPE_P (vr0->type ()))) { - wide_int wmin, wmax; - wide_int vr0_min, vr0_max; - extract_range_into_wide_ints (&vr0, type, vr0_min, vr0_max); - if (wide_int_range_abs (wmin, wmax, sign, prec, vr0_min, vr0_max, - TYPE_OVERFLOW_UNDEFINED (type))) - vr->set (VR_RANGE, wide_int_to_tree (type, wmin), - wide_int_to_tree (type, wmax)); + /* This handles symbolic conversions such such as [25, x_4]. */ + if (!range_includes_zero_p (vr0)) + vr->set_nonzero (expr_type); + else if (vr0->zero_p ()) + vr->set_zero (expr_type); else - vr->set_varying (type); - return; - } - else if (code == ABSU_EXPR) - { - wide_int wmin, wmax; - wide_int vr0_min, vr0_max; - tree signed_type = make_signed_type (TYPE_PRECISION (type)); - extract_range_into_wide_ints (&vr0, signed_type, vr0_min, vr0_max); - wide_int_range_absu (wmin, wmax, prec, vr0_min, vr0_max); - vr->set (VR_RANGE, wide_int_to_tree (type, wmin), - wide_int_to_tree (type, wmax)); + vr->set_varying (expr_type); return; } - /* For unhandled operations fall back to varying. */ - vr->set_varying (type); - return; + /* Do the range-ops dance. */ + value_range_base n0 = normalize_for_range_ops (*vr0); + value_range_base n1 (expr_type); + *vr = op->fold_range (expr_type, n0, n1); } /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, @@ -6361,18 +6024,18 @@ value_range_base::normalize_symbolics () const { // [SYM, NUM] -> [-MIN, NUM] if (min_symbolic) - return value_range_base (VR_RANGE, vrp_val_min (ttype), max ()); + return value_range_base (VR_RANGE, vrp_val_min (ttype, true), max ()); // [NUM, SYM] -> [NUM, +MAX] - return value_range_base (VR_RANGE, min (), vrp_val_max (ttype)); + return value_range_base (VR_RANGE, min (), vrp_val_max (ttype, true)); } - gcc_assert (kind () == VR_ANTI_RANGE); + gcc_checking_assert (kind () == VR_ANTI_RANGE); // ~[SYM, NUM] -> [NUM + 1, +MAX] if (min_symbolic) { if (!vrp_val_is_max (max ())) { tree n = wide_int_to_tree (ttype, wi::to_wide (max ()) + 1); - return value_range_base (VR_RANGE, n, vrp_val_max (ttype)); + return value_range_base (VR_RANGE, n, vrp_val_max (ttype, true)); } value_range_base var; var.set_varying (ttype); @@ -6382,13 +6045,178 @@ value_range_base::normalize_symbolics () const if (!vrp_val_is_min (min ())) { tree n = wide_int_to_tree (ttype, wi::to_wide (min ()) - 1); - return value_range_base (VR_RANGE, vrp_val_min (ttype), n); + return value_range_base (VR_RANGE, vrp_val_min (ttype, true), n); } value_range_base var; var.set_varying (ttype); return var; } +/* Return the number of sub-ranges in a range. */ + +unsigned +value_range_base::num_pairs () const +{ + if (undefined_p ()) + return 0; + if (varying_p ()) + return 1; + if (symbolic_p ()) + return normalize_symbolics ().num_pairs (); + if (m_kind == VR_ANTI_RANGE) + { + // ~[MIN, X] has one sub-range of [X+1, MAX], and + // ~[X, MAX] has one sub-range of [MIN, X-1]. + if (vrp_val_is_min (m_min, true) || vrp_val_is_max (m_max, true)) + return 1; + return 2; + } + return 1; +} + +/* Return the lower bound for a sub-range. PAIR is the sub-range in + question. */ + +wide_int +value_range_base::lower_bound (unsigned pair) const +{ + if (symbolic_p ()) + return normalize_symbolics ().lower_bound (pair); + + gcc_checking_assert (!undefined_p ()); + gcc_checking_assert (pair + 1 <= num_pairs ()); + tree t = NULL; + if (m_kind == VR_ANTI_RANGE) + { + tree typ = type (); + if (pair == 1 || vrp_val_is_min (m_min, true)) + t = wide_int_to_tree (typ, wi::to_wide (m_max) + 1); + else + t = vrp_val_min (typ, true); + } + else + t = m_min; + return wi::to_wide (t); +} + +/* Return the upper bound for a sub-range. PAIR is the sub-range in + question. */ + +wide_int +value_range_base::upper_bound (unsigned pair) const +{ + if (symbolic_p ()) + return normalize_symbolics ().upper_bound (pair); + + gcc_checking_assert (!undefined_p ()); + gcc_checking_assert (pair + 1 <= num_pairs ()); + tree t = NULL; + if (m_kind == VR_ANTI_RANGE) + { + tree typ = type (); + if (pair == 1 || vrp_val_is_min (m_min, true)) + t = vrp_val_max (typ, true); + else + t = wide_int_to_tree (typ, wi::to_wide (m_min) - 1); + } + else + t = m_max; + return wi::to_wide (t); +} + +/* Return the highest bound in a range. */ + +wide_int +value_range_base::upper_bound () const +{ + unsigned pairs = num_pairs (); + gcc_checking_assert (pairs > 0); + return upper_bound (pairs - 1); +} + +/* Return TRUE if range contains INTEGER_CST. */ + +bool +value_range_base::contains_p (tree cst) const +{ + gcc_checking_assert (TREE_CODE (cst) == INTEGER_CST); + if (symbolic_p ()) + return normalize_symbolics ().contains_p (cst); + return value_inside_range (cst) == 1; +} + +/* Return the inverse of a range. */ + +void +value_range_base::invert () +{ + if (m_kind == VR_RANGE) + m_kind = VR_ANTI_RANGE; + else if (m_kind == VR_ANTI_RANGE) + m_kind = VR_RANGE; + else + gcc_unreachable (); +} + +/* Range union, but for references. */ + +void +value_range_base::union_ (const value_range_base &r) +{ + /* Disable details for now, because it makes the ranger dump + unnecessarily verbose. */ + bool details = dump_flags & TDF_DETAILS; + if (details) + dump_flags &= ~TDF_DETAILS; + union_ (&r); + if (details) + dump_flags |= TDF_DETAILS; +} + +/* Range intersect, but for references. */ + +void +value_range_base::intersect (const value_range_base &r) +{ + /* Disable details for now, because it makes the ranger dump + unnecessarily verbose. */ + bool details = dump_flags & TDF_DETAILS; + if (details) + dump_flags &= ~TDF_DETAILS; + intersect (&r); + if (details) + dump_flags |= TDF_DETAILS; +} + +/* Return TRUE if two types are compatible for range operations. */ + +static bool +range_compatible_p (tree t1, tree t2) +{ + if (POINTER_TYPE_P (t1) && POINTER_TYPE_P (t2)) + return true; + + return types_compatible_p (t1, t2); +} + +bool +value_range_base::operator== (const value_range_base &r) const +{ + if (undefined_p ()) + return r.undefined_p (); + + if (num_pairs () != r.num_pairs () + || !range_compatible_p (type (), r.type ())) + return false; + + for (unsigned p = 0; p < num_pairs (); p++) + if (wi::ne_p (lower_bound (p), r.lower_bound (p)) + || wi::ne_p (upper_bound (p), r.upper_bound (p))) + return false; + + return true; +} + /* Visit all arguments for PHI node PHI that flow through executable edges. If a valid value range can be derived from all the incoming value ranges, set a new range for the LHS of PHI. */ @@ -7039,15 +6867,15 @@ determine_value_range_1 (value_range_base *vr, tree expr) value_range_base vr0, vr1; determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0)); determine_value_range_1 (&vr1, TREE_OPERAND (expr, 1)); - extract_range_from_binary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr), - &vr0, &vr1); + range_fold_binary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr), + &vr0, &vr1); } else if (UNARY_CLASS_P (expr)) { value_range_base vr0; determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0)); - extract_range_from_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr), - &vr0, TREE_TYPE (TREE_OPERAND (expr, 0))); + range_fold_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr), + &vr0, TREE_TYPE (TREE_OPERAND (expr, 0))); } else if (TREE_CODE (expr) == INTEGER_CST) vr->set (expr); diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h index cf236fa..d20d004 100644 --- a/gcc/tree-vrp.h +++ b/gcc/tree-vrp.h @@ -35,14 +35,19 @@ enum value_range_kind VR_LAST }; - /* Range of values that can be associated with an SSA_NAME after VRP has executed. */ class GTY((for_user)) value_range_base { + friend void range_tests (); public: value_range_base (); value_range_base (value_range_kind, tree, tree); + value_range_base (tree, tree); + value_range_base (value_range_kind, + tree type, const wide_int &, const wide_int &); + value_range_base (tree type, const wide_int &, const wide_int &); + value_range_base (tree type); void set (value_range_kind, tree, tree); void set (tree); @@ -63,8 +68,10 @@ public: void union_ (const value_range_base *); void intersect (const value_range_base *); + void union_ (const value_range_base &); + void intersect (const value_range_base &); - bool operator== (const value_range_base &) const /* = delete */; + bool operator== (const value_range_base &) const; bool operator!= (const value_range_base &) const /* = delete */; bool equal_p (const value_range_base &) const; @@ -80,6 +87,14 @@ public: static bool supports_type_p (tree); value_range_base normalize_symbolics () const; + static const unsigned int m_max_pairs = 2; + bool contains_p (tree) const; + unsigned num_pairs () const; + wide_int lower_bound (unsigned = 0) const; + wide_int upper_bound (unsigned) const; + wide_int upper_bound () const; + void invert (); + protected: void check (); static value_range_base union_helper (const value_range_base *, @@ -281,21 +296,17 @@ extern bool range_int_cst_singleton_p (const value_range_base *); extern int compare_values (tree, tree); extern int compare_values_warnv (tree, tree, bool *); extern int operand_less_p (tree, tree); -extern bool vrp_val_is_min (const_tree); -extern bool vrp_val_is_max (const_tree); +extern bool vrp_val_is_min (const_tree, bool handle_pointers = false); +extern bool vrp_val_is_max (const_tree, bool handle_pointers = false); extern tree vrp_val_min (const_tree, bool handle_pointers = false); extern tree vrp_val_max (const_tree, bool handle_pointers = false); -extern void extract_range_from_unary_expr (value_range_base *vr, - enum tree_code code, - tree type, - const value_range_base *vr0_, - tree op0_type); -extern void extract_range_from_binary_expr (value_range_base *, - enum tree_code, - tree, const value_range_base *, - const value_range_base *); +void range_fold_unary_expr (value_range_base *, enum tree_code, tree type, + const value_range_base *, tree op0_type); +void range_fold_binary_expr (value_range_base *, enum tree_code, tree type, + const value_range_base *, + const value_range_base *); extern bool vrp_operand_equal_p (const_tree, const_tree); extern enum value_range_kind intersect_range_with_nonzero_bits diff --git a/gcc/vr-values.c b/gcc/vr-values.c index 0ebb6e3..3acbfc6 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -46,8 +46,10 @@ along with GCC; see the file COPYING3. If not see #include "case-cfn-macros.h" #include "alloc-pool.h" #include "attribs.h" +#include "range.h" #include "vr-values.h" #include "cfghooks.h" +#include "range-op.h" /* Set value range VR to a non-negative range of type TYPE. */ @@ -803,7 +805,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr, vrp_val_max (expr_type)); } - ::extract_range_from_binary_expr (vr, code, expr_type, &vr0, &vr1); + range_fold_binary_expr (vr, code, expr_type, &vr0, &vr1); /* Set value_range for n in following sequence: def = __builtin_memchr (arg, 0, sz) @@ -864,7 +866,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr, else n_vr1.set (VR_RANGE, op1, op1); - ::extract_range_from_binary_expr (vr, code, expr_type, &vr0, &n_vr1); + range_fold_binary_expr (vr, code, expr_type, &vr0, &n_vr1); } if (vr->varying_p () @@ -888,7 +890,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr, else n_vr0.set (op0); - ::extract_range_from_binary_expr (vr, code, expr_type, &n_vr0, &vr1); + range_fold_binary_expr (vr, code, expr_type, &n_vr0, &vr1); } /* If we didn't derive a range for MINUS_EXPR, and @@ -929,7 +931,7 @@ vr_values::extract_range_from_unary_expr (value_range *vr, enum tree_code code, else vr0.set_varying (type); - ::extract_range_from_unary_expr (vr, code, type, &vr0, TREE_TYPE (op0)); + range_fold_unary_expr (vr, code, type, &vr0, TREE_TYPE (op0)); } @@ -1427,8 +1429,7 @@ vr_values::extract_range_basic (value_range *vr, gimple *stmt) type, op0); extract_range_from_unary_expr (&vr1, NOP_EXPR, type, op1); - ::extract_range_from_binary_expr (vr, subcode, type, - &vr0, &vr1); + range_fold_binary_expr (vr, subcode, type, &vr0, &vr1); flag_wrapv = saved_flag_wrapv; } return; diff --git a/gcc/wide-int-range.cc b/gcc/wide-int-range.cc deleted file mode 100644 index 90c58f6..0000000 --- a/gcc/wide-int-range.cc +++ /dev/null @@ -1,865 +0,0 @@ -/* Support routines for range operations on wide ints. - Copyright (C) 2018-2019 Free Software Foundation, Inc. - -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 -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "fold-const.h" -#include "wide-int-range.h" - -/* Wrapper around wide_int_binop that adjusts for overflow. - - Return true if we can compute the result; i.e. if the operation - doesn't overflow or if the overflow is undefined. In the latter - case (if the operation overflows and overflow is undefined), then - adjust the result to be -INF or +INF depending on CODE, VAL1 and - VAL2. Return the value in *RES. - - Return false for division by zero, for which the result is - indeterminate. */ - -static bool -wide_int_binop_overflow (wide_int &res, - enum tree_code code, - const wide_int &w0, const wide_int &w1, - signop sign, bool overflow_undefined) -{ - wi::overflow_type overflow; - if (!wide_int_binop (res, code, w0, w1, sign, &overflow)) - return false; - - /* If the operation overflowed return -INF or +INF depending on the - operation and the combination of signs of the operands. */ - if (overflow && overflow_undefined) - { - switch (code) - { - case MULT_EXPR: - /* For multiplication, the sign of the overflow is given - by the comparison of the signs of the operands. */ - if (sign == UNSIGNED || w0.sign_mask () == w1.sign_mask ()) - res = wi::max_value (w0.get_precision (), sign); - else - res = wi::min_value (w0.get_precision (), sign); - return true; - - case TRUNC_DIV_EXPR: - case FLOOR_DIV_EXPR: - case CEIL_DIV_EXPR: - case EXACT_DIV_EXPR: - case ROUND_DIV_EXPR: - /* For division, the only case is -INF / -1 = +INF. */ - res = wi::max_value (w0.get_precision (), sign); - return true; - - default: - gcc_unreachable (); - } - } - return !overflow; -} - -/* For range [LB, UB] compute two wide_int bit masks. - - In the MAY_BE_NONZERO bit mask, if some bit is unset, it means that - for all numbers in the range the bit is 0, otherwise it might be 0 - or 1. - - In the MUST_BE_NONZERO bit mask, if some bit is set, it means that - for all numbers in the range the bit is 1, otherwise it might be 0 - or 1. */ - -void -wide_int_range_set_zero_nonzero_bits (signop sign, - const wide_int &lb, const wide_int &ub, - wide_int &may_be_nonzero, - wide_int &must_be_nonzero) -{ - may_be_nonzero = wi::minus_one (lb.get_precision ()); - must_be_nonzero = wi::zero (lb.get_precision ()); - - if (wi::eq_p (lb, ub)) - { - may_be_nonzero = lb; - must_be_nonzero = may_be_nonzero; - } - else if (wi::ge_p (lb, 0, sign) || wi::lt_p (ub, 0, sign)) - { - wide_int xor_mask = lb ^ ub; - may_be_nonzero = lb | ub; - must_be_nonzero = lb & ub; - if (xor_mask != 0) - { - wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false, - may_be_nonzero.get_precision ()); - may_be_nonzero = may_be_nonzero | mask; - must_be_nonzero = wi::bit_and_not (must_be_nonzero, mask); - } - } -} - -/* Order 2 sets of wide int ranges (w0/w1, w2/w3) and set MIN/MAX - accordingly. */ - -static void -wide_int_range_order_set (wide_int &min, wide_int &max, - wide_int &w0, wide_int &w1, - wide_int &w2, wide_int &w3, - signop sign) -{ - /* Order pairs w0,w1 and w2,w3. */ - if (wi::gt_p (w0, w1, sign)) - std::swap (w0, w1); - if (wi::gt_p (w2, w3, sign)) - std::swap (w2, w3); - - /* Choose min and max from the ordered pairs. */ - min = wi::min (w0, w2, sign); - max = wi::max (w1, w3, sign); -} - -/* Calculate the cross product of two sets of ranges (VR0 and VR1) and - store the result in [RES_LB, RES_UB]. - - CODE is the operation to perform with sign SIGN. - - OVERFLOW_UNDEFINED is set if overflow is undefined for the operation type. - - Return TRUE if we were able to calculate the cross product. */ - -bool -wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub, - enum tree_code code, signop sign, - const wide_int &vr0_lb, const wide_int &vr0_ub, - const wide_int &vr1_lb, const wide_int &vr1_ub, - bool overflow_undefined) -{ - wide_int cp1, cp2, cp3, cp4; - - /* Compute the 4 cross operations, bailing if we get an overflow we - can't handle. */ - - if (!wide_int_binop_overflow (cp1, code, vr0_lb, vr1_lb, sign, - overflow_undefined)) - return false; - - if (wi::eq_p (vr0_lb, vr0_ub)) - cp3 = cp1; - else if (!wide_int_binop_overflow (cp3, code, vr0_ub, vr1_lb, sign, - overflow_undefined)) - return false; - - if (wi::eq_p (vr1_lb, vr1_ub)) - cp2 = cp1; - else if (!wide_int_binop_overflow (cp2, code, vr0_lb, vr1_ub, sign, - overflow_undefined)) - return false; - - if (wi::eq_p (vr0_lb, vr0_ub)) - cp4 = cp2; - else if (!wide_int_binop_overflow (cp4, code, vr0_ub, vr1_ub, sign, - overflow_undefined)) - return false; - - wide_int_range_order_set (res_lb, res_ub, cp1, cp2, cp3, cp4, sign); - return true; -} - -/* Multiply two ranges when TYPE_OVERFLOW_WRAPS: - - [RES_LB, RES_UB] = [MIN0, MAX0] * [MIN1, MAX1] - - This is basically fancy code so we don't drop to varying with an - unsigned [-3,-1]*[-3,-1]. - - Return TRUE if we were able to perform the operation. */ - -bool -wide_int_range_mult_wrapping (wide_int &res_lb, - wide_int &res_ub, - signop sign, - unsigned prec, - const wide_int &min0_, - const wide_int &max0_, - const wide_int &min1_, - const wide_int &max1_) -{ - /* This test requires 2*prec bits if both operands are signed and - 2*prec + 2 bits if either is not. Therefore, extend the values - using the sign of the result to PREC2. From here on out, - everthing is just signed math no matter what the input types - were. */ - widest2_int min0 = widest2_int::from (min0_, sign); - widest2_int max0 = widest2_int::from (max0_, sign); - widest2_int min1 = widest2_int::from (min1_, sign); - widest2_int max1 = widest2_int::from (max1_, sign); - widest2_int sizem1 = wi::mask (prec, false); - widest2_int size = sizem1 + 1; - - /* Canonicalize the intervals. */ - if (sign == UNSIGNED) - { - if (wi::ltu_p (size, min0 + max0)) - { - min0 -= size; - max0 -= size; - } - - if (wi::ltu_p (size, min1 + max1)) - { - min1 -= size; - max1 -= size; - } - } - - widest2_int prod0 = min0 * min1; - widest2_int prod1 = min0 * max1; - widest2_int prod2 = max0 * min1; - widest2_int prod3 = max0 * max1; - - /* Sort the 4 products so that min is in prod0 and max is in - prod3. */ - /* min0min1 > max0max1 */ - if (prod0 > prod3) - std::swap (prod0, prod3); - - /* min0max1 > max0min1 */ - if (prod1 > prod2) - std::swap (prod1, prod2); - - if (prod0 > prod1) - std::swap (prod0, prod1); - - if (prod2 > prod3) - std::swap (prod2, prod3); - - /* diff = max - min. */ - prod2 = prod3 - prod0; - if (wi::geu_p (prod2, sizem1)) - /* The range covers all values. */ - return false; - - res_lb = wide_int::from (prod0, prec, sign); - res_ub = wide_int::from (prod3, prec, sign); - return true; -} - -/* Perform multiplicative operation CODE on two ranges: - - [RES_LB, RES_UB] = [VR0_LB, VR0_UB] .CODE. [VR1_LB, VR1_LB] - - Return TRUE if we were able to perform the operation. - - NOTE: If code is MULT_EXPR and !TYPE_OVERFLOW_UNDEFINED, the resulting - range must be canonicalized by the caller because its components - may be swapped. */ - -bool -wide_int_range_multiplicative_op (wide_int &res_lb, wide_int &res_ub, - enum tree_code code, - signop sign, - unsigned prec, - const wide_int &vr0_lb, - const wide_int &vr0_ub, - const wide_int &vr1_lb, - const wide_int &vr1_ub, - bool overflow_undefined) -{ - /* Multiplications, divisions and shifts are a bit tricky to handle, - depending on the mix of signs we have in the two ranges, we - need to operate on different values to get the minimum and - maximum values for the new range. One approach is to figure - out all the variations of range combinations and do the - operations. - - However, this involves several calls to compare_values and it - is pretty convoluted. It's simpler to do the 4 operations - (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP - MAX1) and then figure the smallest and largest values to form - the new range. */ - if (code == MULT_EXPR && !overflow_undefined) - return wide_int_range_mult_wrapping (res_lb, res_ub, - sign, prec, - vr0_lb, vr0_ub, vr1_lb, vr1_ub); - return wide_int_range_cross_product (res_lb, res_ub, - code, sign, - vr0_lb, vr0_ub, vr1_lb, vr1_ub, - overflow_undefined); -} - -/* Perform a left shift operation on two ranges: - - [RES_LB, RES_UB] = [VR0_LB, VR0_UB] << [VR1_LB, VR1_LB] - - Return TRUE if we were able to perform the operation. - - NOTE: The resulting range must be canonicalized by the caller - because its contents components may be swapped. */ - -bool -wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub, - signop sign, unsigned prec, - const wide_int &vr0_lb, const wide_int &vr0_ub, - const wide_int &vr1_lb, const wide_int &vr1_ub, - bool overflow_undefined) -{ - /* Transform left shifts by constants into multiplies. */ - if (wi::eq_p (vr1_lb, vr1_ub)) - { - unsigned shift = vr1_ub.to_uhwi (); - wide_int tmp = wi::set_bit_in_zero (shift, prec); - return wide_int_range_multiplicative_op (res_lb, res_ub, - MULT_EXPR, sign, prec, - vr0_lb, vr0_ub, tmp, tmp, - /*overflow_undefined=*/false); - } - - int overflow_pos = prec; - if (sign == SIGNED) - overflow_pos -= 1; - int bound_shift = overflow_pos - vr1_ub.to_shwi (); - /* If bound_shift == HOST_BITS_PER_WIDE_INT, the llshift can - overflow. However, for that to happen, vr1.max needs to be - zero, which means vr1 is a singleton range of zero, which - means it should be handled by the previous LSHIFT_EXPR - if-clause. */ - wide_int bound = wi::set_bit_in_zero (bound_shift, prec); - wide_int complement = ~(bound - 1); - wide_int low_bound, high_bound; - bool in_bounds = false; - if (sign == UNSIGNED) - { - low_bound = bound; - high_bound = complement; - if (wi::ltu_p (vr0_ub, low_bound)) - { - /* [5, 6] << [1, 2] == [10, 24]. */ - /* We're shifting out only zeroes, the value increases - monotonically. */ - in_bounds = true; - } - else if (wi::ltu_p (high_bound, vr0_lb)) - { - /* [0xffffff00, 0xffffffff] << [1, 2] - == [0xfffffc00, 0xfffffffe]. */ - /* We're shifting out only ones, the value decreases - monotonically. */ - in_bounds = true; - } - } - else - { - /* [-1, 1] << [1, 2] == [-4, 4]. */ - low_bound = complement; - high_bound = bound; - if (wi::lts_p (vr0_ub, high_bound) - && wi::lts_p (low_bound, vr0_lb)) - { - /* For non-negative numbers, we're shifting out only - zeroes, the value increases monotonically. - For negative numbers, we're shifting out only ones, the - value decreases monotomically. */ - in_bounds = true; - } - } - if (in_bounds) - return wide_int_range_multiplicative_op (res_lb, res_ub, - LSHIFT_EXPR, sign, prec, - vr0_lb, vr0_ub, - vr1_lb, vr1_ub, - overflow_undefined); - return false; -} - -/* Return TRUE if a bit operation on two ranges can be easily - optimized in terms of a mask. - - Basically, for BIT_AND_EXPR or BIT_IOR_EXPR see if we can optimize: - - [LB, UB] op Z - into: - [LB op Z, UB op Z] - - It is up to the caller to perform the actual folding above. */ - -static bool -wide_int_range_can_optimize_bit_op (tree_code code, - const wide_int &lb, const wide_int &ub, - const wide_int &mask) - -{ - if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR) - return false; - /* If Z is a constant which (for op | its bitwise not) has n - consecutive least significant bits cleared followed by m 1 - consecutive bits set immediately above it and either - m + n == precision, or (x >> (m + n)) == (y >> (m + n)). - - The least significant n bits of all the values in the range are - cleared or set, the m bits above it are preserved and any bits - above these are required to be the same for all values in the - range. */ - - wide_int w = mask; - int m = 0, n = 0; - if (code == BIT_IOR_EXPR) - w = ~w; - if (wi::eq_p (w, 0)) - n = w.get_precision (); - else - { - n = wi::ctz (w); - w = ~(w | wi::mask (n, false, w.get_precision ())); - if (wi::eq_p (w, 0)) - m = w.get_precision () - n; - else - m = wi::ctz (w) - n; - } - wide_int new_mask = wi::mask (m + n, true, w.get_precision ()); - if ((new_mask & lb) == (new_mask & ub)) - return true; - - return false; -} - -/* Helper function for wide_int_range_optimize_bit_op. - - Calculates bounds and mask for a pair of ranges. The mask is the - singleton range among the ranges, if any. The bounds are the - bounds for the remaining range. */ - -bool -wide_int_range_get_mask_and_bounds (wide_int &mask, - wide_int &lower_bound, - wide_int &upper_bound, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max) -{ - if (wi::eq_p (vr1_min, vr1_max)) - { - mask = vr1_min; - lower_bound = vr0_min; - upper_bound = vr0_max; - return true; - } - else if (wi::eq_p (vr0_min, vr0_max)) - { - mask = vr0_min; - lower_bound = vr1_min; - upper_bound = vr1_max; - return true; - } - return false; -} - -/* Optimize a bit operation (BIT_AND_EXPR or BIT_IOR_EXPR) if - possible. If so, return TRUE and store the result in - [RES_LB, RES_UB]. */ - -bool -wide_int_range_optimize_bit_op (wide_int &res_lb, wide_int &res_ub, - enum tree_code code, - signop sign, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max) -{ - gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); - - wide_int lower_bound, upper_bound, mask; - if (!wide_int_range_get_mask_and_bounds (mask, lower_bound, upper_bound, - vr0_min, vr0_max, vr1_min, vr1_max)) - return false; - if (wide_int_range_can_optimize_bit_op (code, - lower_bound, upper_bound, mask)) - { - wi::overflow_type ovf; - wide_int_binop (res_lb, code, lower_bound, mask, sign, &ovf); - wide_int_binop (res_ub, code, upper_bound, mask, sign, &ovf); - return true; - } - return false; -} - -/* Calculate the XOR of two ranges and store the result in [WMIN,WMAX]. - The two input ranges are described by their MUST_BE_NONZERO and - MAY_BE_NONZERO bit masks. - - Return TRUE if we were able to successfully calculate the new range. */ - -bool -wide_int_range_bit_xor (wide_int &wmin, wide_int &wmax, - signop sign, - unsigned prec, - const wide_int &must_be_nonzero0, - const wide_int &may_be_nonzero0, - const wide_int &must_be_nonzero1, - const wide_int &may_be_nonzero1) -{ - wide_int result_zero_bits = ((must_be_nonzero0 & must_be_nonzero1) - | ~(may_be_nonzero0 | may_be_nonzero1)); - wide_int result_one_bits - = (wi::bit_and_not (must_be_nonzero0, may_be_nonzero1) - | wi::bit_and_not (must_be_nonzero1, may_be_nonzero0)); - wmax = ~result_zero_bits; - wmin = result_one_bits; - /* If the range has all positive or all negative values, the result - is better than VARYING. */ - if (wi::lt_p (wmin, 0, sign) || wi::ge_p (wmax, 0, sign)) - return true; - wmin = wi::min_value (prec, sign); - wmax = wi::max_value (prec, sign); - return false; -} - -/* Calculate the IOR of two ranges and store the result in [WMIN,WMAX]. - Return TRUE if we were able to successfully calculate the new range. */ - -bool -wide_int_range_bit_ior (wide_int &wmin, wide_int &wmax, - signop sign, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max, - const wide_int &must_be_nonzero0, - const wide_int &may_be_nonzero0, - const wide_int &must_be_nonzero1, - const wide_int &may_be_nonzero1) -{ - if (wide_int_range_optimize_bit_op (wmin, wmax, BIT_IOR_EXPR, sign, - vr0_min, vr0_max, - vr1_min, vr1_max)) - return true; - wmin = must_be_nonzero0 | must_be_nonzero1; - wmax = may_be_nonzero0 | may_be_nonzero1; - /* If the input ranges contain only positive values we can - truncate the minimum of the result range to the maximum - of the input range minima. */ - if (wi::ge_p (vr0_min, 0, sign) - && wi::ge_p (vr1_min, 0, sign)) - { - wmin = wi::max (wmin, vr0_min, sign); - wmin = wi::max (wmin, vr1_min, sign); - } - /* If either input range contains only negative values - we can truncate the minimum of the result range to the - respective minimum range. */ - if (wi::lt_p (vr0_max, 0, sign)) - wmin = wi::max (wmin, vr0_min, sign); - if (wi::lt_p (vr1_max, 0, sign)) - wmin = wi::max (wmin, vr1_min, sign); - /* If the limits got swapped around, indicate error so we can adjust - the range to VARYING. */ - if (wi::gt_p (wmin, wmax,sign)) - return false; - return true; -} - -/* Calculate the bitwise AND of two ranges and store the result in [WMIN,WMAX]. - Return TRUE if we were able to successfully calculate the new range. */ - -bool -wide_int_range_bit_and (wide_int &wmin, wide_int &wmax, - signop sign, - unsigned prec, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max, - const wide_int &must_be_nonzero0, - const wide_int &may_be_nonzero0, - const wide_int &must_be_nonzero1, - const wide_int &may_be_nonzero1) -{ - if (wide_int_range_optimize_bit_op (wmin, wmax, BIT_AND_EXPR, sign, - vr0_min, vr0_max, - vr1_min, vr1_max)) - return true; - wmin = must_be_nonzero0 & must_be_nonzero1; - wmax = may_be_nonzero0 & may_be_nonzero1; - /* If both input ranges contain only negative values we can - truncate the result range maximum to the minimum of the - input range maxima. */ - if (wi::lt_p (vr0_max, 0, sign) && wi::lt_p (vr1_max, 0, sign)) - { - wmax = wi::min (wmax, vr0_max, sign); - wmax = wi::min (wmax, vr1_max, sign); - } - /* If either input range contains only non-negative values - we can truncate the result range maximum to the respective - maximum of the input range. */ - if (wi::ge_p (vr0_min, 0, sign)) - wmax = wi::min (wmax, vr0_max, sign); - if (wi::ge_p (vr1_min, 0, sign)) - wmax = wi::min (wmax, vr1_max, sign); - /* PR68217: In case of signed & sign-bit-CST should - result in [-INF, 0] instead of [-INF, INF]. */ - if (wi::gt_p (wmin, wmax, sign)) - { - wide_int sign_bit = wi::set_bit_in_zero (prec - 1, prec); - if (sign == SIGNED - && ((wi::eq_p (vr0_min, vr0_max) - && !wi::cmps (vr0_min, sign_bit)) - || (wi::eq_p (vr1_min, vr1_max) - && !wi::cmps (vr1_min, sign_bit)))) - { - wmin = wi::min_value (prec, sign); - wmax = wi::zero (prec); - } - } - /* If the limits got swapped around, indicate error so we can adjust - the range to VARYING. */ - if (wi::gt_p (wmin, wmax,sign)) - return false; - return true; -} - -/* Calculate TRUNC_MOD_EXPR on two ranges and store the result in - [WMIN,WMAX]. */ - -void -wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax, - signop sign, - unsigned prec, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max) -{ - wide_int tmp; - - /* ABS (A % B) < ABS (B) and either - 0 <= A % B <= A or A <= A % B <= 0. */ - wmax = vr1_max - 1; - if (sign == SIGNED) - { - tmp = -1 - vr1_min; - wmax = wi::smax (wmax, tmp); - } - - if (sign == UNSIGNED) - wmin = wi::zero (prec); - else - { - wmin = -wmax; - tmp = vr0_min; - if (wi::gts_p (tmp, 0)) - tmp = wi::zero (prec); - wmin = wi::smax (wmin, tmp); - } - tmp = vr0_max; - if (sign == SIGNED && wi::neg_p (tmp)) - tmp = wi::zero (prec); - wmax = wi::min (wmax, tmp, sign); -} - -/* Calculate ABS_EXPR on a range and store the result in [MIN, MAX]. */ - -bool -wide_int_range_abs (wide_int &min, wide_int &max, - signop sign, unsigned prec, - const wide_int &vr0_min, const wide_int &vr0_max, - bool overflow_undefined) -{ - /* Pass through VR0 the easy cases. */ - if (sign == UNSIGNED || wi::ge_p (vr0_min, 0, sign)) - { - min = vr0_min; - max = vr0_max; - return true; - } - - /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a - useful range. */ - wide_int min_value = wi::min_value (prec, sign); - wide_int max_value = wi::max_value (prec, sign); - if (!overflow_undefined && wi::eq_p (vr0_min, min_value)) - return false; - - /* ABS_EXPR may flip the range around, if the original range - included negative values. */ - if (wi::eq_p (vr0_min, min_value)) - min = max_value; - else - min = wi::abs (vr0_min); - if (wi::eq_p (vr0_max, min_value)) - max = max_value; - else - max = wi::abs (vr0_max); - - /* If the range contains zero then we know that the minimum value in the - range will be zero. */ - if (wi::le_p (vr0_min, 0, sign) && wi::ge_p (vr0_max, 0, sign)) - { - if (wi::gt_p (min, max, sign)) - max = min; - min = wi::zero (prec); - } - else - { - /* If the range was reversed, swap MIN and MAX. */ - if (wi::gt_p (min, max, sign)) - std::swap (min, max); - } - - /* If the new range has its limits swapped around (MIN > MAX), then - the operation caused one of them to wrap around. The only thing - we know is that the result is positive. */ - if (wi::gt_p (min, max, sign)) - { - min = wi::zero (prec); - max = max_value; - } - return true; -} - -/* Calculate ABSU_EXPR on a range and store the result in [MIN, MAX]. */ - -void -wide_int_range_absu (wide_int &min, wide_int &max, - unsigned prec, const wide_int &vr0_min, - const wide_int &vr0_max) -{ - /* Pass through VR0 the easy cases. */ - if (wi::ges_p (vr0_min, 0)) - { - min = vr0_min; - max = vr0_max; - return; - } - - min = wi::abs (vr0_min); - max = wi::abs (vr0_max); - - /* If the range contains zero then we know that the minimum value in the - range will be zero. */ - if (wi::ges_p (vr0_max, 0)) - { - if (wi::gtu_p (min, max)) - max = min; - min = wi::zero (prec); - } - else - /* Otherwise, swap MIN and MAX. */ - std::swap (min, max); -} - -/* Convert range in [VR0_MIN, VR0_MAX] with INNER_SIGN and INNER_PREC, - to a range in [MIN, MAX] with OUTER_SIGN and OUTER_PREC. - - Return TRUE if we were able to successfully calculate the new range. - - Caller is responsible for canonicalizing the resulting range. */ - -bool -wide_int_range_convert (wide_int &min, wide_int &max, - signop inner_sign, - unsigned inner_prec, - signop outer_sign, - unsigned outer_prec, - const wide_int &vr0_min, - const wide_int &vr0_max) -{ - /* If the conversion is not truncating we can convert the min and - max values and canonicalize the resulting range. Otherwise we - can do the conversion if the size of the range is less than what - the precision of the target type can represent. */ - if (outer_prec >= inner_prec - || wi::rshift (wi::sub (vr0_max, vr0_min), - wi::uhwi (outer_prec, inner_prec), - inner_sign) == 0) - { - min = wide_int::from (vr0_min, outer_prec, inner_sign); - max = wide_int::from (vr0_max, outer_prec, inner_sign); - return (!wi::eq_p (min, wi::min_value (outer_prec, outer_sign)) - || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign))); - } - return false; -} - -/* Calculate a division operation on two ranges and store the result in - [WMIN, WMAX] U [EXTRA_MIN, EXTRA_MAX]. - - If EXTRA_RANGE_P is set upon return, EXTRA_MIN/EXTRA_MAX hold - meaningful information, otherwise they should be ignored. - - Return TRUE if we were able to successfully calculate the new range. */ - -bool -wide_int_range_div (wide_int &wmin, wide_int &wmax, - tree_code code, signop sign, unsigned prec, - const wide_int ÷nd_min, const wide_int ÷nd_max, - const wide_int &divisor_min, const wide_int &divisor_max, - bool overflow_undefined, - bool &extra_range_p, - wide_int &extra_min, wide_int &extra_max) -{ - extra_range_p = false; - - /* If we know we won't divide by zero, just do the division. */ - if (!wide_int_range_includes_zero_p (divisor_min, divisor_max, sign)) - return wide_int_range_multiplicative_op (wmin, wmax, code, sign, prec, - dividend_min, dividend_max, - divisor_min, divisor_max, - overflow_undefined); - - /* If flag_non_call_exceptions, we must not eliminate a division - by zero. */ - if (cfun->can_throw_non_call_exceptions) - return false; - - /* If we're definitely dividing by zero, there's nothing to do. */ - if (wide_int_range_zero_p (divisor_min, divisor_max, prec)) - return false; - - /* Perform the division in 2 parts, [LB, -1] and [1, UB], - which will skip any division by zero. - - First divide by the negative numbers, if any. */ - if (wi::neg_p (divisor_min, sign)) - { - if (!wide_int_range_multiplicative_op (wmin, wmax, - code, sign, prec, - dividend_min, dividend_max, - divisor_min, wi::minus_one (prec), - overflow_undefined)) - return false; - extra_range_p = true; - } - /* Then divide by the non-zero positive numbers, if any. */ - if (wi::gt_p (divisor_max, wi::zero (prec), sign)) - { - if (!wide_int_range_multiplicative_op (extra_range_p ? extra_min : wmin, - extra_range_p ? extra_max : wmax, - code, sign, prec, - dividend_min, dividend_max, - wi::one (prec), divisor_max, - overflow_undefined)) - return false; - } - else - extra_range_p = false; - return true; -} diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h deleted file mode 100644 index fc9af72..0000000 --- a/gcc/wide-int-range.h +++ /dev/null @@ -1,188 +0,0 @@ -/* Support routines for range operations on wide ints. - Copyright (C) 2018-2019 Free Software Foundation, Inc. - -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 -. */ - -#ifndef GCC_WIDE_INT_RANGE_H -#define GCC_WIDE_INT_RANGE_H - -extern bool wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub, - enum tree_code code, signop sign, - const wide_int &, const wide_int &, - const wide_int &, const wide_int &, - bool overflow_undefined); -extern bool wide_int_range_mult_wrapping (wide_int &res_lb, - wide_int &res_ub, - signop sign, - unsigned prec, - const wide_int &min0_, - const wide_int &max0_, - const wide_int &min1_, - const wide_int &max1_); -extern bool wide_int_range_multiplicative_op (wide_int &res_lb, - wide_int &res_ub, - enum tree_code code, - signop sign, - unsigned prec, - const wide_int &vr0_lb, - const wide_int &vr0_ub, - const wide_int &vr1_lb, - const wide_int &vr1_ub, - bool overflow_undefined); -extern bool wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub, - signop sign, unsigned prec, - const wide_int &, const wide_int &, - const wide_int &, const wide_int &, - bool overflow_undefined); -extern void wide_int_range_set_zero_nonzero_bits (signop, - const wide_int &lb, - const wide_int &ub, - wide_int &may_be_nonzero, - wide_int &must_be_nonzero); -extern bool wide_int_range_optimize_bit_op (wide_int &res_lb, wide_int &res_ub, - enum tree_code code, - signop sign, - const wide_int &vr0_lb, - const wide_int &vr0_ub, - const wide_int &vr1_lb, - const wide_int &vr1_ub); -extern bool wide_int_range_get_mask_and_bounds (wide_int &mask, - wide_int &lower_bound, - wide_int &upper_bound, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max); -extern bool wide_int_range_bit_xor (wide_int &wmin, wide_int &wmax, - signop sign, - unsigned prec, - const wide_int &must_be_nonzero0, - const wide_int &may_be_nonzero0, - const wide_int &must_be_nonzero1, - const wide_int &may_be_nonzero1); -extern bool wide_int_range_bit_ior (wide_int &wmin, wide_int &wmax, - signop sign, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max, - const wide_int &must_be_nonzero0, - const wide_int &may_be_nonzero0, - const wide_int &must_be_nonzero1, - const wide_int &may_be_nonzero1); -extern bool wide_int_range_bit_and (wide_int &wmin, wide_int &wmax, - signop sign, - unsigned prec, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max, - const wide_int &must_be_nonzero0, - const wide_int &may_be_nonzero0, - const wide_int &must_be_nonzero1, - const wide_int &may_be_nonzero1); -extern void wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax, - signop sign, - unsigned prec, - const wide_int &vr0_min, - const wide_int &vr0_max, - const wide_int &vr1_min, - const wide_int &vr1_max); -extern bool wide_int_range_abs (wide_int &min, wide_int &max, - signop sign, unsigned prec, - const wide_int &vr0_min, - const wide_int &vr0_max, - bool overflow_undefined); -extern void wide_int_range_absu (wide_int &min, wide_int &max, - unsigned prec, - const wide_int &vr0_min, - const wide_int &vr0_max); -extern bool wide_int_range_convert (wide_int &min, wide_int &max, - signop inner_sign, - unsigned inner_prec, - signop outer_sign, - unsigned outer_prec, - const wide_int &vr0_min, - const wide_int &vr0_max); -extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax, - enum tree_code code, - signop sign, unsigned prec, - const wide_int ÷nd_min, - const wide_int ÷nd_max, - const wide_int &divisor_min, - const wide_int &divisor_max, - bool overflow_undefined, - bool &extra_range_p, - wide_int &extra_min, wide_int &extra_max); - -/* Return TRUE if shifting by range [MIN, MAX] is undefined behavior, - interpreting MIN and MAX according to SIGN. */ - -inline bool -wide_int_range_shift_undefined_p (signop sign, unsigned prec, - const wide_int &min, const wide_int &max) -{ - /* ?? Note: The original comment said this only applied to - RSHIFT_EXPR, but it was being applied to both left and right - shifts. */ - - /* Shifting by any values outside [0..prec-1], gets undefined - behavior from the shift operation. We cannot even trust - SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl - shifts, and the operation at the tree level may be widened. */ - return wi::lt_p (min, 0, sign) || wi::ge_p (max, prec, sign); -} - -/* Calculate MIN/MAX_EXPR of two ranges and store the result in [MIN, MAX]. */ - -inline bool -wide_int_range_min_max (wide_int &min, wide_int &max, - tree_code code, - signop sign, unsigned prec, - const wide_int &vr0_min, const wide_int &vr0_max, - const wide_int &vr1_min, const wide_int &vr1_max) -{ - wi::overflow_type overflow; - wide_int_binop (min, code, vr0_min, vr1_min, sign, &overflow); - wide_int_binop (max, code, vr0_max, vr1_max, sign, &overflow); - /* If the new range covers the entire domain, that's really no range - at all. */ - if (min == wi::min_value (prec, sign) - && max == wi::max_value (prec, sign)) - return false; - return true; -} - -/* Return TRUE if 0 is within [WMIN, WMAX]. */ - -inline bool -wide_int_range_includes_zero_p (const wide_int &wmin, const wide_int &wmax, - signop sign) -{ - return wi::le_p (wmin, 0, sign) && wi::ge_p (wmax, 0, sign); -} - -/* Return TRUE if [WMIN, WMAX] is the singleton 0. */ - -inline bool -wide_int_range_zero_p (const wide_int &wmin, const wide_int &wmax, - unsigned prec) -{ - return wmin == wmax && wi::eq_p (wmin, wi::zero (prec)); -} - -#endif /* GCC_WIDE_INT_RANGE_H */ -- cgit v1.1 From f61e54e59cda5a2e281d525d3f87ffa179fae1ae Mon Sep 17 00:00:00 2001 From: Mark Eggleston Date: Thu, 3 Oct 2019 09:40:23 +0000 Subject: Character typenames in errors and warnings Character type names now incorporate length, kind is only shown if the default character is not being used. Examples: character(7) is reported as CHARACTER(7) character(len=20,kind=4) is reported as CHARACTER(20,4) dummy character variables with assumed length: character(*) is reported as CHARACTER(*) character(*,kind=4) is reported as CHARACTER(*,4) From-SVN: r276505 --- gcc/fortran/ChangeLog | 44 +++++++++++++ gcc/fortran/array.c | 2 +- gcc/fortran/check.c | 10 +-- gcc/fortran/decl.c | 2 +- gcc/fortran/expr.c | 8 +-- gcc/fortran/gfortran.h | 2 + gcc/fortran/interface.c | 11 ++-- gcc/fortran/intrinsic.c | 27 ++++---- gcc/fortran/misc.c | 71 +++++++++++++++++++- gcc/fortran/resolve.c | 32 ++++----- gcc/testsuite/ChangeLog | 14 ++++ gcc/testsuite/gfortran.dg/bad_operands.f90 | 10 +++ gcc/testsuite/gfortran.dg/character_mismatch.f90 | 76 ++++++++++++++++++++++ gcc/testsuite/gfortran.dg/compare_interfaces.f90 | 73 +++++++++++++++++++++ .../gfortran.dg/hollerith_to_char_parameter_1.f90 | 11 ++++ .../gfortran.dg/hollerith_to_char_parameter_2.f90 | 12 ++++ .../gfortran.dg/widechar_intrinsics_1.f90 | 12 ++-- .../gfortran.dg/widechar_intrinsics_2.f90 | 10 +-- .../gfortran.dg/widechar_intrinsics_3.f90 | 4 +- 19 files changed, 373 insertions(+), 58 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/bad_operands.f90 create mode 100644 gcc/testsuite/gfortran.dg/character_mismatch.f90 create mode 100644 gcc/testsuite/gfortran.dg/compare_interfaces.f90 create mode 100644 gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_1.f90 create mode 100644 gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_2.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index ea1177f..64812f2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,47 @@ +2019-10-03 Mark Eggleston + + * array.c (check_element_type): Call gfc_typename with the gfc_expr + "expr" instead of its gfc_typespec "ts". + * check.c (gfc_check_co_reduce): Call gfc_typename with the gfc_expr + "a" instead of its gfc_typespec "ts". + (gfc_check_co_reduce): Call gfc_typename with the gfc_expr "a" instead + of its gfc_typespec "ts". + (gfc_check_eoshift): Call gfc_typename with the gfc_expr "array" + instead of its gfc_typespec ts. + (gfc_check_same_type_as): In two calls to gfc_typename use "a" and "b" + of type gfc_expr instead of the "ts" fields of "a" and "b" + * decl.c (variable_decl): Call gfc_typename with the gfc_expr + "initializer" instead of its gfc_typespec "ts". + * expr.c (gfc_check_assign): Use "rvalue" and "lvalue" of type gfc_expr + in calls to gfc_typename instead of their "ts" fields of type + gfc_typespec. + (gfc_check_pointer_assign): Use "rvalue" and "lvalue" of type gfc_expr + in calls to gfc_typename instead of their "ts" fields of type + gfc_typespec. + * gfortran.h: Add prototypes for gfc_dummy_typename and a new function + gfc_typename for gfc_expr *. + *interface.c (gfc_check_dummy_characteristics): Use gfc_dummy_typename + for the dummy variable. + (compare_parameter): Use gfc_dummy_typename for the formal argument. + Use "actual" of type gfc_expr in call to gfc_typename for the actual + argument. + * intrinsic.c (check_arglist): Use gfc_dummy_typename for the formal + argument. Use expressions of type gfc_expr from the argument list to + call gfc_typename. + (gfc_convert_type_warn): New local variable "is_char_constant" set if + the expression type is a character constant. At the "bad" label + determine source type name by calling gfc_typename with either "expr" + for character constants or "from_ts" and use that in the warning + messages instead of the original call to gfc_typename. + * misc.c (gfc_typename): New function for gfc_expr *, use for where + character types are possible it can get the character length from + gfc_expr for character literals. + (gfc_dummy_typename): New functionfor gfc_typespec *, if no character + length is present the character type is assumed and the appropriate + string is return otherwise it calls gfc_typename for gfc_typespec *. + (gfc_typespec): for character types construct the type name with length + and kind (if it is not default kind). + 2019-10-02 Steven G. Kargl PR fortran/91784 diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c index ba8a816..3a504eb 100644 --- a/gcc/fortran/array.c +++ b/gcc/fortran/array.c @@ -1358,7 +1358,7 @@ check_element_type (gfc_expr *expr, bool convert) gfc_error ("Element in %s array constructor at %L is %s", gfc_typename (&constructor_ts), &expr->where, - gfc_typename (&expr->ts)); + gfc_typename (expr)); cons_state = CONS_BAD; return 1; diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index 98203bc..87a8196 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -2266,7 +2266,7 @@ gfc_check_co_reduce (gfc_expr *a, gfc_expr *op, gfc_expr *result_image, { gfc_error ("The A argument at %L has type %s but the function passed as " "OPERATOR at %L returns %s", - &a->where, gfc_typename (&a->ts), &op->where, + &a->where, gfc_typename (a), &op->where, gfc_typename (&sym->result->ts)); return false; } @@ -2276,7 +2276,7 @@ gfc_check_co_reduce (gfc_expr *a, gfc_expr *op, gfc_expr *result_image, gfc_error ("The function passed as OPERATOR at %L has arguments of type " "%s and %s but shall have type %s", &op->where, gfc_typename (&formal->sym->ts), - gfc_typename (&formal->next->sym->ts), gfc_typename (&a->ts)); + gfc_typename (&formal->next->sym->ts), gfc_typename (a)); return false; } if (op->rank || attr.allocatable || attr.pointer || formal->sym->as @@ -2844,7 +2844,7 @@ gfc_check_eoshift (gfc_expr *array, gfc_expr *shift, gfc_expr *boundary, "of type %qs", gfc_current_intrinsic_arg[2]->name, gfc_current_intrinsic, &array->where, gfc_current_intrinsic_arg[0]->name, - gfc_typename (&array->ts)); + gfc_typename (array)); return false; } } @@ -4808,7 +4808,7 @@ gfc_check_same_type_as (gfc_expr *a, gfc_expr *b) "cannot be of type %s", gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic, - &a->where, gfc_typename (&a->ts)); + &a->where, gfc_typename (a)); return false; } @@ -4827,7 +4827,7 @@ gfc_check_same_type_as (gfc_expr *a, gfc_expr *b) "cannot be of type %s", gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic, - &b->where, gfc_typename (&b->ts)); + &b->where, gfc_typename (b)); return false; } diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 3ba61a0..96b6f3f 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -2908,7 +2908,7 @@ variable_decl (int elem) { gfc_error ("Incompatible initialization between a derived type " "entity and an entity with %qs type at %C", - gfc_typename (&initializer->ts)); + gfc_typename (initializer)); m = MATCH_ERROR; goto cleanup; } diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index 5d3480e..9f638fe 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -3693,8 +3693,7 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform, return true; gfc_error ("BOZ literal constant near %L cannot be assigned to a " - "%qs variable", &rvalue->where, gfc_typename (&lvalue->ts)); - + "%qs variable", &rvalue->where, gfc_typename (lvalue)); return false; } @@ -3726,7 +3725,7 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform, where = lvalue->where.lb ? &lvalue->where : &rvalue->where; gfc_error ("Incompatible types in DATA statement at %L; attempted " "conversion of %s to %s", where, - gfc_typename (&rvalue->ts), gfc_typename (&lvalue->ts)); + gfc_typename (rvalue), gfc_typename (lvalue)); return false; } @@ -4139,8 +4138,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue, else if (!suppress_type_test) gfc_error ("Different types in pointer assignment at %L; " "attempted assignment of %s to %s", &lvalue->where, - gfc_typename (&rvalue->ts), - gfc_typename (&lvalue->ts)); + gfc_typename (rvalue), gfc_typename (lvalue)); return false; } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index a70978b..d84d1fa 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2884,7 +2884,9 @@ void gfc_end_source_files (void); void gfc_clear_ts (gfc_typespec *); FILE *gfc_open_file (const char *); const char *gfc_basic_typename (bt); +const char *gfc_dummy_typename (gfc_typespec *); const char *gfc_typename (gfc_typespec *); +const char *gfc_typename (gfc_expr *); const char *gfc_op2string (gfc_intrinsic_op); const char *gfc_code2string (const mstring *, int); int gfc_string2code (const mstring *, const char *); diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 08e4f06..3313e72 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -1330,7 +1330,8 @@ gfc_check_dummy_characteristics (gfc_symbol *s1, gfc_symbol *s2, || !compare_type_characteristics (s2, s1)) { snprintf (errmsg, err_len, "Type mismatch in argument '%s' (%s/%s)", - s1->name, gfc_typename (&s1->ts), gfc_typename (&s2->ts)); + s1->name, gfc_dummy_typename (&s1->ts), + gfc_dummy_typename (&s2->ts)); return false; } if (!compare_rank (s1, s2)) @@ -2338,15 +2339,15 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual, "and actual argument at %L (%s/%s).", &actual->where, &formal->declared_at, - gfc_typename (&actual->ts), - gfc_typename (&formal->ts)); + gfc_typename (actual), + gfc_dummy_typename (&formal->ts)); formal->error = 1; } else gfc_error_opt (0, "Type mismatch in argument %qs at %L; passed %s " - "to %s", formal->name, where, gfc_typename (&actual->ts), - gfc_typename (&formal->ts)); + "to %s", formal->name, where, gfc_typename (actual), + gfc_dummy_typename (&formal->ts)); } return false; } diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index 764e350..ac5af10 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4363,11 +4363,12 @@ check_arglist (gfc_actual_arglist **ap, gfc_intrinsic_sym *sym, if (!gfc_compare_types (&ts, &actual->expr->ts)) { if (error_flag) - gfc_error ("Type of argument %qs in call to %qs at %L should " - "be %s, not %s", gfc_current_intrinsic_arg[i]->name, - gfc_current_intrinsic, &actual->expr->where, - gfc_typename (&formal->ts), - gfc_typename (&actual->expr->ts)); + gfc_error ("In call to %qs at %L, type mismatch in argument " + "%qs; pass %qs to %qs", gfc_current_intrinsic, + &actual->expr->where, + gfc_current_intrinsic_arg[i]->name, + gfc_typename (actual->expr), + gfc_dummy_typename (&formal->ts)); return false; } @@ -5076,6 +5077,8 @@ gfc_convert_type_warn (gfc_expr *expr, gfc_typespec *ts, int eflag, int wflag) gfc_expr *new_expr; int rank; mpz_t *shape; + bool is_char_constant = (expr->expr_type == EXPR_CONSTANT) + && (expr->ts.type == BT_CHARACTER); from_ts = expr->ts; /* expr->ts gets clobbered */ @@ -5117,7 +5120,7 @@ gfc_convert_type_warn (gfc_expr *expr, gfc_typespec *ts, int eflag, int wflag) if ((gfc_option.warn_std & sym->standard) != 0) { gfc_warning_now (0, "Extension: Conversion from %s to %s at %L", - gfc_typename (&from_ts), gfc_typename (ts), + gfc_typename (&from_ts), gfc_dummy_typename (ts), &expr->where); } else if (wflag) @@ -5179,7 +5182,7 @@ gfc_convert_type_warn (gfc_expr *expr, gfc_typespec *ts, int eflag, int wflag) /* If HOLLERITH is involved, all bets are off. */ if (warn_conversion) gfc_warning_now (OPT_Wconversion, "Conversion from %s to %s at %L", - gfc_typename (&from_ts), gfc_typename (ts), + gfc_typename (&from_ts), gfc_dummy_typename (ts), &expr->where); } else @@ -5231,15 +5234,17 @@ gfc_convert_type_warn (gfc_expr *expr, gfc_typespec *ts, int eflag, int wflag) return true; bad: + const char *type_name = is_char_constant ? gfc_typename (expr) + : gfc_typename (&from_ts); if (eflag == 1) { - gfc_error ("Cannot convert %s to %s at %L", - gfc_typename (&from_ts), gfc_typename (ts), &expr->where); + gfc_error ("Cannot convert %s to %s at %L", type_name, gfc_typename (ts), + &expr->where); return false; } - gfc_internal_error ("Cannot convert %qs to %qs at %L", - gfc_typename (&from_ts), gfc_typename (ts), + gfc_internal_error ("Cannot convert %qs to %qs at %L", type_name, + gfc_typename (ts), &expr->where); /* Not reached */ } diff --git a/gcc/fortran/misc.c b/gcc/fortran/misc.c index eed203d..97df9ee 100644 --- a/gcc/fortran/misc.c +++ b/gcc/fortran/misc.c @@ -129,6 +129,7 @@ gfc_typename (gfc_typespec *ts) static int flag = 0; char *buffer; gfc_typespec *ts1; + gfc_charlen_t length = 0; buffer = flag ? buffer1 : buffer2; flag = !flag; @@ -148,7 +149,13 @@ gfc_typename (gfc_typespec *ts) sprintf (buffer, "LOGICAL(%d)", ts->kind); break; case BT_CHARACTER: - sprintf (buffer, "CHARACTER(%d)", ts->kind); + if (ts->u.cl && ts->u.cl->length) + length = gfc_mpz_get_hwi (ts->u.cl->length->value.integer); + if (ts->kind == gfc_default_character_kind) + sprintf (buffer, "CHARACTER(" HOST_WIDE_INT_PRINT_DEC ")", length); + else + sprintf (buffer, "CHARACTER(" HOST_WIDE_INT_PRINT_DEC ",%d)", length, + ts->kind); break; case BT_HOLLERITH: sprintf (buffer, "HOLLERITH"); @@ -186,6 +193,68 @@ gfc_typename (gfc_typespec *ts) } +const char * +gfc_typename (gfc_expr *ex) +{ + /* 34 character buffer: 14 for "CHARACTER(n,4)", n can be upto 20 characters, + add 19 for the extra width and 1 for '\0' */ + static char buffer1[34]; + static char buffer2[34]; + static bool flag = false; + char *buffer; + gfc_charlen_t length; + buffer = flag ? buffer1 : buffer2; + flag = !flag; + + if (ex->ts.type == BT_CHARACTER) + { + if (ex->ts.u.cl && ex->ts.u.cl->length) + length = gfc_mpz_get_hwi (ex->ts.u.cl->length->value.integer); + else + length = ex->value.character.length; + if (ex->ts.kind == gfc_default_character_kind) + sprintf (buffer, "CHARACTER(" HOST_WIDE_INT_PRINT_DEC ")", length); + else + sprintf (buffer, "CHARACTER(" HOST_WIDE_INT_PRINT_DEC ",%d)", length, + ex->ts.kind); + return buffer; + } + return gfc_typename(&ex->ts); +} + +/* The type of a dummy variable can also be CHARACTER(*). */ + +const char * +gfc_dummy_typename (gfc_typespec *ts) +{ + static char buffer1[15]; /* 15 for "CHARACTER(*,4)" + '\0'. */ + static char buffer2[15]; + static bool flag = false; + char *buffer; + + buffer = flag ? buffer1 : buffer2; + flag = !flag; + + if (ts->type == BT_CHARACTER) + { + bool has_length = false; + if (ts->u.cl) + has_length = ts->u.cl->length != NULL; + if (!has_length) + { + if (ts->kind == gfc_default_character_kind) + sprintf(buffer, "CHARACTER(*)"); + else if (ts->kind < 10) + sprintf(buffer, "CHARACTER(*,%d)", ts->kind); + else + sprintf(buffer, "CHARACTER(*,?)"); + return buffer; + } + } + return gfc_typename(ts); +} + + /* Given an mstring array and a code, locate the code in the table, returning a pointer to the string. */ diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index a792547..20ecafd 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -3980,7 +3980,7 @@ resolve_operator (gfc_expr *e) } sprintf (msg, _("Operand of unary numeric operator %%<%s%%> at %%L is %s"), - gfc_op2string (e->value.op.op), gfc_typename (&e->ts)); + gfc_op2string (e->value.op.op), gfc_typename (e)); goto bad_op; case INTRINSIC_PLUS: @@ -4002,8 +4002,8 @@ resolve_operator (gfc_expr *e) else sprintf (msg, _("Operands of binary numeric operator %%<%s%%> at %%L are %s/%s"), - gfc_op2string (e->value.op.op), gfc_typename (&op1->ts), - gfc_typename (&op2->ts)); + gfc_op2string (e->value.op.op), gfc_typename (op1), + gfc_typename (op2)); goto bad_op; case INTRINSIC_CONCAT: @@ -4017,7 +4017,7 @@ resolve_operator (gfc_expr *e) sprintf (msg, _("Operands of string concatenation operator at %%L are %s/%s"), - gfc_typename (&op1->ts), gfc_typename (&op2->ts)); + gfc_typename (op1), gfc_typename (op2)); goto bad_op; case INTRINSIC_AND: @@ -4059,8 +4059,8 @@ resolve_operator (gfc_expr *e) } sprintf (msg, _("Operands of logical operator %%<%s%%> at %%L are %s/%s"), - gfc_op2string (e->value.op.op), gfc_typename (&op1->ts), - gfc_typename (&op2->ts)); + gfc_op2string (e->value.op.op), gfc_typename (op1), + gfc_typename (op2)); goto bad_op; @@ -4082,7 +4082,7 @@ resolve_operator (gfc_expr *e) } sprintf (msg, _("Operand of .not. operator at %%L is %s"), - gfc_typename (&op1->ts)); + gfc_typename (op1)); goto bad_op; case INTRINSIC_GT: @@ -4168,7 +4168,7 @@ resolve_operator (gfc_expr *e) msg = "Inequality comparison for %s at %L"; gfc_warning (OPT_Wcompare_reals, msg, - gfc_typename (&op1->ts), &op1->where); + gfc_typename (op1), &op1->where); } } @@ -4184,8 +4184,8 @@ resolve_operator (gfc_expr *e) else sprintf (msg, _("Operands of comparison operator %%<%s%%> at %%L are %s/%s"), - gfc_op2string (e->value.op.op), gfc_typename (&op1->ts), - gfc_typename (&op2->ts)); + gfc_op2string (e->value.op.op), gfc_typename (op1), + gfc_typename (op2)); goto bad_op; @@ -4203,12 +4203,12 @@ resolve_operator (gfc_expr *e) } else if (op2 == NULL) sprintf (msg, _("Operand of user operator %%<%s%%> at %%L is %s"), - e->value.op.uop->name, gfc_typename (&op1->ts)); + e->value.op.uop->name, gfc_typename (op1)); else { sprintf (msg, _("Operands of user operator %%<%s%%> at %%L are %s/%s"), - e->value.op.uop->name, gfc_typename (&op1->ts), - gfc_typename (&op2->ts)); + e->value.op.uop->name, gfc_typename (op1), + gfc_typename (op2)); e->value.op.uop->op->sym->attr.referenced = 1; } @@ -8509,7 +8509,7 @@ resolve_select (gfc_code *code, bool select_type) if (type != BT_LOGICAL && type != BT_INTEGER && type != BT_CHARACTER) { gfc_error ("Argument of SELECT statement at %L cannot be %s", - &case_expr->where, gfc_typename (&case_expr->ts)); + &case_expr->where, gfc_typename (case_expr)); /* Punt. Going on here just produce more garbage error messages. */ return; @@ -8538,7 +8538,7 @@ resolve_select (gfc_code *code, bool select_type) case_expr->ts.kind) != ARITH_OK) gfc_warning (0, "Expression in CASE statement at %L is " "not in the range of %s", &cp->low->where, - gfc_typename (&case_expr->ts)); + gfc_typename (case_expr)); if (cp->high && cp->low != cp->high @@ -8546,7 +8546,7 @@ resolve_select (gfc_code *code, bool select_type) case_expr->ts.kind) != ARITH_OK) gfc_warning (0, "Expression in CASE statement at %L is " "not in the range of %s", &cp->high->where, - gfc_typename (&case_expr->ts)); + gfc_typename (case_expr)); } /* PR 19168 has a long discussion concerning a mismatch of the kinds diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e57cc72..10de7b9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2019-10-03 Mark Eggleston + + * gfortran.dg/bad_operands.f90: New test. + * gfortran.dg/character mismatch.f90: New test. + * gfortran.dg/compare_interfaces.f90: New test. + * gfortran.dg/hollerith_to_char_parameter_1.f90: New test. + * gfortran.dg/hollerith_to_char_parameter_2.f90: New test. + * gfortran.dg/widechar_intrinsics_1.f90: Checked for specific character + type names instead of "Type of argument". + * gfortran.dg/widechar_intrinsics_2.f90: Checked for specific character + type names instead of "Type of argument". + * gfortran.dg/widechar_intrinsics_3.f90: Checked for specific character + type names instead of "Type of argument". + 2019-10-02 Joseph Myers * gcc.dg/cr-decimal-dig-2.c: New test. diff --git a/gcc/testsuite/gfortran.dg/bad_operands.f90 b/gcc/testsuite/gfortran.dg/bad_operands.f90 new file mode 100644 index 0000000..e82a07f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/bad_operands.f90 @@ -0,0 +1,10 @@ +! { dg-do compile } +! +! Test case contributed by Mark Eggleston + +program test + integer(4) :: x + + x = x // "rubbish" ! { dg-error "INTEGER\\(4\\)/CHARACTER\\(7\\)" } + x = 4_"more rubbish" + 6 ! { dg-error "CHARACTER\\(12,4\\)/INTEGER\\(4\\)" } +end program diff --git a/gcc/testsuite/gfortran.dg/character_mismatch.f90 b/gcc/testsuite/gfortran.dg/character_mismatch.f90 new file mode 100644 index 0000000..e1619467 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/character_mismatch.f90 @@ -0,0 +1,76 @@ +! { dg-do compile } +! +! Test case contributed by Mark Eggleston + +program test + use iso_fortran_env + implicit none + integer, parameter :: ucs4 = selected_char_kind('ISO_10646') + integer :: x + character(len=7) :: s = "abcd123" + character(4, ucs4) :: s4 = char(int(z'20ac'), ucs4) // ucs4_"100" + + x = s + x = "string" + x = "A longer string" // " plus a bit" + x = s // s + x = s // "a bit more" + x = "prefix:" // s + x = s4 + x = ucs4_"string" + x = ucs4_"A longer string" // ucs4_" plus a bit" + x = s4 // s4 + x = s4 // ucs4_"a bit more" + x = ucs4_"prefix:" // s4 + + call f(s) + call f("string") + call f("A longer string" // " plus a bit") + call f(s // s) + call f(s // "a bit more") + call f("a string:" // s) + + call f(s4) + call f(ucs4_"string") + call f(ucs4_"A longer string" // ucs4_" plus a bit") + call f(s4 // s4) + call f(s4 // ucs4_"a bit more") + call f(ucs4_"a string:" // s4) + + write(*,*) "" // ucs4_"" + +contains + subroutine f(y) + integer, intent(in) :: y + + write(*,*) y + end subroutine f + +end program + +! { dg-error "CHARACTER\\(7\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 13 } +! { dg-error "CHARACTER\\(6\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 14 } +! { dg-error "CHARACTER\\(26\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 15 } +! { dg-error "CHARACTER\\(14\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 16 } +! { dg-error "CHARACTER\\(17\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 17 } +! { dg-error "CHARACTER\\(14\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 18 } +! { dg-error "CHARACTER\\(4,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 19 } +! { dg-error "CHARACTER\\(6,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 20 } +! { dg-error "CHARACTER\\(26,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 21 } +! { dg-error "CHARACTER\\(8,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 22 } +! { dg-error "CHARACTER\\(14,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 23 } +! { dg-error "CHARACTER\\(11,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 24 } +! { dg-error "CHARACTER\\(7\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 26 } +! { dg-error "CHARACTER\\(6\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 27 } +! { dg-error "CHARACTER\\(26\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 28 } +! { dg-error "CHARACTER\\(14\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 29 } +! { dg-error "CHARACTER\\(17\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 30 } +! { dg-error "CHARACTER\\(16\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 31 } +! { dg-error "CHARACTER\\(4,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 33 } +! { dg-error "CHARACTER\\(6,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 34 } +! { dg-error "CHARACTER\\(26,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 35 } +! { dg-error "CHARACTER\\(8,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 36 } +! { dg-error "CHARACTER\\(14,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 37 } +! { dg-error "CHARACTER\\(13,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 38 } +! { dg-error "CHARACTER\\(0\\)/CHARACTER\\(0,4\\)" "operand type mismatch" { target \*-\*-\* } 40 } + diff --git a/gcc/testsuite/gfortran.dg/compare_interfaces.f90 b/gcc/testsuite/gfortran.dg/compare_interfaces.f90 new file mode 100644 index 0000000..cb2cbb7 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/compare_interfaces.f90 @@ -0,0 +1,73 @@ +! { dg-do compile } +! +! Contributed by Mark Eggleston + +subroutine f(a, b) + integer :: a + real :: b + + write(*,*) a, b +end subroutine + +subroutine g(a, b) + integer :: a + character(*) :: b + + write(*,*) a, b +end subroutine + +subroutine h + interface + subroutine f(a, b) ! { dg-error "\\(CHARACTER\\(\\*\\)/REAL\\(4\\)\\)" } + integer :: a + character(*) :: b + end subroutine + subroutine g(a, b) ! { dg-error "\\(REAL\\(4\\)/CHARACTER\\(\\*\\)\\)" } + integer :: a + real :: b + end subroutine + end interface + + call f(6, 6.0) + call g(6, "abcdef") +end subroutine + +subroutine f4(a, b) + integer :: a + real :: b + + write(*,*) a, b +end subroutine + +subroutine g4(a, b) + integer :: a + character(*,4) :: b + + write(*,*) a, b +end subroutine + +subroutine h4 + interface + subroutine f4(a, b) ! { dg-error "\\(CHARACTER\\(\\*,4\\)/REAL\\(4\\)\\)" } + integer :: a + character(*,4) :: b + end subroutine + subroutine g4(a, b) ! { dg-error "REAL\\(4\\)/CHARACTER\\(\\*,4\\)" } + integer :: a + real :: b + end subroutine + end interface + + call f4(6, 6.0) + call g4(6, 4_"abcdef") +end subroutine + +program test + call h + call h4 +end program + +! { dg-error "passed REAL\\(4\\) to CHARACTER\\(\\*\\)" "type mismatch" { target \*-\*-\* } 31 } +! { dg-error "passed CHARACTER\\(6\\) to REAL\\(4\\)" "type mismatch" { target \*-\*-\* } 32 } +! { dg-error "passed REAL\\(4\\) to CHARACTER\\(\\*,4\\)" "type mismatch" { target \*-\*-\* } 61 } +! { dg-error "passed CHARACTER\\(6,4\\) to REAL\\(4\\)" "type mismatch" { target \*-\*-\* } 62 } diff --git a/gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_1.f90 b/gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_1.f90 new file mode 100644 index 0000000..4c50be4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_1.f90 @@ -0,0 +1,11 @@ +! { dg-do compile } +! { dg-options "-Wconversion -std=legacy" } +! +! Test case contributed by Mark Eggleston + +program test + character(*), parameter :: h = 5hABCDE ! { dg-warning "HOLLERITH to CHARACTER\\(\\*\\)" } + + write(*,*) h +end program + diff --git a/gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_2.f90 b/gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_2.f90 new file mode 100644 index 0000000..1d5bc6c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/hollerith_to_char_parameter_2.f90 @@ -0,0 +1,12 @@ +! { dg-do compile } +! +! Test case contributed by Mark Eggleston + +program test + character(*), parameter :: h = 5hABCDE ! { dg-warning "HOLLERITH to CHARACTER\\(\\*\\)" } + + write(*,*) h +end program + +! { dg-warning "Legacy Extension" "extension" { target \*-\*-\* } 6 } + diff --git a/gcc/testsuite/gfortran.dg/widechar_intrinsics_1.f90 b/gcc/testsuite/gfortran.dg/widechar_intrinsics_1.f90 index cb98042..259ed1b 100644 --- a/gcc/testsuite/gfortran.dg/widechar_intrinsics_1.f90 +++ b/gcc/testsuite/gfortran.dg/widechar_intrinsics_1.f90 @@ -15,18 +15,18 @@ call date_and_time(s4, t4, u4) ! { dg-error "must be of kind 1" } call get_command(s1) - call get_command(s4) ! { dg-error "Type of argument" } + call get_command(s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } call get_command_argument(1, s1) - call get_command_argument(1, s4) ! { dg-error "Type of argument" } + call get_command_argument(1, s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } call get_environment_variable("PATH", s1) call get_environment_variable(s1) call get_environment_variable(s1, t1) - call get_environment_variable(4_"PATH", s1) ! { dg-error "Type of argument" } - call get_environment_variable(s4) ! { dg-error "Type of argument" } - call get_environment_variable(s1, t4) ! { dg-error "Type of argument" } - call get_environment_variable(s4, t1) ! { dg-error "Type of argument" } + call get_environment_variable(4_"PATH", s1) ! { dg-error "'CHARACTER\\(4,4\\)' to 'CHARACTER\\(\\*\\)'" } + call get_environment_variable(s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } + call get_environment_variable(s1, t4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } + call get_environment_variable(s4, t1) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } print *, lge(s1,t1) print *, lge(s1,"foo") diff --git a/gcc/testsuite/gfortran.dg/widechar_intrinsics_2.f90 b/gcc/testsuite/gfortran.dg/widechar_intrinsics_2.f90 index 0a1d449..db4fc3c 100644 --- a/gcc/testsuite/gfortran.dg/widechar_intrinsics_2.f90 +++ b/gcc/testsuite/gfortran.dg/widechar_intrinsics_2.f90 @@ -38,9 +38,9 @@ program failme call getcwd (s4, i) ! { dg-error "must be of kind" } call getenv (s1, t1) - call getenv (s1, t4) ! { dg-error "Type of argument" } - call getenv (s4, t1) ! { dg-error "Type of argument" } - call getenv (s4, t4) ! { dg-error "Type of argument" } + call getenv (s1, t4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } + call getenv (s4, t1) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } + call getenv (s4, t4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } call getarg (i, s1) call getarg (i, s4) ! { dg-error "must be of kind" } @@ -115,8 +115,8 @@ program failme call system (s1) call system (s1, i) - call system (s4) ! { dg-error "Type of argument" } - call system (s4, i) ! { dg-error "Type of argument" } + call system (s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } + call system (s4, i) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } call ttynam (i, s1) call ttynam (i, s4) ! { dg-error "must be of kind" } diff --git a/gcc/testsuite/gfortran.dg/widechar_intrinsics_3.f90 b/gcc/testsuite/gfortran.dg/widechar_intrinsics_3.f90 index 7073b89..7995c36 100644 --- a/gcc/testsuite/gfortran.dg/widechar_intrinsics_3.f90 +++ b/gcc/testsuite/gfortran.dg/widechar_intrinsics_3.f90 @@ -35,7 +35,7 @@ program failme print *, fputc (i, s4) ! { dg-error "must be of kind" } print *, getcwd (s1) - print *, getcwd (s4) ! { dg-error "Type of argument" } + print *, getcwd (s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } print *, hostnm (s1) print *, hostnm (s4) ! { dg-error "must be of kind" } @@ -61,7 +61,7 @@ program failme print *, symlnk (s4, t4) ! { dg-error "must be of kind" } print *, system (s1) - print *, system (s4) ! { dg-error "Type of argument" } + print *, system (s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" } print *, unlink (s1) print *, unlink (s4) ! { dg-error "must be of kind" } -- cgit v1.1 From 3aad513c68676dc93ae24ed70022093dc3920e18 Mon Sep 17 00:00:00 2001 From: Thomas Koenig Date: Thu, 3 Oct 2019 12:39:42 +0000 Subject: re PR fortran/84487 (Large rodate section increase in 465.tonto with r254427) 2019-10-03 Thomas Koenig PR fortran/84487 * trans-decl.c (gfc_get_symbol_decl): For __def_init, set DECL_ARTIFICAL and do not set TREE_READONLY. 2019-10-03 Thomas Koenig PR fortran/84487 * gfortran.dg/typebound_call_22.f03: xfail. From-SVN: r276506 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/trans-decl.c | 6 +++++- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gfortran.dg/typebound_call_22.f03 | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 64812f2..9367322 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2019-10-03 Thomas Koenig + + PR fortran/84487 + * trans-decl.c (gfc_get_symbol_decl): For __def_init, set + DECL_ARTIFICAL and do not set TREE_READONLY. + 2019-10-03 Mark Eggleston * array.c (check_element_type): Call gfc_typename with the gfc_expr diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index a113f08..b701f49 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -1911,9 +1911,13 @@ gfc_get_symbol_decl (gfc_symbol * sym) if (sym->attr.associate_var) GFC_DECL_ASSOCIATE_VAR_P (decl) = 1; + /* We no longer mark __def_init as read-only so it does not take up + space in the read-only section and dan go into the BSS instead, + see PR 84487. Marking this as artificial means that OpenMP will + treat this as predetermined shared. */ if (sym->attr.vtab || (sym->name[0] == '_' && gfc_str_startswith (sym->name, "__def_init"))) - TREE_READONLY (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; return decl; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 10de7b9..9acbf0e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Thomas Koenig + + PR fortran/84487 + * gfortran.dg/typebound_call_22.f03: xfail. + 2019-10-03 Mark Eggleston * gfortran.dg/bad_operands.f90: New test. diff --git a/gcc/testsuite/gfortran.dg/typebound_call_22.f03 b/gcc/testsuite/gfortran.dg/typebound_call_22.f03 index b9f0b71..30f8693 100644 --- a/gcc/testsuite/gfortran.dg/typebound_call_22.f03 +++ b/gcc/testsuite/gfortran.dg/typebound_call_22.f03 @@ -26,4 +26,4 @@ program test call x%bar () end program -! { dg-final { scan-tree-dump-times "base \\(\\);" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "base \\(\\);" 1 "optimized" { xfail *-*-* } } } -- cgit v1.1 From 12e088ba57ee2735dab15ce56cbf3c936a7d44db Mon Sep 17 00:00:00 2001 From: Andrea Corallo Date: Thu, 3 Oct 2019 12:39:55 +0000 Subject: re PR jit/91928 (libgccjit fails on subsequent compilations in ipa-cp) PR jit/91928 * ipa-cp.c (ipa_cp_c_finalize): Release ipcp_transformation_sum. * ipa-prop.c (ipcp_free_transformation_sum): New function. * ipa-prop.h (ipcp_free_transformation_sum): Add declaration. From-SVN: r276507 --- gcc/ChangeLog | 6 ++++++ gcc/ipa-cp.c | 1 + gcc/ipa-prop.c | 12 ++++++++++++ gcc/ipa-prop.h | 1 + 4 files changed, 20 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 991949b..bd550af 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-03 Andrea Corallo + + * ipa-cp.c (ipa_cp_c_finalize): Release ipcp_transformation_sum. + * ipa-prop.c (ipcp_free_transformation_sum): New function. + * ipa-prop.h (ipcp_free_transformation_sum): Add declaration. + 2019-10-03 Aldy Hernandez * Makefile.in (OBJS): Add range.o and range-op.o. diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 67664ec..045072e 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -5304,4 +5304,5 @@ ipa_cp_c_finalize (void) max_count = profile_count::uninitialized (); overall_size = 0; max_new_size = 0; + ipcp_free_transformation_sum (); } diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 25a108d..e79add1 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -3758,6 +3758,18 @@ ipcp_transformation_initialize (void) ipcp_transformation_sum = ipcp_transformation_t::create_ggc (symtab); } +/* Release the IPA CP transformation summary. */ + +void +ipcp_free_transformation_sum (void) +{ + if (!ipcp_transformation_sum) + return; + + ipcp_transformation_sum->release (); + ipcp_transformation_sum = NULL; +} + /* Set the aggregate replacements of NODE to be AGGVALS. */ void diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 30948fb..0ff8085 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -561,6 +561,7 @@ struct GTY(()) ipcp_transformation void ipa_set_node_agg_value_chain (struct cgraph_node *node, struct ipa_agg_replacement_value *aggvals); void ipcp_transformation_initialize (void); +void ipcp_free_transformation_sum (void); /* ipa_edge_args stores information related to a callsite and particularly its arguments. It can be accessed by the IPA_EDGE_REF macro. */ -- cgit v1.1 From eec306385da4905bdc4c0f5b3768218a874a5362 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 3 Oct 2019 13:05:31 +0000 Subject: [arm] Fix rtl-checking failure in arm_print_value Noticed while debugging the arm bootstrap failure. 2019-10-03 Richard Sandiford gcc/ * config/arm/arm.c (arm_print_value): Use real_to_decimal to print CONST_DOUBLEs. From-SVN: r276508 --- gcc/ChangeLog | 5 +++++ gcc/config/arm/arm.c | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bd550af..ae3a0799 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Richard Sandiford + + * config/arm/arm.c (arm_print_value): Use real_to_decimal + to print CONST_DOUBLEs. + 2019-10-03 Andrea Corallo * ipa-cp.c (ipa_cp_c_finalize): Release ipcp_transformation_sum. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 9f0975d..39e1a1e 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -16122,7 +16122,12 @@ arm_print_value (FILE *f, rtx x) return; case CONST_DOUBLE: - fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3)); + { + char fpstr[20]; + real_to_decimal (fpstr, CONST_DOUBLE_REAL_VALUE (x), + sizeof (fpstr), 0, 1); + fputs (fpstr, f); + } return; case CONST_VECTOR: -- cgit v1.1 From a164d19acb50f67c2b39ab394f8c8e4b6ea9114b Mon Sep 17 00:00:00 2001 From: Rainer Orth Date: Thu, 3 Oct 2019 13:23:52 +0000 Subject: Check init_priority in g++.dg/cpp0x/gen-attrs-67.C gcc/testsuite: * g++.dg/cpp0x/gen-attrs-67.C: Expect constructor priorities error on any !init_priority target. From-SVN: r276510 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9acbf0e..d4852d3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Rainer Orth + + * g++.dg/cpp0x/gen-attrs-67.C: Expect constructor priorities error + on any !init_priority target. + 2019-10-03 Thomas Koenig PR fortran/84487 diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C index 5d151cc..3dd3a1f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C @@ -8,4 +8,4 @@ [[nodiscard()]] int f4(); // { dg-error ".nodiscard. attribute does not take any arguments" } [[gnu::noinline()]] int f5(); // { dg-error ".noinline. attribute does not take any arguments" } [[gnu::constructor]] int f6(); -[[gnu::constructor(101)]] int f7(); // { dg-error "constructor priorities are not supported" "" { target *-*-darwin* } } +[[gnu::constructor(101)]] int f7(); // { dg-error "constructor priorities are not supported" "" { target { ! init_priority } } } -- cgit v1.1 From 2925cad2151842daa387950e62d989090e47c91d Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 3 Oct 2019 17:08:21 +0200 Subject: params.def (PARAM_INLINE_HEURISTICS_HINT_PERCENT, [...]): New. * params.def (PARAM_INLINE_HEURISTICS_HINT_PERCENT, PARAM_INLINE_HEURISTICS_HINT_PERCENT_O2): New. * doc/invoke.texi (inline-heuristics-hint-percent, inline-heuristics-hint-percent-O2): Document. * tree-inline.c (inline_insns_single, inline_insns_auto): Add new hint attribute. (can_inline_edge_by_limits_p): Use it. From-SVN: r276516 --- gcc/ChangeLog | 10 ++++++ gcc/doc/invoke.texi | 12 +++++++ gcc/ipa-inline.c | 99 +++++++++++++++++++++++++++++++---------------------- gcc/params.def | 10 ++++++ 4 files changed, 90 insertions(+), 41 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ae3a0799..ff52beb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-10-03 Jan Hubicka + + * params.def (PARAM_INLINE_HEURISTICS_HINT_PERCENT, + PARAM_INLINE_HEURISTICS_HINT_PERCENT_O2): New. + * doc/invoke.texi (inline-heuristics-hint-percent, + inline-heuristics-hint-percent-O2): Document. + * tree-inline.c (inline_insns_single, inline_insns_auto): Add new + hint attribute. + (can_inline_edge_by_limits_p): Use it. + 2019-10-03 Richard Sandiford * config/arm/arm.c (arm_print_value): Use real_to_decimal diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4861920..ac20e3a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -11215,6 +11215,18 @@ function prologue and epilogue. Extra time accounted by inliner for function overhead such as time needed to execute function prologue and epilogue +@item inline-heuristics-hint-percent +@item inline-heuristics-hint-percent-O2 +The scale (in percents) applied to @option{inline-insns-single}, +@option{inline-insns-single-O2}, @option{inline-insns-auto}, +@option{inline-insns-auto-O2} when inline heuristics hints that inlining is +very profitable (will enable later optimizations). + +For functions compiled with optimization levels +@option{-O3} and @option{-Ofast} parameter +@option{inline-heuristics-hint-percent} is applied. In other cases +@option{inline-heuristics-hint-percent-O2} is applied. + @item uninlined-thunk-insns @item uninlined-thunk-time Same as @option{--param uninlined-function-insns} and diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 98d7fd3..725e675 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -390,26 +390,48 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, return inlinable; } -/* Return inlining_insns_single limit for function N */ +/* Return inlining_insns_single limit for function N. If HINT is true + scale up the bound. */ static int -inline_insns_single (cgraph_node *n) +inline_insns_single (cgraph_node *n, bool hint) { if (opt_for_fn (n->decl, optimize >= 3)) - return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE); + { + if (hint) + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE) + * PARAM_VALUE (PARAM_INLINE_HEURISTICS_HINT_PERCENT) / 100; + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE); + } else - return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE_O2); + { + if (hint) + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE_O2) + * PARAM_VALUE (PARAM_INLINE_HEURISTICS_HINT_PERCENT_O2) / 100; + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE_O2); + } } -/* Return inlining_insns_auto limit for function N */ +/* Return inlining_insns_auto limit for function N. If HINT is true + scale up the bound. */ static int -inline_insns_auto (cgraph_node *n) +inline_insns_auto (cgraph_node *n, bool hint) { if (opt_for_fn (n->decl, optimize >= 3)) - return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO); + { + if (hint) + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO) + * PARAM_VALUE (PARAM_INLINE_HEURISTICS_HINT_PERCENT) / 100; + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO); + } else - return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO_O2); + { + if (hint) + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO_O2) + * PARAM_VALUE (PARAM_INLINE_HEURISTICS_HINT_PERCENT_O2) / 100; + return PARAM_VALUE (PARAM_MAX_INLINE_INSNS_AUTO_O2); + } } /* Decide if we can inline the edge and possibly update @@ -554,8 +576,8 @@ can_inline_edge_by_limits_p (struct cgraph_edge *e, bool report, int growth = estimate_edge_growth (e); if (growth > PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SIZE) && (!DECL_DECLARED_INLINE_P (callee->decl) - && growth >= MAX (inline_insns_single (caller), - inline_insns_auto (caller)))) + && growth >= MAX (inline_insns_single (caller, false), + inline_insns_auto (caller, false)))) { e->inline_failed = CIF_OPTIMIZATION_MISMATCH; inlinable = false; @@ -801,15 +823,12 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) want_inline = false; } /* Do fast and conservative check if the function can be good - inline candidate. At the moment we allow inline hints to - promote non-inline functions to inline and we increase - MAX_INLINE_INSNS_SINGLE 16-fold for inline functions. */ + inline candidate. */ else if ((!DECL_DECLARED_INLINE_P (callee->decl) && (!e->count.ipa ().initialized_p () || !e->maybe_hot_p ())) && ipa_fn_summaries->get (callee)->min_size - ipa_call_summaries->get (e)->call_stmt_size - > MAX (inline_insns_single (e->caller), - inline_insns_auto (e->caller))) + > inline_insns_auto (e->caller, true)) { if (opt_for_fn (e->caller->decl, optimize) >= 3) e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; @@ -821,7 +840,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) || e->count.ipa ().nonzero_p ()) && ipa_fn_summaries->get (callee)->min_size - ipa_call_summaries->get (e)->call_stmt_size - > 16 * inline_insns_single (e->caller)) + > inline_insns_single (e->caller, true)) { if (opt_for_fn (e->caller->decl, optimize) >= 3) e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl) @@ -837,20 +856,22 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) { int growth = estimate_edge_growth (e); ipa_hints hints = estimate_edge_hints (e); - int big_speedup = -1; /* compute this lazily */ + bool apply_hints = (hints & (INLINE_HINT_indirect_call + | INLINE_HINT_known_hot + | INLINE_HINT_loop_iterations + | INLINE_HINT_loop_stride)); if (growth <= PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SIZE)) ; /* Apply MAX_INLINE_INSNS_SINGLE limit. Do not do so when - hints suggests that inlining given function is very profitable. */ + hints suggests that inlining given function is very profitable. + Avoid computation of big_speedup_p when not necessary to change + outcome of decision. */ else if (DECL_DECLARED_INLINE_P (callee->decl) - && growth >= inline_insns_single (e->caller) - && (growth >= inline_insns_single (e->caller) * 16 - || (!(hints & (INLINE_HINT_indirect_call - | INLINE_HINT_known_hot - | INLINE_HINT_loop_iterations - | INLINE_HINT_loop_stride)) - && !(big_speedup = big_speedup_p (e))))) + && growth >= inline_insns_single (e->caller, apply_hints) + && (apply_hints + || growth >= inline_insns_single (e->caller, true) + || !big_speedup_p (e))) { if (opt_for_fn (e->caller->decl, optimize) >= 3) e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; @@ -863,28 +884,23 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && growth >= PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SMALL)) { /* growth_likely_positive is expensive, always test it last. */ - if (growth >= inline_insns_single (e->caller) + if (growth >= inline_insns_single (e->caller, false) || growth_likely_positive (callee, growth)) { e->inline_failed = CIF_NOT_DECLARED_INLINED; want_inline = false; } } - /* Apply MAX_INLINE_INSNS_AUTO limit for functions not declared inline - Upgrade it to MAX_INLINE_INSNS_SINGLE when hints suggests that - inlining given function is very profitable. */ + /* Apply MAX_INLINE_INSNS_AUTO limit for functions not declared inline. + Bypass the limit when speedup seems big. */ else if (!DECL_DECLARED_INLINE_P (callee->decl) - && !(hints & INLINE_HINT_known_hot) - && growth >= ((hints & (INLINE_HINT_indirect_call - | INLINE_HINT_loop_iterations - | INLINE_HINT_loop_stride)) - ? MAX (inline_insns_auto (e->caller), - inline_insns_single (e->caller)) - : inline_insns_auto (e->caller)) - && !(big_speedup == -1 ? big_speedup_p (e) : big_speedup)) + && growth >= inline_insns_auto (e->caller, apply_hints) + && (apply_hints + || growth >= inline_insns_auto (e->caller, true) + || !big_speedup_p (e))) { /* growth_likely_positive is expensive, always test it last. */ - if (growth >= inline_insns_single (e->caller) + if (growth >= inline_insns_single (e->caller, false) || growth_likely_positive (callee, growth)) { if (opt_for_fn (e->caller->decl, optimize) >= 3) @@ -896,7 +912,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) } /* If call is cold, do not inline when function body would grow. */ else if (!e->maybe_hot_p () - && (growth >= inline_insns_single (e->caller) + && (growth >= inline_insns_single (e->caller, false) || growth_likely_positive (callee, growth))) { e->inline_failed = CIF_UNLIKELY_CALL; @@ -1200,12 +1216,13 @@ edge_badness (struct cgraph_edge *edge, bool dump) int caller_growth = caller_info->growth; /* Only apply the penalty when caller looks like inline candidate, - and it is not called once and. */ + and it is not called once. */ if (!caller_info->single_caller && overall_growth < caller_growth && caller_info->inlinable && caller_info->size < (DECL_DECLARED_INLINE_P (caller->decl) - ? inline_insns_single (caller) : inline_insns_auto (caller))) + ? inline_insns_single (caller, false) + : inline_insns_auto (caller, false))) { if (dump) fprintf (dump_file, diff --git a/gcc/params.def b/gcc/params.def index 80f73b8..4cb48d9 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -102,6 +102,16 @@ DEFPARAM (PARAM_MAX_INLINE_INSNS_SMALL, "The maximum number of instructions when automatically inlining small functions.", 0, 0, 0) +DEFPARAM (PARAM_INLINE_HEURISTICS_HINT_PERCENT, + "inline-heuristics-hint-percent", + "The scale (in percents) applied to inline-insns-single and auto limits when heuristics hints that inlining is very profitable with -O3 and -Ofast.", + 1600, 100, 1000000) + +DEFPARAM (PARAM_INLINE_HEURISTICS_HINT_PERCENT_O2, + "inline-heuristics-hint-percent-O2", + "The scale (in percents) applied to inline-insns-single and auto limits when heuristics hints that inlining is very profitable.", + 200, 100, 1000000) + DEFPARAM (PARAM_MAX_INLINE_INSNS_SIZE, "max-inline-insns-size", "The maximum number of instructions when inlining for size.", -- cgit v1.1 From 5dbe01a1ffe4a3920f81a2b4349d31ec6871b9de Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Thu, 3 Oct 2019 17:03:43 +0000 Subject: primary.c (match_real_constant): Remove shadowing local vars. 2019-10-03 Bernd Edlinger * primary.c (match_real_constant): Remove shadowing local vars. Rename local vars. Fix undefined behavior in loop termination. (gfc_convert_to_structure_constructor): Rename local var. From-SVN: r276518 --- gcc/fortran/ChangeLog | 6 ++++++ gcc/fortran/primary.c | 25 +++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 9367322..f7414b6 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2019-10-03 Bernd Edlinger + + * primary.c (match_real_constant): Remove shadowing local vars. + Rename local vars. Fix undefined behavior in loop termination. + (gfc_convert_to_structure_constructor): Rename local var. + 2019-10-03 Thomas Koenig PR fortran/84487 diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c index 7c65b2e..6b6c7d2 100644 --- a/gcc/fortran/primary.c +++ b/gcc/fortran/primary.c @@ -789,16 +789,17 @@ done: if (warn_conversion_extra) { mpfr_t r; - char *c, *p; + char *c1; bool did_break; - c = strchr (buffer, 'e'); - if (c == NULL) - c = buffer + strlen(buffer); + c1 = strchr (buffer, 'e'); + if (c1 == NULL) + c1 = buffer + strlen(buffer); did_break = false; - for (p = c - 1; p >= buffer; p--) + for (p = c1; p > buffer;) { + p--; if (*p == '.') continue; @@ -3099,21 +3100,21 @@ gfc_convert_to_structure_constructor (gfc_expr *e, gfc_symbol *sym, gfc_expr **c && actual->expr->ts.type == BT_CHARACTER && actual->expr->expr_type == EXPR_CONSTANT) { - ptrdiff_t c, e; + ptrdiff_t c, e1; c = gfc_mpz_get_hwi (this_comp->ts.u.cl->length->value.integer); - e = actual->expr->value.character.length; + e1 = actual->expr->value.character.length; - if (c != e) + if (c != e1) { ptrdiff_t i, to; gfc_char_t *dest; dest = gfc_get_wide_string (c + 1); - to = e < c ? e : c; + to = e1 < c ? e1 : c; for (i = 0; i < to; i++) dest[i] = actual->expr->value.character.string[i]; - for (i = e; i < c; i++) + for (i = e1; i < c; i++) dest[i] = ' '; dest[c] = '\0'; @@ -3122,11 +3123,11 @@ gfc_convert_to_structure_constructor (gfc_expr *e, gfc_symbol *sym, gfc_expr **c actual->expr->value.character.length = c; actual->expr->value.character.string = dest; - if (warn_line_truncation && c < e) + if (warn_line_truncation && c < e1) gfc_warning_now (OPT_Wcharacter_truncation, "CHARACTER expression will be truncated " "in constructor (%ld/%ld) at %L", (long int) c, - (long int) e, &actual->expr->where); + (long int) e1, &actual->expr->where); } } -- cgit v1.1 From 206c926ae2e422b358e63b555298ac21119502ed Mon Sep 17 00:00:00 2001 From: Dragan Mladjenovic Date: Thu, 3 Oct 2019 19:17:20 +0000 Subject: re PR target/91769 (wrong code with -O2 on MIPS) Fix PR target/91769 This fixes the issue by checking that addr's base reg is not part of dest multiword reg instead just checking the first reg of dest. gcc/ChangeLog: 2019-10-03 Dragan Mladjenovic PR target/91769 * config/mips/mips.c (mips_split_move): Use reg_overlap_mentioned_p instead of REGNO equality check on addr.reg. gcc/testsuite/ChangeLog: 2019-10-03 Dragan Mladjenovic PR target/91769 * gcc.target/mips/pr91769.c: New test. From-SVN: r276525 --- gcc/ChangeLog | 6 ++++++ gcc/config/mips/mips.c | 2 +- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/mips/pr91769.c | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/mips/pr91769.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ff52beb..1815dc9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-10-03 Dragan Mladjenovic + + PR target/91769 + * config/mips/mips.c (mips_split_move): Use reg_overlap_mentioned_p + instead of REGNO equality check on addr.reg. + 2019-10-03 Jan Hubicka * params.def (PARAM_INLINE_HEURISTICS_HINT_PERCENT, diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 648d95f..e7c2212 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -4862,7 +4862,7 @@ mips_split_move (rtx dest, rtx src, enum mips_split_type split_type, rtx insn_) { rtx tmp = XEXP (src, 0); mips_classify_address (&addr, tmp, GET_MODE (tmp), true); - if (addr.reg && REGNO (addr.reg) != REGNO (dest)) + if (addr.reg && !reg_overlap_mentioned_p (dest, addr.reg)) validate_change (next, &SET_SRC (set), src, false); } else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d4852d3..7939c36 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Dragan Mladjenovic + + PR target/91769 + * gcc.target/mips/pr91769.c: New test. + 2019-10-03 Rainer Orth * g++.dg/cpp0x/gen-attrs-67.C: Expect constructor priorities error diff --git a/gcc/testsuite/gcc.target/mips/pr91769.c b/gcc/testsuite/gcc.target/mips/pr91769.c new file mode 100644 index 0000000..c9ad70d --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/pr91769.c @@ -0,0 +1,19 @@ +/* PR target/91769 */ +/* { dg-do compile } */ +/* { dg-skip-if "naming registers makes this a code quality test" { *-*-* } { "-O0" "-g" } { "" } } */ +/* { dg-options "-EL -mgp32 -mhard-float" } */ + +NOCOMPRESSION double +foo (void) +{ + register double* pf __asm__ ("$a1"); + __asm__ __volatile__ ("":"=r"(pf)); + double f = *pf; + + if (f != f) + f = -f; + return f; +} + +/* { dg-final { scan-assembler-not "lw\t\\\$4,0\\(\\\$5\\)\n\tlw\t\\\$5,4\\(\\\$5\\)\n\tldc1\t\\\$.*,0\\(\\\$5\\)" } } */ +/* { dg-final { scan-assembler "lw\t\\\$4,0\\(\\\$5\\)\n\tlw\t\\\$5,4\\(\\\$5\\)\n\tmtc1\t\\\$4,\\\$.*\n\tmthc1\t\\\$5,\\\$.*" } } */ -- cgit v1.1 From cfcf3551c432da3a8154ef11a26a4d75655deb3d Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 3 Oct 2019 21:45:23 +0200 Subject: * g++.dg/tree-ssa/pr61034.C: Add --param max-inline-insns-single-O2=200. From-SVN: r276527 --- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/g++.dg/tree-ssa/pr61034.C | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7939c36..78a26a2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-03 Jan Hubicka + + * g++.dg/tree-ssa/pr61034.C: Add --param max-inline-insns-single-O2=200. + 2019-10-03 Dragan Mladjenovic PR target/91769 diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr61034.C b/gcc/testsuite/g++.dg/tree-ssa/pr61034.C index 2e3dfec..6a76adb 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr61034.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr61034.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-options "-O2 -fdump-tree-fre3 -fdump-tree-optimized -fdelete-null-pointer-checks --param early-inlining-insns-O2=14" } +// { dg-options "-O2 -fdump-tree-fre3 -fdump-tree-optimized -fdelete-null-pointer-checks --param early-inlining-insns-O2=14 --param max-inline-insns-single-O2=200" } #define assume(x) if(!(x))__builtin_unreachable() -- cgit v1.1 From 24ec3cc957c4181d8da9972cb2aa212a3e0cec1c Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 3 Oct 2019 20:19:18 +0000 Subject: [Darwin] Pick up SDKROOT as the sysroot fallback. For compatibility with xcrun and the behaviour of the clang driver, make use of the setting of the SDKROOT environment variable when it is available. This applies to both finding headers and libraries (i.e. it is also passed to ld64). Priority: 1. User's command-line specified --sysroot= or -isysroot. 2. The SDKROOT variable when set, and validated. 3. Any sysroot provided by --with-sysroot= configuration parameter. SDKROOT is checked thus: 1. Presence. 2. That it starts with "/" (i.e. 'absolute'). 3. That it is not "/" only (since that's the default). 4. That it is readable by the process executing the driver. This is pretty much the same rule set as used by the clang driver. NOTE: (3) might turn out to be overly restrictive in the case that we have configured with --with-sysroot= and then we want to run on a system with an installation of the headers/libraries in /. We can revisit this if that turns out to be an important use-case. So one can do: xcrun --sdk macosx /path/to/gcc .... and that provides the SDK path as the sysroot to GCC as expected. CAVEAT: An unfortunate effect of the fact that "gcc" (and "g++") are executables in the Xcode installation, which are found ahead of any such named in the $PATH: PATH=/path/to/gcc/install:$PATH xcrun --sdk macosx gcc .... does *not* work, instead that executes the clang from the xcode/commmand line tools installation. PATH=/path/to/gcc/install:$PATH xcrun --sdk macosx x64_64-apple-darwinXX-gcc ... does work as expected, however. gcc/ChangeLog: 2019-10-03 Iain Sandoe PR target/87243 * config/darwin-driver.c (maybe_get_sysroot_from_sdkroot): New. (darwin_driver_init): Use the sysroot provided by SDKROOT when that is available and the user has not set one on the command line. From-SVN: r276530 --- gcc/ChangeLog | 7 +++++++ gcc/config/darwin-driver.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1815dc9..9be4a6f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-03 Iain Sandoe + + PR target/87243 + * config/darwin-driver.c (maybe_get_sysroot_from_sdkroot): New. + (darwin_driver_init): Use the sysroot provided by SDKROOT when that + is available and the user has not set one on the command line. + 2019-10-03 Dragan Mladjenovic PR target/91769 diff --git a/gcc/config/darwin-driver.c b/gcc/config/darwin-driver.c index 49716fa..82ac231 100644 --- a/gcc/config/darwin-driver.c +++ b/gcc/config/darwin-driver.c @@ -210,6 +210,28 @@ darwin_default_min_version (void) return new_flag; } +/* See if we can find the sysroot from the SDKROOT environment variable. */ + +static const char * +maybe_get_sysroot_from_sdkroot () +{ + const char *maybe_sysroot = getenv ("SDKROOT"); + + /* We'll use the same rules as the clang driver, for compatibility. + 1) The path must be absolute + 2) Ignore "/", that is the default anyway and we do not want the + sysroot semantics to be applied to it. + 3) It must exist (actually, we'll check it's readable too). */ + + if (maybe_sysroot == NULL + || *maybe_sysroot != '/' + || strlen (maybe_sysroot) == 1 + || access (maybe_sysroot, R_OK) == -1) + return NULL; + + return xstrndup (maybe_sysroot, strlen (maybe_sysroot)); +} + /* Translate -filelist and -framework options in *DECODED_OPTIONS (size *DECODED_OPTIONS_COUNT) to use -Xlinker so that they are considered to be linker inputs in the case that no other inputs are @@ -234,6 +256,7 @@ darwin_driver_init (unsigned int *decoded_options_count, bool appendM64 = false; const char *vers_string = NULL; bool seen_version_min = false; + bool seen_sysroot_p = false; for (i = 1; i < *decoded_options_count; i++) { @@ -314,6 +337,11 @@ darwin_driver_init (unsigned int *decoded_options_count, --*decoded_options_count; break; + case OPT__sysroot_: + case OPT_isysroot: + seen_sysroot_p = true; + break; + default: break; } @@ -375,6 +403,22 @@ darwin_driver_init (unsigned int *decoded_options_count, &(*decoded_options)[*decoded_options_count - 1]); } + if (! seen_sysroot_p) + { + /* We will pick up an SDKROOT if we didn't specify a sysroot and treat + it as overriding any configure-time --with-sysroot. */ + const char *sdkroot = maybe_get_sysroot_from_sdkroot (); + if (sdkroot) + { + ++*decoded_options_count; + *decoded_options = XRESIZEVEC (struct cl_decoded_option, + *decoded_options, + *decoded_options_count); + generate_option (OPT__sysroot_, sdkroot, 1, CL_DRIVER, + &(*decoded_options)[*decoded_options_count - 1]); + } + } + /* We will need to know the OS X version we're trying to build for here so that we can figure out the mechanism and source for the sysroot to be used. */ -- cgit v1.1 From e23390d29e19a8a6aea06fd3c4cc3990c9977ac8 Mon Sep 17 00:00:00 2001 From: "Steven G. Kargl" Date: Thu, 3 Oct 2019 20:46:26 +0000 Subject: re PR fortran/91497 (-Wconversion warns when doing explicit type conversion) 2019-10-03 Steven G. Kargl PR fortran/91497 * simplify.c (gfc_simplify_dble, simplify_intconv, gfc_simplify_real, gfc_simplify_sngl): Disable -Wconversion and -Wconversion-extra warnings for explicit conversion of literal constants. 2019-10-03 Steven G. Kargl PR fortran/91497 * gfortran.dg/pr91497.f90: New test. From-SVN: r276532 --- gcc/fortran/ChangeLog | 7 ++ gcc/fortran/simplify.c | 45 +++++++++++- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gfortran.dg/pr91497.f90 | 127 ++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/pr91497.f90 (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f7414b6..9a2a800 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2019-10-03 Steven G. Kargl + + PR fortran/91497 + * simplify.c (gfc_simplify_dble, simplify_intconv, gfc_simplify_real, + gfc_simplify_sngl): Disable -Wconversion and -Wconversion-extra + warnings for explicit conversion of literal constants. + 2019-10-03 Bernd Edlinger * primary.c (match_real_constant): Remove shadowing local vars. diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c index 32ebcc0..8c1577e 100644 --- a/gcc/fortran/simplify.c +++ b/gcc/fortran/simplify.c @@ -2189,11 +2189,22 @@ gfc_expr * gfc_simplify_dble (gfc_expr *e) { gfc_expr *result = NULL; + int tmp1, tmp2; if (e->expr_type != EXPR_CONSTANT) return NULL; + /* For explicit conversion, turn off -Wconversion and -Wconversion-extra + warnings. */ + tmp1 = warn_conversion; + tmp2 = warn_conversion_extra; + warn_conversion = warn_conversion_extra = 0; + result = gfc_convert_constant (e, BT_REAL, gfc_default_double_kind); + + warn_conversion = tmp1; + warn_conversion_extra = tmp2; + if (result == &gfc_bad_expr) return &gfc_bad_expr; @@ -3572,6 +3583,7 @@ static gfc_expr * simplify_intconv (gfc_expr *e, int kind, const char *name) { gfc_expr *result = NULL; + int tmp1, tmp2; /* Convert BOZ to integer, and return without range checking. */ if (e->ts.type == BT_BOZ) @@ -3585,7 +3597,17 @@ simplify_intconv (gfc_expr *e, int kind, const char *name) if (e->expr_type != EXPR_CONSTANT) return NULL; + /* For explicit conversion, turn off -Wconversion and -Wconversion-extra + warnings. */ + tmp1 = warn_conversion; + tmp2 = warn_conversion_extra; + warn_conversion = warn_conversion_extra = 0; + result = gfc_convert_constant (e, BT_INTEGER, kind); + + warn_conversion = tmp1; + warn_conversion_extra = tmp2; + if (result == &gfc_bad_expr) return &gfc_bad_expr; @@ -6472,7 +6494,7 @@ gfc_expr * gfc_simplify_real (gfc_expr *e, gfc_expr *k) { gfc_expr *result = NULL; - int kind; + int kind, tmp1, tmp2; /* Convert BOZ to real, and return without range checking. */ if (e->ts.type == BT_BOZ) @@ -6500,7 +6522,17 @@ gfc_simplify_real (gfc_expr *e, gfc_expr *k) if (e->expr_type != EXPR_CONSTANT) return NULL; + /* For explicit conversion, turn off -Wconversion and -Wconversion-extra + warnings. */ + tmp1 = warn_conversion; + tmp2 = warn_conversion_extra; + warn_conversion = warn_conversion_extra = 0; + result = gfc_convert_constant (e, BT_REAL, kind); + + warn_conversion = tmp1; + warn_conversion_extra = tmp2; + if (result == &gfc_bad_expr) return &gfc_bad_expr; @@ -7551,11 +7583,22 @@ gfc_expr * gfc_simplify_sngl (gfc_expr *a) { gfc_expr *result; + int tmp1, tmp2; if (a->expr_type != EXPR_CONSTANT) return NULL; + /* For explicit conversion, turn off -Wconversion and -Wconversion-extra + warnings. */ + tmp1 = warn_conversion; + tmp2 = warn_conversion_extra; + warn_conversion = warn_conversion_extra = 0; + result = gfc_real2real (a, gfc_default_real_kind); + + warn_conversion = tmp1; + warn_conversion_extra = tmp2; + return range_check (result, "SNGL"); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 78a26a2..fdfcde2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Steven G. Kargl + + PR fortran/91497 + * gfortran.dg/pr91497.f90: New test. + 2019-10-03 Jan Hubicka * g++.dg/tree-ssa/pr61034.C: Add --param max-inline-insns-single-O2=200. diff --git a/gcc/testsuite/gfortran.dg/pr91497.f90 b/gcc/testsuite/gfortran.dg/pr91497.f90 new file mode 100644 index 0000000..aa06a49 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr91497.f90 @@ -0,0 +1,127 @@ +! { dg-do compile } +! { dg-options "-Wall" } +! Code contributed by Manfred Schwarb +! PR fortran/91497 +! +! Prior to applying the patch for this PR, the following code +! would generate numerous conversion warnings. +! +program foo + + real*4 a,aa + real*8 b,bb + real*10 c,cc + real*16 d + integer*2 e,ee + integer*4 f,ff + integer*8 g,gg + PARAMETER(a=3.1415927_4) + PARAMETER(b=3.1415927_8) + PARAMETER(c=3.1415927_10) + PARAMETER(d=3.1415927_16) + PARAMETER(e=123_2) + PARAMETER(f=123_4) + PARAMETER(g=123_8) + + aa=REAL(b) + aa=REAL(c) + aa=REAL(d) + aa=REAL(e) + aa=REAL(f) + aa=REAL(g) + aa=FLOAT(f) + aa=FLOOR(b) + aa=FLOOR(c) + aa=FLOOR(d) + aa=CEILING(b) + aa=CEILING(c) + aa=CEILING(d) + !---unknown but documented type conversions: + !!aa=FLOATI(e) + !!aa=FLOATJ(f) + !!aa=FLOATK(g) + !---documentation is wrong for sngl: + aa=SNGL(c) + aa=SNGL(d) + bb=REAL(c, kind=8) + bb=REAL(d, kind=8) + bb=DBLE(c) + bb=DBLE(d) + bb=DFLOAT(g) + bb=FLOOR(c) + bb=FLOOR(d) + bb=CEILING(c) + bb=CEILING(d) + cc=REAL(d, kind=10) + cc=FLOOR(d) + cc=CEILING(d) + + aa=AINT(b) + aa=ANINT(b) + aa=AINT(c) + aa=ANINT(c) + aa=AINT(d) + aa=ANINT(d) + bb=DINT(b) + bb=DNINT(b) + + ee=INT(a, kind=2) + ee=NINT(a, kind=2) + ee=INT(b, kind=2) + ee=NINT(b, kind=2) + ee=INT(c, kind=2) + ee=NINT(c, kind=2) + ee=INT(d, kind=2) + ee=NINT(d, kind=2) + ee=INT(f, kind=2) + ee=INT(g, kind=2) + ee=IFIX(a) + ee=IDINT(b) + ee=IDNINT(b) + ee=INT2(a) + ee=INT2(b) + ee=INT2(c) + ee=INT2(d) + ee=INT2(f) + ee=INT2(g) + + ff=INT(a, kind=4) + ff=NINT(a, kind=4) + ff=INT(b, kind=4) + ff=NINT(b, kind=4) + ff=INT(c, kind=4) + ff=NINT(c, kind=4) + ff=INT(d, kind=4) + ff=NINT(d, kind=4) + ff=INT(f, kind=4) + ff=INT(g, kind=4) + ff=IFIX(a) + ff=IDINT(b) + ff=IDNINT(b) + !---LONG not allowed anymore in gfortran 10 (?): + !!ff=LONG(a) + !!ff=LONG(b) + !!ff=LONG(c) + !!ff=LONG(d) + !!ff=LONG(g) + + gg=INT(a, kind=8) + gg=NINT(a, kind=8) + gg=INT(b, kind=8) + gg=NINT(b, kind=8) + gg=INT(c, kind=8) + gg=NINT(c, kind=8) + gg=INT(d, kind=8) + gg=NINT(d, kind=8) + gg=INT(f, kind=8) + gg=INT(g, kind=8) + gg=IFIX(a) + gg=IDINT(b) + gg=IDNINT(b) + gg=INT8(a) + gg=INT8(b) + gg=INT8(c) + gg=INT8(d) + gg=INT8(g) +end + -- cgit v1.1 From 5d8bb3897ef3fba6b4ac677e64188b1da86eda39 Mon Sep 17 00:00:00 2001 From: Aaron Sawdey Date: Thu, 3 Oct 2019 22:19:14 +0000 Subject: expr.c (emit_block_move_hints): Slightly cleaner fix to can_move_by_pieces issue. 2019-10-03 Aaron Sawdey * expr.c (emit_block_move_hints): Slightly cleaner fix to can_move_by_pieces issue. From-SVN: r276542 --- gcc/ChangeLog | 5 +++++ gcc/expr.c | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9be4a6f..73c45b3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 Aaron Sawdey + + * expr.c (emit_block_move_hints): Slightly cleaner fix to + can_move_by_pieces issue. + 2019-10-03 Iain Sandoe PR target/87243 diff --git a/gcc/expr.c b/gcc/expr.c index c421054..2ee2906 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1624,9 +1624,8 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, set_mem_size (y, const_size); } - bool pieces_ok = false; - if (CONST_INT_P (size)) - pieces_ok = can_move_by_pieces (INTVAL (size), align); + bool pieces_ok = CONST_INT_P (size) + && can_move_by_pieces (INTVAL (size), align); bool pattern_ok = false; if (!pieces_ok || might_overlap) -- cgit v1.1 From 4a6cb9c0da73ce8733a68fc802b1f5a332cfebdc Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Thu, 3 Oct 2019 22:39:49 +0000 Subject: pa.c (pa_output_call): Remove 64-bit sibcall sequence. * config/pa/pa.c (pa_output_call): Remove 64-bit sibcall sequence. (pa_attr_length_call): Adjust length for 64-bit plabel sequence. From-SVN: r276543 --- gcc/ChangeLog | 5 +++++ gcc/config/pa/pa.c | 30 ++++++++---------------------- 2 files changed, 13 insertions(+), 22 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 73c45b3..2068d05 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-03 John David Anglin + + * config/pa/pa.c (pa_output_call): Remove 64-bit sibcall sequence. + (pa_attr_length_call): Adjust length for 64-bit plabel sequence. + 2019-10-03 Aaron Sawdey * expr.c (emit_block_move_hints): Slightly cleaner fix to diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 55637df..4f48c41 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -7845,7 +7845,7 @@ pa_attr_length_call (rtx_insn *insn, int sibcall) /* 64-bit plabel sequence. */ else if (TARGET_64BIT && !local_call) - length += sibcall ? 28 : 24; + length += 24; /* non-pic long absolute branch sequence. */ else if ((TARGET_LONG_ABS_CALL || local_call) && !flag_pic) @@ -7917,38 +7917,24 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall) xoperands[0] = pa_get_deferred_plabel (call_dest); xoperands[1] = gen_label_rtx (); - /* If this isn't a sibcall, we put the load of %r27 into the - delay slot. We can't do this in a sibcall as we don't - have a second call-clobbered scratch register available. - We don't need to do anything when generating fast indirect - calls. */ - if (seq_length != 0 && !sibcall) + /* Put the load of %r27 into the delay slot. We don't need to + do anything when generating fast indirect calls. */ + if (seq_length != 0) { final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, NULL); /* Now delete the delay insn. */ SET_INSN_DELETED (NEXT_INSN (insn)); - seq_length = 0; } output_asm_insn ("addil LT'%0,%%r27", xoperands); output_asm_insn ("ldd RT'%0(%%r1),%%r1", xoperands); output_asm_insn ("ldd 0(%%r1),%%r1", xoperands); - - if (sibcall) - { - output_asm_insn ("ldd 24(%%r1),%%r27", xoperands); - output_asm_insn ("ldd 16(%%r1),%%r1", xoperands); - output_asm_insn ("bve (%%r1)", xoperands); - } - else - { - output_asm_insn ("ldd 16(%%r1),%%r2", xoperands); - output_asm_insn ("bve,l (%%r2),%%r2", xoperands); - output_asm_insn ("ldd 24(%%r1),%%r27", xoperands); - seq_length = 1; - } + output_asm_insn ("ldd 16(%%r1),%%r2", xoperands); + output_asm_insn ("bve,l (%%r2),%%r2", xoperands); + output_asm_insn ("ldd 24(%%r1),%%r27", xoperands); + seq_length = 1; } else { -- cgit v1.1 From 320be74c5ca406ca2ad37de9a059879217ec1bf1 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Thu, 3 Oct 2019 23:32:53 +0000 Subject: pa.h (MAX_PCREL17F_OFFSET): Adjust. * config/pa/pa.h (MAX_PCREL17F_OFFSET): Adjust. From-SVN: r276555 --- gcc/ChangeLog | 2 ++ gcc/config/pa/pa.h | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2068d05..54240d5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,7 @@ 2019-10-03 John David Anglin + * config/pa/pa.h (MAX_PCREL17F_OFFSET): Adjust. + * config/pa/pa.c (pa_output_call): Remove 64-bit sibcall sequence. (pa_attr_length_call): Adjust length for 64-bit plabel sequence. diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index f38a6dc..1a43e5c 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -1292,13 +1292,12 @@ do { \ #endif /* The maximum offset in bytes for a PA 1.X pc-relative call to the - head of the preceding stub table. The selected offsets have been - chosen so that approximately one call stub is allocated for every - 86.7 instructions. A long branch stub is two instructions when - not generating PIC code. For HP-UX and ELF targets, PIC stubs are - seven and four instructions, respectively. */ -#define MAX_PCREL17F_OFFSET \ - (flag_pic ? (TARGET_HPUX ? 198164 : 221312) : 240000) + head of the preceding stub table. A long branch stub is two or three + instructions for non-PIC and PIC, respectively. Import stubs are + seven and five instructions for HP-UX and ELF targets, respectively. + The default stub group size for ELF targets is 217856 bytes. + FIXME: We need an option to set the maximum offset. */ +#define MAX_PCREL17F_OFFSET (TARGET_HPUX ? 198164 : 217856) #define NEED_INDICATE_EXEC_STACK 0 -- cgit v1.1 From 38b8d26b4604c3672678de6d8972ac254bb18793 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 4 Oct 2019 00:16:26 +0000 Subject: Daily bump. From-SVN: r276560 --- gcc/DATESTAMP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index e0a8c09..cd0a63a 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20191003 +20191004 -- cgit v1.1 From cf09ecdb94d617f740e938c476252e61dffacc29 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 4 Oct 2019 05:42:08 +0000 Subject: invoke.texi (-Wshadow=global, [...]): Fix description. 2019-10-04 Bernd Edlinger * doc/invoke.texi (-Wshadow=global, -Wshadow=local, -Wshadow=compatible-local): Fix description. Add an example where -Wshadow=compatible-local does not warn. From-SVN: r276561 --- gcc/ChangeLog | 7 +++++++ gcc/doc/invoke.texi | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 54240d5..0c8f331 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-04 Bernd Edlinger + + * doc/invoke.texi (-Wshadow=global, -Wshadow=local, + -Wshadow=compatible-local): Fix description. + Add an example where -Wshadow=compatible-local does not + warn. + 2019-10-03 John David Anglin * config/pa/pa.h (MAX_PCREL17F_OFFSET): Adjust. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ac20e3a..0b56162 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -6477,13 +6477,14 @@ Do not warn whenever a local variable shadows an instance variable in an Objective-C method. @item -Wshadow=global -@opindex Wshadow=local +@opindex Wshadow=global The default for @option{-Wshadow}. Warns for any (global) shadowing. +This warning is enabled by @option{-Wshadow=global}. @item -Wshadow=local @opindex Wshadow=local Warn when a local variable shadows another local variable or parameter. -This warning is enabled by @option{-Wshadow=global}. +This warning is enabled by @option{-Wshadow=local}. @item -Wshadow=compatible-local @opindex Wshadow=compatible-local @@ -6515,8 +6516,10 @@ in place of the other, type checking will catch that and emit an error or warning. So not warning (about shadowing) in this case will not lead to undetected bugs. Use of this flag instead of @option{-Wshadow=local} can possibly reduce the number of warnings triggered by intentional shadowing. +Note that this does also mean that shadowing @code{const char *i} by +@code{char *i} will not emit a warning. -This warning is enabled by @option{-Wshadow=local}. +This warning is enabled by @option{-Wshadow=compatible-local}. @item -Wlarger-than=@var{byte-size} @opindex Wlarger-than= -- cgit v1.1 From 708935b2b44663505a1cccf1a4aec80b310d0052 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 4 Oct 2019 08:54:05 +0200 Subject: re PR c++/91974 (function not sequenced before function argument) PR c++/91974 * cp-gimplify.c (cp_gimplify_expr) : For -fstrong-eval-order ensure CALL_EXPR_FN side-effects are evaluated before any arguments. Additionally, ensure CALL_EXPR_FN that isn't invariant nor OBJ_TYPE_REF nor SSA_NAME is forced into a temporary. * g++.dg/cpp1z/eval-order5.C: New test. From-SVN: r276562 --- gcc/cp/ChangeLog | 8 ++++++++ gcc/cp/cp-gimplify.c | 15 +++++++++++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp1z/eval-order5.C | 31 +++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1z/eval-order5.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bd3592a..a11bdaf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-10-04 Jakub Jelinek + + PR c++/91974 + * cp-gimplify.c (cp_gimplify_expr) : For + -fstrong-eval-order ensure CALL_EXPR_FN side-effects are evaluated + before any arguments. Additionally, ensure CALL_EXPR_FN that isn't + invariant nor OBJ_TYPE_REF nor SSA_NAME is forced into a temporary. + 2019-10-03 Paolo Carlini * init.c (build_new): Use cp_expr_loc_or_input_loc in two places. diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 8bda736..6545392 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -818,6 +818,21 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case CALL_EXPR: ret = GS_OK; + if (flag_strong_eval_order == 2 + && CALL_EXPR_FN (*expr_p) + && cp_get_callee_fndecl_nofold (*expr_p) == NULL_TREE) + { + enum gimplify_status t + = gimplify_expr (&CALL_EXPR_FN (*expr_p), pre_p, NULL, + is_gimple_call_addr, fb_rvalue); + if (t == GS_ERROR) + ret = GS_ERROR; + else if (is_gimple_variable (CALL_EXPR_FN (*expr_p)) + && TREE_CODE (CALL_EXPR_FN (*expr_p)) != SSA_NAME) + CALL_EXPR_FN (*expr_p) + = get_initialized_tmp_var (CALL_EXPR_FN (*expr_p), pre_p, + NULL); + } if (!CALL_EXPR_FN (*expr_p)) /* Internal function call. */; else if (CALL_EXPR_REVERSE_ARGS (*expr_p)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fdfcde2..1dce341 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Jakub Jelinek + + PR c++/91974 + * g++.dg/cpp1z/eval-order5.C: New test. + 2019-10-03 Steven G. Kargl PR fortran/91497 diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order5.C b/gcc/testsuite/g++.dg/cpp1z/eval-order5.C new file mode 100644 index 0000000..a8f06ed --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/eval-order5.C @@ -0,0 +1,31 @@ +// PR c++/91974 +// { dg-do run } +// { dg-options "-fstrong-eval-order" } + +extern "C" void abort (); + +bool ok = false; + +void +foo (int x) +{ + if (x != 0) + abort (); + ok = true; +} + +void +bar (int) +{ + abort (); +} + +int +main () +{ + typedef void (*T) (int); + T fn = foo; + fn ((fn = bar, 0)); + if (fn != bar || !ok) + abort (); +} -- cgit v1.1 From 0fe2ae2902e9e65a4ce6cf56b3c34c02677d33a4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 4 Oct 2019 08:56:02 +0200 Subject: re PR c++/71504 ([C++11] constexpr fails with multidimensional arrays) PR c++/71504 * constexpr.c (cxx_fold_indirect_ref_1): New function. (cxx_fold_indirect_ref): Use it. * g++.dg/cpp0x/constexpr-array21.C: New test. * g++.dg/cpp1y/constexpr-array7.C: New test. * g++.dg/cpp1z/constexpr-array1.C: New test. 2019-10-04 Jason Merrill PR c++/71504 * g++.dg/cpp0x/constexpr-array20.C: New test. From-SVN: r276563 --- gcc/cp/ChangeLog | 4 + gcc/cp/constexpr.c | 231 +++++++++++-------------- gcc/testsuite/ChangeLog | 12 ++ gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C | 15 ++ gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C | 27 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C | 16 ++ gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C | 46 +++++ 7 files changed, 223 insertions(+), 128 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C (limited to 'gcc') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a11bdaf..e705bcc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2019-10-04 Jakub Jelinek + PR c++/71504 + * constexpr.c (cxx_fold_indirect_ref_1): New function. + (cxx_fold_indirect_ref): Use it. + PR c++/91974 * cp-gimplify.c (cp_gimplify_expr) : For -fstrong-eval-order ensure CALL_EXPR_FN side-effects are evaluated diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 2008793..2dc57f1 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3346,6 +3346,103 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) return same_type_ignoring_top_level_qualifiers_p (type1, type2); } +/* Helper function for cxx_fold_indirect_ref_1, called recursively. */ + +static tree +cxx_fold_indirect_ref_1 (location_t loc, tree type, tree op, + unsigned HOST_WIDE_INT off, bool *empty_base) +{ + tree optype = TREE_TYPE (op); + unsigned HOST_WIDE_INT const_nunits; + if (off == 0) + { + if (similar_type_p (optype, type)) + return op; + /* Also handle conversion to an empty base class, which + is represented with a NOP_EXPR. */ + /* *(foo *)&complexfoo => __real__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && similar_type_p (type, TREE_TYPE (optype))) + return build1_loc (loc, REALPART_EXPR, type, op); + } + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && similar_type_p (type, TREE_TYPE (optype)) + && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off) + return build1_loc (loc, IMAGPART_EXPR, type, op); + if (is_empty_class (type) + && CLASS_TYPE_P (optype) + && DERIVED_FROM_P (type, optype)) + { + *empty_base = true; + return op; + } + /* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF */ + else if (VECTOR_TYPE_P (optype) + && similar_type_p (type, TREE_TYPE (optype)) + && TYPE_VECTOR_SUBPARTS (optype).is_constant (&const_nunits)) + { + unsigned HOST_WIDE_INT part_width = tree_to_uhwi (TYPE_SIZE_UNIT (type)); + unsigned HOST_WIDE_INT max_offset = part_width * const_nunits; + if (off < max_offset && off % part_width == 0) + { + tree index = bitsize_int (off * BITS_PER_UNIT); + return build3_loc (loc, BIT_FIELD_REF, type, op, + TYPE_SIZE (type), index); + } + } + /* ((foo *)&fooarray)[x] => fooarray[x] */ + else if (TREE_CODE (optype) == ARRAY_TYPE + && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (optype))) + && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype)))) + { + tree type_domain = TYPE_DOMAIN (optype); + tree min_val = size_zero_node; + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + unsigned HOST_WIDE_INT el_sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (optype))); + unsigned HOST_WIDE_INT idx = off / el_sz; + unsigned HOST_WIDE_INT rem = off % el_sz; + if (tree_fits_uhwi_p (min_val)) + { + tree index = size_int (idx + tree_to_uhwi (min_val)); + op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index, + NULL_TREE, NULL_TREE); + return cxx_fold_indirect_ref_1 (loc, type, op, rem, + empty_base); + } + } + /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */ + else if (TREE_CODE (optype) == RECORD_TYPE) + { + for (tree field = TYPE_FIELDS (optype); + field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && TREE_TYPE (field) != error_mark_node + && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (field)))) + { + tree pos = byte_position (field); + if (!tree_fits_uhwi_p (pos)) + continue; + unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos); + unsigned el_sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); + if (upos <= off && off < upos + el_sz) + { + tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), + op, field, NULL_TREE); + if (tree ret = cxx_fold_indirect_ref_1 (loc, type, cop, + off - upos, + empty_base)) + return ret; + } + } + } + + return NULL_TREE; +} + /* A less strict version of fold_indirect_ref_1, which requires cv-quals to match. We want to be less strict for simple *& folding; if we have a non-const temporary that we access through a const pointer, that should @@ -3353,9 +3450,7 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) because we're dealing with things like ADDR_EXPR of INTEGER_CST which don't really make sense outside of constant expression evaluation. Also we want to allow folding to COMPONENT_REF, which could cause trouble - with TBAA in fold_indirect_ref_1. - - Try to keep this function synced with fold_indirect_ref_1. */ + with TBAA in fold_indirect_ref_1. */ static tree cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) @@ -3386,139 +3481,19 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) else return op; } - /* *(foo *)&fooarray => fooarray[0] */ - else if (TREE_CODE (optype) == ARRAY_TYPE - && similar_type_p (type, TREE_TYPE (optype))) - { - tree type_domain = TYPE_DOMAIN (optype); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - return build4_loc (loc, ARRAY_REF, type, op, min_val, - NULL_TREE, NULL_TREE); - } - /* *(foo *)&complexfoo => __real__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (optype))) - return fold_build1_loc (loc, REALPART_EXPR, type, op); - /* *(foo *)&vectorfoo => BIT_FIELD_REF */ - else if (VECTOR_TYPE_P (optype) - && similar_type_p (type, TREE_TYPE (optype))) - { - tree part_width = TYPE_SIZE (type); - tree index = bitsize_int (0); - return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, - index); - } - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ - else if (is_empty_class (type) - && CLASS_TYPE_P (optype) - && DERIVED_FROM_P (type, optype)) - { - *empty_base = true; - return op; - } - /* *(foo *)&struct_with_foo_field => COMPONENT_REF */ - else if (RECORD_OR_UNION_TYPE_P (optype)) - { - tree field = TYPE_FIELDS (optype); - for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && TREE_TYPE (field) != error_mark_node - && integer_zerop (byte_position (field)) - && similar_type_p (TREE_TYPE (field), type)) - return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE); - } + else + return cxx_fold_indirect_ref_1 (loc, type, op, 0, empty_base); } else if (TREE_CODE (sub) == POINTER_PLUS_EXPR - && poly_int_tree_p (TREE_OPERAND (sub, 1), &const_op01)) + && tree_fits_uhwi_p (TREE_OPERAND (sub, 1))) { tree op00 = TREE_OPERAND (sub, 0); tree op01 = TREE_OPERAND (sub, 1); STRIP_NOPS (op00); if (TREE_CODE (op00) == ADDR_EXPR) - { - tree op00type; - op00 = TREE_OPERAND (op00, 0); - op00type = TREE_TYPE (op00); - - /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF */ - if (VECTOR_TYPE_P (op00type) - && similar_type_p (type, TREE_TYPE (op00type)) - /* POINTER_PLUS_EXPR second operand is sizetype, unsigned, - but we want to treat offsets with MSB set as negative. - For the code below negative offsets are invalid and - TYPE_SIZE of the element is something unsigned, so - check whether op01 fits into poly_int64, which implies - it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and - then just use poly_uint64 because we want to treat the - value as unsigned. */ - && tree_fits_poly_int64_p (op01)) - { - tree part_width = TYPE_SIZE (type); - poly_uint64 max_offset - = (tree_to_uhwi (part_width) / BITS_PER_UNIT - * TYPE_VECTOR_SUBPARTS (op00type)); - if (known_lt (const_op01, max_offset)) - { - tree index = bitsize_int (const_op01 * BITS_PER_UNIT); - return fold_build3_loc (loc, - BIT_FIELD_REF, type, op00, - part_width, index); - } - } - /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ - else if (TREE_CODE (op00type) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (op00type))) - { - if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)), - const_op01)) - return fold_build1_loc (loc, IMAGPART_EXPR, type, op00); - } - /* ((foo *)&fooarray)[1] => fooarray[1] */ - else if (TREE_CODE (op00type) == ARRAY_TYPE - && similar_type_p (type, TREE_TYPE (op00type))) - { - tree type_domain = TYPE_DOMAIN (op00type); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - offset_int off = wi::to_offset (op01); - offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (type)); - offset_int remainder; - off = wi::divmod_trunc (off, el_sz, SIGNED, &remainder); - if (remainder == 0 && TREE_CODE (min_val) == INTEGER_CST) - { - off = off + wi::to_offset (min_val); - op01 = wide_int_to_tree (sizetype, off); - return build4_loc (loc, ARRAY_REF, type, op00, op01, - NULL_TREE, NULL_TREE); - } - } - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ - else if (is_empty_class (type) - && CLASS_TYPE_P (op00type) - && DERIVED_FROM_P (type, op00type)) - { - *empty_base = true; - return op00; - } - /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */ - else if (RECORD_OR_UNION_TYPE_P (op00type)) - { - tree field = TYPE_FIELDS (op00type); - for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && TREE_TYPE (field) != error_mark_node - && tree_int_cst_equal (byte_position (field), op01) - && similar_type_p (TREE_TYPE (field), type)) - return fold_build3 (COMPONENT_REF, type, op00, - field, NULL_TREE); - } - } + return cxx_fold_indirect_ref_1 (loc, type, TREE_OPERAND (op00, 0), + tree_to_uhwi (op01), empty_base); } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1dce341..60e6caa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,17 @@ 2019-10-04 Jakub Jelinek + PR c++/71504 + * g++.dg/cpp0x/constexpr-array21.C: New test. + * g++.dg/cpp1y/constexpr-array7.C: New test. + * g++.dg/cpp1z/constexpr-array1.C: New test. + +2019-10-04 Jason Merrill + + PR c++/71504 + * g++.dg/cpp0x/constexpr-array20.C: New test. + +2019-10-04 Jakub Jelinek + PR c++/91974 * g++.dg/cpp1z/eval-order5.C: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C new file mode 100644 index 0000000..217bbf4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C @@ -0,0 +1,15 @@ +// PR c++/71504 +// { dg-do compile { target c++11 } } + +enum E { e }; + +constexpr bool arr[1][1] = {{true}}; + +template +void check() { + static_assert(arr[x][y], ""); +} + +int main() { + check(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C new file mode 100644 index 0000000..e085098 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C @@ -0,0 +1,27 @@ +// PR c++/71504 +// { dg-do compile { target c++11 } } + +typedef const char A4 [10]; + +constexpr A4 a [] = { "123", "123456", "123456789" }; + +constexpr int len (const char *s) +{ + return *s ? 1 + len (s + 1) : 0; +} + +constexpr const char *s = a[0]; +constexpr const char *t = (a + 2)[-2]; + +constexpr int n0 = len (s); +constexpr int n1 = len (t); + +constexpr int n2 = len (a[0]); +constexpr int n3 = len ((a + 2)[-2]); + +#define A(e) static_assert ((e), #e) + +A (n0 == 3); +A (n0 == n1); +A (n0 == n2); +A (n0 == n3); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C new file mode 100644 index 0000000..30bd8fd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C @@ -0,0 +1,16 @@ +// PR c++/71504 +// { dg-do compile { target c++14 } } + +template +constexpr auto +sum (A const &a) +{ + int tot = 0; + for (auto &row : a) + for (auto elem : row) + tot += elem; + return tot; +} + +constexpr int const a22[2][2] = {{1,2},{3,4}}; +static_assert (sum(a22) == 10, "badsum"); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C new file mode 100644 index 0000000..02435d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C @@ -0,0 +1,46 @@ +// PR c++/71504 +// { dg-do compile { target c++17 } } + +typedef __SIZE_TYPE__ size_t; +template +struct integral_constant +{ + static constexpr T value = v; + typedef T value_type; + typedef integral_constant type; + constexpr operator value_type () const noexcept { return value; } + constexpr value_type operator() () const noexcept { return value; } +}; +template +constexpr T integral_constant::value; +typedef integral_constant true_type; +typedef integral_constant false_type; +template +struct is_array : public false_type { }; +template +struct is_array : public true_type { }; +template +struct is_array : public true_type { }; +template +struct conditional; +template +struct conditional { typedef T type; }; +template +struct conditional { typedef F type; }; +template +struct array_ref; +template +using ref_t = typename conditional::value, array_ref, T&>::type; +template +struct array_ref +{ + T *a; + using const_reference = const ref_t; + constexpr const_reference operator[] (unsigned I) const { return {a[I]}; } +}; +template +array_ref (A&) -> array_ref; +constexpr int a2[2] = {1,2}; +static_assert (array_ref{a2}[0] == 1); +constexpr int a22[2][2] = {{1,2},{3,4}}; +static_assert (array_ref{a22}[0][0] == 1); -- cgit v1.1 From 3d203d01760ed8e5a81a9406fee67c139d116ad0 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 4 Oct 2019 07:08:56 +0000 Subject: Adjust various comments and rename some functions in range-op.cc to improve readability. From-SVN: r276564 --- gcc/ChangeLog | 10 ++++++++++ gcc/range-op.cc | 53 +++++++++++++++++++++++++++-------------------------- 2 files changed, 37 insertions(+), 26 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0c8f331..6e4f145 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-10-04 Aldy Hernandez + + (value_range_from_overflowed_bounds): Rename from + adjust_overflow_bound. + (value_range_with_overflow): Rename from + create_range_with_overflow. + (create_possibly_reversed_range): Adjusted for above renames. + (operator_*::wi_fold): Same. + (cross_product_operator::wi_cross_productor): Same. + 2019-10-04 Bernd Edlinger * doc/invoke.texi (-Wshadow=global, -Wshadow=local, diff --git a/gcc/range-op.cc b/gcc/range-op.cc index b538b00..fff4a55 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -185,12 +185,13 @@ range_operator::op2_range (value_range_base &r ATTRIBUTE_UNUSED, } -// Called when there is either an overflow OR an underflow... which -// means an anti range must be created to compensate. This does not -// cover the case where there are 2 possible overflows, or none. +// Create and return a range from a pair of wide-ints that are known +// to have overflowed (or underflowed). static value_range_base -adjust_overflow_bound (tree type, const wide_int &wmin, const wide_int &wmax) +value_range_from_overflowed_bounds (tree type, + const wide_int &wmin, + const wide_int &wmax) { const signop sgn = TYPE_SIGN (type); const unsigned int prec = TYPE_PRECISION (type); @@ -216,15 +217,15 @@ adjust_overflow_bound (tree type, const wide_int &wmin, const wide_int &wmax) return value_range_base (VR_ANTI_RANGE, type, tmin, tmax); } -// Given a newly calculated lbound and ubound, examine their -// respective overflow bits to determine how to create a range. -// Return said range. +// Create and return a range from a pair of wide-ints. MIN_OVF and +// MAX_OVF describe any overflow that might have occurred while +// calculating WMIN and WMAX respectively. static value_range_base -create_range_with_overflow (tree type, - const wide_int &wmin, const wide_int &wmax, - wi::overflow_type min_ovf = wi::OVF_NONE, - wi::overflow_type max_ovf = wi::OVF_NONE) +value_range_with_overflow (tree type, + const wide_int &wmin, const wide_int &wmax, + wi::overflow_type min_ovf = wi::OVF_NONE, + wi::overflow_type max_ovf = wi::OVF_NONE) { const signop sgn = TYPE_SIGN (type); const unsigned int prec = TYPE_PRECISION (type); @@ -255,7 +256,7 @@ create_range_with_overflow (tree type, if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE) || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE)) - return adjust_overflow_bound (type, wmin, wmax); + return value_range_from_overflowed_bounds (type, wmin, wmax); // Other underflow and/or overflow, drop to VR_VARYING. return value_range_base (type); @@ -282,9 +283,9 @@ create_range_with_overflow (tree type, } } -// Like above, but canonicalize the case where the bounds are swapped -// and overflow may wrap. In which case, we transform [10,5] into -// [MIN,5][10,MAX]. +// Create and return a range from a pair of wide-ints. Canonicalize +// the case where the bounds are swapped. In which case, we transform +// [10,5] into [MIN,5][10,MAX]. static inline value_range_base create_possibly_reversed_range (tree type, @@ -293,7 +294,7 @@ create_possibly_reversed_range (tree type, signop s = TYPE_SIGN (type); // If the bounds are swapped, treat the result as if an overflow occured. if (wi::gt_p (new_lb, new_ub, s)) - return adjust_overflow_bound (type, new_lb, new_ub); + return value_range_from_overflowed_bounds (type, new_lb, new_ub); // Otherwise its just a normal range. return value_range_base (type, new_lb, new_ub); @@ -907,7 +908,7 @@ operator_plus::wi_fold (tree type, signop s = TYPE_SIGN (type); wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb); wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub); - return create_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); + return value_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); } bool @@ -954,7 +955,7 @@ operator_minus::wi_fold (tree type, signop s = TYPE_SIGN (type); wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb); wide_int new_ub = wi::sub (lh_ub, rh_lb, s, &ov_ub); - return create_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); + return value_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); } bool @@ -994,7 +995,7 @@ operator_min::wi_fold (tree type, signop s = TYPE_SIGN (type); wide_int new_lb = wi::min (lh_lb, rh_lb, s); wide_int new_ub = wi::min (lh_ub, rh_ub, s); - return create_range_with_overflow (type, new_lb, new_ub); + return value_range_with_overflow (type, new_lb, new_ub); } @@ -1016,7 +1017,7 @@ operator_max::wi_fold (tree type, signop s = TYPE_SIGN (type); wide_int new_lb = wi::max (lh_lb, rh_lb, s); wide_int new_ub = wi::max (lh_ub, rh_ub, s); - return create_range_with_overflow (type, new_lb, new_ub); + return value_range_with_overflow (type, new_lb, new_ub); } @@ -1087,7 +1088,7 @@ cross_product_operator::wi_cross_product (tree type, // Choose min and max from the ordered pairs. wide_int res_lb = wi::min (cp1, cp3, sign); wide_int res_ub = wi::max (cp2, cp4, sign); - return create_range_with_overflow (type, res_lb, res_ub); + return value_range_with_overflow (type, res_lb, res_ub); } @@ -1832,7 +1833,7 @@ wi_optimize_and_or (value_range_base &r, } else gcc_unreachable (); - r = create_range_with_overflow (type, res_lb, res_ub); + r = value_range_with_overflow (type, res_lb, res_ub); return true; } @@ -1932,7 +1933,7 @@ operator_bitwise_and::wi_fold (tree type, if (wi::gt_p (new_lb, new_ub,sign)) return value_range_base (type); - return create_range_with_overflow (type, new_lb, new_ub); + return value_range_with_overflow (type, new_lb, new_ub); } bool @@ -2070,7 +2071,7 @@ operator_bitwise_or::wi_fold (tree type, if (wi::gt_p (new_lb, new_ub,sign)) return value_range_base (type); - return create_range_with_overflow (type, new_lb, new_ub); + return value_range_with_overflow (type, new_lb, new_ub); } bool @@ -2132,7 +2133,7 @@ operator_bitwise_xor::wi_fold (tree type, // If the range has all positive or all negative values, the result // is better than VARYING. if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign)) - return create_range_with_overflow (type, new_lb, new_ub); + return value_range_with_overflow (type, new_lb, new_ub); return value_range_base (type); } @@ -2186,7 +2187,7 @@ operator_trunc_mod::wi_fold (tree type, tmp = wi::zero (prec); new_ub = wi::min (new_ub, tmp, sign); - return create_range_with_overflow (type, new_lb, new_ub); + return value_range_with_overflow (type, new_lb, new_ub); } -- cgit v1.1 From 48528394eafa9d1db9f956570f910c76d429a3e5 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 4 Oct 2019 09:18:26 +0000 Subject: re PR target/91982 (gcc.target/aarch64/sve/clastb_*.c tests failing with segfault) 2019-10-04 Richard Biener PR tree-optimization/91982 * tree-vect-loop.c (vectorizable_live_operation): Also guard against EXTRACT_LAST_REDUCTION. * tree-vect-stmts.c (vect_transform_stmt): Likewise. From-SVN: r276566 --- gcc/ChangeLog | 7 +++++++ gcc/tree-vect-loop.c | 5 ++++- gcc/tree-vect-stmts.c | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6e4f145..9a303c5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-04 Richard Biener + + PR tree-optimization/91982 + * tree-vect-loop.c (vectorizable_live_operation): Also guard + against EXTRACT_LAST_REDUCTION. + * tree-vect-stmts.c (vect_transform_stmt): Likewise. + 2019-10-04 Aldy Hernandez (value_range_from_overflowed_bounds): Rename from diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 31e7457..3db4a5c 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -7901,7 +7901,10 @@ vectorizable_live_operation (stmt_vec_info stmt_info, return true; if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def) { - if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION) + if (STMT_VINFO_REDUC_TYPE (stmt_info) == FOLD_LEFT_REDUCTION + || (STMT_VINFO_REDUC_TYPE (stmt_info) == COND_REDUCTION + && (STMT_VINFO_VEC_REDUCTION_TYPE (stmt_info) + == EXTRACT_LAST_REDUCTION))) return true; if (slp_node) { diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index f997ad2..cac7410 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -10897,6 +10897,9 @@ vect_transform_stmt (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, stmt_vec_info orig_stmt_info = vect_orig_stmt (stmt_info); if (!slp_node && STMT_VINFO_REDUC_DEF (orig_stmt_info) && STMT_VINFO_REDUC_TYPE (orig_stmt_info) != FOLD_LEFT_REDUCTION + && (STMT_VINFO_REDUC_TYPE (orig_stmt_info) != COND_REDUCTION + || (STMT_VINFO_VEC_REDUCTION_TYPE (orig_stmt_info) + != EXTRACT_LAST_REDUCTION)) && is_a (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt)) { gphi *phi = as_a (STMT_VINFO_REDUC_DEF (orig_stmt_info)->stmt); -- cgit v1.1 From 981e39974ea31cb418507eadcb2cd7bbdf27ed79 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Fri, 4 Oct 2019 11:29:31 +0200 Subject: [Fortran] Fix column of %C diagnostic location gcc/fortran/ * error (error_print, gfc_format_decoder): Fix off-by one issue with %C. gcc/testsuite/ * gfortran.dg/use_without_only_1.f90: Update column num in dg-warning. From-SVN: r276567 --- gcc/fortran/ChangeLog | 10 +++++++--- gcc/fortran/error.c | 11 ++++++++++- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gfortran.dg/use_without_only_1.f90 | 6 +++--- 4 files changed, 24 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 9a2a800..196b40b 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,7 @@ +2019-10-04 Tobias Burnus + + * error (error_print, gfc_format_decoder): Fix off-by one issue with %C. + 2019-10-03 Steven G. Kargl PR fortran/91497 @@ -54,7 +58,7 @@ messages instead of the original call to gfc_typename. * misc.c (gfc_typename): New function for gfc_expr *, use for where character types are possible it can get the character length from - gfc_expr for character literals. + gfc_expr for character literals. (gfc_dummy_typename): New functionfor gfc_typespec *, if no character length is present the character type is assumed and the appropriate string is return otherwise it calls gfc_typename for gfc_typespec *. @@ -88,10 +92,10 @@ a subroutine reference. * resolve.c (resolve_function): BOZ cannot be an actual argument in a function reference. - + 2019-10-01 Jan Hubicka - * module.c (load_commons): Initialize flags to 0 to silecne + * module.c (load_commons): Initialize flags to 0 to silence -Wmaybe-uninitialized warning. (read_module): Likewise for n and comp_name. diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c index a7c27f0..1019f17 100644 --- a/gcc/fortran/error.c +++ b/gcc/fortran/error.c @@ -618,12 +618,18 @@ error_print (const char *type, const char *format0, va_list argp) { l2 = loc; arg[pos].u.stringval = "(2)"; + /* Point %C first offending character not the last good one. */ + if (arg[pos].type == TYPE_CURRENTLOC) + l2->nextc++; } else { l1 = loc; have_l1 = 1; arg[pos].u.stringval = "(1)"; + /* Point %C first offending character not the last good one. */ + if (arg[pos].type == TYPE_CURRENTLOC) + l1->nextc++; } break; @@ -963,6 +969,9 @@ gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec, loc = va_arg (*text->args_ptr, locus *); gcc_assert (loc->nextc - loc->lb->line >= 0); unsigned int offset = loc->nextc - loc->lb->line; + if (*spec == 'C') + /* Point %C first offending character not the last good one. */ + offset++; /* If location[0] != UNKNOWN_LOCATION means that we already processed one of %C/%L. */ int loc_num = text->get_location (0) == UNKNOWN_LOCATION ? 0 : 1; @@ -1401,7 +1410,7 @@ gfc_internal_error (const char *gmsgid, ...) void gfc_clear_error (void) { - error_buffer.flag = 0; + error_buffer.flag = false; warnings_not_errors = false; gfc_clear_pp_buffer (pp_error_buffer); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 60e6caa..b8c9f4c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-04 Tobias Burnus + + * gfortran.dg/use_without_only_1.f90: Update column num in dg-warning. + 2019-10-04 Jakub Jelinek PR c++/71504 diff --git a/gcc/testsuite/gfortran.dg/use_without_only_1.f90 b/gcc/testsuite/gfortran.dg/use_without_only_1.f90 index 06af985..ad64b20 100644 --- a/gcc/testsuite/gfortran.dg/use_without_only_1.f90 +++ b/gcc/testsuite/gfortran.dg/use_without_only_1.f90 @@ -6,16 +6,16 @@ MODULE foo END MODULE MODULE testmod - USE foo ! { dg-warning "6:has no ONLY qualifier" } + USE foo ! { dg-warning "7:has no ONLY qualifier" } IMPLICIT NONE CONTAINS SUBROUTINE S1 - USE foo ! { dg-warning "9:has no ONLY qualifier" } + USE foo ! { dg-warning "10:has no ONLY qualifier" } END SUBROUTINE S1 SUBROUTINE S2 USE foo, ONLY: bar END SUBROUTINE SUBROUTINE S3 - USE ISO_C_BINDING ! { dg-warning "9:has no ONLY qualifier" } + USE ISO_C_BINDING ! { dg-warning "10:has no ONLY qualifier" } END SUBROUTINE S3 END MODULE -- cgit v1.1 From 67044452770aefa5b686855b1b1cb5d0728ec994 Mon Sep 17 00:00:00 2001 From: Yuliang Wang Date: Fri, 4 Oct 2019 10:40:47 +0000 Subject: Fix gcc.target/aarch64/sve2/shracc_1.c for ILP32 2019-10-04 Yuliang Wang gcc/testsuite/ * gcc.target/aarch64/sve2/shracc_1.c: Tighten scan-assembler-nots to avoid matching scalar code. From-SVN: r276568 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b8c9f4c..950c748 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Yuliang Wang + + * gcc.target/aarch64/sve2/shracc_1.c: Tighten scan-assembler-nots + to avoid matching scalar code. + 2019-10-04 Tobias Burnus * gfortran.dg/use_without_only_1.f90: Update column num in dg-warning. diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c index 5535c7d..8111237 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/shracc_1.c @@ -24,9 +24,9 @@ SHRACC (uint64_t, 53); /* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 8 "vect" } } */ -/* { dg-final { scan-assembler-not {\tasr\t} } } */ -/* { dg-final { scan-assembler-not {\tlsr\t} } } */ -/* { dg-final { scan-assembler-not {\tadd\t} } } */ +/* { dg-final { scan-assembler-not {\tasr\tz[0-9]+\.[bhsd]} } } */ +/* { dg-final { scan-assembler-not {\tlsr\tz[0-9]+\.[bhsd]} } } */ +/* { dg-final { scan-assembler-not {\tadd\tz[0-9]+\.[bhsd]} } } */ /* { dg-final { scan-assembler-times {\tssra\tz[0-9]+\.b, z[0-9]+\.b, #5\n} 1 } } */ /* { dg-final { scan-assembler-times {\tssra\tz[0-9]+\.h, z[0-9]+\.h, #14\n} 1 } } */ -- cgit v1.1 From dd935a565b5b0fcba5cc595407261cbb1ed48e39 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 4 Oct 2019 11:37:16 +0000 Subject: re PR debug/91968 (DW_AT_low_pc missing for DW_TAG_label with LTO) 2019-10-04 Richard Biener PR lto/91968 * tree.c (find_decls_types_r): Do not remove LABEL_DECLs from BLOCK_VARS. From-SVN: r276571 --- gcc/ChangeLog | 6 ++++++ gcc/tree.c | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9a303c5..97e48c0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2019-10-04 Richard Biener + PR lto/91968 + * tree.c (find_decls_types_r): Do not remove LABEL_DECLs from + BLOCK_VARS. + +2019-10-04 Richard Biener + PR tree-optimization/91982 * tree-vect-loop.c (vectorizable_live_operation): Also guard against EXTRACT_LAST_REDUCTION. diff --git a/gcc/tree.c b/gcc/tree.c index 59ea6b9..e845fc7 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -5963,8 +5963,9 @@ find_decls_types_r (tree *tp, int *ws, void *data) { for (tree *tem = &BLOCK_VARS (t); *tem; ) { - if (TREE_CODE (*tem) != VAR_DECL - || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem))) + if (TREE_CODE (*tem) != LABEL_DECL + && (TREE_CODE (*tem) != VAR_DECL + || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem)))) { gcc_assert (TREE_CODE (*tem) != RESULT_DECL && TREE_CODE (*tem) != PARM_DECL); -- cgit v1.1 From 2e82a4615abc70d4ab75f15948d3396728822dfa Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 4 Oct 2019 11:40:40 +0000 Subject: loop-3.c: Fix undefined behavior. 2019-10-04 Richard Biener * gcc.c-torture/execute/loop-3.c: Fix undefined behavior. From-SVN: r276572 --- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gcc.c-torture/execute/loop-3.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 950c748..3e5a945 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-10-04 Richard Biener + + * gcc.c-torture/execute/loop-3.c: Fix undefined behavior. + 2019-10-04 Yuliang Wang * gcc.target/aarch64/sve2/shracc_1.c: Tighten scan-assembler-nots diff --git a/gcc/testsuite/gcc.c-torture/execute/loop-3.c b/gcc/testsuite/gcc.c-torture/execute/loop-3.c index e314a01..33eb188 100644 --- a/gcc/testsuite/gcc.c-torture/execute/loop-3.c +++ b/gcc/testsuite/gcc.c-torture/execute/loop-3.c @@ -13,7 +13,7 @@ f (m) i = m; do { - g (i * INT_MAX / 2); + g ((int)((unsigned)i * INT_MAX) / 2); } while (--i > 0); } -- cgit v1.1 From 0ced79bc4c9925c574177cb6345c26e4aad4155f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 4 Oct 2019 13:27:53 +0000 Subject: Fix gcc.target/aarch64/torture/simd-abi-8.c for big-endian Fix a big-endian failure reported by Christophe. Also tighten the test so that it doesn't allow saving and restoring 128-bit vectors as Q registers. 2019-10-04 Richard Sandiford gcc/testsuite/ * gcc.target/aarch64/torture/simd-abi-8.c: Use -mlittle-endian. Check that there are no Q register saves or restores. From-SVN: r276577 --- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3e5a945..5c5d869 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Richard Sandiford + + * gcc.target/aarch64/torture/simd-abi-8.c: Use -mlittle-endian. + Check that there are no Q register saves or restores. + 2019-10-04 Richard Biener * gcc.c-torture/execute/loop-3.c: Fix undefined behavior. diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c index 6463f6c..f3be8e7 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-8.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-std=gnu99" } */ +/* { dg-options "-std=gnu99 -mlittle-endian" } */ /* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ #include @@ -18,3 +18,5 @@ g (int64x2x4_t *ptr) /* { dg-final { scan-assembler-times {\tld1\t} 1 } } */ /* { dg-final { scan-assembler-times {\tst1\t} 1 } } */ +/* { dg-final { scan-assembler-not {\tld[pr]\tq} } } */ +/* { dg-final { scan-assembler-not {\tst[pr]\tq} } } */ -- cgit v1.1 From 3694418a6d57c5b48383af8a5c6d1b1c2e3cec9b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 4 Oct 2019 13:50:07 +0000 Subject: compiler: adjust code to avoid shadowing local variables Also add a couple of missing calls to free after mpz_get_str. This should make the code clean with respect to -Wshadow=local. Based on patch by Bernd Edlinger. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/198837 From-SVN: r276579 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/ast-dump.cc | 8 +++--- gcc/go/gofrontend/escape.cc | 1 - gcc/go/gofrontend/expressions.cc | 54 ++++++++++++++++++---------------------- gcc/go/gofrontend/gogo.cc | 28 ++++++++++----------- gcc/go/gofrontend/parse.cc | 26 +++++++++---------- gcc/go/gofrontend/statements.cc | 17 +++++++------ gcc/go/gofrontend/types.cc | 40 ++++++++++++++--------------- 8 files changed, 85 insertions(+), 91 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 54c682a..bb50994 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -a3aef6b6df932ea6c7094d074695bc0b033a3d17 +441f3f1f350b532707c48273d7f454cf1c4e959f The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/ast-dump.cc b/gcc/go/gofrontend/ast-dump.cc index b20f7e4..a3cbda9 100644 --- a/gcc/go/gofrontend/ast-dump.cc +++ b/gcc/go/gofrontend/ast-dump.cc @@ -135,11 +135,11 @@ Ast_dump_traverse_blocks_and_functions::function(Named_object* no) { if (it != res->begin()) this->ast_dump_context_->ostream() << ","; - Named_object* no = (*it); + Named_object* rno = (*it); - this->ast_dump_context_->ostream() << no->name() << " "; - go_assert(no->is_result_variable()); - Result_variable* resvar = no->result_var_value(); + this->ast_dump_context_->ostream() << rno->name() << " "; + go_assert(rno->is_result_variable()); + Result_variable* resvar = rno->result_var_value(); this->ast_dump_context_->dump_type(resvar->type()); diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index bfd1a39..f8e07f7 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -1541,7 +1541,6 @@ Escape_analysis_assign::expression(Expression** pexpr) if (debug_level > 1) { - Node* n = Node::make_node(*pexpr); std::string fn_name = this->context_->current_function_name(); go_debug((*pexpr)->location(), "[%d] %s esc: %s", this->context_->loop_depth(), fn_name.c_str(), diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index a72ba24..9babc34 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -4104,9 +4104,11 @@ Type_conversion_expression::do_get_backend(Translate_context* context) x = mpz_get_ui(intval); else { - char* s = mpz_get_str(NULL, 16, intval); + char* ms = mpz_get_str(NULL, 16, intval); go_warning_at(loc, 0, - "unicode code point 0x%s out of range in string", s); + "unicode code point 0x%s out of range in string", + ms); + free(ms); x = 0xfffd; } Lex::append_char(x, true, &s, loc); @@ -8016,14 +8018,14 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, Expression* ret = Expression::make_struct_composite_literal(st, vals, loc); ret = Expression::make_heap_expression(ret, loc); - Node* n = Node::make_node(this); - if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE) + Node* node = Node::make_node(this); + if ((node->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE) ret->heap_expression()->set_allocate_on_stack(); else if (gogo->compiling_runtime() && gogo->package_name() == "runtime" && !saw_errors()) go_error_at(loc, "%s escapes to heap, not allowed in runtime", - n->ast_format(gogo).c_str()); + node->ast_format(gogo).c_str()); // If necessary, check whether the expression or any embedded // pointers are nil. @@ -8741,8 +8743,6 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter) Expression::make_nil(loc)); else { - Numeric_constant nclen; - unsigned long vlen; if (len_arg->numeric_constant_value(&nclen) && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID && vlen <= Map_type::bucket_size) @@ -9053,8 +9053,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, else { Type* int32_type = Type::lookup_integer_type("int32"); - Expression* zero = - Expression::make_integer_ul(0, int32_type, loc); + zero = Expression::make_integer_ul(0, int32_type, loc); call = Runtime::make_call(Runtime::BUILTIN_MEMSET, loc, 3, a1, zero, a2); } @@ -9064,15 +9063,12 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, // For a slice containing pointers, growslice already zeroed // the memory. We only need to zero in non-growing case. // Note: growslice does not zero the memory in non-pointer case. - Expression* left = - Expression::make_temporary_reference(ntmp, loc); - left = Expression::make_cast(uint_type, left, loc); - Expression* right = - Expression::make_temporary_reference(c1tmp, loc); - right = Expression::make_cast(uint_type, right, loc); - Expression* cond = - Expression::make_binary(OPERATOR_GT, left, right, loc); - Expression* zero = Expression::make_integer_ul(0, int_type, loc); + ref = Expression::make_temporary_reference(ntmp, loc); + ref = Expression::make_cast(uint_type, ref, loc); + ref2 = Expression::make_temporary_reference(c1tmp, loc); + ref2 = Expression::make_cast(uint_type, ref2, loc); + cond = Expression::make_binary(OPERATOR_GT, ref, ref2, loc); + zero = Expression::make_integer_ul(0, int_type, loc); call = Expression::make_conditional(cond, call, zero, loc); } } @@ -10877,9 +10873,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, if (this->result_count() > 1 && this->call_temp_ == NULL) { Struct_field_list* sfl = new Struct_field_list(); - Function_type* fntype = this->get_function_type(); const Typed_identifier_list* results = fntype->results(); - Location loc = this->location(); int i = 0; char buf[20]; @@ -12295,10 +12289,10 @@ Call_expression::do_get_backend(Translate_context* context) } else { - Expression* first_arg; - fn = this->interface_method_function(interface_method, &first_arg, + Expression* arg0; + fn = this->interface_method_function(interface_method, &arg0, location); - fn_args[0] = first_arg->get_backend(context); + fn_args[0] = arg0->get_backend(context); } Bexpression* bclosure = NULL; @@ -16453,11 +16447,11 @@ Composite_literal_expression::lower_array(Type* type) traverse_order = new std::vector(); traverse_order->reserve(v.size()); - for (V::const_iterator p = v.begin(); p != v.end(); ++p) + for (V::const_iterator pv = v.begin(); pv != v.end(); ++pv) { - indexes->push_back(p->index); - vals->push_back(p->expr); - traverse_order->push_back(p->traversal_order); + indexes->push_back(pv->index); + vals->push_back(pv->expr); + traverse_order->push_back(pv->traversal_order); } } @@ -17771,9 +17765,9 @@ Interface_info_expression::do_type() Interface_type* itype = this->iface_->type()->interface_type(); - Hashtable::const_iterator p = result_types.find(itype); - if (p != result_types.end()) - return p->second; + Hashtable::const_iterator pr = result_types.find(itype); + if (pr != result_types.end()) + return pr->second; Type* pdt = Type::make_type_descriptor_ptr_type(); if (itype->is_empty()) diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index e7af673..a79cfc3 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -518,11 +518,11 @@ Gogo::import_package(const std::string& filename, else if (ln == ".") { Bindings* bindings = package->bindings(); - for (Bindings::const_declarations_iterator p = + for (Bindings::const_declarations_iterator pd = bindings->begin_declarations(); - p != bindings->end_declarations(); - ++p) - this->add_dot_import_object(p->second); + pd != bindings->end_declarations(); + ++pd) + this->add_dot_import_object(pd->second); std::string dot_alias = "." + package->package_name(); package->add_alias(dot_alias, location); } @@ -678,8 +678,8 @@ Gogo::recompute_init_priorities() pci != ii->precursors().end(); ++pci) { - Import_init* ii = this->lookup_init(*pci); - nonroots.insert(ii); + Import_init* ii_init = this->lookup_init(*pci); + nonroots.insert(ii_init); } } @@ -2613,11 +2613,11 @@ Gogo::define_global_names() { if (no->type_declaration_value()->has_methods()) { - for (std::vector::const_iterator p = + for (std::vector::const_iterator pm = no->type_declaration_value()->methods()->begin(); - p != no->type_declaration_value()->methods()->end(); - p++) - go_error_at((*p)->location(), + pm != no->type_declaration_value()->methods()->end(); + pm++) + go_error_at((*pm)->location(), "may not define methods on non-local type"); } no->set_type_value(global_no->type_value()); @@ -6550,8 +6550,8 @@ Function::build(Gogo* gogo, Named_object* named_function) // Build the backend representation for all the statements in the // function. - Translate_context context(gogo, named_function, NULL, NULL); - Bblock* code_block = this->block_->get_backend(&context); + Translate_context bcontext(gogo, named_function, NULL, NULL); + Bblock* code_block = this->block_->get_backend(&bcontext); // Initialize variables if necessary. Translate_context icontext(gogo, named_function, this->block_, @@ -6608,8 +6608,8 @@ Function::build(Gogo* gogo, Named_object* named_function) // If we created a descriptor for the function, make sure we emit it. if (this->descriptor_ != NULL) { - Translate_context context(gogo, NULL, NULL, NULL); - this->descriptor_->get_backend(&context); + Translate_context dcontext(gogo, NULL, NULL, NULL); + this->descriptor_->get_backend(&dcontext); } } diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 52371b2..e50af61 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -836,7 +836,7 @@ Parse::parameter_list(bool* is_varargs) { std::string name = token->identifier(); bool is_exported = token->is_identifier_exported(); - Location location = token->location(); + Location id_location = token->location(); token = this->advance_token(); if (!token->is_op(OPERATOR_COMMA)) { @@ -861,7 +861,7 @@ Parse::parameter_list(bool* is_varargs) } this->unget_token(Token::make_identifier_token(name, is_exported, - location)); + id_location)); } else { @@ -872,15 +872,15 @@ Parse::parameter_list(bool* is_varargs) // commas as we can. std::string id_name = this->gogo_->pack_hidden_name(name, is_exported); - ret->push_back(Typed_identifier(id_name, NULL, location)); + ret->push_back(Typed_identifier(id_name, NULL, id_location)); bool just_saw_comma = true; while (this->advance_token()->is_identifier()) { name = this->peek_token()->identifier(); is_exported = this->peek_token()->is_identifier_exported(); - location = this->peek_token()->location(); + id_location = this->peek_token()->location(); id_name = this->gogo_->pack_hidden_name(name, is_exported); - ret->push_back(Typed_identifier(id_name, NULL, location)); + ret->push_back(Typed_identifier(id_name, NULL, id_location)); if (!this->advance_token()->is_op(OPERATOR_COMMA)) { just_saw_comma = false; @@ -909,7 +909,7 @@ Parse::parameter_list(bool* is_varargs) // names. parameters_have_names = false; this->unget_token(Token::make_identifier_token(name, is_exported, - location)); + id_location)); ret->pop_back(); just_saw_comma = true; } @@ -2808,7 +2808,7 @@ Parse::composite_lit(Type* type, int depth, Location location) { std::string identifier = token->identifier(); bool is_exported = token->is_identifier_exported(); - Location location = token->location(); + Location id_location = token->location(); if (this->advance_token()->is_op(OPERATOR_COLON)) { @@ -2820,14 +2820,14 @@ Parse::composite_lit(Type* type, int depth, Location location) Gogo* gogo = this->gogo_; val = this->id_to_expression(gogo->pack_hidden_name(identifier, is_exported), - location, false); + id_location, false); is_name = true; } else { this->unget_token(Token::make_identifier_token(identifier, is_exported, - location)); + id_location)); val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); } @@ -2923,14 +2923,14 @@ Parse::composite_lit(Type* type, int depth, Location location) go_error_at(this->location(), "expected %<,%> or %<}%>"); this->gogo_->mark_locals_used(); - int depth = 0; + int edepth = 0; while (!token->is_eof() - && (depth > 0 || !token->is_op(OPERATOR_RCURLY))) + && (edepth > 0 || !token->is_op(OPERATOR_RCURLY))) { if (token->is_op(OPERATOR_LCURLY)) - ++depth; + ++edepth; else if (token->is_op(OPERATOR_RCURLY)) - --depth; + --edepth; token = this->advance_token(); } if (token->is_op(OPERATOR_RCURLY)) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 3dc394a..f52b33d 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -2938,7 +2938,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) go_assert(call_statement->classification() == STATEMENT_EXPRESSION); Expression_statement* es = static_cast(call_statement); - Call_expression* ce = es->expr()->call_expression(); + ce = es->expr()->call_expression(); if (ce == NULL) go_assert(saw_errors()); else @@ -5972,10 +5972,11 @@ Select_statement::lower_two_case(Block* b) // if selectnbrecv2(&lhs, &ok, chan) { body } else { default body } Type* booltype = Type::make_boolean_type(); - Temporary_statement* ts = Statement::make_temporary(booltype, NULL, loc); - b->add_statement(ts); + Temporary_statement* okts = Statement::make_temporary(booltype, NULL, + loc); + b->add_statement(okts); - okref = Expression::make_temporary_reference(ts, loc); + okref = Expression::make_temporary_reference(okts, loc); Expression* okaddr = Expression::make_unary(OPERATOR_AND, okref, loc); call = Runtime::make_call(Runtime::SELECTNBRECV2, loc, 3, addr, okaddr, chanref); @@ -6595,7 +6596,7 @@ For_range_statement::lower_range_array(Gogo* gogo, iter_init = new Block(body_block, loc); ref = Expression::make_temporary_reference(range_temp, loc); - Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); + ref2 = Expression::make_temporary_reference(index_temp, loc); Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc); tref = Expression::make_temporary_reference(value_temp, loc); @@ -6693,7 +6694,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, iter_init = new Block(body_block, loc); ref = Expression::make_temporary_reference(for_temp, loc); - Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); + ref2 = Expression::make_temporary_reference(index_temp, loc); Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc); tref = Expression::make_temporary_reference(value_temp, loc); @@ -7179,9 +7180,9 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, else { Type* int32_type = Type::lookup_integer_type("int32"); - Expression* zero = Expression::make_integer_ul(0, int32_type, loc); + Expression* zero32 = Expression::make_integer_ul(0, int32_type, loc); call = Runtime::make_call(Runtime::BUILTIN_MEMSET, loc, 3, ptr_arg, - zero, sz_arg); + zero32, sz_arg); } Statement* cs3 = Statement::make_statement(call, true); b->add_statement(cs3); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index eeae9fa4..e02b832 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -6410,12 +6410,11 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) fvals->push_back(Expression::make_nil(bloc)); else { - std::string n; if (is_embedded_builtin) n = gogo->package_name(); else n = Gogo::hidden_name_pkgpath(pf->field_name()); - Expression* s = Expression::make_string(n, bloc); + s = Expression::make_string(n, bloc); fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); } @@ -6429,7 +6428,7 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) fvals->push_back(Expression::make_nil(bloc)); else { - Expression* s = Expression::make_string(pf->tag(), bloc); + s = Expression::make_string(pf->tag(), bloc); fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); } @@ -6635,22 +6634,22 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const { const std::string& tag(p->tag()); ret->append(" \""); - for (std::string::const_iterator p = tag.begin(); - p != tag.end(); - ++p) + for (std::string::const_iterator pt = tag.begin(); + pt != tag.end(); + ++pt) { - if (*p == '\0') + if (*pt == '\0') ret->append("\\x00"); - else if (*p == '\n') + else if (*pt == '\n') ret->append("\\n"); - else if (*p == '\t') + else if (*pt == '\t') ret->append("\\t"); - else if (*p == '"') + else if (*pt == '"') ret->append("\\\""); - else if (*p == '\\') + else if (*pt == '\\') ret->append("\\\\"); else - ret->push_back(*p); + ret->push_back(*pt); } ret->push_back('"'); } @@ -7197,11 +7196,11 @@ Array_type::verify_length() return false; case Numeric_constant::NC_UL_BIG: { - mpz_t val; - if (!nc.to_int(&val)) + mpz_t mval; + if (!nc.to_int(&mval)) go_unreachable(); - unsigned int bits = mpz_sizeinbase(val, 2); - mpz_clear(val); + unsigned int bits = mpz_sizeinbase(mval, 2); + mpz_clear(mval); if (bits >= tbits) { go_error_at(this->length_->location(), "array bound overflows"); @@ -7704,6 +7703,7 @@ Array_type::do_export(Export* exp) const } char* s = mpz_get_str(NULL, 10, val); exp->write_string(s); + free(s); exp->write_string(" "); mpz_clear(val); } @@ -9752,7 +9752,7 @@ Interface_type::do_import(Import* imp) parameters = new Typed_identifier_list; while (true) { - std::string name = imp->read_name(); + std::string pname = imp->read_name(); imp->require_c_string(" "); if (imp->match_c_string("...")) @@ -9764,7 +9764,7 @@ Interface_type::do_import(Import* imp) Type* ptype = imp->read_type(); if (is_varargs) ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(name, ptype, + parameters->push_back(Typed_identifier(pname, ptype, imp->location())); if (imp->peek_char() != ',') break; @@ -9791,10 +9791,10 @@ Interface_type::do_import(Import* imp) imp->advance(1); while (true) { - std::string name = imp->read_name(); + std::string rname = imp->read_name(); imp->require_c_string(" "); Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(name, rtype, + results->push_back(Typed_identifier(rname, rtype, imp->location())); if (imp->peek_char() != ',') break; -- cgit v1.1 From b1fc776335a5d905f6ca37cb0e158613b04d0dc3 Mon Sep 17 00:00:00 2001 From: Mark Eggleston Date: Fri, 4 Oct 2019 14:11:36 +0000 Subject: Replace test cases for using automatic variables in equivalence statements. From-SVN: r276580 --- gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 | 53 +++++++++++++-------------- gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 | 46 ++++++----------------- 3 files changed, 43 insertions(+), 62 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5c5d869..c5ead9f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-10-04 Mark Eggleston + + * gfortran.dg/auto_in_equiv_1.f90: Replaced. + * gfortran.dg/auto_in_equiv_2.f90: Replaced. + * gfortran.dg/auto_in_equiv_3.f90: Deleted. + 2019-10-04 Richard Sandiford * gcc.target/aarch64/torture/simd-abi-8.c: Use -mlittle-endian. diff --git a/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 b/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 index bf6e0c6..2791675 100644 --- a/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 +++ b/gcc/testsuite/gfortran.dg/auto_in_equiv_1.f90 @@ -1,36 +1,35 @@ -! { dg-do compile } +! { dg-do run } +! { dg-options "-fdec-static -frecursive" } ! Contributed by Mark Eggleston +! +! Check automatic variables can be used in equivalence statements. +! Any other variables that do not explicitly have the automatic +! attribute will be given the automatic attribute. +! +! Check that variables are on the stack by incorporating the +! equivalence in a recursive function. +! program test - call suba(0) - call subb(0) - call suba(1) + integer :: f + + f = factorial(5) + if (f.ne.120) stop 2 contains - subroutine suba(option) - integer, intent(in) :: option - integer, automatic :: a ! { dg-error "AUTOMATIC at \\(1\\) is a DEC extension" } + function factorial(n) result(f) + integer :: f + integer, intent(in) :: n + integer, automatic :: a integer :: b - integer :: c - equivalence (a, b) - if (option.eq.0) then - ! initialise a and c - a = 9 - c = 99 - if (a.ne.b) stop 1 - if (loc(a).ne.loc(b)) stop 2 + equivalence (a,b) + + if (loc(a).ne.loc(b)) stop 1 + b = n + if (a.eq.1) then + f = 1 else - ! a should've been overwritten - if (a.eq.9) stop 3 + f = a * factorial(b-1) end if - end subroutine suba - - subroutine subb(dummy) - integer, intent(in) :: dummy - integer, automatic :: x ! { dg-error "AUTOMATIC at \\(1\\) is a DEC extension" } - integer :: y - x = 77 - y = 7 - end subroutine subb - + end function end program test diff --git a/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 b/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 index e40c0f1..5d8a9fb 100644 --- a/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 +++ b/gcc/testsuite/gfortran.dg/auto_in_equiv_2.f90 @@ -1,38 +1,14 @@ ! { dg-do run } -! { dg-options "-fdec-static" } +! { dg-options "-fdec-static -frecursive -fno-automatic" } ! Contributed by Mark Eggleston - -program test - call suba(0) - call subb(0) - call suba(1) - -contains - subroutine suba(option) - integer, intent(in) :: option - integer, automatic :: a - integer :: b - integer :: c - equivalence (a, b) - if (option.eq.0) then - ! initialise a and c - a = 9 - c = 99 - if (a.ne.b) stop 1 - if (loc(a).ne.loc(b)) stop 2 - else - ! a should've been overwritten - if (a.eq.9) stop 3 - end if - end subroutine suba - - subroutine subb(dummy) - integer, intent(in) :: dummy - integer, automatic :: x - integer :: y - x = 77 - y = 7 - end subroutine subb - -end program test +! +! Check that -fno-automatic does not break recursion. The recursive +! function is not marked with the resursive key word consequently +! local variables can be made static when -fno-automatic is used. The +! recursive function contains an equivalence that has a variable with +! the automatic attribute and one without. +! +include "auto_in_equiv_1.f90" + +! { dg-warning "Flag '-fno-automatic' overwrites '-frecursive'" "warning" { target *-*-* } 0 } -- cgit v1.1 From 82de69ffc84e4598f0380e52b9239af7421ba6c9 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 4 Oct 2019 08:27:45 -0600 Subject: range-op.cc (range_tests): Avoid two tests when ints and shorts are the same size. * range-op.cc (range_tests): Avoid two tests when ints and shorts are the same size. From-SVN: r276581 --- gcc/ChangeLog | 5 +++++ gcc/range-op.cc | 26 +++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 97e48c0..02cf697 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Jeff Law + + * range-op.cc (range_tests): Avoid two tests when ints and + shorts are the same size. + 2019-10-04 Richard Biener PR lto/91968 diff --git a/gcc/range-op.cc b/gcc/range-op.cc index fff4a55..fc314853 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -2910,10 +2910,14 @@ range_tests () // If a range is in any way outside of the range for the converted // to range, default to the range for the new type. - r1 = value_range_base (integer_zero_node, maxint); - range_cast (r1, short_integer_type_node); - ASSERT_TRUE (r1.lower_bound () == wi::to_wide (minshort) - && r1.upper_bound() == wi::to_wide (maxshort)); + if (TYPE_PRECISION (TREE_TYPE (maxint)) + > TYPE_PRECISION (short_integer_type_node)) + { + r1 = value_range_base (integer_zero_node, maxint); + range_cast (r1, short_integer_type_node); + ASSERT_TRUE (r1.lower_bound () == wi::to_wide (minshort) + && r1.upper_bound() == wi::to_wide (maxshort)); + } // (unsigned char)[-5,-1] => [251,255]. r0 = rold = value_range_base (SCHAR (-5), SCHAR (-1)); @@ -3020,11 +3024,15 @@ range_tests () // "NOT 0 at signed 32-bits" ==> [-MIN_32,-1][1, +MAX_32]. This is // is outside of the range of a smaller range, return the full // smaller range. - r0 = range_nonzero (integer_type_node); - range_cast (r0, short_integer_type_node); - r1 = value_range_base (TYPE_MIN_VALUE (short_integer_type_node), - TYPE_MAX_VALUE (short_integer_type_node)); - ASSERT_TRUE (r0 == r1); + if (TYPE_PRECISION (integer_type_node) + > TYPE_PRECISION (short_integer_type_node)) + { + r0 = range_nonzero (integer_type_node); + range_cast (r0, short_integer_type_node); + r1 = value_range_base (TYPE_MIN_VALUE (short_integer_type_node), + TYPE_MAX_VALUE (short_integer_type_node)); + ASSERT_TRUE (r0 == r1); + } // Casting NONZERO from a narrower signed to a wider signed. // -- cgit v1.1 From dde4026df03a2b5fdd8bd68bdf51edc23a61ffc8 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 4 Oct 2019 08:45:46 -0600 Subject: h8300.md (cpymemsi): Disable. * config/h8300/h8300.md (cpymemsi): Disable. (movmd, movmd_internal_, movstr, movsd): (movstr, movsd, stpcpy_internal_: Likewise. (movmd splitter, movsd splitter): Likewise. From-SVN: r276582 --- gcc/ChangeLog | 5 +++++ gcc/config/h8300/h8300.md | 14 ++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 02cf697..9bc2aab 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-10-04 Jeff Law + * config/h8300/h8300.md (cpymemsi): Disable. + (movmd, movmd_internal_, movstr, movsd): + (movstr, movsd, stpcpy_internal_: Likewise. + (movmd splitter, movsd splitter): Likewise. + * range-op.cc (range_tests): Avoid two tests when ints and shorts are the same size. diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md index 778d3e1..f3edbb1 100644 --- a/gcc/config/h8300/h8300.md +++ b/gcc/config/h8300/h8300.md @@ -483,7 +483,7 @@ (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:SI 2 "" "")) (use (match_operand:SI 3 "const_int_operand" ""))] - "TARGET_H8300SX" + "TARGET_H8300SX && 0" { if (h8sx_emit_movmd (operands[0], operands[1], operands[2], INTVAL (operands[3]))) DONE; @@ -505,7 +505,7 @@ (clobber (match_dup 5)) (set (match_dup 2) (const_int 0))])] - "TARGET_H8300SX" + "TARGET_H8300SX && 0" { operands[4] = copy_rtx (XEXP (operands[0], 0)); operands[5] = copy_rtx (XEXP (operands[1], 0)); @@ -523,7 +523,7 @@ (clobber (match_operand:P 1 "register_operand" "=f,f")) (set (match_operand:HI 2 "register_operand" "=c,c") (const_int 0))] - "TARGET_H8300SX" + "TARGET_H8300SX && 0" "@ movmd%m6 #" @@ -553,6 +553,7 @@ (set (match_dup 2) (const_int 0))] "TARGET_H8300SX && reload_completed + && 0 && REGNO (operands[4]) != DESTINATION_REG" [(const_int 0)] { @@ -573,7 +574,7 @@ [(use (match_operand 0 "register_operand" "")) (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:BLK 2 "memory_operand" ""))] - "TARGET_H8300SX" + "TARGET_H8300SX && 0" { operands[1] = replace_equiv_address (operands[1], copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); @@ -596,7 +597,7 @@ (clobber (match_dup 3)) (clobber (match_dup 4)) (clobber (match_operand 2 "register_operand" ""))])] - "TARGET_H8300SX" + "TARGET_H8300SX && 0" { operands[3] = copy_rtx (XEXP (operands[0], 0)); operands[4] = copy_rtx (XEXP (operands[1], 0)); @@ -611,7 +612,7 @@ (clobber (match_operand:P 0 "register_operand" "=d,??D")) (clobber (match_operand:P 1 "register_operand" "=f,f")) (clobber (match_operand:P 2 "register_operand" "=c,c"))] - "TARGET_H8300SX" + "TARGET_H8300SX && 0" "@ \n1:\tmovsd\t2f\;bra\t1b\n2: #" @@ -628,6 +629,7 @@ (clobber (match_operand:P 3 "register_operand" "")) (clobber (match_operand:P 4 "register_operand" ""))] "TARGET_H8300SX && reload_completed + && 0 && REGNO (operands[2]) != DESTINATION_REG" [(const_int 0)] { -- cgit v1.1 From 0046f8d750560275c3d82179244b45412073d626 Mon Sep 17 00:00:00 2001 From: Maya Rashish Date: Fri, 4 Oct 2019 15:43:07 +0000 Subject: ira-color.c (update_costs_from_allocno): Call ira_init_register_move_cost_if_necessary. * ira-color.c (update_costs_from_allocno): Call ira_init_register_move_cost_if_necessary. From-SVN: r276587 --- gcc/ChangeLog | 5 +++++ gcc/ira-color.c | 1 + 2 files changed, 6 insertions(+) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9bc2aab..1274b64 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Maya Rashish + + * ira-color.c (update_costs_from_allocno): Call + ira_init_register_move_cost_if_necessary. + 2019-10-04 Jeff Law * config/h8300/h8300.md (cpymemsi): Disable. diff --git a/gcc/ira-color.c b/gcc/ira-color.c index ce5141b..e38c167 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -1372,6 +1372,7 @@ update_costs_from_allocno (ira_allocno_t allocno, int hard_regno, e.g. DImode for AREG on x86. For such cases the register move cost will be maximal. */ mode = narrower_subreg_mode (mode, ALLOCNO_MODE (cp->second)); + ira_init_register_move_cost_if_necessary (mode); cost = (cp->second == allocno ? ira_register_move_cost[mode][rclass][aclass] -- cgit v1.1 From 0fa00483026f58848767c1577e3d76ef2fb2568b Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 4 Oct 2019 17:08:06 +0100 Subject: Mark C2x built-in functions as such. Various built-in functions that GCC has as extensions are now standard functions in C2x. This patch adds DEF_C2X_BUILTIN and uses it to mark them as such. Some of the so-marked functions were previously DEF_EXT_LIB_BUILTIN, while some DFP ones were DEF_GCC_BUILTIN (i.e. __builtin_* only); both sets become DEF_C2X_BUILTIN. This in turn requires flag_isoc2x to be defined in various front ends using builtins.def. As the semantics of the built-in functions should already be tested, the tests added only verify that they are declared in C2x mode but not in C11 mode. The test of DFP built-in functions being declared for C2x goes in gcc.dg/dfp/, as while such built-in functions currently don't depend on whether DFP is supported, that looks like a bug to me (see bug 91985), so it seems best for the tests not to depend on exactly how that bug might be fixed. Bootstrapped with no regressions on x86_64-pc-linux-gnu. gcc: * builtins.def (DEF_C2X_BUILTIN): New macro. (exp10, exp10f, exp10l, fabsd32, fabsd64, fabsd128, nand32) (nand64, nand128, roundeven, roundevenf, roundevenl, strdup) (strndup): Use DEF_C2X_BUILTIN. * coretypes.h (enum function_class): Add function_c2x_misc. gcc/ada: * gcc-interface/utils.c (flag_isoc2x): New variable. gcc/brig: * brig-lang.c (flag_isoc2x): New variable. gcc/lto: * lto-lang.c (flag_isoc2x): New variable. gcc/testsuite: * gcc.dg/c11-builtins-1.c, gcc.dg/c2x-builtins-1.c, gcc.dg/dfp/c2x-builtins-dfp-1.c: New tests. From-SVN: r276588 --- gcc/ChangeLog | 8 ++++++ gcc/ada/ChangeLog | 4 +++ gcc/ada/gcc-interface/utils.c | 1 + gcc/brig/ChangeLog | 4 +++ gcc/brig/brig-lang.c | 1 + gcc/builtins.def | 35 ++++++++++++++++----------- gcc/coretypes.h | 3 ++- gcc/lto/ChangeLog | 4 +++ gcc/lto/lto-lang.c | 1 + gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.dg/c11-builtins-1.c | 19 +++++++++++++++ gcc/testsuite/gcc.dg/c2x-builtins-1.c | 13 ++++++++++ gcc/testsuite/gcc.dg/dfp/c2x-builtins-dfp-1.c | 11 +++++++++ 13 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c11-builtins-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-builtins-1.c create mode 100644 gcc/testsuite/gcc.dg/dfp/c2x-builtins-dfp-1.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1274b64..a9f8da9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-10-04 Joseph Myers + + * builtins.def (DEF_C2X_BUILTIN): New macro. + (exp10, exp10f, exp10l, fabsd32, fabsd64, fabsd128, nand32) + (nand64, nand128, roundeven, roundevenf, roundevenl, strdup) + (strndup): Use DEF_C2X_BUILTIN. + * coretypes.h (enum function_class): Add function_c2x_misc. + 2019-10-04 Maya Rashish * ira-color.c (update_costs_from_allocno): Call diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 6a84b7b..0463038 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,7 @@ +2019-10-04 Joseph Myers + + * gcc-interface/utils.c (flag_isoc2x): New variable. + 2019-10-01 Maciej W. Rozycki * gcc-interface/Makefile.in (ADA_RTL_DSO_DIR): New variable. diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index b9d5af7..d2891f2 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -6901,6 +6901,7 @@ def_builtin_1 (enum built_in_function fncode, static int flag_isoc94 = 0; static int flag_isoc99 = 0; static int flag_isoc11 = 0; +static int flag_isoc2x = 0; /* Install what the common builtins.def offers plus our local additions. diff --git a/gcc/brig/ChangeLog b/gcc/brig/ChangeLog index 462cbab..9f824e2 100644 --- a/gcc/brig/ChangeLog +++ b/gcc/brig/ChangeLog @@ -1,3 +1,7 @@ +2019-10-04 Joseph Myers + + * brig-lang.c (flag_isoc2x): New variable. + 2019-08-23 Jakub Jelinek PR middle-end/91283 diff --git a/gcc/brig/brig-lang.c b/gcc/brig/brig-lang.c index 96c6c57..505a83d 100644 --- a/gcc/brig/brig-lang.c +++ b/gcc/brig/brig-lang.c @@ -587,6 +587,7 @@ static GTY(()) tree signed_size_type_node; int flag_isoc94; int flag_isoc99; int flag_isoc11; +int flag_isoc2x; static void def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) diff --git a/gcc/builtins.def b/gcc/builtins.def index 5b9b706..d8233f5 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -154,6 +154,13 @@ along with GCC; see the file COPYING3. If not see DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ true, true, !flag_isoc11, ATTRS, targetm.libc_has_function (function_c11_misc), true) +/* Like DEF_LIB_BUILTIN, except that the function is only a part of + the standard in C2x or above. */ +#undef DEF_C2X_BUILTIN +#define DEF_C2X_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ + DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ + true, true, !flag_isoc2x, ATTRS, targetm.libc_has_function (function_c2x_misc), true) + /* Like DEF_C99_BUILTIN, but for complex math functions. */ #undef DEF_C99_COMPL_BUILTIN #define DEF_C99_COMPL_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ @@ -335,9 +342,9 @@ DEF_C99_BUILTIN (BUILT_IN_ERFCL, "erfcl", BT_FN_LONGDOUBLE_LONGDOUBLE, AT DEF_C99_BUILTIN (BUILT_IN_ERFF, "erff", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING) DEF_C99_BUILTIN (BUILT_IN_ERFL, "erfl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING) DEF_LIB_BUILTIN (BUILT_IN_EXP, "exp", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) -DEF_EXT_LIB_BUILTIN (BUILT_IN_EXP10, "exp10", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) -DEF_EXT_LIB_BUILTIN (BUILT_IN_EXP10F, "exp10f", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO) -DEF_EXT_LIB_BUILTIN (BUILT_IN_EXP10L, "exp10l", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) +DEF_C2X_BUILTIN (BUILT_IN_EXP10, "exp10", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) +DEF_C2X_BUILTIN (BUILT_IN_EXP10F, "exp10f", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO) +DEF_C2X_BUILTIN (BUILT_IN_EXP10L, "exp10l", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_EXP2, "exp2", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_EXP2F, "exp2f", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_EXP2L, "exp2l", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) @@ -352,9 +359,9 @@ DEF_C99_C90RES_BUILTIN (BUILT_IN_FABSL, "fabsl", BT_FN_LONGDOUBLE_LONGDOUBLE, AT #define FABS_TYPE(F) BT_FN_##F##_##F DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_FABS, "fabs", FABS_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST) #undef FABS_TYPE -DEF_GCC_BUILTIN (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST) -DEF_GCC_BUILTIN (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST) -DEF_GCC_BUILTIN (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_C2X_BUILTIN (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_C2X_BUILTIN (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_C2X_BUILTIN (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO) DEF_C99_BUILTIN (BUILT_IN_FDIML, "fdiml", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO) @@ -501,9 +508,9 @@ DEF_C99_BUILTIN (BUILT_IN_NANF, "nanf", BT_FN_FLOAT_CONST_STRING, ATTR_CO DEF_C99_BUILTIN (BUILT_IN_NANL, "nanl", BT_FN_LONGDOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) #define NAN_TYPE(F) BT_FN_##F##_CONST_STRING DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_NAN, "nan", NAN_TYPE, ATTR_CONST_NOTHROW_NONNULL) -DEF_GCC_BUILTIN (BUILT_IN_NAND32, "nand32", BT_FN_DFLOAT32_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) -DEF_GCC_BUILTIN (BUILT_IN_NAND64, "nand64", BT_FN_DFLOAT64_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) -DEF_GCC_BUILTIN (BUILT_IN_NAND128, "nand128", BT_FN_DFLOAT128_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) +DEF_C2X_BUILTIN (BUILT_IN_NAND32, "nand32", BT_FN_DFLOAT32_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) +DEF_C2X_BUILTIN (BUILT_IN_NAND64, "nand64", BT_FN_DFLOAT64_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) +DEF_C2X_BUILTIN (BUILT_IN_NAND128, "nand128", BT_FN_DFLOAT128_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) DEF_GCC_BUILTIN (BUILT_IN_NANS, "nans", BT_FN_DOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) DEF_GCC_BUILTIN (BUILT_IN_NANSF, "nansf", BT_FN_FLOAT_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) DEF_GCC_BUILTIN (BUILT_IN_NANSL, "nansl", BT_FN_LONGDOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL) @@ -542,9 +549,9 @@ DEF_C99_BUILTIN (BUILT_IN_RINTL, "rintl", BT_FN_LONGDOUBLE_LONGDOUBLE, AT #define RINT_TYPE(F) BT_FN_##F##_##F DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_RINT, "rint", RINT_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST) #undef RINT_TYPE -DEF_EXT_LIB_BUILTIN (BUILT_IN_ROUNDEVEN, "roundeven", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) -DEF_EXT_LIB_BUILTIN (BUILT_IN_ROUNDEVENF, "roundevenf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST) -DEF_EXT_LIB_BUILTIN (BUILT_IN_ROUNDEVENL, "roundevenl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_C2X_BUILTIN (BUILT_IN_ROUNDEVEN, "roundeven", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_C2X_BUILTIN (BUILT_IN_ROUNDEVENF, "roundevenf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_C2X_BUILTIN (BUILT_IN_ROUNDEVENL, "roundevenl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_ROUND, "round", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_ROUNDF, "roundf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_ROUNDL, "roundl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) @@ -706,8 +713,8 @@ DEF_LIB_BUILTIN (BUILT_IN_STRCHR, "strchr", BT_FN_STRING_CONST_STRING_INT DEF_LIB_BUILTIN (BUILT_IN_STRCMP, "strcmp", BT_FN_INT_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF) DEF_LIB_BUILTIN (BUILT_IN_STRCPY, "strcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_RET1_NOTHROW_NONNULL_LEAF) DEF_LIB_BUILTIN (BUILT_IN_STRCSPN, "strcspn", BT_FN_SIZE_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF) -DEF_EXT_LIB_BUILTIN (BUILT_IN_STRDUP, "strdup", BT_FN_STRING_CONST_STRING, ATTR_MALLOC_WARN_UNUSED_RESULT_NOTHROW_NONNULL_LEAF) -DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNDUP, "strndup", BT_FN_STRING_CONST_STRING_SIZE, ATTR_MALLOC_WARN_UNUSED_RESULT_NOTHROW_NONNULL_LEAF) +DEF_C2X_BUILTIN (BUILT_IN_STRDUP, "strdup", BT_FN_STRING_CONST_STRING, ATTR_MALLOC_WARN_UNUSED_RESULT_NOTHROW_NONNULL_LEAF) +DEF_C2X_BUILTIN (BUILT_IN_STRNDUP, "strndup", BT_FN_STRING_CONST_STRING_SIZE, ATTR_MALLOC_WARN_UNUSED_RESULT_NOTHROW_NONNULL_LEAF) DEF_LIB_BUILTIN (BUILT_IN_STRLEN, "strlen", BT_FN_SIZE_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF) DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCASECMP, "strncasecmp", BT_FN_INT_CONST_STRING_CONST_STRING_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF) DEF_LIB_BUILTIN (BUILT_IN_STRNCAT, "strncat", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF) diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 257de22..b683f12 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -378,7 +378,8 @@ enum function_class { function_c99_misc, function_c99_math_complex, function_sincos, - function_c11_misc + function_c11_misc, + function_c2x_misc }; /* Enumerate visibility settings. This is deliberately ordered from most diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index a73cbc4..e410232 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,7 @@ +2019-10-04 Joseph Myers + + * lto-lang.c (flag_isoc2x): New variable. + 2019-09-18 Richard Biener PR lto/91763 diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 414eaf2..0d781da 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -247,6 +247,7 @@ static GTY(()) tree signed_size_type_node; int flag_isoc94; int flag_isoc99; int flag_isoc11; +int flag_isoc2x; /* Attribute handlers. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c5ead9f..68ca51e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Joseph Myers + + * gcc.dg/c11-builtins-1.c, gcc.dg/c2x-builtins-1.c, + gcc.dg/dfp/c2x-builtins-dfp-1.c: New tests. + 2019-10-04 Mark Eggleston * gfortran.dg/auto_in_equiv_1.f90: Replaced. diff --git a/gcc/testsuite/gcc.dg/c11-builtins-1.c b/gcc/testsuite/gcc.dg/c11-builtins-1.c new file mode 100644 index 0000000..bfadf70 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-builtins-1.c @@ -0,0 +1,19 @@ +/* Test C11 built-in functions: test functions new in C2x are not + declared as built-in for C11. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11" } */ + +int exp10 (void); +int exp10f (void); +int exp10l (void); +int fabsd32 (void); +int fabsd64 (void); +int fabsd128 (void); +int nand32 (void); +int nand64 (void); +int nand128 (void); +int roundeven (void); +int roundevenf (void); +int roundevenl (void); +int strdup (void); +int strndup (void); diff --git a/gcc/testsuite/gcc.dg/c2x-builtins-1.c b/gcc/testsuite/gcc.dg/c2x-builtins-1.c new file mode 100644 index 0000000..7476059 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-builtins-1.c @@ -0,0 +1,13 @@ +/* Test C2x built-in functions: test functions new in C2x are indeed + declared as built-in as expected. Non-DFP tests. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +int exp10 (void); /* { dg-warning "conflicting types for built-in function" } */ +int exp10f (void); /* { dg-warning "conflicting types for built-in function" } */ +int exp10l (void); /* { dg-warning "conflicting types for built-in function" } */ +int roundeven (void); /* { dg-warning "conflicting types for built-in function" } */ +int roundevenf (void); /* { dg-warning "conflicting types for built-in function" } */ +int roundevenl (void); /* { dg-warning "conflicting types for built-in function" } */ +int strdup (void); /* { dg-warning "conflicting types for built-in function" } */ +int strndup (void); /* { dg-warning "conflicting types for built-in function" } */ diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-builtins-dfp-1.c b/gcc/testsuite/gcc.dg/dfp/c2x-builtins-dfp-1.c new file mode 100644 index 0000000..88b8b33 --- /dev/null +++ b/gcc/testsuite/gcc.dg/dfp/c2x-builtins-dfp-1.c @@ -0,0 +1,11 @@ +/* Test C2x built-in functions: test functions new in C2x are indeed + declared as built-in as expected. DFP tests. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +int fabsd32 (void); /* { dg-warning "conflicting types for built-in function" } */ +int fabsd64 (void); /* { dg-warning "conflicting types for built-in function" } */ +int fabsd128 (void); /* { dg-warning "conflicting types for built-in function" } */ +int nand32 (void); /* { dg-warning "conflicting types for built-in function" } */ +int nand64 (void); /* { dg-warning "conflicting types for built-in function" } */ +int nand128 (void); /* { dg-warning "conflicting types for built-in function" } */ -- cgit v1.1 From 4e4791ffbae66bc5c4b96c014efb21dd7e7f2775 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 4 Oct 2019 16:15:00 +0000 Subject: genmatch.c (commutate): Rename local var. 2019-10-04 Bernd Edlinger * genmatch.c (commutate): Rename local var. (lower_cond): Reuse local var. (dt_node::gen, dt_node::gen_kids, dt_node::gen_kids_1, dt_operand::gen, dt_operand::gen_gimple_expr, dt_simplify::gen): Add a param. Rename generated vars. (decision_tree::insert_operand, (capture_info::walk_match, capture_info::walk_result, capture_info::walk_c_expr): Rename local vars. (expr::gen_transform): Rename generated vars. Use snprintf. Rename local vars. (capture::gen_transform, dt_operand::get_name, dt_operand::gen_opname): Rename generated vars. (write_predicate): Adjust call to gen_kids. (parser::get_internal_capture_id): Rename generated vars. (parser::parse_expr): Rename local vars. (parser::parse_if): Remove local var. (parser::parse_pattern, add_operator): Rename local vars. From-SVN: r276589 --- gcc/ChangeLog | 20 ++++ gcc/genmatch.c | 299 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 174 insertions(+), 145 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a9f8da9..ba33fe7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2019-10-04 Bernd Edlinger + + * genmatch.c (commutate): Rename local var. + (lower_cond): Reuse local var. + (dt_node::gen, dt_node::gen_kids, dt_node::gen_kids_1, + dt_operand::gen, dt_operand::gen_gimple_expr, + dt_simplify::gen): Add a param. Rename generated vars. + (decision_tree::insert_operand, + (capture_info::walk_match, capture_info::walk_result, + capture_info::walk_c_expr): Rename local vars. + (expr::gen_transform): Rename generated vars. + Use snprintf. Rename local vars. + (capture::gen_transform, dt_operand::get_name, + dt_operand::gen_opname): Rename generated vars. + (write_predicate): Adjust call to gen_kids. + (parser::get_internal_capture_id): Rename generated vars. + (parser::parse_expr): Rename local vars. + (parser::parse_if): Remove local var. + (parser::parse_pattern, add_operator): Rename local vars. + 2019-10-04 Joseph Myers * builtins.def (DEF_C2X_BUILTIN): New macro. diff --git a/gcc/genmatch.c b/gcc/genmatch.c index cede432..7db1f13 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -1022,10 +1022,10 @@ commutate (operand *op, vec > &for_vec) for (unsigned i = 0; i < result.length (); ++i) { expr *ne = new expr (e); - if (operator_id *p = dyn_cast (ne->operation)) + if (operator_id *r = dyn_cast (ne->operation)) { - if (comparison_code_p (p->code)) - ne->operation = swap_tree_comparison (p); + if (comparison_code_p (r->code)) + ne->operation = swap_tree_comparison (r); } else if (user_id *p = dyn_cast (ne->operation)) { @@ -1279,7 +1279,7 @@ lower_cond (operand *o) || (is_a (e->ops[0]) && as_a (e->ops[0])->ops.length () == 2))) { - expr *ne = new expr (e); + ne = new expr (e); for (unsigned j = 0; j < result[i].length (); ++j) ne->append_op (result[i][j]); if (capture *c = dyn_cast (ne->ops[0])) @@ -1637,10 +1637,10 @@ public: unsigned pos); dt_node *append_simplify (simplify *, unsigned, dt_operand **); - virtual void gen (FILE *, int, bool) {} + virtual void gen (FILE *, int, bool, int) {} - void gen_kids (FILE *, int, bool); - void gen_kids_1 (FILE *, int, bool, + void gen_kids (FILE *, int, bool, int); + void gen_kids_1 (FILE *, int, bool, int, vec, vec, vec, vec, vec, vec); @@ -1663,11 +1663,11 @@ public: : dt_node (type, parent_), op (op_), match_dop (match_dop_), pos (pos_), value_match (false), for_id (current_id) {} - void gen (FILE *, int, bool); + void gen (FILE *, int, bool, int); unsigned gen_predicate (FILE *, int, const char *, bool); unsigned gen_match_op (FILE *, int, const char *, bool); - unsigned gen_gimple_expr (FILE *, int); + unsigned gen_gimple_expr (FILE *, int, int); unsigned gen_generic_expr (FILE *, int, const char *); char *get_name (char *); @@ -1689,7 +1689,7 @@ public: indexes (indexes_), info (NULL) {} void gen_1 (FILE *, int, bool, operand *); - void gen (FILE *f, int, bool); + void gen (FILE *f, int, bool, int); }; template<> @@ -1987,9 +1987,9 @@ decision_tree::insert_operand (dt_node *p, operand *o, dt_operand **indexes, if (elm == 0) { - dt_operand temp (dt_node::DT_MATCH, 0, match_op, 0, 0); - temp.value_match = c->value_match; - elm = decision_tree::find_node (p->kids, &temp); + dt_operand match (dt_node::DT_MATCH, 0, match_op, 0, 0); + match.value_match = c->value_match; + elm = decision_tree::find_node (p->kids, &match); } } else @@ -2202,7 +2202,7 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg, for (unsigned i = 0; i < e->ops.length (); ++i) { bool cond_p = conditional_p; - bool cond_expr_cond_p = false; + bool expr_cond_p = false; if (i != 0 && *e->operation == COND_EXPR) cond_p = true; else if (*e->operation == TRUTH_ANDIF_EXPR @@ -2211,8 +2211,8 @@ capture_info::walk_match (operand *o, unsigned toplevel_arg, if (i == 0 && (*e->operation == COND_EXPR || *e->operation == VEC_COND_EXPR)) - cond_expr_cond_p = true; - walk_match (e->ops[i], toplevel_arg, cond_p, cond_expr_cond_p); + expr_cond_p = true; + walk_match (e->ops[i], toplevel_arg, cond_p, expr_cond_p); } } else if (is_a (o)) @@ -2270,42 +2270,42 @@ capture_info::walk_result (operand *o, bool conditional_p, operand *result) walk_result (e->ops[i], cond_p, result); } } - else if (if_expr *e = dyn_cast (o)) + else if (if_expr *ie = dyn_cast (o)) { /* 'if' conditions should be all fine. */ - if (e->trueexpr == result) + if (ie->trueexpr == result) { - walk_result (e->trueexpr, false, result); + walk_result (ie->trueexpr, false, result); return true; } - if (e->falseexpr == result) + if (ie->falseexpr == result) { - walk_result (e->falseexpr, false, result); + walk_result (ie->falseexpr, false, result); return true; } bool res = false; - if (is_a (e->trueexpr) - || is_a (e->trueexpr)) - res |= walk_result (e->trueexpr, false, result); - if (e->falseexpr - && (is_a (e->falseexpr) - || is_a (e->falseexpr))) - res |= walk_result (e->falseexpr, false, result); + if (is_a (ie->trueexpr) + || is_a (ie->trueexpr)) + res |= walk_result (ie->trueexpr, false, result); + if (ie->falseexpr + && (is_a (ie->falseexpr) + || is_a (ie->falseexpr))) + res |= walk_result (ie->falseexpr, false, result); return res; } - else if (with_expr *e = dyn_cast (o)) + else if (with_expr *we = dyn_cast (o)) { - bool res = (e->subexpr == result); + bool res = (we->subexpr == result); if (res - || is_a (e->subexpr) - || is_a (e->subexpr)) - res |= walk_result (e->subexpr, false, result); + || is_a (we->subexpr) + || is_a (we->subexpr)) + res |= walk_result (we->subexpr, false, result); if (res) - walk_c_expr (e->with); + walk_c_expr (we->with); return res; } - else if (c_expr *e = dyn_cast (o)) - walk_c_expr (e); + else if (c_expr *ce = dyn_cast (o)) + walk_c_expr (ce); else gcc_unreachable (); @@ -2347,14 +2347,14 @@ capture_info::walk_c_expr (c_expr *e) || n->type == CPP_NAME) && !(n->flags & PREV_WHITE)) { - const char *id; + const char *id1; if (n->type == CPP_NUMBER) - id = (const char *)n->val.str.text; + id1 = (const char *)n->val.str.text; else - id = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str; - unsigned *where = e->capture_ids->get(id); + id1 = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str; + unsigned *where = e->capture_ids->get(id1); if (! where) - fatal_at (n, "unknown capture id '%s'", id); + fatal_at (n, "unknown capture id '%s'", id1); info[info[*where].same_as].force_no_side_effects_p = true; if (verbose >= 1 && !gimple) @@ -2452,7 +2452,8 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, || *opr == IMAGPART_EXPR) { /* __real and __imag use the component type of its operand. */ - sprintf (optype, "TREE_TYPE (TREE_TYPE (ops%d[0]))", depth); + snprintf (optype, sizeof (optype), "TREE_TYPE (TREE_TYPE (_o%d[0]))", + depth); type = optype; } else if (is_a (opr) @@ -2464,7 +2465,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, type = in_type; else { - sprintf (optype, "boolean_type_node"); + snprintf (optype, sizeof (optype), "boolean_type_node"); type = optype; } in_type = NULL; @@ -2474,13 +2475,13 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, || strncmp (opr->id, "CFN_COND_", 9) == 0) { /* Conditions are of the same type as their first alternative. */ - sprintf (optype, "TREE_TYPE (ops%d[1])", depth); + snprintf (optype, sizeof (optype), "TREE_TYPE (_o%d[1])", depth); type = optype; } else { /* Other operations are of the same type as their first operand. */ - sprintf (optype, "TREE_TYPE (ops%d[0])", depth); + snprintf (optype, sizeof (optype), "TREE_TYPE (_o%d[0])", depth); type = optype; } if (!type) @@ -2488,17 +2489,18 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, fprintf_indent (f, indent, "{\n"); indent += 2; - fprintf_indent (f, indent, "tree ops%d[%u], res;\n", depth, ops.length ()); + fprintf_indent (f, indent, + "tree _o%d[%u], _r%d;\n", depth, ops.length (), depth); char op0type[64]; - snprintf (op0type, 64, "TREE_TYPE (ops%d[0])", depth); + snprintf (op0type, sizeof (op0type), "TREE_TYPE (_o%d[0])", depth); for (unsigned i = 0; i < ops.length (); ++i) { - char dest[32]; - snprintf (dest, 32, "ops%d[%u]", depth, i); - const char *optype + char dest1[32]; + snprintf (dest1, sizeof (dest1), "_o%d[%u]", depth, i); + const char *optype1 = get_operand_type (opr, i, in_type, expr_type, i == 0 ? NULL : op0type); - ops[i]->gen_transform (f, indent, dest, gimple, depth + 1, optype, + ops[i]->gen_transform (f, indent, dest1, gimple, depth + 1, optype1, cinfo, indexes, (*opr == COND_EXPR || *opr == VEC_COND_EXPR) && i == 0 ? 1 : 2); @@ -2515,10 +2517,11 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, if (*opr == CONVERT_EXPR) { fprintf_indent (f, indent, - "if (%s != TREE_TYPE (ops%d[0])\n", + "if (%s != TREE_TYPE (_o%d[0])\n", type, depth); fprintf_indent (f, indent, - " && !useless_type_conversion_p (%s, TREE_TYPE (ops%d[0])))\n", + " && !useless_type_conversion_p (%s, TREE_TYPE " + "(_o%d[0])))\n", type, depth); fprintf_indent (f, indent + 2, "{\n"); indent += 4; @@ -2529,46 +2532,48 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, fprintf_indent (f, indent, "gimple_match_op tem_op " "(res_op->cond.any_else (), %s, %s", opr_name, type); for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", ops%d[%u]", depth, i); + fprintf (f, ", _o%d[%u]", depth, i); fprintf (f, ");\n"); fprintf_indent (f, indent, "gimple_resimplify%d (lseq, &tem_op, valueize);\n", ops.length ()); fprintf_indent (f, indent, - "res = maybe_push_res_to_seq (&tem_op, lseq);\n"); + "_r%d = maybe_push_res_to_seq (&tem_op, lseq);\n", + depth); fprintf_indent (f, indent, - "if (!res) return false;\n"); + "if (!_r%d) return false;\n", + depth); if (*opr == CONVERT_EXPR) { indent -= 4; fprintf_indent (f, indent, " }\n"); fprintf_indent (f, indent, "else\n"); - fprintf_indent (f, indent, " res = ops%d[0];\n", depth); + fprintf_indent (f, indent, " _r%d = _o%d[0];\n", depth, depth); } } else { if (*opr == CONVERT_EXPR) { - fprintf_indent (f, indent, "if (TREE_TYPE (ops%d[0]) != %s)\n", + fprintf_indent (f, indent, "if (TREE_TYPE (_o%d[0]) != %s)\n", depth, type); indent += 2; } if (opr->kind == id_base::CODE) - fprintf_indent (f, indent, "res = fold_build%d_loc (loc, %s, %s", - ops.length(), opr_name, type); + fprintf_indent (f, indent, "_r%d = fold_build%d_loc (loc, %s, %s", + depth, ops.length(), opr_name, type); else { fprintf_indent (f, indent, "{\n"); - fprintf_indent (f, indent, " res = maybe_build_call_expr_loc (loc, " - "%s, %s, %d", opr_name, type, ops.length()); + fprintf_indent (f, indent, " _r%d = maybe_build_call_expr_loc (loc, " + "%s, %s, %d", depth, opr_name, type, ops.length()); } for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", ops%d[%u]", depth, i); + fprintf (f, ", _o%d[%u]", depth, i); fprintf (f, ");\n"); if (opr->kind != id_base::CODE) { - fprintf_indent (f, indent, " if (!res)\n"); + fprintf_indent (f, indent, " if (!_r%d)\n", depth); fprintf_indent (f, indent, " return NULL_TREE;\n"); fprintf_indent (f, indent, "}\n"); } @@ -2576,10 +2581,10 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, { indent -= 2; fprintf_indent (f, indent, "else\n"); - fprintf_indent (f, indent, " res = ops%d[0];\n", depth); + fprintf_indent (f, indent, " _r%d = _o%d[0];\n", depth, depth); } } - fprintf_indent (f, indent, "%s = res;\n", dest); + fprintf_indent (f, indent, "%s = _r%d;\n", dest, depth); indent -= 2; fprintf_indent (f, indent, "}\n"); } @@ -2670,7 +2675,7 @@ capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple, if (indexes[where] == 0) { char buf[20]; - sprintf (buf, "captures[%u]", where); + snprintf (buf, sizeof (buf), "captures[%u]", where); what->gen_transform (f, indent, buf, gimple, depth, in_type, cinfo, NULL); } @@ -2725,11 +2730,11 @@ dt_operand::get_name (char *name) if (! parent) sprintf (name, "t"); else if (parent->level == 1) - sprintf (name, "op%u", pos); + sprintf (name, "_p%u", pos); else if (parent->type == dt_node::DT_MATCH) return as_a (parent)->get_name (name); else - sprintf (name, "o%u%u", parent->level, pos); + sprintf (name, "_q%u%u", parent->level, pos); return name; } @@ -2739,9 +2744,9 @@ void dt_operand::gen_opname (char *name, unsigned pos) { if (! parent) - sprintf (name, "op%u", pos); + sprintf (name, "_p%u", pos); else - sprintf (name, "o%u%u", level, pos); + sprintf (name, "_q%u%u", level, pos); } /* Generate matching code for the decision tree operand which is @@ -2793,7 +2798,7 @@ dt_operand::gen_match_op (FILE *f, int indent, const char *opname, bool) /* Generate GIMPLE matching code for the decision tree operand. */ unsigned -dt_operand::gen_gimple_expr (FILE *f, int indent) +dt_operand::gen_gimple_expr (FILE *f, int indent, int depth) { expr *e = static_cast (op); id_base *id = e->operation; @@ -2825,8 +2830,8 @@ dt_operand::gen_gimple_expr (FILE *f, int indent) else fprintf_indent (f, indent, "tree %s = TREE_OPERAND " - "(gimple_assign_rhs1 (def), %i);\n", - child_opname, i); + "(gimple_assign_rhs1 (_a%d), %i);\n", + child_opname, depth, i); fprintf_indent (f, indent, "if ((TREE_CODE (%s) == SSA_NAME\n", child_opname); @@ -2844,13 +2849,13 @@ dt_operand::gen_gimple_expr (FILE *f, int indent) } else fprintf_indent (f, indent, - "tree %s = gimple_assign_rhs%u (def);\n", - child_opname, i + 1); + "tree %s = gimple_assign_rhs%u (_a%d);\n", + child_opname, i + 1, depth); } else fprintf_indent (f, indent, - "tree %s = gimple_call_arg (def, %u);\n", - child_opname, i); + "tree %s = gimple_call_arg (_c%d, %u);\n", + child_opname, depth, i); fprintf_indent (f, indent, "%s = do_valueize (valueize, %s);\n", child_opname, child_opname); @@ -2902,7 +2907,7 @@ dt_operand::gen_generic_expr (FILE *f, int indent, const char *opname) /* Generate matching code for the children of the decision tree node. */ void -dt_node::gen_kids (FILE *f, int indent, bool gimple) +dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth) { auto_vec gimple_exprs; auto_vec generic_exprs; @@ -2953,10 +2958,10 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple) Like DT_TRUE, DT_MATCH serves as a barrier as it can cause dependent matches to get out-of-order. Generate code now for what we have collected sofar. */ - gen_kids_1 (f, indent, gimple, gimple_exprs, generic_exprs, + gen_kids_1 (f, indent, gimple, depth, gimple_exprs, generic_exprs, fns, generic_fns, preds, others); /* And output the true operand itself. */ - kids[i]->gen (f, indent, gimple); + kids[i]->gen (f, indent, gimple, depth); gimple_exprs.truncate (0); generic_exprs.truncate (0); fns.truncate (0); @@ -2969,14 +2974,14 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple) } /* Generate code for the remains. */ - gen_kids_1 (f, indent, gimple, gimple_exprs, generic_exprs, + gen_kids_1 (f, indent, gimple, depth, gimple_exprs, generic_exprs, fns, generic_fns, preds, others); } /* Generate matching code for the children of the decision tree node. */ void -dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, +dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth, vec gimple_exprs, vec generic_exprs, vec fns, @@ -3010,20 +3015,23 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, if (exprs_len || fns_len) { + depth++; fprintf_indent (f, indent, "case SSA_NAME:\n"); fprintf_indent (f, indent, - " if (gimple *def_stmt = get_def (valueize, %s))\n", - kid_opname); + " if (gimple *_d%d = get_def (valueize, %s))\n", + depth, kid_opname); fprintf_indent (f, indent, " {\n"); indent += 6; if (exprs_len) { fprintf_indent (f, indent, - "if (gassign *def = dyn_cast (def_stmt))\n"); + "if (gassign *_a%d = dyn_cast (_d%d))\n", + depth, depth); fprintf_indent (f, indent, - " switch (gimple_assign_rhs_code (def))\n"); + " switch (gimple_assign_rhs_code (_a%d))\n", + depth); indent += 4; fprintf_indent (f, indent, "{\n"); for (unsigned i = 0; i < exprs_len; ++i) @@ -3035,7 +3043,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, else fprintf_indent (f, indent, "case %s:\n", op->id); fprintf_indent (f, indent, " {\n"); - gimple_exprs[i]->gen (f, indent + 4, true); + gimple_exprs[i]->gen (f, indent + 4, true, depth); fprintf_indent (f, indent, " break;\n"); fprintf_indent (f, indent, " }\n"); } @@ -3047,11 +3055,11 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, if (fns_len) { fprintf_indent (f, indent, - "%sif (gcall *def = dyn_cast " - " (def_stmt))\n", - exprs_len ? "else " : ""); + "%sif (gcall *_c%d = dyn_cast (_d%d))\n", + exprs_len ? "else " : "", depth, depth); fprintf_indent (f, indent, - " switch (gimple_call_combined_fn (def))\n"); + " switch (gimple_call_combined_fn (_c%d))\n", + depth); indent += 4; fprintf_indent (f, indent, "{\n"); @@ -3060,7 +3068,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, expr *e = as_a (fns[i]->op); fprintf_indent (f, indent, "case %s:\n", e->operation->id); fprintf_indent (f, indent, " {\n"); - fns[i]->gen (f, indent + 4, true); + fns[i]->gen (f, indent + 4, true, depth); fprintf_indent (f, indent, " break;\n"); fprintf_indent (f, indent, " }\n"); } @@ -3071,6 +3079,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, } indent -= 6; + depth--; fprintf_indent (f, indent, " }\n"); /* See if there is SSA_NAME among generic_exprs and if yes, emit it here rather than in the next loop. */ @@ -3081,7 +3090,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, if (*op == SSA_NAME && (exprs_len || fns_len)) { fprintf_indent (f, indent + 4, "{\n"); - generic_exprs[i]->gen (f, indent + 6, gimple); + generic_exprs[i]->gen (f, indent + 6, gimple, depth); fprintf_indent (f, indent + 4, "}\n"); } } @@ -3101,7 +3110,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, else fprintf_indent (f, indent, "case %s:\n", op->id); fprintf_indent (f, indent, " {\n"); - generic_exprs[i]->gen (f, indent + 4, gimple); + generic_exprs[i]->gen (f, indent + 4, gimple, depth); fprintf_indent (f, indent, " break;\n"); fprintf_indent (f, indent, " }\n"); } @@ -3124,7 +3133,7 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, fprintf_indent (f, indent, "case %s:\n", e->operation->id); fprintf_indent (f, indent, " {\n"); - generic_fns[j]->gen (f, indent + 4, false); + generic_fns[j]->gen (f, indent + 4, false, depth); fprintf_indent (f, indent, " break;\n"); fprintf_indent (f, indent, " }\n"); } @@ -3163,20 +3172,20 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, fprintf_indent (f, indent + 4, "tree %s = %s_pops[%d];\n", child_opname, kid_opname, j); } - preds[i]->gen_kids (f, indent + 4, gimple); + preds[i]->gen_kids (f, indent + 4, gimple, depth); fprintf (f, "}\n"); indent -= 2; fprintf_indent (f, indent, "}\n"); } for (unsigned i = 0; i < others.length (); ++i) - others[i]->gen (f, indent, gimple); + others[i]->gen (f, indent, gimple, depth); } /* Generate matching code for the decision tree operand. */ void -dt_operand::gen (FILE *f, int indent, bool gimple) +dt_operand::gen (FILE *f, int indent, bool gimple, int depth) { char opname[20]; get_name (opname); @@ -3192,7 +3201,7 @@ dt_operand::gen (FILE *f, int indent, bool gimple) case operand::OP_EXPR: if (gimple) - n_braces = gen_gimple_expr (f, indent); + n_braces = gen_gimple_expr (f, indent, depth); else n_braces = gen_generic_expr (f, indent, opname); break; @@ -3208,7 +3217,7 @@ dt_operand::gen (FILE *f, int indent, bool gimple) gcc_unreachable (); indent += 4 * n_braces; - gen_kids (f, indent, gimple); + gen_kids (f, indent, gimple, depth); for (unsigned i = 0; i < n_braces; ++i) { @@ -3276,7 +3285,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) if (cinfo.force_no_side_effects & (1 << i)) { fprintf_indent (f, indent, - "if (TREE_SIDE_EFFECTS (op%d)) return NULL_TREE;\n", + "if (TREE_SIDE_EFFECTS (_p%d)) return NULL_TREE;\n", i); if (verbose >= 1) warning_at (as_a (s->match)->ops[i]->location, @@ -3381,9 +3390,9 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) { char dest[32]; if (is_predicate) - snprintf (dest, 32, "res_ops[%d]", j); + snprintf (dest, sizeof (dest), "res_ops[%d]", j); else - snprintf (dest, 32, "res_op->ops[%d]", j); + snprintf (dest, sizeof (dest), "res_op->ops[%d]", j); const char *optype = get_operand_type (opr, j, "type", e->expr_type, @@ -3468,11 +3477,11 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) { char dest[32]; if (is_predicate) - snprintf (dest, 32, "res_ops[%d]", j); + snprintf (dest, sizeof (dest), "res_ops[%d]", j); else { fprintf_indent (f, indent, "tree res_op%d;\n", j); - snprintf (dest, 32, "res_op%d", j); + snprintf (dest, sizeof (dest), "res_op%d", j); } const char *optype = get_operand_type (opr, j, @@ -3486,24 +3495,24 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) fprintf_indent (f, indent, "return true;\n"); else { - fprintf_indent (f, indent, "tree res;\n"); + fprintf_indent (f, indent, "tree _r;\n"); /* Re-fold the toplevel result. Use non_lvalue to - build NON_LVALUE_EXPRs so they get properly + build NON_LVALUE_EXPRs so they get properly ignored when in GIMPLE form. */ if (*opr == NON_LVALUE_EXPR) fprintf_indent (f, indent, - "res = non_lvalue_loc (loc, res_op0);\n"); + "_r = non_lvalue_loc (loc, res_op0);\n"); else { if (is_a (opr)) fprintf_indent (f, indent, - "res = fold_build%d_loc (loc, %s, type", + "_r = fold_build%d_loc (loc, %s, type", e->ops.length (), *e->operation == CONVERT_EXPR ? "NOP_EXPR" : e->operation->id); else fprintf_indent (f, indent, - "res = maybe_build_call_expr_loc (loc, " + "_r = maybe_build_call_expr_loc (loc, " "%s, type, %d", e->operation->id, e->ops.length()); for (unsigned j = 0; j < e->ops.length (); ++j) @@ -3511,7 +3520,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) fprintf (f, ");\n"); if (!is_a (opr)) { - fprintf_indent (f, indent, "if (!res)\n"); + fprintf_indent (f, indent, "if (!_r)\n"); fprintf_indent (f, indent, " return NULL_TREE;\n"); } } @@ -3521,8 +3530,8 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) || result->type == operand::OP_C_EXPR) { - fprintf_indent (f, indent, "tree res;\n"); - result->gen_transform (f, indent, "res", false, 1, "type", + fprintf_indent (f, indent, "tree _r;\n"); + result->gen_transform (f, indent, "_r", false, 1, "type", &cinfo, indexes); } else @@ -3543,12 +3552,12 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) "if (TREE_SIDE_EFFECTS (captures[%d]))\n", i); fprintf_indent (f, indent + 2, - "res = build2_loc (loc, COMPOUND_EXPR, type, " - "fold_ignored_result (captures[%d]), res);\n", + "_r = build2_loc (loc, COMPOUND_EXPR, type, " + "fold_ignored_result (captures[%d]), _r);\n", i); } } - fprintf_indent (f, indent, "return res;\n"); + fprintf_indent (f, indent, "return _r;\n"); } } } @@ -3558,7 +3567,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) that is not part of the decision tree (simplify->match). */ void -dt_simplify::gen (FILE *f, int indent, bool gimple) +dt_simplify::gen (FILE *f, int indent, bool gimple, int depth ATTRIBUTE_UNUSED) { fprintf_indent (f, indent, "{\n"); indent += 2; @@ -3597,7 +3606,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) fprintf_indent (f, indent, "tree res = %s (loc, type", info->fname); for (unsigned i = 0; i < as_a (s->match)->ops.length (); ++i) - fprintf (f, ", op%d", i); + fprintf (f, ", _p%d", i); fprintf (f, ", captures"); for (unsigned i = 0; i < s->for_subst_vec.length (); ++i) { @@ -3764,7 +3773,7 @@ decision_tree::gen (FILE *f, bool gimple) (*iter).second->fname); for (unsigned i = 0; i < as_a (s->s->s->match)->ops.length (); ++i) - fprintf (f, " tree ARG_UNUSED (op%d),", i); + fprintf (f, " tree ARG_UNUSED (_p%d),", i); fprintf (f, " tree *captures\n"); } for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i) @@ -3792,9 +3801,9 @@ decision_tree::gen (FILE *f, bool gimple) for (unsigned n = 1; n <= 5; ++n) { /* First generate split-out functions. */ - for (unsigned i = 0; i < root->kids.length (); i++) + for (unsigned j = 0; j < root->kids.length (); j++) { - dt_operand *dop = static_cast(root->kids[i]); + dt_operand *dop = static_cast(root->kids[j]); expr *e = static_cast(dop->op); if (e->ops.length () != n /* Builtin simplifications are somewhat premature on @@ -3820,10 +3829,10 @@ decision_tree::gen (FILE *f, bool gimple) "tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)", e->operation->id); for (unsigned i = 0; i < n; ++i) - fprintf (f, ", tree op%d", i); + fprintf (f, ", tree _p%d", i); fprintf (f, ")\n"); fprintf (f, "{\n"); - dop->gen_kids (f, 2, gimple); + dop->gen_kids (f, 2, gimple, 0); if (gimple) fprintf (f, " return false;\n"); else @@ -3843,7 +3852,7 @@ decision_tree::gen (FILE *f, bool gimple) "generic_simplify (location_t loc, enum tree_code code, " "const tree type ATTRIBUTE_UNUSED"); for (unsigned i = 0; i < n; ++i) - fprintf (f, ", tree op%d", i); + fprintf (f, ", tree _p%d", i); fprintf (f, ")\n"); fprintf (f, "{\n"); @@ -3879,8 +3888,8 @@ decision_tree::gen (FILE *f, bool gimple) else fprintf (f, " return generic_simplify_%s (loc, code, type", e->operation->id); - for (unsigned i = 0; i < n; ++i) - fprintf (f, ", op%d", i); + for (unsigned j = 0; j < n; ++j) + fprintf (f, ", _p%d", j); fprintf (f, ");\n"); } fprintf (f, " default:;\n" @@ -3909,7 +3918,7 @@ write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple) if (!gimple) fprintf_indent (f, 2, "if (TREE_SIDE_EFFECTS (t)) return false;\n"); - dt.root->gen_kids (f, 2, gimple); + dt.root->gen_kids (f, 2, gimple, 0); fprintf_indent (f, 2, "return false;\n" "}\n"); @@ -4114,7 +4123,7 @@ parser::get_internal_capture_id () /* Big enough for a 32-bit UINT_MAX plus prefix. */ char id[13]; bool existed; - sprintf (id, "__%u", newid); + snprintf (id, sizeof (id), "__%u", newid); capture_ids->get_or_insert (xstrdup (id), &existed); if (existed) fatal ("reserved capture id '%s' already used", id); @@ -4261,11 +4270,11 @@ parser::parse_expr () { if (*sp == 'c') { - if (operator_id *p + if (operator_id *o = dyn_cast (e->operation)) { - if (!commutative_tree_code (p->code) - && !comparison_code_p (p->code)) + if (!commutative_tree_code (o->code) + && !comparison_code_p (o->code)) fatal_at (token, "operation is not commutative"); } else if (user_id *p = dyn_cast (e->operation)) @@ -4313,7 +4322,7 @@ parser::parse_expr () op = e; do { - const cpp_token *token = peek (); + token = peek (); if (token->type == CPP_CLOSE_PAREN) { if (e->operation->nargs != -1 @@ -4424,17 +4433,17 @@ parser::parse_op () id_base *opr = get_operator (id); if (!opr) fatal_at (token, "expected predicate name"); - if (operator_id *code = dyn_cast (opr)) + if (operator_id *code1 = dyn_cast (opr)) { - if (code->nargs != 0) + if (code1->nargs != 0) fatal_at (token, "using an operator with operands as predicate"); /* Parse the zero-operand operator "predicates" as expression. */ op = new expr (opr, token->src_loc); } - else if (user_id *code = dyn_cast (opr)) + else if (user_id *code2 = dyn_cast (opr)) { - if (code->nargs != 0) + if (code2->nargs != 0) fatal_at (token, "using an operator with operands as predicate"); /* Parse the zero-operand operator "predicates" as expression. */ @@ -4859,7 +4868,7 @@ parser::parse_if (location_t) active_ifs.safe_push (ifexpr); while (1) { - const cpp_token *token = peek (); + token = peek (); if (token->type == CPP_CLOSE_PAREN) break; @@ -4910,14 +4919,14 @@ parser::parse_pattern () with_args = true; } const char *name = get_ident (); - id_base *id = get_operator (name); + id_base *id1 = get_operator (name); predicate_id *p; - if (!id) + if (!id1) { p = add_predicate (name); user_predicates.safe_push (p); } - else if ((p = dyn_cast (id))) + else if ((p = dyn_cast (id1))) ; else fatal_at (token, "cannot add a match to a non-predicate ID"); @@ -5160,12 +5169,12 @@ add_operator (VIEW_CONVERT2, "view_convert2", "tcc_unary", 1); lower (pred->matchers, gimple); if (verbose == 2) - for (unsigned i = 0; i < pred->matchers.length (); ++i) - print_matches (pred->matchers[i]); + for (unsigned j = 0; j < pred->matchers.length (); ++j) + print_matches (pred->matchers[j]); decision_tree dt; - for (unsigned i = 0; i < pred->matchers.length (); ++i) - dt.insert (pred->matchers[i], i); + for (unsigned j = 0; j < pred->matchers.length (); ++j) + dt.insert (pred->matchers[j], j); if (verbose == 2) dt.print (stderr); -- cgit v1.1 From b51a085b32f2dae08113e513b4fb1f24071009df Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 4 Oct 2019 16:18:22 +0000 Subject: cgraph.h (FOR_EACH_ALIAS): Avoid shadowing the loop variable. 2019-10-04 Bernd Edlinger * cgraph.h (FOR_EACH_ALIAS): Avoid shadowing the loop variable. From-SVN: r276590 --- gcc/ChangeLog | 4 ++++ gcc/cgraph.h | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ba33fe7..23cb589 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,9 @@ 2019-10-04 Bernd Edlinger + * cgraph.h (FOR_EACH_ALIAS): Avoid shadowing the loop variable. + +2019-10-04 Bernd Edlinger + * genmatch.c (commutate): Rename local var. (lower_cond): Reuse local var. (dt_node::gen, dt_node::gen_kids, dt_node::gen_kids_1, diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 66a4dae..73b2be6 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -648,8 +648,10 @@ symtab_node::checking_verify_symtab_nodes (void) } /* Walk all aliases for NODE. */ -#define FOR_EACH_ALIAS(node, alias) \ - for (unsigned x_i = 0; node->iterate_direct_aliases (x_i, alias); x_i++) +#define FOR_EACH_ALIAS(NODE, ALIAS) \ + for (unsigned ALIAS##_iter_ = 0; \ + (NODE)->iterate_direct_aliases (ALIAS##_iter_, ALIAS); \ + ALIAS##_iter_++) /* This is the information that is put into the cgraph local structure to recover a function. */ -- cgit v1.1 From 51b54218c4db612e3db3b7394cbce05c8b825f0a Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 4 Oct 2019 16:21:11 +0000 Subject: expr.c (convert_mode_scalar): Remove shadowing local var. 2019-10-04 Bernd Edlinger * expr.c (convert_mode_scalar): Remove shadowing local var. (emit_block_move): Rename local vars. (block_move_libcall_safe_for_call_parm): Remove shadowing local var. (emit_push_insn): Rename local vars. (expand_assignment): Fix wrong mode in assign_stack_temp. Remove shadowing local vars. (store_constructor): Remove shadowing local vars. Rename local var. (store_field, expand_cond_expr_using_cmove, expand_expr_real_2): Remove shadowing local vars. (expand_expr_real_1, do_store_flag): Remove shadowing local vars. Rename local vars. From-SVN: r276591 --- gcc/ChangeLog | 14 +++++++++++ gcc/expr.c | 74 ++++++++++++++++++++++++++--------------------------------- 2 files changed, 47 insertions(+), 41 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 23cb589..2e60943 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,19 @@ 2019-10-04 Bernd Edlinger + * expr.c (convert_mode_scalar): Remove shadowing local var. + (emit_block_move): Rename local vars. + (block_move_libcall_safe_for_call_parm): Remove shadowing local var. + (emit_push_insn): Rename local vars. + (expand_assignment): Fix wrong mode in assign_stack_temp. Remove + shadowing local vars. + (store_constructor): Remove shadowing local vars. Rename local var. + (store_field, expand_cond_expr_using_cmove, + expand_expr_real_2): Remove shadowing local vars. + (expand_expr_real_1, + do_store_flag): Remove shadowing local vars. Rename local vars. + +2019-10-04 Bernd Edlinger + * cgraph.h (FOR_EACH_ALIAS): Avoid shadowing the loop variable. 2019-10-04 Bernd Edlinger diff --git a/gcc/expr.c b/gcc/expr.c index 2ee2906..124144d 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -560,7 +560,6 @@ convert_mode_scalar (rtx to, rtx from, int unsignedp) } else { - scalar_mode intermediate; rtx tmp; int shift_amount; @@ -1695,9 +1694,7 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method) static bool block_move_libcall_safe_for_call_parm (void) { -#if defined (REG_PARM_STACK_SPACE) tree fn; -#endif /* If arguments are pushed on the stack, then they're safe. */ if (PUSH_ARGS) @@ -1720,7 +1717,7 @@ block_move_libcall_safe_for_call_parm (void) { CUMULATIVE_ARGS args_so_far_v; cumulative_args_t args_so_far; - tree fn, arg; + tree arg; fn = builtin_decl_implicit (BUILT_IN_MEMCPY); INIT_CUMULATIVE_ARGS (args_so_far_v, TREE_TYPE (fn), NULL_RTX, 0, 3); @@ -4482,16 +4479,16 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, /* Get the address of the stack space. In this case, we do not deal with EXTRA separately. A single stack adjust will do. */ - poly_int64 offset; + poly_int64 const_args_so_far; if (! args_addr) { temp = push_block (size, extra, where_pad == PAD_DOWNWARD); extra = 0; } - else if (poly_int_rtx_p (args_so_far, &offset)) + else if (poly_int_rtx_p (args_so_far, &const_args_so_far)) temp = memory_address (BLKmode, plus_constant (Pmode, args_addr, - skip + offset)); + skip + const_args_so_far)); else temp = memory_address (BLKmode, plus_constant (Pmode, @@ -4566,8 +4563,8 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, { /* Scalar partly in registers. This case is only supported for fixed-wdth modes. */ - int size = GET_MODE_SIZE (mode).to_constant (); - size /= UNITS_PER_WORD; + int num_words = GET_MODE_SIZE (mode).to_constant (); + num_words /= UNITS_PER_WORD; int i; int not_stack; /* # bytes of start of argument @@ -4614,7 +4611,7 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, /* Loop over all the words allocated on the stack for this arg. */ /* We can do it by words, because any scalar bigger than a word has a size a multiple of a word. */ - for (i = size - 1; i >= not_stack; i--) + for (i = num_words - 1; i >= not_stack; i--) if (i >= not_stack + offset) if (!emit_push_insn (operand_subword_force (x, i, mode), word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX, @@ -5277,8 +5274,7 @@ expand_assignment (tree to, tree from, bool nontemporal) } else { - machine_mode to_mode - = GET_MODE_INNER (GET_MODE (to_rtx)); + to_mode = GET_MODE_INNER (to_mode); rtx from_real = simplify_gen_subreg (to_mode, result, TYPE_MODE (TREE_TYPE (from)), @@ -5297,7 +5293,7 @@ expand_assignment (tree to, tree from, bool nontemporal) else { concat_store_slow:; - rtx temp = assign_stack_temp (to_mode, + rtx temp = assign_stack_temp (GET_MODE (to_rtx), GET_MODE_SIZE (GET_MODE (to_rtx))); write_complex_part (temp, XEXP (to_rtx, 0), false); write_complex_part (temp, XEXP (to_rtx, 1), true); @@ -6461,7 +6457,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, && exp_size >= 0 && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT) { - tree type = TREE_TYPE (value); + type = TREE_TYPE (value); if (TYPE_PRECISION (type) < BITS_PER_WORD) { @@ -6538,7 +6534,6 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, else { unsigned HOST_WIDE_INT idx; - tree index, value; HOST_WIDE_INT count = 0, zero_count = 0; need_to_clear = ! const_bounds_p; @@ -6827,7 +6822,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, icode = convert_optab_handler (vec_init_optab, mode, emode); if (icode != CODE_FOR_nothing) { - unsigned int i, n = const_n_elts; + unsigned int n = const_n_elts; if (emode != eltmode) { @@ -6835,8 +6830,8 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, vec_vec_init_p = true; } vector = rtvec_alloc (n); - for (i = 0; i < n; i++) - RTVEC_ELT (vector, i) = CONST0_RTX (emode); + for (unsigned int k = 0; k < n; k++) + RTVEC_ELT (vector, k) = CONST0_RTX (emode); } } @@ -7157,7 +7152,7 @@ store_field (rtx target, poly_int64 bitsize, poly_int64 bitpos, word size, we need to load the value (see again store_bit_field). */ if (GET_MODE (temp) == BLKmode && known_le (bitsize, BITS_PER_WORD)) { - scalar_int_mode temp_mode = smallest_int_mode_for_size (bitsize); + temp_mode = smallest_int_mode_for_size (bitsize); temp = extract_bit_field (temp, bitsize, 0, 1, NULL_RTX, temp_mode, temp_mode, false, NULL); } @@ -8380,7 +8375,7 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED, if (TREE_CODE (treeop0) == SSA_NAME && (srcstmt = get_def_for_expr_class (treeop0, tcc_comparison))) { - tree type = TREE_TYPE (gimple_assign_rhs1 (srcstmt)); + type = TREE_TYPE (gimple_assign_rhs1 (srcstmt)); enum tree_code cmpcode = gimple_assign_rhs_code (srcstmt); op00 = expand_normal (gimple_assign_rhs1 (srcstmt)); op01 = expand_normal (gimple_assign_rhs2 (srcstmt)); @@ -8390,7 +8385,7 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED, } else if (COMPARISON_CLASS_P (treeop0)) { - tree type = TREE_TYPE (TREE_OPERAND (treeop0, 0)); + type = TREE_TYPE (TREE_OPERAND (treeop0, 0)); enum tree_code cmpcode = TREE_CODE (treeop0); op00 = expand_normal (TREE_OPERAND (treeop0, 0)); op01 = expand_normal (TREE_OPERAND (treeop0, 1)); @@ -9684,7 +9679,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, tree oprnd0 = treeop0; tree oprnd1 = treeop1; tree oprnd2 = treeop2; - rtx op2; expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); op2 = expand_normal (oprnd2); @@ -9698,7 +9692,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, tree oprnd0 = treeop0; tree oprnd1 = treeop1; tree oprnd2 = treeop2; - rtx op2; expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); op2 = expand_normal (oprnd2); @@ -9712,7 +9705,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, tree oprnd0 = treeop0; tree oprnd1 = treeop1; tree oprnd2 = treeop2; - rtx op2; this_optab = optab_for_tree_code (code, type, optab_default); expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); @@ -9802,8 +9794,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, bitsize = TYPE_PRECISION (TREE_TYPE (treeop1)); else bitsize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (treeop1))); - rtx op0 = expand_normal (treeop0); - rtx op1 = expand_normal (treeop1); + op0 = expand_normal (treeop0); + op1 = expand_normal (treeop1); rtx dst = gen_reg_rtx (mode); emit_move_insn (dst, op0); store_bit_field (dst, bitsize, bitpos, 0, 0, @@ -10002,7 +9994,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, { rtx r; location_t saved_loc = curr_insn_location (); - location_t loc = gimple_location (g); + loc = gimple_location (g); if (loc != UNKNOWN_LOCATION) set_curr_insn_location (loc); ops.code = gimple_assign_rhs_code (g); @@ -10201,9 +10193,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from the former to the latter according to the signedness of the type. */ - scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type); + scalar_int_mode int_mode = SCALAR_INT_TYPE_MODE (type); temp = immed_wide_int_const - (wi::to_wide (exp, GET_MODE_PRECISION (mode)), mode); + (wi::to_wide (exp, GET_MODE_PRECISION (int_mode)), int_mode); return temp; } @@ -10278,9 +10270,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, /* Handle evaluating a complex constant in a CONCAT target. */ if (original_target && GET_CODE (original_target) == CONCAT) { - machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp))); rtx rtarg, itarg; + mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp))); rtarg = XEXP (original_target, 0); itarg = XEXP (original_target, 1); @@ -10584,14 +10576,14 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, if (tree_fits_uhwi_p (index1) && compare_tree_int (index1, TREE_STRING_LENGTH (init)) < 0) { - tree type = TREE_TYPE (TREE_TYPE (init)); - scalar_int_mode mode; + tree char_type = TREE_TYPE (TREE_TYPE (init)); + scalar_int_mode char_mode; - if (is_int_mode (TYPE_MODE (type), &mode) - && GET_MODE_SIZE (mode) == 1) + if (is_int_mode (TYPE_MODE (char_type), &char_mode) + && GET_MODE_SIZE (char_mode) == 1) return gen_int_mode (TREE_STRING_POINTER (init) [TREE_INT_CST_LOW (index1)], - mode); + char_mode); } } } @@ -10745,8 +10737,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, rtx op = read_complex_part (op0, i != 0); if (GET_CODE (op) == SUBREG) op = force_reg (GET_MODE (op), op); - rtx temp = gen_lowpart_common (GET_MODE_INNER (mode1), - op); + temp = gen_lowpart_common (GET_MODE_INNER (mode1), op); if (temp) op = temp; else @@ -12138,11 +12129,12 @@ do_store_flag (sepops ops, rtx target, machine_mode mode) && TREE_CODE (arg0) == SSA_NAME && TREE_CODE (arg1) == INTEGER_CST) { - enum tree_code code = maybe_optimize_mod_cmp (ops->code, &arg0, &arg1); - if (code != ops->code) + enum tree_code new_code = maybe_optimize_mod_cmp (ops->code, + &arg0, &arg1); + if (new_code != ops->code) { struct separate_ops nops = *ops; - nops.code = ops->code = code; + nops.code = ops->code = new_code; nops.op0 = arg0; nops.op1 = arg1; nops.type = TREE_TYPE (arg0); @@ -12245,7 +12237,7 @@ do_store_flag (sepops ops, rtx target, machine_mode mode) && integer_pow2p (gimple_assign_rhs2 (srcstmt))) { enum tree_code tcode = code == NE ? NE_EXPR : EQ_EXPR; - tree type = lang_hooks.types.type_for_mode (mode, unsignedp); + type = lang_hooks.types.type_for_mode (mode, unsignedp); tree temp = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg1), gimple_assign_rhs1 (srcstmt), gimple_assign_rhs2 (srcstmt)); -- cgit v1.1 From ddf25542f2fadde86c04547decb73c08a99ee215 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 4 Oct 2019 16:22:28 +0000 Subject: hash-table.h (hash_table::empty_slow): Don't assign size_t values to int variables. 2019-10-04 Bernd Edlinger * hash-table.h (hash_table::empty_slow): Don't assign size_t values to int variables. From-SVN: r276592 --- gcc/ChangeLog | 5 +++++ gcc/hash-table.h | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2e60943..5883b18 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-10-04 Bernd Edlinger + * hash-table.h (hash_table::empty_slow): Don't assign + size_t values to int variables. + +2019-10-04 Bernd Edlinger + * expr.c (convert_mode_scalar): Remove shadowing local var. (emit_block_move): Rename local vars. (block_move_libcall_safe_for_call_parm): Remove shadowing local var. diff --git a/gcc/hash-table.h b/gcc/hash-table.h index 0e95f5b..ba5d64f 100644 --- a/gcc/hash-table.h +++ b/gcc/hash-table.h @@ -842,9 +842,8 @@ hash_table::empty_slow () size_t size = m_size; size_t nsize = size; value_type *entries = m_entries; - int i; - for (i = size - 1; i >= 0; i--) + for (size_t i = size - 1; i < size; i--) if (!is_empty (entries[i]) && !is_deleted (entries[i])) Descriptor::remove (entries[i]); @@ -856,8 +855,9 @@ hash_table::empty_slow () if (nsize != size) { - int nindex = hash_table_higher_prime_index (nsize); - int nsize = prime_tab[nindex].prime; + unsigned int nindex = hash_table_higher_prime_index (nsize); + + nsize = prime_tab[nindex].prime; if (!m_ggc) Allocator ::data_free (m_entries); -- cgit v1.1 From 432bbcbb1e9d4a2b2bd946a0120c2be52c4ec01d Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 4 Oct 2019 18:25:02 +0200 Subject: Add missing gimple_call_set_fntype 2019-10-04 Martin Jambor * tree-ssa-forwprop.c (simplify_builtin_call): Set gimple call fntype when switching to calling memcpy instead of memset. From-SVN: r276593 --- gcc/ChangeLog | 5 +++++ gcc/tree-ssa-forwprop.c | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5883b18..a013d86 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-04 Martin Jambor + + * tree-ssa-forwprop.c (simplify_builtin_call): Set gimple call + fntype when switching to calling memcpy instead of memset. + 2019-10-04 Bernd Edlinger * hash-table.h (hash_table::empty_slow): Don't assign diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 221f140..a1e22c9 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1426,8 +1426,10 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2) if (!is_gimple_val (ptr1)) ptr1 = force_gimple_operand_gsi (gsi_p, ptr1, true, NULL_TREE, true, GSI_SAME_STMT); - gimple_call_set_fndecl (stmt2, - builtin_decl_explicit (BUILT_IN_MEMCPY)); + tree fndecl = builtin_decl_explicit (BUILT_IN_MEMCPY); + gimple_call_set_fndecl (stmt2, fndecl); + gimple_call_set_fntype (as_a (stmt2), + TREE_TYPE (fndecl)); gimple_call_set_arg (stmt2, 0, ptr1); gimple_call_set_arg (stmt2, 1, new_str_cst); gimple_call_set_arg (stmt2, 2, -- cgit v1.1 From 69b35f396ceb22e2e04b4228a6811291621808c1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 4 Oct 2019 18:14:30 +0000 Subject: compiler: include selected constant types during export processing The machinery that collects types referenced by expressions that are part of inlinable function bodies was missing the types of local named constants in certain cases. This patch updates the Collect_export_references::expression() hook to look for references to local named constants and include their types in the exported set. Fixes golang/go#34577. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/198017 From-SVN: r276594 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/export.cc | 12 ++++++++++++ gcc/go/gofrontend/expressions.cc | 13 +++++++++++++ gcc/go/gofrontend/expressions.h | 5 +++++ 4 files changed, 31 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index bb50994..1508eb1 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -441f3f1f350b532707c48273d7f454cf1c4e959f +ddfb845fad1f2e8b84383f262ed5ea5be7b3e35a The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index 32ab498..5aaa207 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -249,6 +249,14 @@ Collect_export_references::expression(Expression** pexpr) return TRAVERSE_CONTINUE; } + const Named_object* nco = expr->named_constant(); + if (nco != 0 && nco->package() == NULL) + { + const Named_constant *nc = nco->const_value(); + Type::traverse(nc->type(), this); + return TRAVERSE_CONTINUE; + } + return TRAVERSE_CONTINUE; } @@ -322,6 +330,10 @@ Collect_export_references::type(Type* type) if (type->is_void_type()) return TRAVERSE_SKIP_COMPONENTS; + // Skip the nil type, turns up in function bodies. + if (type->is_nil_type()) + return TRAVERSE_SKIP_COMPONENTS; + // Skip abstract types. We should never see these in real code, // only in things like const declarations. if (type->is_abstract()) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 9babc34..b614921 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3234,6 +3234,10 @@ class Const_expression : public Expression named_object() { return this->constant_; } + const Named_object* + named_object() const + { return this->constant_; } + // Check that the initializer does not refer to the constant itself. void check_for_init_loop(); @@ -16782,6 +16786,15 @@ Expression::is_local_variable() const || (no->is_variable() && !no->var_value()->is_global())); } +const Named_object* +Expression::named_constant() const +{ + if (this->classification() != EXPRESSION_CONST_REFERENCE) + return NULL; + const Const_expression* ce = static_cast(this); + return ce->named_object(); +} + // Class Type_guard_expression. // Traversal. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 2e3d1e0..a0370e1 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -587,6 +587,11 @@ class Expression boolean_constant_value(bool* val) const { return this->do_boolean_constant_value(val); } + // If this is a const reference expression, return the named + // object to which the expression refers, otherwise return NULL. + const Named_object* + named_constant() const; + // This is called if the value of this expression is being // discarded. This issues warnings about computed values being // unused. This returns true if all is well, false if it issued an -- cgit v1.1