Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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);
	}
    }
}