Example #1
0
static tree
get_name_for_bit_test (tree candidate)
{
  /* Skip single-use names in favor of using the name from a
     non-widening conversion definition.  */
  if (TREE_CODE (candidate) == SSA_NAME
      && has_single_use (candidate))
    {
      gimple def_stmt = SSA_NAME_DEF_STMT (candidate);
      if (is_gimple_assign (def_stmt)
	  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
	{
	  if (TYPE_PRECISION (TREE_TYPE (candidate))
	      <= TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
	    return gimple_assign_rhs1 (def_stmt);
	}
    }

  return candidate;
}
Example #2
0
static bool
recognize_bits_test (gimple cond, tree *name, tree *bits, bool inv)
{
  gimple stmt;

  /* Get at the definition of the result of the bit test.  */
  if (gimple_cond_code (cond) != (inv ? EQ_EXPR : NE_EXPR)
      || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME
      || !integer_zerop (gimple_cond_rhs (cond)))
    return false;
  stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond));
  if (!is_gimple_assign (stmt)
      || gimple_assign_rhs_code (stmt) != BIT_AND_EXPR)
    return false;

  *name = get_name_for_bit_test (gimple_assign_rhs1 (stmt));
  *bits = gimple_assign_rhs2 (stmt);

  return true;
}
Example #3
0
File: sese.c Project: Gd58/gcc
static void
sese_build_liveouts_use (sese region, bitmap liveouts, basic_block bb,
			 tree use)
{
  unsigned ver;
  basic_block def_bb;

  if (TREE_CODE (use) != SSA_NAME)
    return;

  ver = SSA_NAME_VERSION (use);
  def_bb = gimple_bb (SSA_NAME_DEF_STMT (use));

  if (!def_bb
      || !bb_in_sese_p (def_bb, region)
      || bb_in_sese_p (bb, region))
    return;

  bitmap_set_bit (liveouts, ver);
}
static void
build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
		 tree tidx)
{
  tree array_type, ctor, decl, value_type, name, fetch;
  gimple load;
  gimple_stmt_iterator gsi;

  gcc_assert (info.default_values[num]);
  value_type = TREE_TYPE (info.default_values[num]);
  array_type = build_array_type (value_type, arr_index_type);

  ctor = build_constructor (array_type, info.constructors[num]);
  TREE_CONSTANT (ctor) = true;

  decl = build_decl (VAR_DECL, NULL_TREE, array_type);
  TREE_STATIC (decl) = 1;
  DECL_INITIAL (decl) = ctor;

  DECL_NAME (decl) = create_tmp_var_name ("CSWTCH");
  DECL_ARTIFICIAL (decl) = 1;
  TREE_CONSTANT (decl) = 1;
  add_referenced_var (decl);
  varpool_mark_needed_node (varpool_node (decl));
  varpool_finalize_decl (decl);
  mark_sym_for_renaming (decl);

  name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL);
  info.target_inbound_names[num] = name;

  fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE,
		  NULL_TREE);
  load = gimple_build_assign (name, fetch);
  SSA_NAME_DEF_STMT (name) = load;

  gsi = gsi_for_stmt (swtch);
  gsi_insert_before (&gsi, load, GSI_SAME_STMT);
  mark_symbols_for_renaming (load);

  info.arr_ref_last = load;
}
static tree
tree_may_unswitch_on (basic_block bb, struct loop *loop)
{
  tree stmt, def, cond, use;
  basic_block def_bb;
  ssa_op_iter iter;

  /* BB must end in a simple conditional jump.  */
  stmt = last_stmt (bb);
  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
    return NULL_TREE;

  /* Condition must be invariant.  */
  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
    {
      def = SSA_NAME_DEF_STMT (use);
      def_bb = bb_for_stmt (def);
      if (def_bb
	  && flow_bb_inside_loop_p (loop, def_bb))
	return NULL_TREE;
    }
Example #6
0
static gimple
input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
	   struct function *fn)
{
  unsigned HOST_WIDE_INT ix;
  tree phi_result;
  int i, len;
  gimple result;

  ix = streamer_read_uhwi (ib);
  phi_result = VEC_index (tree, SSANAMES (fn), ix);
  len = EDGE_COUNT (bb->preds);
  result = create_phi_node (phi_result, bb);
  SSA_NAME_DEF_STMT (phi_result) = result;

  /* We have to go through a lookup process here because the preds in the
     reconstructed graph are generally in a different order than they
     were in the original program.  */
  for (i = 0; i < len; i++)
    {
      tree def = stream_read_tree (ib, data_in);
      int src_index = streamer_read_uhwi (ib);
      location_t arg_loc = lto_input_location (ib, data_in);
      basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);

      edge e = NULL;
      int j;

      for (j = 0; j < len; j++)
	if (EDGE_PRED (bb, j)->src == sbb)
	  {
	    e = EDGE_PRED (bb, j);
	    break;
	  }

      add_phi_arg (result, def, e, arg_loc);
    }

  return result;
}
Example #7
0
static bool
remove_prop_source_from_use (tree name, gimple up_to_stmt)
{
  gimple_stmt_iterator gsi;
  gimple stmt;

  do {
    if (!has_zero_uses (name))
      return false;

    stmt = SSA_NAME_DEF_STMT (name);
    if (stmt == up_to_stmt)
      return true;

    gsi = gsi_for_stmt (stmt);
    release_defs (stmt);
    gsi_remove (&gsi, true);

    name = (gimple_assign_copy_p (stmt)) ? gimple_assign_rhs1 (stmt) : NULL;
  } while (name && TREE_CODE (name) == SSA_NAME);

  return false;
}
Example #8
0
void
reserve_phi_args_for_new_edge (basic_block bb)
{
  size_t len = EDGE_COUNT (bb->preds);
  size_t cap = ideal_phi_node_len (len + 4);
  gimple_stmt_iterator gsi;

  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    {
      gimple_statement_phi *stmt =
	as_a <gimple_statement_phi> (gsi_stmt (gsi));

      if (len > gimple_phi_capacity (stmt))
	{
	  gimple_statement_phi *new_phi = resize_phi_node (stmt, cap);

	  /* The result of the PHI is defined by this PHI node.  */
	  SSA_NAME_DEF_STMT (gimple_phi_result (new_phi)) = new_phi;
	  gsi_set_stmt (&gsi, new_phi);

	  release_phi_node (stmt);
	  stmt = new_phi;
	}

      /* We represent a "missing PHI argument" by placing NULL_TREE in
	 the corresponding slot.  If PHI arguments were added
	 immediately after an edge is created, this zeroing would not
	 be necessary, but unfortunately this is not the case.  For
	 example, the loop optimizer duplicates several basic blocks,
	 redirects edges, and then fixes up PHI arguments later in
	 batch.  */
      SET_PHI_ARG_DEF (stmt, len - 1, NULL_TREE);
      gimple_phi_arg_set_location (stmt, len - 1, UNKNOWN_LOCATION);

      stmt->nargs++;
    }
}
Example #9
0
static bool
add_dependency (tree def, struct lim_aux_data *data, struct loop *loop,
		bool add_cost)
{
  tree def_stmt = SSA_NAME_DEF_STMT (def);
  basic_block def_bb = bb_for_stmt (def_stmt);
  struct loop *max_loop;
  struct depend *dep;

  if (!def_bb)
    return true;

  max_loop = outermost_invariant_loop (def, loop);
  if (!max_loop)
    return false;

  if (flow_loop_nested_p (data->max_loop, max_loop))
    data->max_loop = max_loop;

  if (!LIM_DATA (def_stmt))
    return true;

  if (add_cost
      /* Only add the cost if the statement defining DEF is inside LOOP,
	 i.e. if it is likely that by moving the invariants dependent
	 on it, we will be able to avoid creating a new register for
	 it (since it will be only used in these dependent invariants).  */
      && def_bb->loop_father == loop)
    data->cost += LIM_DATA (def_stmt)->cost;

  dep = XNEW (struct depend);
  dep->stmt = def_stmt;
  dep->next = data->depends;
  data->depends = dep;

  return true;
}
Example #10
0
static void
forward_propagate_into_cond (tree cond_expr)
{
  gcc_assert (TREE_CODE (cond_expr) == COND_EXPR);

  while (1)
    {
      tree test_var = NULL_TREE;
      tree cond = COND_EXPR_COND (cond_expr);
      tree new_cond = forward_propagate_into_cond_1 (cond, &test_var);

      /* Return if unsuccessful.  */
      if (new_cond == NULL_TREE)
	break;

      /* Dump details.  */
      if (dump_file && (dump_flags & TDF_DETAILS))
	{
	  fprintf (dump_file, "  Replaced '");
	  print_generic_expr (dump_file, cond, dump_flags);
	  fprintf (dump_file, "' with '");
	  print_generic_expr (dump_file, new_cond, dump_flags);
	  fprintf (dump_file, "'\n");
	}

      COND_EXPR_COND (cond_expr) = new_cond;
      update_stmt (cond_expr);

      if (has_zero_uses (test_var))
	{
	  tree def = SSA_NAME_DEF_STMT (test_var);
	  block_stmt_iterator bsi = bsi_for_stmt (def);
	  bsi_remove (&bsi);
	}
    }
}
Example #11
0
/* Return 1 if check CI against BOUNDS always pass,
   -1 if check CI against BOUNDS always fails and
   0 if we cannot compute check result.  */
static int
chkp_get_check_result (struct check_info *ci, tree bounds)
{
    gimple *bnd_def;
    address_t bound_val;
    int sign, res = 0;

    if (dump_file && (dump_flags & TDF_DETAILS))
    {
        fprintf (dump_file, "Trying to compute result of the check\n");
        fprintf (dump_file, "  check: ");
        print_gimple_stmt (dump_file, ci->stmt, 0, 0);
        fprintf (dump_file, "  address: ");
        chkp_print_addr (ci->addr);
        fprintf (dump_file, "\n  bounds: ");
        print_generic_expr (dump_file, bounds, 0);
        fprintf (dump_file, "\n");
    }

    if (TREE_CODE (bounds) != SSA_NAME)
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: bounds tree code is not ssa_name\n");
        return 0;
    }

    bnd_def = SSA_NAME_DEF_STMT (bounds);
    /* Currently we handle cases when bounds are result of bndmk
       or loaded static bounds var.  */
    if (gimple_code (bnd_def) == GIMPLE_CALL
            && gimple_call_fndecl (bnd_def) == chkp_bndmk_fndecl)
    {
        bound_val.pol.create (0);
        chkp_collect_value (gimple_call_arg (bnd_def, 0), bound_val);
        if (ci->type == CHECK_UPPER_BOUND)
        {
            address_t size_val;
            size_val.pol.create (0);
            chkp_collect_value (gimple_call_arg (bnd_def, 1), size_val);
            chkp_add_addr_addr (bound_val, size_val);
            size_val.pol.release ();
            chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
        }
    }
    else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
             && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ())
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: always pass with zero bounds\n");
        return 1;
    }
    else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
             && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ())
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: always fails with none bounds\n");
        return -1;
    }
    else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
             && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL)
    {
        tree bnd_var = gimple_assign_rhs1 (bnd_def);
        tree var;
        tree size;

        if (!DECL_INITIAL (bnd_var)
                || DECL_INITIAL (bnd_var) == error_mark_node)
        {
            if (dump_file && (dump_flags & TDF_DETAILS))
                fprintf (dump_file, "  result: cannot compute bounds\n");
            return 0;
        }

        gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR);
        var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0);

        bound_val.pol.create (0);
        chkp_collect_value (DECL_INITIAL (bnd_var), bound_val);
        if (ci->type == CHECK_UPPER_BOUND)
        {
            if (TREE_CODE (var) == VAR_DECL)
            {
                if (DECL_SIZE (var)
                        && !chkp_variable_size_type (TREE_TYPE (var)))
                    size = DECL_SIZE_UNIT (var);
                else
                {
                    if (dump_file && (dump_flags & TDF_DETAILS))
                        fprintf (dump_file, "  result: cannot compute bounds\n");
                    return 0;
                }
            }
            else
            {
                gcc_assert (TREE_CODE (var) == STRING_CST);
                size = build_int_cst (size_type_node,
                                      TREE_STRING_LENGTH (var));
            }

            address_t size_val;
            size_val.pol.create (0);
            chkp_collect_value (size, size_val);
            chkp_add_addr_addr (bound_val, size_val);
            size_val.pol.release ();
            chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
        }
    }
    else
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: cannot compute bounds\n");
        return 0;
    }

    if (dump_file && (dump_flags & TDF_DETAILS))
    {
        fprintf (dump_file, "  bound value: ");
        chkp_print_addr (bound_val);
        fprintf (dump_file, "\n");
    }

    chkp_sub_addr_addr (bound_val, ci->addr);

    if (!chkp_is_constant_addr (bound_val, &sign))
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: cannot compute result\n");

        res = 0;
    }
    else if (sign == 0
             || (ci->type == CHECK_UPPER_BOUND && sign > 0)
             || (ci->type == CHECK_LOWER_BOUND && sign < 0))
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: always pass\n");

        res = 1;
    }
    else
    {
        if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  result: always fail\n");

        res = -1;
    }

    bound_val.pol.release ();

    return res;
}
Example #12
0
/* Compute value of PTR and put it into address RES.  */
static void
chkp_collect_value (tree ptr, address_t &res)
{
    gimple *def_stmt;
    enum gimple_code code;
    enum tree_code rhs_code;
    address_t addr;
    tree rhs1;

    if (TREE_CODE (ptr) == INTEGER_CST)
    {
        chkp_add_addr_item (res, ptr, NULL);
        return;
    }
    else if (TREE_CODE (ptr) == ADDR_EXPR)
    {
        chkp_collect_addr_value (ptr, res);
        return;
    }
    else if (TREE_CODE (ptr) != SSA_NAME)
    {
        chkp_add_addr_item (res, integer_one_node, ptr);
        return;
    }

    /* Now we handle the case when polynomial is computed
       for SSA NAME.  */
    def_stmt = SSA_NAME_DEF_STMT (ptr);
    code = gimple_code (def_stmt);

    /* Currently we do not walk through statements other
       than assignment.  */
    if (code != GIMPLE_ASSIGN)
    {
        chkp_add_addr_item (res, integer_one_node, ptr);
        return;
    }

    rhs_code = gimple_assign_rhs_code (def_stmt);
    rhs1 = gimple_assign_rhs1 (def_stmt);

    switch (rhs_code)
    {
    case SSA_NAME:
    case INTEGER_CST:
    case ADDR_EXPR:
        chkp_collect_value (rhs1, res);
        break;

    case PLUS_EXPR:
    case POINTER_PLUS_EXPR:
        chkp_collect_value (rhs1, res);
        addr.pol.create (0);
        chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
        chkp_add_addr_addr (res, addr);
        addr.pol.release ();
        break;

    case MINUS_EXPR:
        chkp_collect_value (rhs1, res);
        addr.pol.create (0);
        chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
        chkp_sub_addr_addr (res, addr);
        addr.pol.release ();
        break;

    case MULT_EXPR:
        if (TREE_CODE (rhs1) == SSA_NAME
                && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == INTEGER_CST)
        {
            chkp_collect_value (rhs1, res);
            chkp_mult_addr (res, gimple_assign_rhs2 (def_stmt));
        }
        else if (TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME
                 && TREE_CODE (rhs1) == INTEGER_CST)
        {
            chkp_collect_value (gimple_assign_rhs2 (def_stmt), res);
            chkp_mult_addr (res, rhs1);
        }
        else
            chkp_add_addr_item (res, integer_one_node, ptr);
        break;

    default:
        chkp_add_addr_item (res, integer_one_node, ptr);
        break;
    }
}
Example #13
0
static tree
rewrite_bittest (block_stmt_iterator *bsi)
{
  tree stmt, lhs, rhs, var, name, use_stmt, stmt1, stmt2, t;
  use_operand_p use;

  stmt = bsi_stmt (*bsi);
  lhs = GENERIC_TREE_OPERAND (stmt, 0);
  rhs = GENERIC_TREE_OPERAND (stmt, 1);

  /* Verify that the single use of lhs is a comparison against zero.  */
  if (TREE_CODE (lhs) != SSA_NAME
      || !single_imm_use (lhs, &use, &use_stmt)
      || TREE_CODE (use_stmt) != COND_EXPR)
    return stmt;
  t = COND_EXPR_COND (use_stmt);
  if (TREE_OPERAND (t, 0) != lhs
      || (TREE_CODE (t) != NE_EXPR
	  && TREE_CODE (t) != EQ_EXPR)
      || !integer_zerop (TREE_OPERAND (t, 1)))
    return stmt;

  /* Get at the operands of the shift.  The rhs is TMP1 & 1.  */
  stmt1 = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
  if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
    return stmt;

  /* There is a conversion in between possibly inserted by fold.  */
  t = GIMPLE_STMT_OPERAND (stmt1, 1);
  if (TREE_CODE (t) == NOP_EXPR
      || TREE_CODE (t) == CONVERT_EXPR)
    {
      t = TREE_OPERAND (t, 0);
      if (TREE_CODE (t) != SSA_NAME
	  || !has_single_use (t))
	return stmt;
      stmt1 = SSA_NAME_DEF_STMT (t);
      if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
	return stmt;
      t = GIMPLE_STMT_OPERAND (stmt1, 1);
    }

  /* Verify that B is loop invariant but A is not.  Verify that with
     all the stmt walking we are still in the same loop.  */
  if (TREE_CODE (t) == RSHIFT_EXPR
      && loop_containing_stmt (stmt1) == loop_containing_stmt (stmt)
      && outermost_invariant_loop_expr (TREE_OPERAND (t, 1),
                                        loop_containing_stmt (stmt1)) != NULL
      && outermost_invariant_loop_expr (TREE_OPERAND (t, 0),
                                        loop_containing_stmt (stmt1)) == NULL)
    {
      tree a = TREE_OPERAND (t, 0);
      tree b = TREE_OPERAND (t, 1);

      /* 1 << B */
      var = create_tmp_var (TREE_TYPE (a), "shifttmp");
      add_referenced_var (var);
      t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (a),
		       build_int_cst (TREE_TYPE (a), 1), b);
      stmt1 = build_gimple_modify_stmt (var, t);
      name = make_ssa_name (var, stmt1);
      GIMPLE_STMT_OPERAND (stmt1, 0) = name;

      /* A & (1 << B) */
      t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (a), a, name);
      stmt2 = build_gimple_modify_stmt (var, t);
      name = make_ssa_name (var, stmt2);
      GIMPLE_STMT_OPERAND (stmt2, 0) = name;

      /* Replace the SSA_NAME we compare against zero.  Adjust
	 the type of zero accordingly.  */
      SET_USE (use, name);
      TREE_OPERAND (COND_EXPR_COND (use_stmt), 1)
	= build_int_cst_type (TREE_TYPE (name), 0);

      bsi_insert_before (bsi, stmt1, BSI_SAME_STMT);
      bsi_replace (bsi, stmt2, true);

      return stmt1;
    }

  return stmt;
}
static bool
recognize_single_bit_test (gimple cond, tree *name, tree *bit)
{
  gimple stmt;

  /* Get at the definition of the result of the bit test.  */
  if (gimple_cond_code (cond) != NE_EXPR
      || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME
      || !integer_zerop (gimple_cond_rhs (cond)))
    return false;
  stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond));
  if (!is_gimple_assign (stmt))
    return false;

  /* Look at which bit is tested.  One form to recognize is
     D.1985_5 = state_3(D) >> control1_4(D);
     D.1986_6 = (int) D.1985_5;
     D.1987_7 = op0 & 1;
     if (D.1987_7 != 0)  */
  if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR
      && integer_onep (gimple_assign_rhs2 (stmt))
      && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
    {
      tree orig_name = gimple_assign_rhs1 (stmt);

      /* Look through copies and conversions to eventually
	 find the stmt that computes the shift.  */
      stmt = SSA_NAME_DEF_STMT (orig_name);

      while (is_gimple_assign (stmt)
	     && ((CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
		  && (TYPE_PRECISION (TREE_TYPE (gimple_assign_lhs (stmt)))
		      <= TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
		 || gimple_assign_ssa_name_copy_p (stmt)))
	stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));

      /* If we found such, decompose it.  */
      if (is_gimple_assign (stmt)
	  && gimple_assign_rhs_code (stmt) == RSHIFT_EXPR)
	{
	  /* op0 & (1 << op1) */
	  *bit = gimple_assign_rhs2 (stmt);
	  *name = gimple_assign_rhs1 (stmt);
	}
      else
	{
	  /* t & 1 */
	  *bit = integer_zero_node;
	  *name = get_name_for_bit_test (orig_name);
	}

      return true;
    }

  /* Another form is
     D.1987_7 = op0 & (1 << CST)
     if (D.1987_7 != 0)  */
  if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR
      && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
      && integer_pow2p (gimple_assign_rhs2 (stmt)))
    {
      *name = gimple_assign_rhs1 (stmt);
      *bit = build_int_cst (integer_type_node,
			    tree_log2 (gimple_assign_rhs2 (stmt)));
      return true;
    }

  /* Another form is
     D.1986_6 = 1 << control1_4(D)
     D.1987_7 = op0 & D.1986_6
     if (D.1987_7 != 0)  */
  if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR
      && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
      && TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME)
    {
      gimple tmp;

      /* Both arguments of the BIT_AND_EXPR can be the single-bit
	 specifying expression.  */
      tmp = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
      if (is_gimple_assign (tmp)
	  && gimple_assign_rhs_code (tmp) == LSHIFT_EXPR
	  && integer_onep (gimple_assign_rhs1 (tmp)))
	{
	  *name = gimple_assign_rhs2 (stmt);
	  *bit = gimple_assign_rhs2 (tmp);
	  return true;
	}

      tmp = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
      if (is_gimple_assign (tmp)
	  && gimple_assign_rhs_code (tmp) == LSHIFT_EXPR
	  && integer_onep (gimple_assign_rhs1 (tmp)))
	{
	  *name = gimple_assign_rhs1 (stmt);
	  *bit = gimple_assign_rhs2 (tmp);
	  return true;
	}
    }

  return false;
}
static bool
forward_propagate_addr_into_variable_array_index (tree offset,
						  tree def_rhs,
						  gimple_stmt_iterator *use_stmt_gsi)
{
  tree index, tunit;
  gimple offset_def, use_stmt = gsi_stmt (*use_stmt_gsi);
  tree tmp;

  tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (def_rhs)));
  if (!host_integerp (tunit, 1))
    return false;

  /* Get the offset's defining statement.  */
  offset_def = SSA_NAME_DEF_STMT (offset);

  /* Try to find an expression for a proper index.  This is either a
     multiplication expression by the element size or just the ssa name we came
     along in case the element size is one. In that case, however, we do not
     allow multiplications because they can be computing index to a higher
     level dimension (PR 37861). */
  if (integer_onep (tunit))
    {
      if (is_gimple_assign (offset_def)
	  && gimple_assign_rhs_code (offset_def) == MULT_EXPR)
	return false;

      index = offset;
    }
  else
    {
      /* The statement which defines OFFSET before type conversion
         must be a simple GIMPLE_ASSIGN.  */
      if (!is_gimple_assign (offset_def))
	return false;

      /* The RHS of the statement which defines OFFSET must be a
	 multiplication of an object by the size of the array elements.
	 This implicitly verifies that the size of the array elements
	 is constant.  */
     if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
	 && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
	 && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), tunit))
       {
	 /* The first operand to the MULT_EXPR is the desired index.  */
	 index = gimple_assign_rhs1 (offset_def);
       }
     /* If we have idx * tunit + CST * tunit re-associate that.  */
     else if ((gimple_assign_rhs_code (offset_def) == PLUS_EXPR
	       || gimple_assign_rhs_code (offset_def) == MINUS_EXPR)
	      && TREE_CODE (gimple_assign_rhs1 (offset_def)) == SSA_NAME
	      && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
	      && (tmp = div_if_zero_remainder (EXACT_DIV_EXPR,
					       gimple_assign_rhs2 (offset_def),
					       tunit)) != NULL_TREE)
       {
	 gimple offset_def2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (offset_def));
	 if (is_gimple_assign (offset_def2)
	     && gimple_assign_rhs_code (offset_def2) == MULT_EXPR
	     && TREE_CODE (gimple_assign_rhs2 (offset_def2)) == INTEGER_CST
	     && tree_int_cst_equal (gimple_assign_rhs2 (offset_def2), tunit))
	   {
	     index = fold_build2 (gimple_assign_rhs_code (offset_def),
				  TREE_TYPE (offset),
				  gimple_assign_rhs1 (offset_def2), tmp);
	   }
	 else
	   return false;
       }
     else
	return false;
    }

  /* Replace the pointer addition with array indexing.  */
  index = force_gimple_operand_gsi (use_stmt_gsi, index, true, NULL_TREE,
				    true, GSI_SAME_STMT);
  gimple_assign_set_rhs_from_tree (use_stmt_gsi, unshare_expr (def_rhs));
  use_stmt = gsi_stmt (*use_stmt_gsi);
  TREE_OPERAND (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0), 1)
    = index;

  /* That should have created gimple, so there is no need to
     record information to undo the propagation.  */
  fold_stmt_inplace (use_stmt);
  tidy_after_forward_propagate_addr (use_stmt);
  return true;
}
Example #16
0
static gimple
vect_recog_widen_sum_pattern (gimple last_stmt, tree *type_in, tree *type_out)
{
  gimple stmt;
  tree oprnd0, oprnd1;
  stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
  tree type, half_type;
  gimple pattern_stmt;
  loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
  struct loop *loop = LOOP_VINFO_LOOP (loop_info);
  tree var;

  if (!is_gimple_assign (last_stmt))
    return NULL;

  type = gimple_expr_type (last_stmt);

  /* Look for the following pattern
          DX = (TYPE) X;
          sum_1 = DX + sum_0;
     In which DX is at least double the size of X, and sum_1 has been
     recognized as a reduction variable.
   */

  /* Starting from LAST_STMT, follow the defs of its uses in search
     of the above pattern.  */

  if (gimple_assign_rhs_code (last_stmt) != PLUS_EXPR)
    return NULL;

  if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def)
    return NULL;

  oprnd0 = gimple_assign_rhs1 (last_stmt);
  oprnd1 = gimple_assign_rhs2 (last_stmt);
  if (!types_compatible_p (TREE_TYPE (oprnd0), type)
      || !types_compatible_p (TREE_TYPE (oprnd1), type))
    return NULL;

  /* So far so good. Since last_stmt was detected as a (summation) reduction,
     we know that oprnd1 is the reduction variable (defined by a loop-header
     phi), and oprnd0 is an ssa-name defined by a stmt in the loop body.
     Left to check that oprnd0 is defined by a cast from type 'type' to type
     'TYPE'.  */

  if (!widened_name_p (oprnd0, last_stmt, &half_type, &stmt))
    return NULL;

  oprnd0 = gimple_assign_rhs1 (stmt);
  *type_in = half_type;
  *type_out = type;

  /* Pattern detected. Create a stmt to be used to replace the pattern: */
  var = vect_recog_temp_ssa_var (type, NULL);
  pattern_stmt = gimple_build_assign_with_ops (WIDEN_SUM_EXPR, var,
					       oprnd0, oprnd1);
  SSA_NAME_DEF_STMT (var) = pattern_stmt;

  if (vect_print_dump_info (REPORT_DETAILS))
    {
      fprintf (vect_dump, "vect_recog_widen_sum_pattern: detected: ");
      print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
    }

  /* We don't allow changing the order of the computation in the inner-loop
     when doing outer-loop vectorization.  */
  gcc_assert (!nested_in_vect_loop_p (loop, last_stmt));

  return pattern_stmt;
}
Example #17
0
static tree
independent_of_stmt_p (tree expr, gimple at, gimple_stmt_iterator gsi)
{
  basic_block bb, call_bb, at_bb;
  edge e;
  edge_iterator ei;

  if (is_gimple_min_invariant (expr))
    return expr;

  if (TREE_CODE (expr) != SSA_NAME)
    return NULL_TREE;

  /* Mark the blocks in the chain leading to the end.  */
  at_bb = gimple_bb (at);
  call_bb = gimple_bb (gsi_stmt (gsi));
  for (bb = call_bb; bb != at_bb; bb = single_succ (bb))
    bb->aux = &bb->aux;
  bb->aux = &bb->aux;

  while (1)
    {
      at = SSA_NAME_DEF_STMT (expr);
      bb = gimple_bb (at);

      /* The default definition or defined before the chain.  */
      if (!bb || !bb->aux)
	break;

      if (bb == call_bb)
	{
	  for (; !gsi_end_p (gsi); gsi_next (&gsi))
	    if (gsi_stmt (gsi) == at)
	      break;

	  if (!gsi_end_p (gsi))
	    expr = NULL_TREE;
	  break;
	}

      if (gimple_code (at) != GIMPLE_PHI)
	{
	  expr = NULL_TREE;
	  break;
	}

      FOR_EACH_EDGE (e, ei, bb->preds)
	if (e->src->aux)
	  break;
      gcc_assert (e);

      expr = PHI_ARG_DEF_FROM_EDGE (at, e);
      if (TREE_CODE (expr) != SSA_NAME)
	{
	  /* The value is a constant.  */
	  break;
	}
    }

  /* Unmark the blocks.  */
  for (bb = call_bb; bb != at_bb; bb = single_succ (bb))
    bb->aux = NULL;
  bb->aux = NULL;

  return expr;
}
Example #18
0
static gimple
vect_recog_pow_pattern (gimple last_stmt, tree *type_in, tree *type_out)
{
  tree fn, base, exp = NULL;
  gimple stmt;
  tree var;

  if (!is_gimple_call (last_stmt) || gimple_call_lhs (last_stmt) == NULL)
    return NULL;

  fn = gimple_call_fndecl (last_stmt);
  if (fn == NULL_TREE || DECL_BUILT_IN_CLASS (fn) != BUILT_IN_NORMAL)
   return NULL;

  switch (DECL_FUNCTION_CODE (fn))
    {
    case BUILT_IN_POWIF:
    case BUILT_IN_POWI:
    case BUILT_IN_POWF:
    case BUILT_IN_POW:
      base = gimple_call_arg (last_stmt, 0);
      exp = gimple_call_arg (last_stmt, 1);
      if (TREE_CODE (exp) != REAL_CST
	  && TREE_CODE (exp) != INTEGER_CST)
        return NULL;
      break;

    default:
      return NULL;
    }

  /* We now have a pow or powi builtin function call with a constant
     exponent.  */

  *type_out = NULL_TREE;

  /* Catch squaring.  */
  if ((host_integerp (exp, 0)
       && tree_low_cst (exp, 0) == 2)
      || (TREE_CODE (exp) == REAL_CST
          && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconst2)))
    {
      *type_in = TREE_TYPE (base);

      var = vect_recog_temp_ssa_var (TREE_TYPE (base), NULL);
      stmt = gimple_build_assign_with_ops (MULT_EXPR, var, base, base);
      SSA_NAME_DEF_STMT (var) = stmt;
      return stmt;
    }

  /* Catch square root.  */
  if (TREE_CODE (exp) == REAL_CST
      && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconsthalf))
    {
      tree newfn = mathfn_built_in (TREE_TYPE (base), BUILT_IN_SQRT);
      *type_in = get_vectype_for_scalar_type (TREE_TYPE (base));
      if (*type_in)
	{
	  gimple stmt = gimple_build_call (newfn, 1, base);
	  if (vectorizable_function (stmt, *type_in, *type_in)
	      != NULL_TREE)
	    {
	      var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt);
	      gimple_call_set_lhs (stmt, var);
	      return stmt;
	    }
	}
    }

  return NULL;
}
Example #19
0
static gimple
vect_recog_widen_mult_pattern (gimple last_stmt,
			       tree *type_in,
			       tree *type_out)
{
  gimple def_stmt0, def_stmt1;
  tree oprnd0, oprnd1;
  tree type, half_type0, half_type1;
  gimple pattern_stmt;
  tree vectype, vectype_out;
  tree dummy;
  tree var;
  enum tree_code dummy_code;
  int dummy_int;
  VEC (tree, heap) *dummy_vec;

  if (!is_gimple_assign (last_stmt))
    return NULL;

  type = gimple_expr_type (last_stmt);

  /* Starting from LAST_STMT, follow the defs of its uses in search
     of the above pattern.  */

  if (gimple_assign_rhs_code (last_stmt) != MULT_EXPR)
    return NULL;

  oprnd0 = gimple_assign_rhs1 (last_stmt);
  oprnd1 = gimple_assign_rhs2 (last_stmt);
  if (!types_compatible_p (TREE_TYPE (oprnd0), type)
      || !types_compatible_p (TREE_TYPE (oprnd1), type))
    return NULL;

  /* Check argument 0 */
  if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0))
    return NULL;
  oprnd0 = gimple_assign_rhs1 (def_stmt0);

  /* Check argument 1 */
  if (!widened_name_p (oprnd1, last_stmt, &half_type1, &def_stmt1))
    return NULL;
  oprnd1 = gimple_assign_rhs1 (def_stmt1);

  if (!types_compatible_p (half_type0, half_type1))
    return NULL;

  /* Pattern detected.  */
  if (vect_print_dump_info (REPORT_DETAILS))
    fprintf (vect_dump, "vect_recog_widen_mult_pattern: detected: ");

  /* Check target support  */
  vectype = get_vectype_for_scalar_type (half_type0);
  vectype_out = get_vectype_for_scalar_type (type);
  if (!vectype
      || !vectype_out
      || !supportable_widening_operation (WIDEN_MULT_EXPR, last_stmt,
					  vectype_out, vectype,
					  &dummy, &dummy, &dummy_code,
					  &dummy_code, &dummy_int, &dummy_vec))
    return NULL;

  *type_in = vectype;
  *type_out = vectype_out;

  /* Pattern supported. Create a stmt to be used to replace the pattern: */
  var = vect_recog_temp_ssa_var (type, NULL);
  pattern_stmt = gimple_build_assign_with_ops (WIDEN_MULT_EXPR, var, oprnd0,
					       oprnd1);
  SSA_NAME_DEF_STMT (var) = pattern_stmt;

  if (vect_print_dump_info (REPORT_DETAILS))
    print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);

  return pattern_stmt;
}
Example #20
0
static gimple
vect_recog_dot_prod_pattern (gimple last_stmt, tree *type_in, tree *type_out)
{
  gimple stmt;
  tree oprnd0, oprnd1;
  tree oprnd00, oprnd01;
  stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
  tree type, half_type;
  gimple pattern_stmt;
  tree prod_type;
  loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
  struct loop *loop = LOOP_VINFO_LOOP (loop_info);
  tree var;

  if (!is_gimple_assign (last_stmt))
    return NULL;

  type = gimple_expr_type (last_stmt);

  /* Look for the following pattern
          DX = (TYPE1) X;
          DY = (TYPE1) Y;
          DPROD = DX * DY;
          DDPROD = (TYPE2) DPROD;
          sum_1 = DDPROD + sum_0;
     In which
     - DX is double the size of X
     - DY is double the size of Y
     - DX, DY, DPROD all have the same type
     - sum is the same size of DPROD or bigger
     - sum has been recognized as a reduction variable.

     This is equivalent to:
       DPROD = X w* Y;          #widen mult
       sum_1 = DPROD w+ sum_0;  #widen summation
     or
       DPROD = X w* Y;          #widen mult
       sum_1 = DPROD + sum_0;   #summation
   */

  /* Starting from LAST_STMT, follow the defs of its uses in search
     of the above pattern.  */

  if (gimple_assign_rhs_code (last_stmt) != PLUS_EXPR)
    return NULL;

  if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
    {
      /* Has been detected as widening-summation?  */

      stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
      type = gimple_expr_type (stmt);
      if (gimple_assign_rhs_code (stmt) != WIDEN_SUM_EXPR)
        return NULL;
      oprnd0 = gimple_assign_rhs1 (stmt);
      oprnd1 = gimple_assign_rhs2 (stmt);
      half_type = TREE_TYPE (oprnd0);
    }
  else
    {
      gimple def_stmt;

      if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def)
        return NULL;
      oprnd0 = gimple_assign_rhs1 (last_stmt);
      oprnd1 = gimple_assign_rhs2 (last_stmt);
      if (!types_compatible_p (TREE_TYPE (oprnd0), type)
	  || !types_compatible_p (TREE_TYPE (oprnd1), type))
        return NULL;
      stmt = last_stmt;

      if (widened_name_p (oprnd0, stmt, &half_type, &def_stmt))
        {
          stmt = def_stmt;
          oprnd0 = gimple_assign_rhs1 (stmt);
        }
      else
        half_type = type;
    }

  /* So far so good. Since last_stmt was detected as a (summation) reduction,
     we know that oprnd1 is the reduction variable (defined by a loop-header
     phi), and oprnd0 is an ssa-name defined by a stmt in the loop body.
     Left to check that oprnd0 is defined by a (widen_)mult_expr  */

  prod_type = half_type;
  stmt = SSA_NAME_DEF_STMT (oprnd0);

  /* It could not be the dot_prod pattern if the stmt is outside the loop.  */
  if (!gimple_bb (stmt) || !flow_bb_inside_loop_p (loop, gimple_bb (stmt)))
    return NULL;

  /* FORNOW.  Can continue analyzing the def-use chain when this stmt in a phi
     inside the loop (in case we are analyzing an outer-loop).  */
  if (!is_gimple_assign (stmt))
    return NULL;
  stmt_vinfo = vinfo_for_stmt (stmt);
  gcc_assert (stmt_vinfo);
  if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_internal_def)
    return NULL;
  if (gimple_assign_rhs_code (stmt) != MULT_EXPR)
    return NULL;
  if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
    {
      /* Has been detected as a widening multiplication?  */

      stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
      if (gimple_assign_rhs_code (stmt) != WIDEN_MULT_EXPR)
        return NULL;
      stmt_vinfo = vinfo_for_stmt (stmt);
      gcc_assert (stmt_vinfo);
      gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_internal_def);
      oprnd00 = gimple_assign_rhs1 (stmt);
      oprnd01 = gimple_assign_rhs2 (stmt);
    }
  else
    {
      tree half_type0, half_type1;
      gimple def_stmt;
      tree oprnd0, oprnd1;

      oprnd0 = gimple_assign_rhs1 (stmt);
      oprnd1 = gimple_assign_rhs2 (stmt);
      if (!types_compatible_p (TREE_TYPE (oprnd0), prod_type)
          || !types_compatible_p (TREE_TYPE (oprnd1), prod_type))
        return NULL;
      if (!widened_name_p (oprnd0, stmt, &half_type0, &def_stmt))
        return NULL;
      oprnd00 = gimple_assign_rhs1 (def_stmt);
      if (!widened_name_p (oprnd1, stmt, &half_type1, &def_stmt))
        return NULL;
      oprnd01 = gimple_assign_rhs1 (def_stmt);
      if (!types_compatible_p (half_type0, half_type1))
        return NULL;
      if (TYPE_PRECISION (prod_type) != TYPE_PRECISION (half_type0) * 2)
	return NULL;
    }

  half_type = TREE_TYPE (oprnd00);
  *type_in = half_type;
  *type_out = type;

  /* Pattern detected. Create a stmt to be used to replace the pattern: */
  var = vect_recog_temp_ssa_var (type, NULL);
  pattern_stmt = gimple_build_assign_with_ops3 (DOT_PROD_EXPR, var,
						oprnd00, oprnd01, oprnd1);

  if (vect_print_dump_info (REPORT_DETAILS))
    {
      fprintf (vect_dump, "vect_recog_dot_prod_pattern: detected: ");
      print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
    }

  /* We don't allow changing the order of the computation in the inner-loop
     when doing outer-loop vectorization.  */
  gcc_assert (!nested_in_vect_loop_p (loop, last_stmt));

  return pattern_stmt;
}
Example #21
0
static gimple
input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
		   struct function *fn, enum LTO_tags tag)
{
  gimple stmt;
  enum gimple_code code;
  unsigned HOST_WIDE_INT num_ops;
  size_t i;
  struct bitpack_d bp;

  code = lto_tag_to_gimple_code (tag);

  /* Read the tuple header.  */
  bp = streamer_read_bitpack (ib);
  num_ops = bp_unpack_var_len_unsigned (&bp);
  stmt = gimple_alloc (code, num_ops);
  stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
  if (is_gimple_assign (stmt))
    stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
  stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
  stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);

  /* Read location information.  */
  gimple_set_location (stmt, lto_input_location (ib, data_in));

  /* Read lexical block reference.  */
  gimple_set_block (stmt, stream_read_tree (ib, data_in));

  /* Read in all the operands.  */
  switch (code)
    {
    case GIMPLE_RESX:
      gimple_resx_set_region (stmt, streamer_read_hwi (ib));
      break;

    case GIMPLE_EH_MUST_NOT_THROW:
      gimple_eh_must_not_throw_set_fndecl (stmt, stream_read_tree (ib, data_in));
      break;

    case GIMPLE_EH_DISPATCH:
      gimple_eh_dispatch_set_region (stmt, streamer_read_hwi (ib));
      break;

    case GIMPLE_ASM:
      {
	/* FIXME lto.  Move most of this into a new gimple_asm_set_string().  */
	tree str;
	stmt->gimple_asm.ni = streamer_read_uhwi (ib);
	stmt->gimple_asm.no = streamer_read_uhwi (ib);
	stmt->gimple_asm.nc = streamer_read_uhwi (ib);
	stmt->gimple_asm.nl = streamer_read_uhwi (ib);
	str = streamer_read_string_cst (data_in, ib);
	stmt->gimple_asm.string = TREE_STRING_POINTER (str);
      }
      /* Fallthru  */

    case GIMPLE_ASSIGN:
    case GIMPLE_CALL:
    case GIMPLE_RETURN:
    case GIMPLE_SWITCH:
    case GIMPLE_LABEL:
    case GIMPLE_COND:
    case GIMPLE_GOTO:
    case GIMPLE_DEBUG:
      for (i = 0; i < num_ops; i++)
	{
	  tree op = stream_read_tree (ib, data_in);
	  gimple_set_op (stmt, i, op);
	  if (!op)
	    continue;

	  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
	     by decl merging.  */
	  if (TREE_CODE (op) == ADDR_EXPR)
	    op = TREE_OPERAND (op, 0);
	  while (handled_component_p (op))
	    {
	      if (TREE_CODE (op) == COMPONENT_REF)
		{
		  tree field, type, tem;
		  tree closest_match = NULL_TREE;
		  field = TREE_OPERAND (op, 1);
		  type = DECL_CONTEXT (field);
		  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
		    {
		      if (TREE_CODE (tem) != FIELD_DECL)
			continue;
		      if (tem == field)
			break;
		      if (DECL_NONADDRESSABLE_P (tem)
			  == DECL_NONADDRESSABLE_P (field)
			  && gimple_compare_field_offset (tem, field))
			{
			  if (types_compatible_p (TREE_TYPE (tem),
						  TREE_TYPE (field)))
			    break;
			  else
			    closest_match = tem;
			}
		    }
		  /* In case of type mismatches across units we can fail
		     to unify some types and thus not find a proper
		     field-decl here.  */
		  if (tem == NULL_TREE)
		    {
		      /* Thus, emit a ODR violation warning.  */
		      if (warning_at (gimple_location (stmt), 0,
				      "use of type %<%E%> with two mismatching "
				      "declarations at field %<%E%>",
				      type, TREE_OPERAND (op, 1)))
			{
			  if (TYPE_FIELDS (type))
			    inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
				    "original type declared here");
			  inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
				  "field in mismatching type declared here");
			  if (TYPE_NAME (TREE_TYPE (field))
			      && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
				  == TYPE_DECL))
			    inform (DECL_SOURCE_LOCATION
				      (TYPE_NAME (TREE_TYPE (field))),
				    "type of field declared here");
			  if (closest_match
			      && TYPE_NAME (TREE_TYPE (closest_match))
			      && (TREE_CODE (TYPE_NAME
				   (TREE_TYPE (closest_match))) == TYPE_DECL))
			    inform (DECL_SOURCE_LOCATION
				      (TYPE_NAME (TREE_TYPE (closest_match))),
				    "type of mismatching field declared here");
			}
		      /* And finally fixup the types.  */
		      TREE_OPERAND (op, 0)
			= build1 (VIEW_CONVERT_EXPR, type,
				  TREE_OPERAND (op, 0));
		    }
		  else
		    TREE_OPERAND (op, 1) = tem;
		}

	      op = TREE_OPERAND (op, 0);
	    }
	}
      if (is_gimple_call (stmt))
	{
	  if (gimple_call_internal_p (stmt))
	    gimple_call_set_internal_fn
	      (stmt, streamer_read_enum (ib, internal_fn, IFN_LAST));
	  else
	    gimple_call_set_fntype (stmt, stream_read_tree (ib, data_in));
	}
      break;

    case GIMPLE_NOP:
    case GIMPLE_PREDICT:
      break;

    case GIMPLE_TRANSACTION:
      gimple_transaction_set_label (stmt, stream_read_tree (ib, data_in));
      break;

    default:
      internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
		      lto_tag_name (tag));
    }

  /* Update the properties of symbols, SSA names and labels associated
     with STMT.  */
  if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
    {
      tree lhs = gimple_get_lhs (stmt);
      if (lhs && TREE_CODE (lhs) == SSA_NAME)
	SSA_NAME_DEF_STMT (lhs) = stmt;
    }
  else if (code == GIMPLE_LABEL)
    gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
	        || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
  else if (code == GIMPLE_ASM)
    {
      unsigned i;

      for (i = 0; i < gimple_asm_noutputs (stmt); i++)
	{
	  tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
	  if (TREE_CODE (op) == SSA_NAME)
	    SSA_NAME_DEF_STMT (op) = stmt;
	}
    }

  /* Reset alias information.  */
  if (code == GIMPLE_CALL)
    gimple_call_reset_alias_info (stmt);

  /* Mark the statement modified so its operand vectors can be filled in.  */
  gimple_set_modified (stmt, true);

  return stmt;
}
static void restrict_range_to_consts()
{
  size_t i;
  unsigned num_vr_values = num_ssa_names;
  for (i = 0; i < num_vr_values; i++)
    if (vr_value[i])
      {
        value_range_t *vr = vr_value[i];
        tree type = TREE_TYPE (ssa_name(i));
        tree minimum = NULL;
        tree maximum = NULL;
        unsigned var_prec = TYPE_PRECISION(type);

	//fprintf(stderr, "%ld\n", i);

        if (INTEGRAL_TYPE_P(type) && vr->min && vr->max)
	  {
	    bool is_neg_inf = is_negative_overflow_infinity (vr->min) || 
                 (INTEGRAL_TYPE_P (type)
	           && !TYPE_UNSIGNED (type)
	           && vrp_val_is_min (vr->min));
	           
	    bool is_pos_inf = is_positive_overflow_infinity (vr->max) || 
	        (INTEGRAL_TYPE_P (type)
	         && vrp_val_is_max (vr->max));
	    if(TREE_CODE (vr->min) != INTEGER_CST && !is_neg_inf)
	    {
	      /// check if greater than zero
	      bool strict_overflow_p;
	      tree val = compare_name_with_value(GE_EXPR, ssa_name(i), integer_zero_node, &strict_overflow_p);
	      if(!strict_overflow_p && val)
	      {
	        if(integer_onep (val))
	        {
	          minimum = integer_zero_node;
	        }
	        else
	        {
	          tree neg_const;
	          unsigned prec_index = 1;
	          while(prec_index < var_prec && !strict_overflow_p)
	          {
	            neg_const = build_int_cst (type, -(((unsigned HOST_WIDE_INT)1) << prec_index));
	            tree val = compare_name_with_value(GE_EXPR, ssa_name(i), neg_const, &strict_overflow_p);
	            if(val && integer_onep (val))
	            {
	              minimum = neg_const;
	              break;
	            }
	            ++prec_index;
	          }
	        }
	      }
	    } else if(is_neg_inf)
	      minimum = vr->min;
	    
	    if(TREE_CODE (vr->max) != INTEGER_CST && !is_pos_inf)
	    {
	      bool strict_overflow_p=false;
	      tree pos_const;
	      unsigned prec_index = 0;
	      while(prec_index < var_prec && !strict_overflow_p)
	      {
	        pos_const = build_int_cst (type, (((unsigned HOST_WIDE_INT)1) << prec_index));
	        tree val = compare_name_with_value(LT_EXPR, ssa_name(i), pos_const, &strict_overflow_p);
	        if(val && integer_onep (val))
	        {
	          maximum = build_int_cst (type, (((unsigned HOST_WIDE_INT)1) << prec_index)-1);
	          break;
	        }
	        ++prec_index;
	      }
	    }
	    else if(is_pos_inf)
	      maximum = vr->max;
	      
	    if(minimum)
	    {
	      vr->min = minimum;
	      vr->type = VR_RANGE;
	    }
	    if(maximum)
	    {
	      vr->max = maximum;
	      vr->type = VR_RANGE;
	    }
	  }
    }
  // do further restrictions by exploiting assert_expr
  for (i = 0; i < num_vr_values; i++)
    if (vr_value[i])
    {
      tree type = TREE_TYPE (ssa_name(i));
      value_range_t *vr = vr_value[i];
      if(INTEGRAL_TYPE_P(type) && vr->type == VR_RANGE && vr->min && vr->max)
      {
        tree sa_var = ssa_name(i);
        GIMPLE_type def_stmt = SSA_NAME_DEF_STMT (sa_var );
        if(is_gimple_assign (def_stmt)
	  && gimple_assign_rhs_code (def_stmt) == ASSERT_EXPR)
	{
	  tree src_var = ASSERT_EXPR_VAR (gimple_assign_rhs1 (def_stmt));
	  value_range_t *src_vr = vr_value[SSA_NAME_VERSION(src_var)];
	  if(src_vr && src_vr->type == VR_RANGE && src_vr->min && src_vr->max)
	  {
	    bool strict_overflow_p=false;
	    tree val = compare_name_with_value(LT_EXPR, src_var, vr->max, &strict_overflow_p);
	    if(val && integer_onep (val))
	      vr->max = src_vr->max;
	    strict_overflow_p=false;
	    val = compare_name_with_value(GT_EXPR, src_var, vr->min, &strict_overflow_p);
	    if(val && integer_onep (val))
	      vr->min = src_vr->min;
	  }
	}
      }
    }
}
Example #23
0
static bool
verify_use (basic_block bb, basic_block def_bb, use_operand_p use_p,
	    tree stmt, bool check_abnormal, bool is_virtual,
	    bitmap names_defined_in_bb)
{
  bool err = false;
  tree ssa_name = USE_FROM_PTR (use_p);

  err = verify_ssa_name (ssa_name, is_virtual);

  if (!TREE_VISITED (ssa_name))
    if (verify_imm_links (stderr, ssa_name))
      err = true;

  TREE_VISITED (ssa_name) = 1;

  if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (ssa_name))
      && default_def (SSA_NAME_VAR (ssa_name)) == ssa_name)
    ; /* Default definitions have empty statements.  Nothing to do.  */
  else if (!def_bb)
    {
      error ("missing definition");
      err = true;
    }
  else if (bb != def_bb
	   && !dominated_by_p (CDI_DOMINATORS, bb, def_bb))
    {
      error ("definition in block %i does not dominate use in block %i",
	     def_bb->index, bb->index);
      err = true;
    }
  else if (bb == def_bb
	   && names_defined_in_bb != NULL
	   && !bitmap_bit_p (names_defined_in_bb, SSA_NAME_VERSION (ssa_name)))
    {
      error ("definition in block %i follows the use", def_bb->index);
      err = true;
    }

  if (check_abnormal
      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssa_name))
    {
      error ("SSA_NAME_OCCURS_IN_ABNORMAL_PHI should be set");
      err = true;
    }

  /* Make sure the use is in an appropriate list by checking the previous 
     element to make sure it's the same.  */
  if (use_p->prev == NULL)
    {
      error ("no immediate_use list");
      err = true;
    }
  else
    {
      tree listvar ;
      if (use_p->prev->use == NULL)
	listvar = use_p->prev->stmt;
      else
	listvar = USE_FROM_PTR (use_p->prev);
      if (listvar != ssa_name)
        {
	  error ("wrong immediate use list");
	  err = true;
	}
    }

  if (err)
    {
      fprintf (stderr, "for SSA_NAME: ");
      print_generic_expr (stderr, ssa_name, TDF_VOPS);
      fprintf (stderr, " in statement:\n");
      print_generic_stmt (stderr, stmt, TDF_VOPS);
    }

  return err;
}
Example #24
0
static bool
fini_copy_prop (void)
{
  unsigned i;

  /* Set the final copy-of value for each variable by traversing the
     copy-of chains.  */
  for (i = 1; i < num_ssa_names; i++)
    {
      tree var = ssa_name (i);
      if (!var
	  || !copy_of[i].value
	  || copy_of[i].value == var)
	continue;

      /* In theory the points-to solution of all members of the
         copy chain is their intersection.  For now we do not bother
	 to compute this but only make sure we do not lose points-to
	 information completely by setting the points-to solution
	 of the representative to the first solution we find if
	 it doesn't have one already.  */
      if (copy_of[i].value != var
	  && TREE_CODE (copy_of[i].value) == SSA_NAME)
	{
	  basic_block copy_of_bb
	    = gimple_bb (SSA_NAME_DEF_STMT (copy_of[i].value));
	  basic_block var_bb = gimple_bb (SSA_NAME_DEF_STMT (var));
	  if (POINTER_TYPE_P (TREE_TYPE (var))
	      && SSA_NAME_PTR_INFO (var)
	      && !SSA_NAME_PTR_INFO (copy_of[i].value))
	    {
	      duplicate_ssa_name_ptr_info (copy_of[i].value,
					   SSA_NAME_PTR_INFO (var));
	      /* Points-to information is cfg insensitive,
		 but alignment info might be cfg sensitive, if it
		 e.g. is derived from VRP derived non-zero bits.
		 So, do not copy alignment info if the two SSA_NAMEs
		 aren't defined in the same basic block.  */
	      if (var_bb != copy_of_bb)
		mark_ptr_info_alignment_unknown
				(SSA_NAME_PTR_INFO (copy_of[i].value));
	    }
	  else if (!POINTER_TYPE_P (TREE_TYPE (var))
		   && SSA_NAME_RANGE_INFO (var)
		   && !SSA_NAME_RANGE_INFO (copy_of[i].value)
		   && var_bb == copy_of_bb)
	    duplicate_ssa_name_range_info (copy_of[i].value,
					   SSA_NAME_RANGE_TYPE (var),
					   SSA_NAME_RANGE_INFO (var));
	}
    }

  bool changed = substitute_and_fold (get_value, NULL, true);
  if (changed)
    {
      free_numbers_of_iterations_estimates ();
      if (scev_initialized_p ())
	scev_reset ();
    }

  free (copy_of);

  return changed;
}
Example #25
0
static void
adjust_simduid_builtins (hash_table<simduid_to_vf> *htab)
{
  basic_block bb;

  FOR_EACH_BB_FN (bb, cfun)
    {
      gimple_stmt_iterator i;

      for (i = gsi_start_bb (bb); !gsi_end_p (i); )
	{
	  unsigned int vf = 1;
	  enum internal_fn ifn;
	  gimple *stmt = gsi_stmt (i);
	  tree t;
	  if (!is_gimple_call (stmt)
	      || !gimple_call_internal_p (stmt))
	    {
	      gsi_next (&i);
	      continue;
	    }
	  ifn = gimple_call_internal_fn (stmt);
	  switch (ifn)
	    {
	    case IFN_GOMP_SIMD_LANE:
	    case IFN_GOMP_SIMD_VF:
	    case IFN_GOMP_SIMD_LAST_LANE:
	      break;
	    case IFN_GOMP_SIMD_ORDERED_START:
	    case IFN_GOMP_SIMD_ORDERED_END:
	      if (integer_onep (gimple_call_arg (stmt, 0)))
		{
		  enum built_in_function bcode
		    = (ifn == IFN_GOMP_SIMD_ORDERED_START
		       ? BUILT_IN_GOMP_ORDERED_START
		       : BUILT_IN_GOMP_ORDERED_END);
		  gimple *g
		    = gimple_build_call (builtin_decl_explicit (bcode), 0);
		  tree vdef = gimple_vdef (stmt);
		  gimple_set_vdef (g, vdef);
		  SSA_NAME_DEF_STMT (vdef) = g;
		  gimple_set_vuse (g, gimple_vuse (stmt));
		  gsi_replace (&i, g, true);
		  continue;
		}
	      gsi_remove (&i, true);
	      unlink_stmt_vdef (stmt);
	      continue;
	    default:
	      gsi_next (&i);
	      continue;
	    }
	  tree arg = gimple_call_arg (stmt, 0);
	  gcc_assert (arg != NULL_TREE);
	  gcc_assert (TREE_CODE (arg) == SSA_NAME);
	  simduid_to_vf *p = NULL, data;
	  data.simduid = DECL_UID (SSA_NAME_VAR (arg));
	  /* Need to nullify loop safelen field since it's value is not
	     valid after transformation.  */
	  if (bb->loop_father && bb->loop_father->safelen > 0)
	    bb->loop_father->safelen = 0;
	  if (htab)
	    {
	      p = htab->find (&data);
	      if (p)
		vf = p->vf;
	    }
	  switch (ifn)
	    {
	    case IFN_GOMP_SIMD_VF:
	      t = build_int_cst (unsigned_type_node, vf);
	      break;
	    case IFN_GOMP_SIMD_LANE:
	      t = build_int_cst (unsigned_type_node, 0);
	      break;
	    case IFN_GOMP_SIMD_LAST_LANE:
	      t = gimple_call_arg (stmt, 1);
	      break;
	    default:
	      gcc_unreachable ();
	    }
	  update_call_from_tree (&i, t);
	  gsi_next (&i);
	}
    }
static void
use_internal_fn (gcall *call)
{
  /* We'll be inserting another call with the same arguments after the
     lhs has been set, so prevent any possible coalescing failure from
     having both values live at once.  See PR 71020.  */
  replace_abnormal_ssa_names (call);

  unsigned nconds = 0;
  auto_vec<gimple *, 12> conds;
  if (can_test_argument_range (call))
    {
      gen_shrink_wrap_conditions (call, conds, &nconds);
      gcc_assert (nconds != 0);
    }
  else
    gcc_assert (edom_only_function (call));

  internal_fn ifn = replacement_internal_fn (call);
  gcc_assert (ifn != IFN_LAST);

  /* Construct the new call, with the same arguments as the original one.  */
  auto_vec <tree, 16> args;
  unsigned int nargs = gimple_call_num_args (call);
  for (unsigned int i = 0; i < nargs; ++i)
    args.safe_push (gimple_call_arg (call, i));
  gcall *new_call = gimple_build_call_internal_vec (ifn, args);
  gimple_set_location (new_call, gimple_location (call));
  gimple_call_set_nothrow (new_call, gimple_call_nothrow_p (call));

  /* Transfer the LHS to the new call.  */
  tree lhs = gimple_call_lhs (call);
  gimple_call_set_lhs (new_call, lhs);
  gimple_call_set_lhs (call, NULL_TREE);
  SSA_NAME_DEF_STMT (lhs) = new_call;

  /* Insert the new call.  */
  gimple_stmt_iterator gsi = gsi_for_stmt (call);
  gsi_insert_before (&gsi, new_call, GSI_SAME_STMT);

  if (nconds == 0)
    {
      /* Skip the call if LHS == LHS.  If we reach here, EDOM is the only
	 valid errno value and it is used iff the result is NaN.  */
      conds.quick_push (gimple_build_cond (EQ_EXPR, lhs, lhs,
					   NULL_TREE, NULL_TREE));
      nconds++;

      /* Try replacing the original call with a direct assignment to
	 errno, via an internal function.  */
      if (set_edom_supported_p () && !stmt_ends_bb_p (call))
	{
	  gimple_stmt_iterator gsi = gsi_for_stmt (call);
	  gcall *new_call = gimple_build_call_internal (IFN_SET_EDOM, 0);
	  gimple_set_vuse (new_call, gimple_vuse (call));
	  gimple_set_vdef (new_call, gimple_vdef (call));
	  SSA_NAME_DEF_STMT (gimple_vdef (new_call)) = new_call;
	  gimple_set_location (new_call, gimple_location (call));
	  gsi_replace (&gsi, new_call, false);
	  call = new_call;
	}
    }

  shrink_wrap_one_built_in_call_with_conds (call, conds, nconds);
}
Example #27
0
static void
eliminate_tail_call (struct tailcall *t)
{
  tree param, rslt;
  gimple stmt, call;
  tree arg;
  size_t idx;
  basic_block bb, first;
  edge e;
  gimple phi;
  gimple_stmt_iterator gsi;
  gimple orig_stmt;

  stmt = orig_stmt = gsi_stmt (t->call_gsi);
  bb = gsi_bb (t->call_gsi);

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "Eliminated tail recursion in bb %d : ",
	       bb->index);
      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
      fprintf (dump_file, "\n");
    }

  gcc_assert (is_gimple_call (stmt));

  first = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));

  /* Remove the code after call_gsi that will become unreachable.  The
     possibly unreachable code in other blocks is removed later in
     cfg cleanup.  */
  gsi = t->call_gsi;
  gsi_next (&gsi);
  while (!gsi_end_p (gsi))
    {
      gimple t = gsi_stmt (gsi);
      /* Do not remove the return statement, so that redirect_edge_and_branch
	 sees how the block ends.  */
      if (gimple_code (t) == GIMPLE_RETURN)
	break;

      gsi_remove (&gsi, true);
      release_defs (t);
    }

  /* Number of executions of function has reduced by the tailcall.  */
  e = single_succ_edge (gsi_bb (t->call_gsi));
  decrease_profile (EXIT_BLOCK_PTR_FOR_FN (cfun), e->count, EDGE_FREQUENCY (e));
  decrease_profile (ENTRY_BLOCK_PTR_FOR_FN (cfun), e->count,
		    EDGE_FREQUENCY (e));
  if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
    decrease_profile (e->dest, e->count, EDGE_FREQUENCY (e));

  /* Replace the call by a jump to the start of function.  */
  e = redirect_edge_and_branch (single_succ_edge (gsi_bb (t->call_gsi)),
				first);
  gcc_assert (e);
  PENDING_STMT (e) = NULL;

  /* Add phi node entries for arguments.  The ordering of the phi nodes should
     be the same as the ordering of the arguments.  */
  for (param = DECL_ARGUMENTS (current_function_decl),
	 idx = 0, gsi = gsi_start_phis (first);
       param;
       param = DECL_CHAIN (param), idx++)
    {
      if (!arg_needs_copy_p (param))
	continue;

      arg = gimple_call_arg (stmt, idx);
      phi = gsi_stmt (gsi);
      gcc_assert (param == SSA_NAME_VAR (PHI_RESULT (phi)));

      add_phi_arg (phi, arg, e, gimple_location (stmt));
      gsi_next (&gsi);
    }

  /* Update the values of accumulators.  */
  adjust_accumulator_values (t->call_gsi, t->mult, t->add, e);

  call = gsi_stmt (t->call_gsi);
  rslt = gimple_call_lhs (call);
  if (rslt != NULL_TREE)
    {
      /* Result of the call will no longer be defined.  So adjust the
	 SSA_NAME_DEF_STMT accordingly.  */
      SSA_NAME_DEF_STMT (rslt) = gimple_build_nop ();
    }

  gsi_remove (&t->call_gsi, true);
  release_defs (call);
}
Example #28
0
static void
gen_conditions_for_pow_int_base (tree base, tree expn,
                                 vec<gimple> conds,
                                 unsigned *nconds)
{
  gimple base_def;
  tree base_val0;
  tree int_type;
  tree temp, tempn;
  tree cst0;
  gimple stmt1, stmt2;
  int bit_sz, max_exp;
  inp_domain exp_domain;

  base_def = SSA_NAME_DEF_STMT (base);
  base_val0 = gimple_assign_rhs1 (base_def);
  int_type = TREE_TYPE (base_val0);
  bit_sz = TYPE_PRECISION (int_type);
  gcc_assert (bit_sz > 0
              && bit_sz <= MAX_BASE_INT_BIT_SIZE);

  /* Determine the max exp argument value according to
     the size of the base integer.  The max exp value
     is conservatively estimated assuming IEEE754 double
     precision format.  */
  if (bit_sz == 8)
    max_exp = 128;
  else if (bit_sz == 16)
    max_exp = 64;
  else
    {
      gcc_assert (bit_sz == MAX_BASE_INT_BIT_SIZE);
      max_exp = 32;
    }

  /* For pow ((double)x, y), generate the following conditions:
     cond 1:
     temp1 = x;
     if (temp1 <= 0)

     cond 2:
     temp2 = y;
     if (temp2 > max_exp_real_cst)  */

  /* Generate condition in reverse order -- first
     the condition for the exp argument.  */

  exp_domain = get_domain (0, false, false,
                           max_exp, true, true);

  gen_conditions_for_domain (expn, exp_domain,
                             conds, nconds);

  /* Now generate condition for the base argument.
     Note it does not use the helper function
     gen_conditions_for_domain because the base
     type is integer.  */

  /* Push a separator.  */
  conds.quick_push (NULL);

  temp = create_tmp_var (int_type, "DCE_COND1");
  cst0 = build_int_cst (int_type, 0);
  stmt1 = gimple_build_assign (temp, base_val0);
  tempn = make_ssa_name (temp, stmt1);
  gimple_assign_set_lhs (stmt1, tempn);
  stmt2 = gimple_build_cond (LE_EXPR, tempn, cst0, NULL_TREE, NULL_TREE);

  conds.quick_push (stmt1);
  conds.quick_push (stmt2);
  (*nconds)++;
}
Example #29
0
static bool
check_pow (gimple pow_call)
{
  tree base, expn;
  enum tree_code bc, ec;

  if (gimple_call_num_args (pow_call) != 2)
    return false;

  base = gimple_call_arg (pow_call, 0);
  expn = gimple_call_arg (pow_call, 1);

  if (!check_target_format (expn))
    return false;

  bc = TREE_CODE (base);
  ec = TREE_CODE (expn);

  /* Folding candidates are not interesting.
     Can actually assert that it is already folded.  */
  if (ec == REAL_CST && bc == REAL_CST)
    return false;

  if (bc == REAL_CST)
    {
      /* Only handle a fixed range of constant.  */
      REAL_VALUE_TYPE mv;
      REAL_VALUE_TYPE bcv = TREE_REAL_CST (base);
      if (REAL_VALUES_EQUAL (bcv, dconst1))
        return false;
      if (REAL_VALUES_LESS (bcv, dconst1))
        return false;
      real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, 0, 1);
      if (REAL_VALUES_LESS (mv, bcv))
        return false;
      return true;
    }
  else if (bc == SSA_NAME)
    {
      tree base_val0, base_var, type;
      gimple base_def;
      int bit_sz;

      /* Only handles cases where base value is converted
         from integer values.  */
      base_def = SSA_NAME_DEF_STMT (base);
      if (gimple_code (base_def) != GIMPLE_ASSIGN)
        return false;

      if (gimple_assign_rhs_code (base_def) != FLOAT_EXPR)
        return false;
      base_val0 = gimple_assign_rhs1 (base_def);

      base_var = SSA_NAME_VAR (base_val0);
      if (!DECL_P  (base_var))
        return false;

      type = TREE_TYPE (base_var);
      if (TREE_CODE (type) != INTEGER_TYPE)
        return false;
      bit_sz = TYPE_PRECISION (type);
      /* If the type of the base is too wide,
         the resulting shrink wrapping condition
	 will be too conservative.  */
      if (bit_sz > MAX_BASE_INT_BIT_SIZE)
        return false;

      return true;
    }
  else
    return false;
}
Example #30
0
static tree
get_non_ssa_expr (tree expr)
{
  if (!expr)
    return NULL_TREE;
  switch (TREE_CODE (expr))
    {
      case VAR_DECL:
      case PARM_DECL:
      case FIELD_DECL:
        {
          if (DECL_NAME (expr))
            return expr;
          else
            return NULL_TREE;
        }
      case COMPONENT_REF:
        {
          tree base, orig_base = TREE_OPERAND (expr, 0);
          tree component, orig_component = TREE_OPERAND (expr, 1);
          base = get_non_ssa_expr (orig_base);
          if (!base)
            return NULL_TREE;
          component = get_non_ssa_expr (orig_component);
          if (!component)
            return NULL_TREE;
          /* If either BASE or COMPONENT is converted, build a new
             component reference tree.  */
          if (base != orig_base || component != orig_component)
            return build3 (COMPONENT_REF, TREE_TYPE (component),
                           base, component, NULL_TREE);
          else
            return expr;
        }
      case MEM_REF:
        {
          tree orig_base = TREE_OPERAND (expr, 0);
	  if (TREE_CODE (orig_base) == SSA_NAME)
	    {
	      tree base = get_non_ssa_expr (orig_base);
	      if (!base)
		return NULL_TREE;
	      return fold_build2 (MEM_REF, TREE_TYPE (expr),
				  base, TREE_OPERAND (expr, 1));
	    }
	  return expr;
        }
      case ARRAY_REF:
        {
          tree array, orig_array = TREE_OPERAND (expr, 0);
          tree index, orig_index = TREE_OPERAND (expr, 1);
          array = get_non_ssa_expr (orig_array);
          if (!array)
            return NULL_TREE;
          index = get_non_ssa_expr (orig_index);
          if (!index)
            return NULL_TREE;
          /* If either ARRAY or INDEX is converted, build a new array
             reference tree.  */
          if (array != orig_array || index != orig_index)
            return build4 (ARRAY_REF, TREE_TYPE (expr), array, index,
                           TREE_OPERAND (expr, 2), TREE_OPERAND (expr, 3));
          else
            return expr;
        }
      case SSA_NAME:
        {
          tree vdecl = SSA_NAME_VAR (expr);
          if ((!vdecl || DECL_ARTIFICIAL (vdecl))
              && !gimple_nop_p (SSA_NAME_DEF_STMT (expr)))
            {
              gimple def_stmt = SSA_NAME_DEF_STMT (expr);
              if (gimple_assign_single_p (def_stmt))
                vdecl = gimple_assign_rhs1 (def_stmt);
            }
          return get_non_ssa_expr (vdecl);
        }
      case INTEGER_CST:
        return expr;
      default:
        /* Return NULL_TREE for any other kind of tree nodes.  */
        return NULL_TREE;
    }
}