void gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p, tree *lhs_p, tree *rhs_p) { gcc_assert (COMPARISON_CLASS_P (cond) || TREE_CODE (cond) == TRUTH_NOT_EXPR || is_gimple_min_invariant (cond) || SSA_VAR_P (cond)); extract_ops_from_tree (cond, code_p, lhs_p, rhs_p); /* Canonicalize conditionals of the form 'if (!VAL)'. */ if (*code_p == TRUTH_NOT_EXPR) { *code_p = EQ_EXPR; gcc_assert (*lhs_p && *rhs_p == NULL_TREE); *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); } /* Canonicalize conditionals of the form 'if (VAL)' */ else if (TREE_CODE_CLASS (*code_p) != tcc_comparison) { *code_p = NE_EXPR; gcc_assert (*lhs_p && *rhs_p == NULL_TREE); *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p)); } }
static tree cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data) { if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo))) return dfs_skip_bases; if (!BINFO_PRIMARY_P (binfo)) { tree base_ptr = TREE_VALUE ((tree) data); base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1, tf_warning_or_error); /* Compute the location of the vtpr. */ tree vtbl_ptr = build_vfield_ref (cp_build_fold_indirect_ref (base_ptr), TREE_TYPE (binfo)); gcc_assert (vtbl_ptr != error_mark_node); /* Assign NULL to the vptr. */ tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr)); tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR, vtbl, tf_warning_or_error); if (vptr_via_virtual_p (binfo)) /* If this vptr comes from a virtual base of the complete object, only clear it if we're in charge of virtual bases. */ stmt = build_if_in_charge (stmt); finish_expr_stmt (stmt); } return NULL_TREE; }
static tree cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data) { if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo))) return dfs_skip_bases; if (!BINFO_PRIMARY_P (binfo) || BINFO_VIRTUAL_P (binfo)) { tree base_ptr = TREE_VALUE ((tree) data); base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1, tf_warning_or_error); /* Compute the location of the vtpr. */ tree vtbl_ptr = build_vfield_ref (cp_build_indirect_ref (base_ptr, RO_NULL, tf_warning_or_error), TREE_TYPE (binfo)); gcc_assert (vtbl_ptr != error_mark_node); /* Assign NULL to the vptr. */ tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr)); finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl, tf_warning_or_error)); } return NULL_TREE; }
tree gfc_unlikely (tree cond) { tree tmp; cond = fold_convert (long_integer_type_node, cond); tmp = build_zero_cst (long_integer_type_node); cond = build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_EXPECT), 2, cond, tmp); cond = fold_convert (boolean_type_node, cond); return cond; }
static tree cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr, enum ubsan_null_ckind ckind) { type = TYPE_MAIN_VARIANT (type); const char *mangled = mangle_type_string (type); hashval_t str_hash1 = htab_hash_string (mangled); hashval_t str_hash2 = iterative_hash (mangled, strlen (mangled), 0); tree str_hash = wide_int_to_tree (uint64_type_node, wi::uhwi (((uint64_t) str_hash1 << 32) | str_hash2, 64)); if (!is_addr) op = build_fold_addr_expr_loc (loc, op); op = save_expr (op); tree vptr = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)), build_fold_indirect_ref_loc (loc, op), TYPE_VFIELD (type), NULL_TREE); vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr); vptr = fold_convert_loc (loc, uint64_type_node, vptr); if (ckind == UBSAN_DOWNCAST_POINTER) { tree cond = build2_loc (loc, NE_EXPR, boolean_type_node, op, build_zero_cst (TREE_TYPE (op))); /* This is a compiler generated comparison, don't emit e.g. -Wnonnull-compare warning for it. */ TREE_NO_WARNING (cond) = 1; vptr = build3_loc (loc, COND_EXPR, uint64_type_node, cond, vptr, build_int_cst (uint64_type_node, 0)); } tree ti_decl = get_tinfo_decl (type); mark_used (ti_decl); tree ptype = build_pointer_type (type); tree call = build_call_expr_internal_loc (loc, IFN_UBSAN_VPTR, void_type_node, 5, op, vptr, str_hash, build_address (ti_decl), build_int_cst (ptype, ckind)); TREE_SIDE_EFFECTS (call) = 1; return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op); }
void propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) { gimple stmt = gsi_stmt (*gsi); if (is_gimple_assign (stmt)) { tree expr = NULL_TREE; if (gimple_assign_single_p (stmt)) expr = gimple_assign_rhs1 (stmt); propagate_tree_value (&expr, val); gimple_assign_set_rhs_from_tree (gsi, expr); } else if (gimple_code (stmt) == GIMPLE_COND) { tree lhs = NULL_TREE; tree rhs = build_zero_cst (TREE_TYPE (val)); propagate_tree_value (&lhs, val); gimple_cond_set_code (stmt, NE_EXPR); gimple_cond_set_lhs (stmt, lhs); gimple_cond_set_rhs (stmt, rhs); } else if (is_gimple_call (stmt) && gimple_call_lhs (stmt) != NULL_TREE) { tree expr = NULL_TREE; bool res; propagate_tree_value (&expr, val); res = update_call_from_tree (gsi, expr); gcc_assert (res); } else if (gimple_code (stmt) == GIMPLE_SWITCH) propagate_tree_value (gimple_switch_index_ptr (stmt), val); else gcc_unreachable (); }
static tree fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var) { tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr; tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list; tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE; tree new_exp_init = NULL_TREE; vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; size_t list_size = 0, rank = 0, ii = 0; tree loop_init, array_op0; tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body; location_t location = UNKNOWN_LOCATION; tree loop_with_init = alloc_stmt_list (); vec<vec<an_parts> > an_info = vNULL; vec<an_loop_parts> an_loop_info = vNULL; enum built_in_function an_type = is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn)); if (an_type == BUILT_IN_NONE) return NULL_TREE; /* Builtin call should contain at least one argument. */ if (call_expr_nargs (an_builtin_fn) == 0) { error_at (EXPR_LOCATION (an_builtin_fn), "Invalid builtin arguments"); return error_mark_node; } if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) { call_fn = CALL_EXPR_ARG (an_builtin_fn, 2); if (TREE_CODE (call_fn) == ADDR_EXPR) call_fn = TREE_OPERAND (call_fn, 0); identity_value = CALL_EXPR_ARG (an_builtin_fn, 0); func_parm = CALL_EXPR_ARG (an_builtin_fn, 1); } else func_parm = CALL_EXPR_ARG (an_builtin_fn, 0); /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function parameter. */ func_parm = c_fully_fold (func_parm, false, NULL); if (func_parm == error_mark_node) return error_mark_node; location = EXPR_LOCATION (an_builtin_fn); if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank)) return error_mark_node; if (rank == 0) { error_at (location, "Invalid builtin arguments"); return error_mark_node; } else if (rank > 1 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)) { error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot" " have arrays with dimension greater than 1"); return error_mark_node; } extract_array_notation_exprs (func_parm, true, &array_list); list_size = vec_safe_length (array_list); switch (an_type) { case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: new_var_type = TREE_TYPE ((*array_list)[0]); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: new_var_type = integer_type_node; break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: new_var_type = integer_type_node; break; case BUILT_IN_CILKPLUS_SEC_REDUCE: if (call_fn && identity_value) new_var_type = TREE_TYPE ((*array_list)[0]); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: new_var_type = NULL_TREE; break; default: gcc_unreachable (); } an_loop_info.safe_grow_cleared (rank); cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); loop_init = alloc_stmt_list (); for (ii = 0; ii < rank; ii++) { an_loop_info[ii].var = create_tmp_var (integer_type_node); an_loop_info[ii].ind_init = build_modify_expr (location, an_loop_info[ii].var, TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location, build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0), TREE_TYPE (an_loop_info[ii].var)); } array_operand = create_array_refs (location, an_info, an_loop_info, list_size, rank); replace_array_notations (&func_parm, true, array_list, array_operand); create_cmp_incr (location, &an_loop_info, rank, an_info); if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) { *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type); gcc_assert (*new_var && *new_var != error_mark_node); } else *new_var = NULL_TREE; if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) array_ind_value = build_decl (location, VAR_DECL, NULL_TREE, TREE_TYPE (func_parm)); array_op0 = (*array_operand)[0]; if (TREE_CODE (array_op0) == INDIRECT_REF) array_op0 = TREE_OPERAND (array_op0, 0); switch (an_type) { case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (new_var_type), new_var_type); new_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR, location, func_parm, TREE_TYPE (func_parm)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_one_cst (new_var_type), new_var_type); new_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR, location, func_parm, TREE_TYPE (func_parm)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_one_cst (new_var_type), new_var_type); /* Initially you assume everything is zero, now if we find a case where it is NOT true, then we set the result to false. Otherwise we just keep the previous value. */ new_yes_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (TREE_TYPE (*new_var)), TREE_TYPE (*new_var)); new_no_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm, build_zero_cst (TREE_TYPE (func_parm))); new_expr = build_conditional_expr (location, new_cond_expr, false, new_yes_expr, TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_one_cst (new_var_type), new_var_type); /* Initially you assume everything is non-zero, now if we find a case where it is NOT true, then we set the result to false. Otherwise we just keep the previous value. */ new_yes_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (TREE_TYPE (*new_var)), TREE_TYPE (*new_var)); new_no_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm, build_zero_cst (TREE_TYPE (func_parm))); new_expr = build_conditional_expr (location, new_cond_expr, false, new_yes_expr, TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (new_var_type), new_var_type); /* Initially we assume there are NO zeros in the list. When we find a non-zero, we keep the previous value. If we find a zero, we set the value to true. */ new_yes_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_one_cst (new_var_type), new_var_type); new_no_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm, build_zero_cst (TREE_TYPE (func_parm))); new_expr = build_conditional_expr (location, new_cond_expr, false, new_yes_expr, TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (new_var_type), new_var_type); /* Initially we assume there are NO non-zeros in the list. When we find a zero, we keep the previous value. If we find a non-zero, we set the value to true. */ new_yes_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_one_cst (new_var_type), new_var_type); new_no_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm, build_zero_cst (TREE_TYPE (func_parm))); new_expr = build_conditional_expr (location, new_cond_expr, false, new_yes_expr, TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: if (TYPE_MIN_VALUE (new_var_type)) new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, TYPE_MIN_VALUE (new_var_type), new_var_type); else new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, func_parm, new_var_type); new_no_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_yes_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, func_parm, TREE_TYPE (*new_var)); new_expr = build_conditional_expr (location, build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false, new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: if (TYPE_MAX_VALUE (new_var_type)) new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, TYPE_MAX_VALUE (new_var_type), new_var_type); else new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, func_parm, new_var_type); new_no_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_yes_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, func_parm, TREE_TYPE (*new_var)); new_expr = build_conditional_expr (location, build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false, new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (new_var_type), new_var_type); new_exp_init = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, func_parm, TREE_TYPE (func_parm)); new_no_ind = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_no_expr = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, array_ind_value, TREE_TYPE (array_ind_value)); if (list_size > 1) { new_yes_ind = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var)); new_yes_expr = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, func_parm, TREE_TYPE ((*array_operand)[0])); } else { new_yes_ind = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, TREE_OPERAND (array_op0, 1), TREE_TYPE (TREE_OPERAND (array_op0, 1))); new_yes_expr = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, func_parm, TREE_OPERAND (array_op0, 1)); } new_yes_list = alloc_stmt_list (); append_to_statement_list (new_yes_ind, &new_yes_list); append_to_statement_list (new_yes_expr, &new_yes_list); new_no_list = alloc_stmt_list (); append_to_statement_list (new_no_ind, &new_no_list); append_to_statement_list (new_no_expr, &new_no_list); new_expr = build_conditional_expr (location, build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value, func_parm), false, new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, build_zero_cst (new_var_type), new_var_type); new_exp_init = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, func_parm, TREE_TYPE (func_parm)); new_no_ind = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, *new_var, TREE_TYPE (*new_var)); new_no_expr = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, array_ind_value, TREE_TYPE (array_ind_value)); if (list_size > 1) { new_yes_ind = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var)); new_yes_expr = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, func_parm, TREE_TYPE (array_op0)); } else { new_yes_ind = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, TREE_OPERAND (array_op0, 1), TREE_TYPE (TREE_OPERAND (array_op0, 1))); new_yes_expr = build_modify_expr (location, array_ind_value, TREE_TYPE (array_ind_value), NOP_EXPR, location, func_parm, TREE_OPERAND (array_op0, 1)); } new_yes_list = alloc_stmt_list (); append_to_statement_list (new_yes_ind, &new_yes_list); append_to_statement_list (new_yes_expr, &new_yes_list); new_no_list = alloc_stmt_list (); append_to_statement_list (new_no_ind, &new_no_list); append_to_statement_list (new_no_expr, &new_no_list); new_expr = build_conditional_expr (location, build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value, func_parm), false, new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE: new_var_init = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, identity_value, new_var_type); new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm); new_expr = build_modify_expr (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, location, new_call_expr, TREE_TYPE (*new_var)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: new_expr = build_call_expr (call_fn, 2, identity_value, func_parm); break; default: gcc_unreachable (); break; } for (ii = 0; ii < rank; ii++) append_to_statement_list (an_loop_info[ii].ind_init, &loop_init); if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) append_to_statement_list (new_exp_init, &loop_init); if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) append_to_statement_list (new_var_init, &loop_init); append_to_statement_list_force (loop_init, &loop_with_init); body = new_expr; for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); } append_to_statement_list_force (body, &loop_with_init); an_info.release (); an_loop_info.release (); return loop_with_init; }
static void emit_case_bit_tests (gswitch *swtch, tree index_expr, tree minval, tree range, tree maxval) { struct case_bit_test test[MAX_CASE_BIT_TESTS]; unsigned int i, j, k; unsigned int count; basic_block switch_bb = gimple_bb (swtch); basic_block default_bb, new_default_bb, new_bb; edge default_edge; bool update_dom = dom_info_available_p (CDI_DOMINATORS); vec<basic_block> bbs_to_fix_dom = vNULL; tree index_type = TREE_TYPE (index_expr); tree unsigned_index_type = unsigned_type_for (index_type); unsigned int branch_num = gimple_switch_num_labels (swtch); gimple_stmt_iterator gsi; gassign *shift_stmt; tree idx, tmp, csui; tree word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); tree word_mode_zero = fold_convert (word_type_node, integer_zero_node); tree word_mode_one = fold_convert (word_type_node, integer_one_node); int prec = TYPE_PRECISION (word_type_node); wide_int wone = wi::one (prec); memset (&test, 0, sizeof (test)); /* Get the edge for the default case. */ tmp = gimple_switch_default_label (swtch); default_bb = label_to_block (CASE_LABEL (tmp)); default_edge = find_edge (switch_bb, default_bb); /* Go through all case labels, and collect the case labels, profile counts, and other information we need to build the branch tests. */ count = 0; for (i = 1; i < branch_num; i++) { unsigned int lo, hi; tree cs = gimple_switch_label (swtch, i); tree label = CASE_LABEL (cs); edge e = find_edge (switch_bb, label_to_block (label)); for (k = 0; k < count; k++) if (e == test[k].target_edge) break; if (k == count) { gcc_checking_assert (count < MAX_CASE_BIT_TESTS); test[k].mask = wi::zero (prec); test[k].target_edge = e; test[k].label = label; test[k].bits = 1; count++; } else test[k].bits++; lo = tree_to_uhwi (int_const_binop (MINUS_EXPR, CASE_LOW (cs), minval)); if (CASE_HIGH (cs) == NULL_TREE) hi = lo; else hi = tree_to_uhwi (int_const_binop (MINUS_EXPR, CASE_HIGH (cs), minval)); for (j = lo; j <= hi; j++) test[k].mask |= wi::lshift (wone, j); } qsort (test, count, sizeof (*test), case_bit_test_cmp); /* If all values are in the 0 .. BITS_PER_WORD-1 range, we can get rid of the minval subtractions, but it might make the mask constants more expensive. So, compare the costs. */ if (compare_tree_int (minval, 0) > 0 && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0) { int cost_diff; HOST_WIDE_INT m = tree_to_uhwi (minval); rtx reg = gen_raw_REG (word_mode, 10000); bool speed_p = optimize_bb_for_speed_p (gimple_bb (swtch)); cost_diff = set_rtx_cost (gen_rtx_PLUS (word_mode, reg, GEN_INT (-m)), speed_p); for (i = 0; i < count; i++) { rtx r = immed_wide_int_const (test[i].mask, word_mode); cost_diff += set_src_cost (gen_rtx_AND (word_mode, reg, r), word_mode, speed_p); r = immed_wide_int_const (wi::lshift (test[i].mask, m), word_mode); cost_diff -= set_src_cost (gen_rtx_AND (word_mode, reg, r), word_mode, speed_p); } if (cost_diff > 0) { for (i = 0; i < count; i++) test[i].mask = wi::lshift (test[i].mask, m); minval = build_zero_cst (TREE_TYPE (minval)); range = maxval; } } /* We generate two jumps to the default case label. Split the default edge, so that we don't have to do any PHI node updating. */ new_default_bb = split_edge (default_edge); if (update_dom) { bbs_to_fix_dom.create (10); bbs_to_fix_dom.quick_push (switch_bb); bbs_to_fix_dom.quick_push (default_bb); bbs_to_fix_dom.quick_push (new_default_bb); } /* Now build the test-and-branch code. */ gsi = gsi_last_bb (switch_bb); /* idx = (unsigned)x - minval. */ idx = fold_convert (unsigned_index_type, index_expr); idx = fold_build2 (MINUS_EXPR, unsigned_index_type, idx, fold_convert (unsigned_index_type, minval)); idx = force_gimple_operand_gsi (&gsi, idx, /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); /* if (idx > range) goto default */ range = force_gimple_operand_gsi (&gsi, fold_convert (unsigned_index_type, range), /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); tmp = fold_build2 (GT_EXPR, boolean_type_node, idx, range); new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, default_edge, update_dom); if (update_dom) bbs_to_fix_dom.quick_push (new_bb); gcc_assert (gimple_bb (swtch) == new_bb); gsi = gsi_last_bb (new_bb); /* Any blocks dominated by the GIMPLE_SWITCH, but that are not successors of NEW_BB, are still immediately dominated by SWITCH_BB. Make it so. */ if (update_dom) { vec<basic_block> dom_bbs; basic_block dom_son; dom_bbs = get_dominated_by (CDI_DOMINATORS, new_bb); FOR_EACH_VEC_ELT (dom_bbs, i, dom_son) { edge e = find_edge (new_bb, dom_son); if (e && single_pred_p (e->dest)) continue; set_immediate_dominator (CDI_DOMINATORS, dom_son, switch_bb); bbs_to_fix_dom.safe_push (dom_son); } dom_bbs.release (); }
static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); location_t loc = gimple_location (stmt); tree cont_label = create_artificial_label (loc); tree next_label = create_artificial_label (loc); tree dest, t, arg; gimple g; /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ FORCED_LABEL (next_label) = 1; dest = gimple_call_lhs (stmt); /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 0' and insert. */ if (dest) { g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'goto CONT_LABEL' and insert. */ g = gimple_build_goto (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'NEXT_LABEL:' and insert. */ g = gimple_build_label (next_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 1' and insert. */ if (dest) { g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), integer_one_node)); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'CONT_LABEL:' and insert. */ g = gimple_build_label (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Remove the call to __builtin_setjmp. */ gsi_remove (gsi, false); }
static tree expand_unary_array_notation_exprs (tree orig_stmt) { vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; size_t list_size = 0, rank = 0, ii = 0; tree body; tree builtin_loop, stmt = NULL_TREE, new_var = NULL_TREE; location_t location = EXPR_LOCATION (orig_stmt); tree an_init, loop_with_init = alloc_stmt_list (); vec<vec<an_parts> > an_info = vNULL; auto_vec<an_loop_parts> an_loop_info; if (!find_rank (location, orig_stmt, orig_stmt, true, &rank)) return error_mark_node; if (rank == 0) return orig_stmt; extract_array_notation_exprs (orig_stmt, false, &array_list); list_size = vec_safe_length (array_list); location = EXPR_LOCATION (orig_stmt); stmt = NULL_TREE; for (ii = 0; ii < list_size; ii++) if (TREE_CODE ((*array_list)[ii]) == CALL_EXPR || TREE_CODE ((*array_list)[ii]) == AGGR_INIT_EXPR) { tree list_node = (*array_list)[ii]; builtin_loop = expand_sec_reduce_builtin (list_node, &new_var); if (builtin_loop == error_mark_node) return error_mark_node; else if (builtin_loop) { vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL; stmt = alloc_stmt_list (); append_to_statement_list (builtin_loop, &stmt); vec_safe_push (sub_list, list_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&orig_stmt, false, sub_list, new_var_list); } } if (stmt != NULL_TREE) append_to_statement_list (finish_expr_stmt (orig_stmt), &stmt); else stmt = orig_stmt; rank = 0; list_size = 0; array_list = NULL; extract_array_notation_exprs (stmt, true, &array_list); list_size = vec_safe_length (array_list); if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) return error_mark_node; if (rank == 0 || list_size == 0) return stmt; an_loop_info.safe_grow_cleared (rank); an_init = push_stmt_list (); /* Assign the array notation components to variable so that they can satisfy the exec-once rule. */ for (ii = 0; ii < list_size; ii++) { tree array_node = (*array_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (array_node)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (array_node)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (array_node)); } cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); for (ii = 0; ii < rank; ii++) { tree typ = ptrdiff_type_node; an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (an_loop_info[ii].var); an_loop_info[ii].ind_init = build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), tf_warning_or_error); } array_operand = create_array_refs (location, an_info, an_loop_info, list_size, rank); replace_array_notations (&stmt, true, array_list, array_operand); create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = stmt; for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, an_loop_info[ii].incr, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (an_info); return loop_with_init; }
static tree cp_expand_cond_array_notations (tree orig_stmt) { vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; size_t list_size = 0; size_t rank = 0, ii = 0; tree an_init, body, stmt = NULL_TREE; tree builtin_loop, new_var = NULL_TREE; tree loop_with_init = alloc_stmt_list (); location_t location = UNKNOWN_LOCATION; vec<vec<an_parts> > an_info = vNULL; auto_vec<an_loop_parts> an_loop_info; if (TREE_CODE (orig_stmt) == COND_EXPR) { size_t cond_rank = 0, yes_rank = 0, no_rank = 0; tree yes_expr = COND_EXPR_THEN (orig_stmt); tree no_expr = COND_EXPR_ELSE (orig_stmt); tree cond = COND_EXPR_COND (orig_stmt); if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, &yes_rank) || find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, &no_rank)) return error_mark_node; /* If the condition has a zero rank, then handle array notations in body separately. */ if (cond_rank == 0) return orig_stmt; if (cond_rank != yes_rank && yes_rank != 0) { error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" " expression of parent if-statement"); return error_mark_node; } else if (cond_rank != no_rank && no_rank != 0) { error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " "expression of parent if-statement"); return error_mark_node; } } else if (TREE_CODE (orig_stmt) == IF_STMT) { size_t cond_rank = 0, yes_rank = 0, no_rank = 0; tree yes_expr = THEN_CLAUSE (orig_stmt); tree no_expr = ELSE_CLAUSE (orig_stmt); tree cond = IF_COND (orig_stmt); if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) || (yes_expr && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, &yes_rank)) || (no_expr && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, &no_rank))) return error_mark_node; /* Same reasoning as for COND_EXPR. */ if (cond_rank == 0) return orig_stmt; else if (cond_rank != yes_rank && yes_rank != 0) { error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" " expression of parent if-statement"); return error_mark_node; } else if (cond_rank != no_rank && no_rank != 0) { error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " "expression of parent if-statement"); return error_mark_node; } } else if (truth_value_p (TREE_CODE (orig_stmt))) { size_t left_rank = 0, right_rank = 0; tree left_expr = TREE_OPERAND (orig_stmt, 0); tree right_expr = TREE_OPERAND (orig_stmt, 1); if (!find_rank (EXPR_LOCATION (left_expr), left_expr, left_expr, true, &left_rank) || !find_rank (EXPR_LOCATION (right_expr), right_expr, right_expr, true, &right_rank)) return error_mark_node; if (right_rank == 0 && left_rank == 0) return orig_stmt; } if (!find_rank (EXPR_LOCATION (orig_stmt), orig_stmt, orig_stmt, true, &rank)) return error_mark_node; if (rank == 0) return orig_stmt; extract_array_notation_exprs (orig_stmt, false, &array_list); stmt = alloc_stmt_list (); for (ii = 0; ii < vec_safe_length (array_list); ii++) { tree array_node = (*array_list)[ii]; if (TREE_CODE (array_node) == CALL_EXPR || TREE_CODE (array_node) == AGGR_INIT_EXPR) { builtin_loop = expand_sec_reduce_builtin (array_node, &new_var); if (builtin_loop == error_mark_node) finish_expr_stmt (error_mark_node); else if (new_var) { vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL; vec_safe_push (sub_list, array_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&orig_stmt, false, sub_list, new_var_list); append_to_statement_list (builtin_loop, &stmt); } } } append_to_statement_list (orig_stmt, &stmt); rank = 0; array_list = NULL; if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) return error_mark_node; if (rank == 0) return stmt; extract_array_notation_exprs (stmt, true, &array_list); list_size = vec_safe_length (array_list); if (list_size == 0) return stmt; location = EXPR_LOCATION (orig_stmt); list_size = vec_safe_length (array_list); an_loop_info.safe_grow_cleared (rank); an_init = push_stmt_list (); /* Assign the array notation components to variable so that they can satisfy the exec-once rule. */ for (ii = 0; ii < list_size; ii++) { tree anode = (*array_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); } cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); for (ii = 0; ii < rank; ii++) { tree typ = ptrdiff_type_node; an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (an_loop_info[ii].var); an_loop_info[ii].ind_init = build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), tf_warning_or_error); } array_operand = create_array_refs (location, an_info, an_loop_info, list_size, rank); replace_array_notations (&stmt, true, array_list, array_operand); create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = stmt; for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, an_loop_info[ii].incr, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (an_info); return loop_with_init; }
static tree expand_an_in_modify_expr (location_t location, tree lhs, enum tree_code modifycode, tree rhs, tsubst_flags_t complain) { tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE; tree array_expr = NULL_TREE; tree body = NULL_TREE; auto_vec<tree> cond_expr; vec<tree, va_gc> *lhs_array_operand = NULL, *rhs_array_operand = NULL; size_t lhs_rank = 0, rhs_rank = 0, ii = 0; vec<tree, va_gc> *rhs_list = NULL, *lhs_list = NULL; size_t rhs_list_size = 0, lhs_list_size = 0; tree new_modify_expr, new_var = NULL_TREE, builtin_loop, scalar_mods; bool found_builtin_fn = false; tree an_init, loop_with_init = alloc_stmt_list (); vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL; auto_vec<an_loop_parts> lhs_an_loop_info, rhs_an_loop_info; tree lhs_len, rhs_len; if (!find_rank (location, rhs, rhs, false, &rhs_rank)) return error_mark_node; extract_array_notation_exprs (rhs, false, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); an_init = push_stmt_list (); if (rhs_rank) { scalar_mods = replace_invariant_exprs (&rhs); if (scalar_mods) finish_expr_stmt (scalar_mods); } for (ii = 0; ii < rhs_list_size; ii++) { tree rhs_node = (*rhs_list)[ii]; if (TREE_CODE (rhs_node) == CALL_EXPR) { builtin_loop = expand_sec_reduce_builtin (rhs_node, &new_var); if (builtin_loop == error_mark_node) return error_mark_node; else if (builtin_loop) { finish_expr_stmt (builtin_loop); found_builtin_fn = true; if (new_var) { vec <tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL; vec_safe_push (rhs_sub_list, rhs_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&rhs, false, rhs_sub_list, new_var_list); } } } } lhs_rank = 0; rhs_rank = 0; if (!find_rank (location, lhs, lhs, true, &lhs_rank) || !find_rank (location, rhs, rhs, true, &rhs_rank)) { pop_stmt_list (an_init); return error_mark_node; } /* If both are scalar, then the only reason why we will get this far is if there is some array notations inside it and was using a builtin array notation functions. If so, we have already broken those guys up and now a simple build_x_modify_expr would do. */ if (lhs_rank == 0 && rhs_rank == 0) { if (found_builtin_fn) { new_modify_expr = build_x_modify_expr (location, lhs, modifycode, rhs, complain); finish_expr_stmt (new_modify_expr); pop_stmt_list (an_init); return an_init; } else gcc_unreachable (); } /* If for some reason location is not set, then find if LHS or RHS has location info. If so, then use that so we atleast have an idea. */ if (location == UNKNOWN_LOCATION) { if (EXPR_LOCATION (lhs) != UNKNOWN_LOCATION) location = EXPR_LOCATION (lhs); else if (EXPR_LOCATION (rhs) != UNKNOWN_LOCATION) location = EXPR_LOCATION (rhs); } /* We need this when we have a scatter issue. */ extract_array_notation_exprs (lhs, true, &lhs_list); rhs_list = NULL; extract_array_notation_exprs (rhs, true, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); lhs_list_size = vec_safe_length (lhs_list); if (lhs_rank == 0 && rhs_rank != 0) { error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs); return error_mark_node; } if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank) { error_at (location, "rank mismatch between %qE and %qE", lhs, rhs); return error_mark_node; } /* Assign the array notation components to variable so that they can satisfy the execute-once rule. */ for (ii = 0; ii < lhs_list_size; ii++) { tree anode = (*lhs_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); } for (ii = 0; ii < rhs_list_size; ii++) if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF) { tree aa = (*rhs_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (aa)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (aa)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (aa)); } lhs_an_loop_info.safe_grow_cleared (lhs_rank); if (rhs_rank) rhs_an_loop_info.safe_grow_cleared (rhs_rank); cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank)); cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank, &lhs_an_info); if (rhs_list) cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank, &rhs_an_info); if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info) || (rhs_list && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info))) { pop_stmt_list (an_init); goto error; } rhs_len = ((rhs_list_size > 0 && rhs_rank > 0) ? rhs_an_info[0][0].length : NULL_TREE); lhs_len = ((lhs_list_size > 0 && lhs_rank > 0) ? lhs_an_info[0][0].length : NULL_TREE); if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0 && TREE_CODE (lhs_len) == INTEGER_CST && rhs_len && TREE_CODE (rhs_len) == INTEGER_CST && !tree_int_cst_equal (rhs_len, lhs_len)) { error_at (location, "length mismatch between LHS and RHS"); pop_stmt_list (an_init); goto error; } for (ii = 0; ii < lhs_rank; ii++) { tree typ = ptrdiff_type_node; lhs_an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (lhs_an_loop_info[ii].var); lhs_an_loop_info[ii].ind_init = build_x_modify_expr (location, lhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), complain); } if (rhs_list_size > 0) { rhs_array_operand = fix_sec_implicit_args (location, rhs_list, lhs_an_loop_info, lhs_rank, lhs); if (!rhs_array_operand) goto error; } replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); rhs_list_size = 0; rhs_list = NULL; extract_array_notation_exprs (rhs, true, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); for (ii = 0; ii < rhs_rank; ii++) { tree typ = ptrdiff_type_node; rhs_an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (rhs_an_loop_info[ii].var); rhs_an_loop_info[ii].ind_init = build_x_modify_expr (location, rhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), complain); } if (lhs_rank) { lhs_array_operand = create_array_refs (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank); replace_array_notations (&lhs, true, lhs_list, lhs_array_operand); } if (rhs_array_operand) vec_safe_truncate (rhs_array_operand, 0); if (rhs_rank) { rhs_array_operand = create_array_refs (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank); /* Replace all the array refs created by the above function because this variable is blown away by the fix_sec_implicit_args function below. */ replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); vec_safe_truncate (rhs_array_operand , 0); rhs_array_operand = fix_sec_implicit_args (location, rhs_list, rhs_an_loop_info, rhs_rank, rhs); if (!rhs_array_operand) goto error; replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); } array_expr_rhs = rhs; array_expr_lhs = lhs; array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode, array_expr_rhs, complain); create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info, complain); if (rhs_rank) create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info, complain); for (ii = 0; ii < MAX (rhs_rank, lhs_rank); ii++) if (ii < lhs_rank && ii < rhs_rank) cond_expr[ii] = build_x_binary_op (location, TRUTH_ANDIF_EXPR, lhs_an_loop_info[ii].cmp, TREE_CODE (lhs_an_loop_info[ii].cmp), rhs_an_loop_info[ii].cmp, TREE_CODE (rhs_an_loop_info[ii].cmp), NULL, complain); else if (ii < lhs_rank && ii >= rhs_rank) cond_expr[ii] = lhs_an_loop_info[ii].cmp; else /* No need to compare ii < rhs_rank && ii >= lhs_rank because in a valid Array notation expression, rank of RHS cannot be greater than LHS. */ gcc_unreachable (); an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = array_expr; for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) { tree incr_list = alloc_stmt_list (); tree init_list = alloc_stmt_list (); tree new_loop = push_stmt_list (); if (lhs_rank) { append_to_statement_list (lhs_an_loop_info[ii].ind_init, &init_list); append_to_statement_list (lhs_an_loop_info[ii].incr, &incr_list); } if (rhs_rank) { append_to_statement_list (rhs_an_loop_info[ii].ind_init, &init_list); append_to_statement_list (rhs_an_loop_info[ii].incr, &incr_list); } create_an_loop (init_list, cond_expr[ii], incr_list, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (lhs_an_info); release_vec_vec (rhs_an_info); return loop_with_init; error: release_vec_vec (lhs_an_info); release_vec_vec (rhs_an_info); return error_mark_node; }
static tree expand_sec_reduce_builtin (tree an_builtin_fn, tree *new_var) { tree new_var_type = NULL_TREE, func_parm, new_yes_expr, new_no_expr; tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list; tree new_yes_list, new_cond_expr, new_expr = NULL_TREE; vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; size_t list_size = 0, rank = 0, ii = 0; tree body, an_init, loop_with_init = alloc_stmt_list (); tree array_op0, comp_node = NULL_TREE; tree call_fn = NULL_TREE, identity_value = NULL_TREE; tree init = NULL_TREE, cond_init = NULL_TREE; enum tree_code code = NOP_EXPR; location_t location = UNKNOWN_LOCATION; vec<vec<an_parts> > an_info = vNULL; auto_vec<an_loop_parts> an_loop_info; enum built_in_function an_type = is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn)); vec <tree, va_gc> *func_args; if (an_type == BUILT_IN_NONE) return NULL_TREE; if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE && an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) func_parm = CALL_EXPR_ARG (an_builtin_fn, 0); else { call_fn = CALL_EXPR_ARG (an_builtin_fn, 2); /* We need to do this because we are "faking" the builtin function types, so the compiler does a bunch of typecasts and this will get rid of all that! */ STRIP_NOPS (call_fn); if (TREE_CODE (call_fn) != OVERLOAD && TREE_CODE (call_fn) != FUNCTION_DECL) call_fn = TREE_OPERAND (call_fn, 0); identity_value = CALL_EXPR_ARG (an_builtin_fn, 0); func_parm = CALL_EXPR_ARG (an_builtin_fn, 1); STRIP_NOPS (identity_value); } STRIP_NOPS (func_parm); location = EXPR_LOCATION (an_builtin_fn); /* Note about using find_rank (): If find_rank returns false, then it must have already reported an error, thus we just return an error_mark_node without any doing any error emission. */ if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank)) return error_mark_node; if (rank == 0) { error_at (location, "Invalid builtin arguments"); return error_mark_node; } else if (rank > 1 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)) { error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot " "have arrays with dimension greater than 1"); return error_mark_node; } extract_array_notation_exprs (func_parm, true, &array_list); list_size = vec_safe_length (array_list); switch (an_type) { case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: new_var_type = TREE_TYPE ((*array_list)[0]); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: new_var_type = boolean_type_node; break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: new_var_type = size_type_node; break; case BUILT_IN_CILKPLUS_SEC_REDUCE: if (call_fn && identity_value) new_var_type = TREE_TYPE ((*array_list)[0]); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: new_var_type = NULL_TREE; break; default: gcc_unreachable (); } if (new_var_type && TREE_CODE (new_var_type) == ARRAY_TYPE) new_var_type = TREE_TYPE (new_var_type); an_loop_info.safe_grow_cleared (rank); an_init = push_stmt_list (); /* Assign the array notation components to variable so that they can satisfy the exec-once rule. */ for (ii = 0; ii < list_size; ii++) if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) { tree anode = (*array_list)[ii]; make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); } cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); for (ii = 0; ii < rank; ii++) { tree typ = ptrdiff_type_node; /* In this place, we are using get_temp_regvar instead of create_temporary_var if an_type is SEC_REDUCE_MAX/MIN_IND because the array_ind_value depends on this value being initalized to 0. */ if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) an_loop_info[ii].var = get_temp_regvar (typ, build_zero_cst (typ)); else { an_loop_info[ii].var = create_temporary_var (typ); add_decl_expr (an_loop_info[ii].var); } an_loop_info[ii].ind_init = build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), tf_warning_or_error); } array_operand = create_array_refs (location, an_info, an_loop_info, list_size, rank); replace_array_notations (&func_parm, true, array_list, array_operand); if (!TREE_TYPE (func_parm)) TREE_TYPE (func_parm) = TREE_TYPE ((*array_list)[0]); create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) array_ind_value = get_temp_regvar (TREE_TYPE (func_parm), func_parm); array_op0 = (*array_operand)[0]; if (INDIRECT_REF_P (array_op0)) array_op0 = TREE_OPERAND (array_op0, 0); switch (an_type) { case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: code = PLUS_EXPR; init = build_zero_cst (new_var_type); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: code = MULT_EXPR; init = build_one_cst (new_var_type); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: code = ((an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO) ? EQ_EXPR : NE_EXPR); init = build_zero_cst (new_var_type); cond_init = build_one_cst (new_var_type); comp_node = build_zero_cst (TREE_TYPE (func_parm)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: code = ((an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO) ? NE_EXPR : EQ_EXPR); init = build_one_cst (new_var_type); cond_init = build_zero_cst (new_var_type); comp_node = build_zero_cst (TREE_TYPE (func_parm)); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: code = MAX_EXPR; init = (TYPE_MIN_VALUE (new_var_type) ? TYPE_MIN_VALUE (new_var_type) : func_parm); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: code = MIN_EXPR; init = (TYPE_MAX_VALUE (new_var_type) ? TYPE_MAX_VALUE (new_var_type) : func_parm); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: code = (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND ? LE_EXPR : GE_EXPR); init = an_loop_info[0].var; break; case BUILT_IN_CILKPLUS_SEC_REDUCE: init = identity_value; break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: init = NULL_TREE; break; default: gcc_unreachable (); } if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) *new_var = get_temp_regvar (new_var_type, init); else *new_var = NULL_TREE; switch (an_type) { case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: new_expr = build_x_modify_expr (location, *new_var, code, func_parm, tf_warning_or_error); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: /* In all these cases, assume the false case is true and as soon as we find a true case, set the true flag on and latch it in. */ new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, cond_init, tf_warning_or_error); new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, *new_var, tf_warning_or_error); new_cond_expr = build_x_binary_op (location, code, func_parm, TREE_CODE (func_parm), comp_node, TREE_CODE (comp_node), NULL, tf_warning_or_error); new_expr = build_x_conditional_expr (location, new_cond_expr, new_yes_expr, new_no_expr, tf_warning_or_error); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: new_cond_expr = build_x_binary_op (location, code, *new_var, TREE_CODE (*new_var), func_parm, TREE_CODE (func_parm), NULL, tf_warning_or_error); new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, func_parm, tf_warning_or_error); break; case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: new_yes_expr = build_x_modify_expr (location, array_ind_value, NOP_EXPR, func_parm, tf_warning_or_error); new_no_expr = build_x_modify_expr (location, array_ind_value, NOP_EXPR, array_ind_value, tf_warning_or_error); if (list_size > 1) new_yes_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, an_loop_info[0].var, tf_warning_or_error); else new_yes_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, TREE_OPERAND (array_op0, 1), tf_warning_or_error); new_no_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, *new_var, tf_warning_or_error); new_yes_list = alloc_stmt_list (); append_to_statement_list (new_yes_ind, &new_yes_list); append_to_statement_list (new_yes_expr, &new_yes_list); new_no_list = alloc_stmt_list (); append_to_statement_list (new_no_ind, &new_no_list); append_to_statement_list (new_no_expr, &new_no_list); new_cond_expr = build_x_binary_op (location, code, array_ind_value, TREE_CODE (array_ind_value), func_parm, TREE_CODE (func_parm), NULL, tf_warning_or_error); new_expr = build_x_conditional_expr (location, new_cond_expr, new_yes_list, new_no_list, tf_warning_or_error); break; case BUILT_IN_CILKPLUS_SEC_REDUCE: case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: func_args = make_tree_vector (); if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE) vec_safe_push (func_args, *new_var); else vec_safe_push (func_args, identity_value); vec_safe_push (func_args, func_parm); new_expr = finish_call_expr (call_fn, &func_args, false, true, tf_warning_or_error); if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE) new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, new_expr, tf_warning_or_error); release_tree_vector (func_args); break; default: gcc_unreachable (); } an_init = pop_stmt_list (an_init); append_to_statement_list (an_init, &loop_with_init); body = new_expr; for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, an_loop_info[ii].incr, body); body = pop_stmt_list (new_loop); } append_to_statement_list (body, &loop_with_init); release_vec_vec (an_info); return loop_with_init; }
tree build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype, enum tree_code modifycode, location_t rhs_loc, tree rhs, tree rhs_origtype) { bool found_builtin_fn = false; tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE; tree array_expr = NULL_TREE; tree an_init = NULL_TREE; vec<tree> cond_expr = vNULL; tree body, loop_with_init = alloc_stmt_list(); tree scalar_mods = NULL_TREE; vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL; size_t lhs_rank = 0, rhs_rank = 0; size_t ii = 0; vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL; tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE; size_t rhs_list_size = 0, lhs_list_size = 0; vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL; vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL; /* If either of this is true, an error message must have been send out already. Not necessary to send out multiple error messages. */ if (lhs == error_mark_node || rhs == error_mark_node) return error_mark_node; if (!find_rank (location, rhs, rhs, false, &rhs_rank)) return error_mark_node; extract_array_notation_exprs (rhs, false, &rhs_list); rhs_list_size = vec_safe_length (rhs_list); an_init = push_stmt_list (); if (rhs_rank) { scalar_mods = replace_invariant_exprs (&rhs); if (scalar_mods) add_stmt (scalar_mods); } for (ii = 0; ii < rhs_list_size; ii++) { tree rhs_node = (*rhs_list)[ii]; if (TREE_CODE (rhs_node) == CALL_EXPR) { builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var); if (builtin_loop == error_mark_node) { pop_stmt_list (an_init); return error_mark_node; } else if (builtin_loop) { add_stmt (builtin_loop); found_builtin_fn = true; if (new_var) { vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL; vec_safe_push (rhs_sub_list, rhs_node); vec_safe_push (new_var_list, new_var); replace_array_notations (&rhs, false, rhs_sub_list, new_var_list); } } } } lhs_rank = 0; rhs_rank = 0; if (!find_rank (location, lhs, lhs, true, &lhs_rank)) { pop_stmt_list (an_init); return error_mark_node; } if (!find_rank (location, rhs, rhs, true, &rhs_rank)) { pop_stmt_list (an_init); return error_mark_node; } if (lhs_rank == 0 && rhs_rank == 0) { if (found_builtin_fn) { new_modify_expr = build_modify_expr (location, lhs, lhs_origtype, modifycode, rhs_loc, rhs, rhs_origtype); add_stmt (new_modify_expr); pop_stmt_list (an_init); return an_init; } else { pop_stmt_list (an_init); return NULL_TREE; } } rhs_list_size = 0; rhs_list = NULL; extract_array_notation_exprs (rhs, true, &rhs_list); extract_array_notation_exprs (lhs, true, &lhs_list); rhs_list_size = vec_safe_length (rhs_list); lhs_list_size = vec_safe_length (lhs_list); if (lhs_rank == 0 && rhs_rank != 0) { tree rhs_base = rhs; if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF) { for (ii = 0; ii < (size_t) rhs_rank; ii++) rhs_base = ARRAY_NOTATION_ARRAY (rhs); error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs_base); return error_mark_node; } else { error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs_base); return error_mark_node; } } if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank) { error_at (location, "rank mismatch between %qE and %qE", lhs, rhs); pop_stmt_list (an_init); return error_mark_node; } /* Here we assign the array notation components to variable so that we can satisfy the exec once rule. */ for (ii = 0; ii < lhs_list_size; ii++) { tree array_node = (*lhs_list)[ii]; make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node)); make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node)); make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node)); } for (ii = 0; ii < rhs_list_size; ii++) if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF) { tree array_node = (*rhs_list)[ii]; make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node)); make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node)); make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node)); } cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank)); lhs_an_loop_info.safe_grow_cleared (lhs_rank); if (rhs_rank) rhs_an_loop_info.safe_grow_cleared (rhs_rank); cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank, &lhs_an_info); if (rhs_rank) { rhs_an_loop_info.safe_grow_cleared (rhs_rank); cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank, &rhs_an_info); } if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info) || (rhs_rank && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info))) { pop_stmt_list (an_init); return error_mark_node; } if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST && rhs_an_info[0][0].length && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST) { HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length); HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length); /* Length can be negative or positive. As long as the magnitude is OK, then the array notation is valid. */ if (absu_hwi (l_length) != absu_hwi (r_length)) { error_at (location, "length mismatch between LHS and RHS"); pop_stmt_list (an_init); return error_mark_node; } } for (ii = 0; ii < lhs_rank; ii++) if (lhs_an_info[0][ii].is_vector) { lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node); lhs_an_loop_info[ii].ind_init = build_modify_expr (location, lhs_an_loop_info[ii].var, TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR, location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)), TREE_TYPE (lhs_an_loop_info[ii].var)); } for (ii = 0; ii < rhs_rank; ii++) { /* When we have a polynomial, we assume that the indices are of type integer. */ rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node); rhs_an_loop_info[ii].ind_init = build_modify_expr (location, rhs_an_loop_info[ii].var, TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR, location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0), TREE_TYPE (rhs_an_loop_info[ii].var)); } if (lhs_rank) { lhs_array_operand = create_array_refs (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank); replace_array_notations (&lhs, true, lhs_list, lhs_array_operand); array_expr_lhs = lhs; } if (rhs_array_operand) vec_safe_truncate (rhs_array_operand, 0); if (rhs_rank) { rhs_array_operand = create_array_refs (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank); replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); vec_safe_truncate (rhs_array_operand, 0); rhs_array_operand = fix_sec_implicit_args (location, rhs_list, rhs_an_loop_info, rhs_rank, rhs); if (!rhs_array_operand) return error_mark_node; replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); } else if (rhs_list_size > 0) { rhs_array_operand = fix_sec_implicit_args (location, rhs_list, lhs_an_loop_info, lhs_rank, lhs); if (!rhs_array_operand) return error_mark_node; replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); } array_expr_lhs = lhs; array_expr_rhs = rhs; array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype, modifycode, rhs_loc, array_expr_rhs, rhs_origtype); create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info); if (rhs_rank) create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info); for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) if (ii < lhs_rank && ii < rhs_rank) cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node, lhs_an_loop_info[ii].cmp, rhs_an_loop_info[ii].cmp); else if (ii < lhs_rank && ii >= rhs_rank) cond_expr[ii] = lhs_an_loop_info[ii].cmp; else gcc_unreachable (); an_init = pop_stmt_list (an_init); append_to_statement_list_force (an_init, &loop_with_init); body = array_expr; for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) { tree incr_list = alloc_stmt_list (); tree new_loop = push_stmt_list (); if (lhs_rank) add_stmt (lhs_an_loop_info[ii].ind_init); if (rhs_rank) add_stmt (rhs_an_loop_info[ii].ind_init); if (lhs_rank) append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list); if (rhs_rank && rhs_an_loop_info[ii].incr) append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list); c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); } append_to_statement_list_force (body, &loop_with_init); lhs_an_info.release (); lhs_an_loop_info.release (); if (rhs_rank) { rhs_an_info.release (); rhs_an_loop_info.release (); } cond_expr.release (); return loop_with_init; }
static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); location_t loc = gimple_location (stmt); tree cont_label = create_artificial_label (loc); tree next_label = create_artificial_label (loc); tree dest, t, arg; gimple *g; /* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and for RTL these builtins are modelled as non-local label jumps to the label that is passed to these two builtins, so pretend we have a non-local label during GIMPLE passes too. See PR60003. */ cfun->has_nonlocal_label = 1; /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ FORCED_LABEL (next_label) = 1; tree orig_dest = dest = gimple_call_lhs (stmt); if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME) dest = create_tmp_reg (TREE_TYPE (orig_dest)); /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label); t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 0' and insert. */ if (dest) { g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'goto CONT_LABEL' and insert. */ g = gimple_build_goto (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'NEXT_LABEL:' and insert. */ g = gimple_build_label (next_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label); t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 1' and insert. */ if (dest) { g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), integer_one_node)); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'CONT_LABEL:' and insert. */ g = gimple_build_label (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build orig_dest = dest if necessary. */ if (dest != orig_dest) { g = gimple_build_assign (orig_dest, dest); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Remove the call to __builtin_setjmp. */ gsi_remove (gsi, false); }
void omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd, struct omp_for_data_loop *loops) { tree t, var, *collapse_iter, *collapse_count; tree count = NULL_TREE, iter_type = long_integer_type_node; struct omp_for_data_loop *loop; int i; struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_SIMD; bool distribute = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE; bool taskloop = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_TASKLOOP; tree iterv, countv; fd->for_stmt = for_stmt; fd->pre = NULL; if (gimple_omp_for_collapse (for_stmt) > 1) fd->loops = loops; else fd->loops = &fd->loop; fd->have_nowait = distribute || simd; fd->have_ordered = false; fd->collapse = 1; fd->ordered = 0; fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; fd->sched_modifiers = 0; fd->chunk_size = NULL_TREE; fd->simd_schedule = false; if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_CILKFOR) fd->sched_kind = OMP_CLAUSE_SCHEDULE_CILKFOR; collapse_iter = NULL; collapse_count = NULL; for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t)) switch (OMP_CLAUSE_CODE (t)) { case OMP_CLAUSE_NOWAIT: fd->have_nowait = true; break; case OMP_CLAUSE_ORDERED: fd->have_ordered = true; if (OMP_CLAUSE_ORDERED_EXPR (t)) fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t)); break; case OMP_CLAUSE_SCHEDULE: gcc_assert (!distribute && !taskloop); fd->sched_kind = (enum omp_clause_schedule_kind) (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK); fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t) & ~OMP_CLAUSE_SCHEDULE_MASK); fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t); fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t); break; case OMP_CLAUSE_DIST_SCHEDULE: gcc_assert (distribute); fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t); break; case OMP_CLAUSE_COLLAPSE: fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t)); if (fd->collapse > 1) { collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t); collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t); } break; default: break; } if (fd->ordered && fd->collapse == 1 && loops != NULL) { fd->loops = loops; iterv = NULL_TREE; countv = NULL_TREE; collapse_iter = &iterv; collapse_count = &countv; } /* FIXME: for now map schedule(auto) to schedule(static). There should be analysis to determine whether all iterations are approximately the same amount of work (then schedule(static) is best) or if it varies (then schedule(dynamic,N) is better). */ if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO) { fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; gcc_assert (fd->chunk_size == NULL); } gcc_assert (fd->collapse == 1 || collapse_iter != NULL); if (taskloop) fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME; if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME) gcc_assert (fd->chunk_size == NULL); else if (fd->chunk_size == NULL) { /* We only need to compute a default chunk size for ordered static loops and dynamic loops. */ if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC || fd->have_ordered) fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) ? integer_zero_node : integer_one_node; } int cnt = fd->ordered ? fd->ordered : fd->collapse; for (i = 0; i < cnt; i++) { if (i == 0 && fd->collapse == 1 && (fd->ordered == 0 || loops == NULL)) loop = &fd->loop; else if (loops != NULL) loop = loops + i; else loop = &dummy_loop; loop->v = gimple_omp_for_index (for_stmt, i); gcc_assert (SSA_VAR_P (loop->v)); gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE); var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v; loop->n1 = gimple_omp_for_initial (for_stmt, i); loop->cond_code = gimple_omp_for_cond (for_stmt, i); loop->n2 = gimple_omp_for_final (for_stmt, i); gcc_assert (loop->cond_code != NE_EXPR || gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD || gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKFOR); omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2); t = gimple_omp_for_incr (for_stmt, i); gcc_assert (TREE_OPERAND (t, 0) == var); loop->step = omp_get_for_step_from_incr (loc, t); if (simd || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC && !fd->have_ordered)) { if (fd->collapse == 1) iter_type = TREE_TYPE (loop->v); else if (i == 0 || TYPE_PRECISION (iter_type) < TYPE_PRECISION (TREE_TYPE (loop->v))) iter_type = build_nonstandard_integer_type (TYPE_PRECISION (TREE_TYPE (loop->v)), 1); } else if (iter_type != long_long_unsigned_type_node) { if (POINTER_TYPE_P (TREE_TYPE (loop->v))) iter_type = long_long_unsigned_type_node; else if (TYPE_UNSIGNED (TREE_TYPE (loop->v)) && TYPE_PRECISION (TREE_TYPE (loop->v)) >= TYPE_PRECISION (iter_type)) { tree n; if (loop->cond_code == LT_EXPR) n = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v), loop->n2, loop->step); else n = loop->n1; if (TREE_CODE (n) != INTEGER_CST || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n)) iter_type = long_long_unsigned_type_node; } else if (TYPE_PRECISION (TREE_TYPE (loop->v)) > TYPE_PRECISION (iter_type)) { tree n1, n2; if (loop->cond_code == LT_EXPR) { n1 = loop->n1; n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v), loop->n2, loop->step); } else { n1 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (loop->v), loop->n2, loop->step); n2 = loop->n1; } if (TREE_CODE (n1) != INTEGER_CST || TREE_CODE (n2) != INTEGER_CST || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1) || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type))) iter_type = long_long_unsigned_type_node; } } if (i >= fd->collapse) continue; if (collapse_count && *collapse_count == NULL) { t = fold_binary (loop->cond_code, boolean_type_node, fold_convert (TREE_TYPE (loop->v), loop->n1), fold_convert (TREE_TYPE (loop->v), loop->n2)); if (t && integer_zerop (t)) count = build_zero_cst (long_long_unsigned_type_node); else if ((i == 0 || count != NULL_TREE) && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE && TREE_CONSTANT (loop->n1) && TREE_CONSTANT (loop->n2) && TREE_CODE (loop->step) == INTEGER_CST) { tree itype = TREE_TYPE (loop->v); if (POINTER_TYPE_P (itype)) itype = signed_type_for (itype); t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1)); t = fold_build2_loc (loc, PLUS_EXPR, itype, fold_convert_loc (loc, itype, loop->step), t); t = fold_build2_loc (loc, PLUS_EXPR, itype, t, fold_convert_loc (loc, itype, loop->n2)); t = fold_build2_loc (loc, MINUS_EXPR, itype, t, fold_convert_loc (loc, itype, loop->n1)); if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR) t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, fold_build1_loc (loc, NEGATE_EXPR, itype, t), fold_build1_loc (loc, NEGATE_EXPR, itype, fold_convert_loc (loc, itype, loop->step))); else t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t, fold_convert_loc (loc, itype, loop->step)); t = fold_convert_loc (loc, long_long_unsigned_type_node, t); if (count != NULL_TREE) count = fold_build2_loc (loc, MULT_EXPR, long_long_unsigned_type_node, count, t); else count = t; if (TREE_CODE (count) != INTEGER_CST) count = NULL_TREE; } else if (count && !integer_zerop (count)) count = NULL_TREE; } } if (count && !simd && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC || fd->have_ordered)) { if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node))) iter_type = long_long_unsigned_type_node; else iter_type = long_integer_type_node; } else if (collapse_iter && *collapse_iter != NULL) iter_type = TREE_TYPE (*collapse_iter); fd->iter_type = iter_type; if (collapse_iter && *collapse_iter == NULL) *collapse_iter = create_tmp_var (iter_type, ".iter"); if (collapse_count && *collapse_count == NULL) { if (count) *collapse_count = fold_convert_loc (loc, iter_type, count); else *collapse_count = create_tmp_var (iter_type, ".count"); } if (fd->collapse > 1 || (fd->ordered && loops)) { fd->loop.v = *collapse_iter; fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0); fd->loop.n2 = *collapse_count; fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1); fd->loop.cond_code = LT_EXPR; } else if (loops) loops[0] = fd->loop; }
void ubsan_expand_null_ifn (gimple_stmt_iterator gsi) { gimple stmt = gsi_stmt (gsi); location_t loc = gimple_location (stmt); gcc_assert (gimple_call_num_args (stmt) == 2); tree ptr = gimple_call_arg (stmt, 0); tree ckind = gimple_call_arg (stmt, 1); basic_block cur_bb = gsi_bb (gsi); /* Split the original block holding the pointer dereference. */ edge e = split_block (cur_bb, stmt); /* Get a hold on the 'condition block', the 'then block' and the 'else block'. */ basic_block cond_bb = e->src; basic_block fallthru_bb = e->dest; basic_block then_bb = create_empty_bb (cond_bb); add_bb_to_loop (then_bb, cond_bb->loop_father); loops_state_set (LOOPS_NEED_FIXUP); /* Make an edge coming from the 'cond block' into the 'then block'; this edge is unlikely taken, so set up the probability accordingly. */ e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); e->probability = PROB_VERY_UNLIKELY; /* Connect 'then block' with the 'else block'. This is needed as the ubsan routines we call in the 'then block' are not noreturn. The 'then block' only has one outcoming edge. */ make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU); /* Set up the fallthrough basic block. */ e = find_edge (cond_bb, fallthru_bb); e->flags = EDGE_FALSE_VALUE; e->count = cond_bb->count; e->probability = REG_BR_PROB_BASE - PROB_VERY_UNLIKELY; /* Update dominance info for the newly created then_bb; note that fallthru_bb's dominance info has already been updated by split_bock. */ if (dom_info_available_p (CDI_DOMINATORS)) set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb); /* Put the ubsan builtin call into the newly created BB. */ gimple g; if (flag_sanitize_undefined_trap_on_error) g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0); else { enum built_in_function bcode = flag_sanitize_recover ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT; tree fn = builtin_decl_implicit (bcode); const struct ubsan_mismatch_data m = { build_zero_cst (pointer_sized_int_node), ckind }; tree data = ubsan_create_data ("__ubsan_null_data", &loc, &m, ubsan_type_descriptor (TREE_TYPE (ptr), UBSAN_PRINT_POINTER), NULL_TREE); data = build_fold_addr_expr_loc (loc, data); g = gimple_build_call (fn, 2, data, build_zero_cst (pointer_sized_int_node)); } gimple_set_location (g, loc); gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb); gsi_insert_after (&gsi2, g, GSI_NEW_STMT); /* Unlink the UBSAN_NULLs vops before replacing it. */ unlink_stmt_vdef (stmt); g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0), NULL_TREE, NULL_TREE); gimple_set_location (g, loc); /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */ gsi_replace (&gsi, g, false); }
/* User-deallocate; we emit the code directly from the front-end, and the logic is the same as the previous library function: void deallocate (void *pointer, GFC_INTEGER_4 * stat) { if (!pointer) { if (stat) *stat = 1; else runtime_error ("Attempt to DEALLOCATE unallocated memory."); } else { free (pointer); if (stat) *stat = 0; } } In this front-end version, status doesn't have to be GFC_INTEGER_4. Moreover, if CAN_FAIL is true, then we will not emit a runtime error, even when no status variable is passed to us (this is used for unconditional deallocation generated by the front-end at end of each procedure). If a runtime-message is possible, `expr' must point to the original expression being deallocated for its locus and variable name. For coarrays, "pointer" must be the array descriptor and not its "data" component. */ tree gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, tree errlen, tree label_finish, bool can_fail, gfc_expr* expr, bool coarray) { stmtblock_t null, non_null; tree cond, tmp, error; tree status_type = NULL_TREE; tree caf_decl = NULL_TREE; if (coarray) { gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (pointer))); caf_decl = pointer; pointer = gfc_conv_descriptor_data_get (caf_decl); STRIP_NOPS (pointer); } cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, pointer, build_int_cst (TREE_TYPE (pointer), 0)); /* When POINTER is NULL, we set STATUS to 1 if it's present, otherwise we emit a runtime error. */ gfc_start_block (&null); if (!can_fail) { tree varname; gcc_assert (expr && expr->expr_type == EXPR_VARIABLE && expr->symtree); varname = gfc_build_cstring_const (expr->symtree->name); varname = gfc_build_addr_expr (pchar_type_node, varname); error = gfc_trans_runtime_error (true, &expr->where, "Attempt to DEALLOCATE unallocated '%s'", varname); } else error = build_empty_stmt (input_location); if (status != NULL_TREE && !integer_zerop (status)) { tree cond2; status_type = TREE_TYPE (TREE_TYPE (status)); cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_int_cst (TREE_TYPE (status), 0)); tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), build_int_cst (status_type, 1)); error = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2, tmp, error); } gfc_add_expr_to_block (&null, error); /* When POINTER is not NULL, we free it. */ gfc_start_block (&non_null); if (!coarray || gfc_option.coarray != GFC_FCOARRAY_LIB) { tmp = build_call_expr_loc (input_location, builtin_decl_explicit (BUILT_IN_FREE), 1, fold_convert (pvoid_type_node, pointer)); gfc_add_expr_to_block (&non_null, tmp); if (status != NULL_TREE && !integer_zerop (status)) { /* We set STATUS to zero if it is present. */ tree status_type = TREE_TYPE (TREE_TYPE (status)); tree cond2; cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_int_cst (TREE_TYPE (status), 0)); tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), build_int_cst (status_type, 0)); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, gfc_unlikely (cond2), tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (&non_null, tmp); } } else { tree caf_type, token, cond2; tree pstat = null_pointer_node; if (errmsg == NULL_TREE) { gcc_assert (errlen == NULL_TREE); errmsg = null_pointer_node; errlen = build_zero_cst (integer_type_node); } else { gcc_assert (errlen != NULL_TREE); if (!POINTER_TYPE_P (TREE_TYPE (errmsg))) errmsg = gfc_build_addr_expr (NULL_TREE, errmsg); } caf_type = TREE_TYPE (caf_decl); if (status != NULL_TREE && !integer_zerop (status)) { gcc_assert (status_type == integer_type_node); pstat = status; } if (GFC_DESCRIPTOR_TYPE_P (caf_type) && GFC_TYPE_ARRAY_AKIND (caf_type) == GFC_ARRAY_ALLOCATABLE) token = gfc_conv_descriptor_token (caf_decl); else if (DECL_LANG_SPECIFIC (caf_decl) && GFC_DECL_TOKEN (caf_decl) != NULL_TREE) token = GFC_DECL_TOKEN (caf_decl); else { gcc_assert (GFC_ARRAY_TYPE_P (caf_type) && GFC_TYPE_ARRAY_CAF_TOKEN (caf_type) != NULL_TREE); token = GFC_TYPE_ARRAY_CAF_TOKEN (caf_type); } token = gfc_build_addr_expr (NULL_TREE, token); tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_deregister, 4, token, pstat, errmsg, errlen); gfc_add_expr_to_block (&non_null, tmp); if (status != NULL_TREE) { tree stat = build_fold_indirect_ref_loc (input_location, status); TREE_USED (label_finish) = 1; tmp = build1_v (GOTO_EXPR, label_finish); cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, stat, build_zero_cst (TREE_TYPE (stat))); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, gfc_unlikely (cond2), tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (&non_null, tmp); } } return fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, gfc_finish_block (&null), gfc_finish_block (&non_null)); }
/* Generate code for an ALLOCATE statement when the argument is an allocatable variable. If the variable is currently allocated, it is an error to allocate it again. This function follows the following pseudo-code: void * allocate_allocatable (void *mem, size_t size, integer_type stat) { if (mem == NULL) return allocate (size, stat); else { if (stat) stat = LIBERROR_ALLOCATION; else runtime_error ("Attempting to allocate already allocated variable"); } } expr must be set to the original expression being allocated for its locus and variable name in case a runtime error has to be printed. */ void gfc_allocate_allocatable (stmtblock_t * block, tree mem, tree size, tree token, tree status, tree errmsg, tree errlen, tree label_finish, gfc_expr* expr) { stmtblock_t alloc_block; tree tmp, null_mem, alloc, error; tree type = TREE_TYPE (mem); if (TREE_TYPE (size) != TREE_TYPE (size_type_node)) size = fold_convert (size_type_node, size); null_mem = gfc_unlikely (fold_build2_loc (input_location, NE_EXPR, boolean_type_node, mem, build_int_cst (type, 0))); /* If mem is NULL, we call gfc_allocate_using_malloc or gfc_allocate_using_lib. */ gfc_start_block (&alloc_block); if (gfc_option.coarray == GFC_FCOARRAY_LIB && gfc_expr_attr (expr).codimension) { tree cond; gfc_allocate_using_lib (&alloc_block, mem, size, token, status, errmsg, errlen); if (status != NULL_TREE) { TREE_USED (label_finish) = 1; tmp = build1_v (GOTO_EXPR, label_finish); cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, status, build_zero_cst (TREE_TYPE (status))); tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, gfc_unlikely (cond), tmp, build_empty_stmt (input_location)); gfc_add_expr_to_block (&alloc_block, tmp); } } else gfc_allocate_using_malloc (&alloc_block, mem, size, status); alloc = gfc_finish_block (&alloc_block); /* If mem is not NULL, we issue a runtime error or set the status variable. */ if (expr) { tree varname; gcc_assert (expr->expr_type == EXPR_VARIABLE && expr->symtree); varname = gfc_build_cstring_const (expr->symtree->name); varname = gfc_build_addr_expr (pchar_type_node, varname); error = gfc_trans_runtime_error (true, &expr->where, "Attempting to allocate already" " allocated variable '%s'", varname); } else error = gfc_trans_runtime_error (true, NULL, "Attempting to allocate already allocated" " variable"); if (status != NULL_TREE) { tree status_type = TREE_TYPE (status); error = fold_build2_loc (input_location, MODIFY_EXPR, status_type, status, build_int_cst (status_type, LIBERROR_ALLOCATION)); } tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, null_mem, error, alloc); gfc_add_expr_to_block (block, tmp); }