static bool idx_analyze_ref (tree base, tree *index, void *data) { struct ar_data *ar_data = data; tree ibase, step, stepsize; HOST_WIDE_INT istep, idelta = 0, imult = 1; affine_iv iv; if (TREE_CODE (base) == MISALIGNED_INDIRECT_REF || TREE_CODE (base) == ALIGN_INDIRECT_REF) return false; if (!simple_iv (ar_data->loop, ar_data->stmt, *index, &iv, false)) return false; ibase = iv.base; step = iv.step; if (zero_p (step)) istep = 0; else { if (!cst_and_fits_in_hwi (step)) return false; istep = int_cst_value (step); } if (TREE_CODE (ibase) == PLUS_EXPR && cst_and_fits_in_hwi (TREE_OPERAND (ibase, 1))) { idelta = int_cst_value (TREE_OPERAND (ibase, 1)); ibase = TREE_OPERAND (ibase, 0); } if (cst_and_fits_in_hwi (ibase)) { idelta += int_cst_value (ibase); ibase = build_int_cst (TREE_TYPE (ibase), 0); } if (TREE_CODE (base) == ARRAY_REF) { stepsize = array_ref_element_size (base); if (!cst_and_fits_in_hwi (stepsize)) return false; imult = int_cst_value (stepsize); istep *= imult; idelta *= imult; } *ar_data->step += istep; *ar_data->delta += idelta; *index = ibase; return true; }
HOST_WIDE_INT extract_sec_implicit_index_arg (location_t location, tree fn) { tree fn_arg; HOST_WIDE_INT return_int = 0; if (TREE_CODE (fn) == CALL_EXPR) { fn_arg = CALL_EXPR_ARG (fn, 0); if (TREE_CODE (fn_arg) == INTEGER_CST) return_int = int_cst_value (fn_arg); else { /* If the location is unknown, and if fn has a location, then use that information so that the user has a better idea where the error could be. */ if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (fn)) location = EXPR_LOCATION (fn); error_at (location, "__sec_implicit_index parameter must be an " "integer constant expression"); return -1; } } return return_int; }
static bool loop_prefetch_arrays (struct loops *loops, struct loop *loop) { struct mem_ref_group *refs; unsigned ahead, ninsns, unroll_factor; struct tree_niter_desc desc; bool unrolled = false; /* Step 1: gather the memory references. */ refs = gather_memory_references (loop); /* Step 2: estimate the reuse effects. */ prune_by_reuse (refs); if (!anything_to_prefetch_p (refs)) goto fail; /* Step 3: determine the ahead and unroll factor. */ /* FIXME: We should use not size of the loop, but the average number of instructions executed per iteration of the loop. */ ninsns = tree_num_loop_insns (loop); ahead = (PREFETCH_LATENCY + ninsns - 1) / ninsns; unroll_factor = determine_unroll_factor (loop, refs, ahead, ninsns, &desc); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Ahead %d, unroll factor %d\n", ahead, unroll_factor); /* If the loop rolls less than the required unroll factor, prefetching is useless. */ if (unroll_factor > 1 && cst_and_fits_in_hwi (desc.niter) && (unsigned HOST_WIDE_INT) int_cst_value (desc.niter) < unroll_factor) goto fail; /* Step 4: what to prefetch? */ if (!schedule_prefetches (refs, unroll_factor, ahead)) goto fail; /* Step 5: unroll the loop. TODO -- peeling of first and last few iterations so that we do not issue superfluous prefetches. */ if (unroll_factor != 1) { tree_unroll_loop (loops, loop, unroll_factor, single_dom_exit (loop), &desc); unrolled = true; } /* Step 6: issue the prefetches. */ issue_prefetches (refs, unroll_factor, ahead); fail: release_mem_refs (refs); return unrolled; }
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 gather_interchange_stats (varray_type dependence_relations, varray_type datarefs, struct loop *loop, struct loop *first_loop, unsigned int *dependence_steps, unsigned int *nb_deps_not_carried_by_loop, unsigned int *access_strides) { unsigned int i; *dependence_steps = 0; *nb_deps_not_carried_by_loop = 0; *access_strides = 0; for (i = 0; i < VARRAY_ACTIVE_SIZE (dependence_relations); i++) { int dist; struct data_dependence_relation *ddr = (struct data_dependence_relation *) VARRAY_GENERIC_PTR (dependence_relations, i); /* If we don't know anything about this dependence, or the distance vector is NULL, or there is no dependence, then there is no reuse of data. */ if (DDR_DIST_VECT (ddr) == NULL || DDR_ARE_DEPENDENT (ddr) == chrec_dont_know || DDR_ARE_DEPENDENT (ddr) == chrec_known) continue; dist = DDR_DIST_VECT (ddr)[loop->depth - first_loop->depth]; if (dist == 0) (*nb_deps_not_carried_by_loop) += 1; else if (dist < 0) (*dependence_steps) += -dist; else (*dependence_steps) += dist; } /* Compute the access strides. */ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++) { unsigned int it; struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i); tree stmt = DR_STMT (dr); struct loop *stmt_loop = loop_containing_stmt (stmt); struct loop *inner_loop = first_loop->inner; if (inner_loop != stmt_loop && !flow_loop_nested_p (inner_loop, stmt_loop)) continue; for (it = 0; it < DR_NUM_DIMENSIONS (dr); it++) { tree chrec = DR_ACCESS_FN (dr, it); tree tstride = evolution_part_in_loop_num (chrec, loop->num); if (tstride == NULL_TREE || TREE_CODE (tstride) != INTEGER_CST) continue; (*access_strides) += int_cst_value (tstride); } } }