예제 #1
0
파일: ccmp.c 프로젝트: woailuoli993/gcc
/* Check whether G is a potential conditional compare candidate.  */
static bool
ccmp_candidate_p (gimple *g)
{
  tree rhs = gimple_assign_rhs_to_tree (g);
  tree lhs, op0, op1;
  gimple *gs0, *gs1;
  enum tree_code tcode, tcode0, tcode1;
  tcode = TREE_CODE (rhs);

  if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR)
    return false;

  lhs = gimple_assign_lhs (g);
  op0 = TREE_OPERAND (rhs, 0);
  op1 = TREE_OPERAND (rhs, 1);

  if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME)
      || !has_single_use (lhs))
    return false;

  gs0 = get_gimple_for_ssa_name (op0);
  gs1 = get_gimple_for_ssa_name (op1);
  if (!gs0 || !gs1 || !is_gimple_assign (gs0) || !is_gimple_assign (gs1)
      /* g, gs0 and gs1 must be in the same basic block, since current stage
	 is out-of-ssa.  We can not guarantee the correctness when forwording
	 the gs0 and gs1 into g whithout DATAFLOW analysis.  */
      || gimple_bb (gs0) != gimple_bb (gs1)
      || gimple_bb (gs0) != gimple_bb (g))
    return false;

  if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))
       || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))))
      || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1)))
	   || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1)))))
    return false;

  tcode0 = gimple_assign_rhs_code (gs0);
  tcode1 = gimple_assign_rhs_code (gs1);
  if (TREE_CODE_CLASS (tcode0) == tcc_comparison
      && TREE_CODE_CLASS (tcode1) == tcc_comparison)
    return true;
  if (TREE_CODE_CLASS (tcode0) == tcc_comparison
      && ccmp_candidate_p (gs1))
    return true;
  else if (TREE_CODE_CLASS (tcode1) == tcc_comparison
	   && ccmp_candidate_p (gs0))
    return true;
  /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since
     there is no way to set the CC flag.  */
  return false;
}
예제 #2
0
static bool
widened_name_p (tree name, tree use_stmt, tree *half_type, tree *def_stmt)
{
  tree dummy;
  loop_vec_info loop_vinfo;
  stmt_vec_info stmt_vinfo;
  tree expr;
  tree type = TREE_TYPE (name);
  tree oprnd0;
  enum vect_def_type dt;
  tree def;

  stmt_vinfo = vinfo_for_stmt (use_stmt);
  loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);

  if (!vect_is_simple_use (name, loop_vinfo, def_stmt, &def, &dt))
    return false;

  if (dt != vect_loop_def
      && dt != vect_invariant_def && dt != vect_constant_def)
    return false;

  if (! *def_stmt)
    return false;

  if (TREE_CODE (*def_stmt) != MODIFY_EXPR)
    return false;

  expr = TREE_OPERAND (*def_stmt, 1);
  if (TREE_CODE (expr) != NOP_EXPR)
    return false;

  oprnd0 = TREE_OPERAND (expr, 0);

  *half_type = TREE_TYPE (oprnd0);
  if (!INTEGRAL_TYPE_P (type) || !INTEGRAL_TYPE_P (*half_type)
      || (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (*half_type))
      || (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
    return false;

  if (!vect_is_simple_use (oprnd0, loop_vinfo, &dummy, &dummy, &dt))
    return false;

  if (dt != vect_invariant_def && dt != vect_constant_def
      && dt != vect_loop_def)
    return false;

  return true;
}
예제 #3
0
bool
cilkplus_an_triplet_types_ok_p (location_t loc, tree start_index, tree length,
				tree stride, tree type)
{
  size_t stride_rank = 0, length_rank = 0, start_rank = 0;
  if (!TREE_TYPE (start_index) || !INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
    {
      error_at (loc, "start-index of array notation triplet is not an integer");
      return false;
    }
  if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length)))
    {
      error_at (loc, "length of array notation triplet is not an integer");
      return false;
    }
  if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
    {
      error_at (loc, "stride of array notation triplet is not an integer");
      return false;
    }
  if (TREE_CODE (type) == FUNCTION_TYPE)
    {
      error_at (loc, "array notation cannot be used with function type");
      return false;
    }
  if (!find_rank (loc, start_index, start_index, false, &start_rank)
      || !find_rank (loc, length, length, false, &length_rank)
      || !find_rank (loc, stride, stride, false, &stride_rank))
    return false;

  if (start_rank != 0)
    {
      error_at (loc, "rank of an array notation triplet%'s start-index is not "
		"zero");
      return false;
    }
  if (length_rank != 0)
    {
      error_at (loc, "rank of an array notation triplet%'s length is not zero");
      return false;
    }
  if (stride_rank != 0)
    {
      error_at (loc, "rank of array notation triplet%'s stride is not zero");
      return false;
    }
  return true;
}
예제 #4
0
tree
build_real_imag_expr (location_t location, enum tree_code code, tree arg)
{
  tree ret;
  tree arg_type = TREE_TYPE (arg);

  gcc_assert (code == REALPART_EXPR || code == IMAGPART_EXPR);

  if (TREE_CODE (arg_type) == COMPLEX_TYPE)
    {
      ret = build1 (code, TREE_TYPE (TREE_TYPE (arg)), arg);
      SET_EXPR_LOCATION (ret, location);
    }
  else if (INTEGRAL_TYPE_P (arg_type) || SCALAR_FLOAT_TYPE_P (arg_type))
    {
      ret = (code == REALPART_EXPR
	     ? arg
	     : omit_one_operand_loc (location, arg_type,
				     integer_zero_node, arg));
    }
  else
    {
      error_at (location, "wrong type argument to %s",
		code == REALPART_EXPR ? "__real" : "__imag");
      ret = error_mark_node;
    }

  return ret;
}
예제 #5
0
static bool
widened_name_p (tree name, gimple use_stmt, tree *half_type, gimple *def_stmt,
		bool check_sign)
{
  tree dummy;
  gimple dummy_gimple;
  loop_vec_info loop_vinfo;
  stmt_vec_info stmt_vinfo;
  tree type = TREE_TYPE (name);
  tree oprnd0;
  enum vect_def_type dt;
  tree def;

  stmt_vinfo = vinfo_for_stmt (use_stmt);
  loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);

  if (!vect_is_simple_use (name, loop_vinfo, NULL, def_stmt, &def, &dt))
    return false;

  if (dt != vect_internal_def
      && dt != vect_external_def && dt != vect_constant_def)
    return false;

  if (! *def_stmt)
    return false;

  if (!is_gimple_assign (*def_stmt))
    return false;

  if (gimple_assign_rhs_code (*def_stmt) != NOP_EXPR)
    return false;

  oprnd0 = gimple_assign_rhs1 (*def_stmt);

  *half_type = TREE_TYPE (oprnd0);
  if (!INTEGRAL_TYPE_P (type) || !INTEGRAL_TYPE_P (*half_type)
      || ((TYPE_UNSIGNED (type) != TYPE_UNSIGNED (*half_type)) && check_sign)
      || (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
    return false;

  if (!vect_is_simple_use (oprnd0, loop_vinfo, NULL, &dummy_gimple, &dummy,
                           &dt))
    return false;

  return true;
}
예제 #6
0
파일: c-omp.c 프로젝트: FilipinOTech/gcc
tree
c_finish_omp_atomic (location_t loc, enum tree_code code, tree lhs, tree rhs)
{
  tree x, type, addr;

  if (lhs == error_mark_node || rhs == error_mark_node)
    return error_mark_node;

  /* ??? According to one reading of the OpenMP spec, complex type are
     supported, but there are no atomic stores for any architecture.
     But at least icc 9.0 doesn't support complex types here either.
     And lets not even talk about vector types...  */
  type = TREE_TYPE (lhs);
  if (!INTEGRAL_TYPE_P (type)
      && !POINTER_TYPE_P (type)
      && !SCALAR_FLOAT_TYPE_P (type))
    {
      error_at (loc, "invalid expression type for %<#pragma omp atomic%>");
      return error_mark_node;
    }

  /* ??? Validate that rhs does not overlap lhs.  */

  /* Take and save the address of the lhs.  From then on we'll reference it
     via indirection.  */
  addr = build_unary_op (loc, ADDR_EXPR, lhs, 0);
  if (addr == error_mark_node)
    return error_mark_node;
  addr = save_expr (addr);
  if (TREE_CODE (addr) != SAVE_EXPR
      && (TREE_CODE (addr) != ADDR_EXPR
	  || TREE_CODE (TREE_OPERAND (addr, 0)) != VAR_DECL))
    {
      /* Make sure LHS is simple enough so that goa_lhs_expr_p can recognize
	 it even after unsharing function body.  */
      tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL);
      DECL_CONTEXT (var) = current_function_decl;
      addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL);
    }
  lhs = build_indirect_ref (loc, addr, RO_NULL);

  /* There are lots of warnings, errors, and conversions that need to happen
     in the course of interpreting a statement.  Use the normal mechanisms
     to do this, and then take it apart again.  */
  x = build_modify_expr (input_location, lhs, NULL_TREE, code,
      			 input_location, rhs, NULL_TREE);
  if (x == error_mark_node)
    return error_mark_node;
  gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
  rhs = TREE_OPERAND (x, 1);

  /* Punt the actual generation of atomic operations to common code.  */
  x = build2 (OMP_ATOMIC, void_type_node, addr, rhs);
  SET_EXPR_LOCATION (x, loc);
  return x;
}
예제 #7
0
/* Classify an invariant tree into integer, float, or other, so that
   we can sort them to be near other constants of the same type.  */
static inline int
constant_type (tree t)
{
  if (INTEGRAL_TYPE_P (TREE_TYPE (t)))
    return INTEGER_CONST_TYPE;
  else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (t)))
    return FLOAT_CONST_TYPE;
  else
    return OTHER_CONST_TYPE;
}
static void
insert_trap_and_remove_trailing_statements (gimple_stmt_iterator *si_p, tree op)
{
  /* We want the NULL pointer dereference to actually occur so that
     code that wishes to catch the signal can do so.

     If the dereference is a load, then there's nothing to do as the
     LHS will be a throw-away SSA_NAME and the RHS is the NULL dereference.

     If the dereference is a store and we can easily transform the RHS,
     then simplify the RHS to enable more DCE.   Note that we require the
     statement to be a GIMPLE_ASSIGN which filters out calls on the RHS.  */
  gimple stmt = gsi_stmt (*si_p);
  if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
      && is_gimple_assign (stmt)
      && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
    {
      /* We just need to turn the RHS into zero converted to the proper
         type.  */
      tree type = TREE_TYPE (gimple_assign_lhs (stmt));
      gimple_assign_set_rhs_code (stmt, INTEGER_CST);
      gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
      update_stmt (stmt);
    }

  gimple new_stmt
    = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
  gimple_seq seq = NULL;
  gimple_seq_add_stmt (&seq, new_stmt);

  /* If we had a NULL pointer dereference, then we want to insert the
     __builtin_trap after the statement, for the other cases we want
     to insert before the statement.  */
  if (walk_stmt_load_store_ops (stmt, (void *)op,
			        check_loadstore,
				check_loadstore))
    gsi_insert_after (si_p, seq, GSI_NEW_STMT);
  else
    gsi_insert_before (si_p, seq, GSI_NEW_STMT);

  /* We must remove statements from the end of the block so that we
     never reference a released SSA_NAME.  */
  basic_block bb = gimple_bb (gsi_stmt (*si_p));
  for (gimple_stmt_iterator si = gsi_last_bb (bb);
       gsi_stmt (si) != gsi_stmt (*si_p);
       si = gsi_last_bb (bb))
    {
      stmt = gsi_stmt (si);
      unlink_stmt_vdef (stmt);
      gsi_remove (&si, true);
      release_defs (stmt);
    }
}
예제 #9
0
파일: ubsan.c 프로젝트: didemoto/gcc
static void
instrument_si_overflow (gimple_stmt_iterator gsi)
{
  gimple stmt = gsi_stmt (gsi);
  tree_code code = gimple_assign_rhs_code (stmt);
  tree lhs = gimple_assign_lhs (stmt);
  tree lhstype = TREE_TYPE (lhs);
  tree a, b;
  gimple g;

  /* If this is not a signed operation, don't instrument anything here.
     Also punt on bit-fields.  */
  if (!INTEGRAL_TYPE_P (lhstype)
      || TYPE_OVERFLOW_WRAPS (lhstype)
      || GET_MODE_BITSIZE (TYPE_MODE (lhstype)) != TYPE_PRECISION (lhstype))
    return;

  switch (code)
    {
    case MINUS_EXPR:
    case PLUS_EXPR:
    case MULT_EXPR:
      /* Transform
	 i = u {+,-,*} 5;
	 into
	 i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5);  */
      a = gimple_assign_rhs1 (stmt);
      b = gimple_assign_rhs2 (stmt);
      g = gimple_build_call_internal (code == PLUS_EXPR
				      ? IFN_UBSAN_CHECK_ADD
				      : code == MINUS_EXPR
				      ? IFN_UBSAN_CHECK_SUB
				      : IFN_UBSAN_CHECK_MUL, 2, a, b);
      gimple_call_set_lhs (g, lhs);
      gsi_replace (&gsi, g, false);
      break;
    case NEGATE_EXPR:
      /* Represent i = -u;
	 as
	 i = UBSAN_CHECK_SUB (0, u);  */
      a = build_int_cst (lhstype, 0);
      b = gimple_assign_rhs1 (stmt);
      g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
      gimple_call_set_lhs (g, lhs);
      gsi_replace (&gsi, g, false);
      break;
    default:
      break;
    }
}
예제 #10
0
파일: ubsan.c 프로젝트: acoxepochlabs/gcc
static unsigned short
get_ubsan_type_info_for_type (tree type)
{
  gcc_assert (TYPE_SIZE (type) && tree_fits_uhwi_p (TYPE_SIZE (type)));
  if (TREE_CODE (type) == REAL_TYPE)
    return tree_to_uhwi (TYPE_SIZE (type));
  else if (INTEGRAL_TYPE_P (type))
    {
      int prec = exact_log2 (tree_to_uhwi (TYPE_SIZE (type)));
      gcc_assert (prec != -1);
      return (prec << 1) | !TYPE_UNSIGNED (type);
    }
  else
    return 0;
}
예제 #11
0
tree
java_signed_or_unsigned_type (int unsignedp, tree type)
{
  if (! INTEGRAL_TYPE_P (type))
    return type;
  if (TYPE_PRECISION (type) == TYPE_PRECISION (int_type_node))
    return unsignedp ? unsigned_int_type_node : int_type_node;
  if (TYPE_PRECISION (type) == TYPE_PRECISION (byte_type_node))
    return unsignedp ? unsigned_byte_type_node : byte_type_node;
  if (TYPE_PRECISION (type) == TYPE_PRECISION (short_type_node))
    return unsignedp ? unsigned_short_type_node : short_type_node;
  if (TYPE_PRECISION (type) == TYPE_PRECISION (long_type_node))
    return unsignedp ? unsigned_long_type_node : long_type_node;
  return type;
}
예제 #12
0
파일: c-omp.c 프로젝트: FilipinOTech/gcc
static tree
check_omp_for_incr_expr (location_t loc, tree exp, tree decl)
{
  tree t;

  if (!INTEGRAL_TYPE_P (TREE_TYPE (exp))
      || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl)))
    return error_mark_node;

  if (exp == decl)
    return build_int_cst (TREE_TYPE (exp), 0);

  switch (TREE_CODE (exp))
    {
    CASE_CONVERT:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_convert_loc (loc, TREE_TYPE (exp), t);
      break;
    case MINUS_EXPR:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, MINUS_EXPR,
			    TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
      break;
    case PLUS_EXPR:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, PLUS_EXPR,
			    TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 1), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, PLUS_EXPR,
			    TREE_TYPE (exp), TREE_OPERAND (exp, 0), t);
      break;
    default:
      break;
    }

  return error_mark_node;
}
예제 #13
0
파일: c-ubsan.c 프로젝트: WojciechMigda/gcc
tree
ubsan_instrument_shift (location_t loc, enum tree_code code,
			tree op0, tree op1)
{
  tree t, tt = NULL_TREE;
  tree type0 = TREE_TYPE (op0);
  tree type1 = TREE_TYPE (op1);
  if (!INTEGRAL_TYPE_P (type0))
    return NULL_TREE;

  tree op1_utype = unsigned_type_for (type1);
  HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
  tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);

  op0 = unshare_expr (op0);
  op1 = unshare_expr (op1);

  t = fold_convert_loc (loc, op1_utype, op1);
  t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);

  /* If this is not a signed operation, don't perform overflow checks.
     Also punt on bit-fields.  */
  if (TYPE_OVERFLOW_WRAPS (type0)
      || GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0)
      || (flag_sanitize & SANITIZE_SHIFT_BASE) == 0)
    ;

  /* For signed x << y, in C99/C11, the following:
     (unsigned) x >> (uprecm1 - y)
     if non-zero, is undefined.  */
  else if (code == LSHIFT_EXPR && flag_isoc99 && cxx_dialect < cxx11)
    {
      tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
			    fold_convert (op1_utype, unshare_expr (op1)));
      tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
      tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
      tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
			build_int_cst (TREE_TYPE (tt), 0));
    }

  /* For signed x << y, in C++11 and later, the following:
     x < 0 || ((unsigned) x >> (uprecm1 - y))
     if > 1, is undefined.  */
  else if (code == LSHIFT_EXPR && cxx_dialect >= cxx11)
    {
      tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
			    fold_convert (op1_utype, unshare_expr (op1)));
      tt = fold_convert_loc (loc, unsigned_type_for (type0),
			     unshare_expr (op0));
      tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
      tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
			build_int_cst (TREE_TYPE (tt), 1));
      x = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op0),
		       build_int_cst (type0, 0));
      tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
    }

  /* If the condition was folded to 0, no need to instrument
     this expression.  */
  if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt)))
    return NULL_TREE;

  /* In case we have a SAVE_EXPR in a conditional context, we need to
     make sure it gets evaluated before the condition.  */
  t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);

  enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
  tree else_t = void_node;
  if (tt)
    {
      if ((flag_sanitize & SANITIZE_SHIFT_EXPONENT) == 0)
	{
	  t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
	  t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
	  recover_kind = SANITIZE_SHIFT_BASE;
	}
      else
	{
	  if (flag_sanitize_undefined_trap_on_error
	      || ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
		  == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
	    t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
	  else
	    else_t = tt;
	}
    }

  if (flag_sanitize_undefined_trap_on_error)
    tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
  else
    {
      tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc,
				     ubsan_type_descriptor (type0),
				     ubsan_type_descriptor (type1), NULL_TREE,
				     NULL_TREE);
      data = build_fold_addr_expr_loc (loc, data);

      enum built_in_function bcode
	= (flag_sanitize_recover & recover_kind)
	  ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
	  : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
      tt = builtin_decl_explicit (bcode);
      op0 = unshare_expr (op0);
      op1 = unshare_expr (op1);
      tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
				ubsan_encode_value (op1));
      if (else_t != void_node)
	{
	  bcode = (flag_sanitize_recover & SANITIZE_SHIFT_BASE)
		  ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
		  : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
	  tree else_tt = builtin_decl_explicit (bcode);
	  op0 = unshare_expr (op0);
	  op1 = unshare_expr (op1);
	  else_tt = build_call_expr_loc (loc, else_tt, 3, data,
					 ubsan_encode_value (op0),
					 ubsan_encode_value (op1));
	  else_t = fold_build3 (COND_EXPR, void_type_node, else_t,
				else_tt, void_node);
	}
    }
  t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);

  return t;
}
예제 #14
0
static bool
process_assignment (gimple stmt, gimple_stmt_iterator call, tree *m,
		    tree *a, tree *ass_var)
{
  tree op0, op1 = NULL_TREE, non_ass_var = NULL_TREE;
  tree dest = gimple_assign_lhs (stmt);
  enum tree_code code = gimple_assign_rhs_code (stmt);
  enum gimple_rhs_class rhs_class = get_gimple_rhs_class (code);
  tree src_var = gimple_assign_rhs1 (stmt);

  /* See if this is a simple copy operation of an SSA name to the function
     result.  In that case we may have a simple tail call.  Ignore type
     conversions that can never produce extra code between the function
     call and the function return.  */
  if ((rhs_class == GIMPLE_SINGLE_RHS || gimple_assign_cast_p (stmt))
      && (TREE_CODE (src_var) == SSA_NAME))
    {
      /* Reject a tailcall if the type conversion might need
	 additional code.  */
      if (gimple_assign_cast_p (stmt))
	{
	  if (TYPE_MODE (TREE_TYPE (dest)) != TYPE_MODE (TREE_TYPE (src_var)))
	    return false;

	  /* Even if the type modes are the same, if the precision of the
	     type is smaller than mode's precision,
	     reduce_to_bit_field_precision would generate additional code.  */
	  if (INTEGRAL_TYPE_P (TREE_TYPE (dest))
	      && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (dest)))
		  > TYPE_PRECISION (TREE_TYPE (dest))))
	    return false;
	}

      if (src_var != *ass_var)
	return false;

      *ass_var = dest;
      return true;
    }

  switch (rhs_class)
    {
    case GIMPLE_BINARY_RHS:
      op1 = gimple_assign_rhs2 (stmt);

      /* Fall through.  */

    case GIMPLE_UNARY_RHS:
      op0 = gimple_assign_rhs1 (stmt);
      break;

    default:
      return false;
    }

  /* Accumulator optimizations will reverse the order of operations.
     We can only do that for floating-point types if we're assuming
     that addition and multiplication are associative.  */
  if (!flag_associative_math)
    if (FLOAT_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
      return false;

  if (rhs_class == GIMPLE_UNARY_RHS)
    ;
  else if (op0 == *ass_var
	   && (non_ass_var = independent_of_stmt_p (op1, stmt, call)))
    ;
  else if (op1 == *ass_var
	   && (non_ass_var = independent_of_stmt_p (op0, stmt, call)))
    ;
  else
    return false;

  switch (code)
    {
    case PLUS_EXPR:
      *a = non_ass_var;
      *ass_var = dest;
      return true;

    case POINTER_PLUS_EXPR:
      if (op0 != *ass_var)
	return false;
      *a = non_ass_var;
      *ass_var = dest;
      return true;

    case MULT_EXPR:
      *m = non_ass_var;
      *ass_var = dest;
      return true;

    case NEGATE_EXPR:
      *m = build_minus_one_cst (TREE_TYPE (op0));
      *ass_var = dest;
      return true;

    case MINUS_EXPR:
      if (*ass_var == op0)
        *a = fold_build1 (NEGATE_EXPR, TREE_TYPE (non_ass_var), non_ass_var);
      else
        {
	  *m = build_minus_one_cst (TREE_TYPE (non_ass_var));
          *a = fold_build1 (NEGATE_EXPR, TREE_TYPE (non_ass_var), non_ass_var);
        }

      *ass_var = dest;
      return true;

      /* TODO -- Handle POINTER_PLUS_EXPR.  */

    default:
      return false;
    }
}
예제 #15
0
파일: c-omp.c 프로젝트: austinsc/GCCXML
tree
c_finish_omp_for (location_t locus, tree decl, tree init, tree cond,
                  tree incr, tree body, tree pre_body)
{
    location_t elocus = locus;
    bool fail = false;

    if (EXPR_HAS_LOCATION (init))
        elocus = EXPR_LOCATION (init);

    /* Validate the iteration variable.  */
    if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
    {
        error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
        fail = true;
    }
    if (TYPE_UNSIGNED (TREE_TYPE (decl)))
        warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl);

    /* In the case of "for (int i = 0...)", init will be a decl.  It should
       have a DECL_INITIAL that we can turn into an assignment.  */
    if (init == decl)
    {
        elocus = DECL_SOURCE_LOCATION (decl);

        init = DECL_INITIAL (decl);
        if (init == NULL)
        {
            error ("%H%qE is not initialized", &elocus, decl);
            init = integer_zero_node;
            fail = true;
        }

        init = build_modify_expr (decl, NOP_EXPR, init);
        SET_EXPR_LOCATION (init, elocus);
    }
    gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
    gcc_assert (TREE_OPERAND (init, 0) == decl);

    if (cond == NULL_TREE)
    {
        error ("%Hmissing controlling predicate", &elocus);
        fail = true;
    }
    else
    {
        bool cond_ok = false;

        if (EXPR_HAS_LOCATION (cond))
            elocus = EXPR_LOCATION (cond);

        if (TREE_CODE (cond) == LT_EXPR
                || TREE_CODE (cond) == LE_EXPR
                || TREE_CODE (cond) == GT_EXPR
                || TREE_CODE (cond) == GE_EXPR)
        {
            tree op0 = TREE_OPERAND (cond, 0);
            tree op1 = TREE_OPERAND (cond, 1);

            /* 2.5.1.  The comparison in the condition is computed in the type
               of DECL, otherwise the behavior is undefined.

               For example:
               long n; int i;
               i < n;

               according to ISO will be evaluated as:
               (long)i < n;

               We want to force:
               i < (int)n;  */
            if (TREE_CODE (op0) == NOP_EXPR
                    && decl == TREE_OPERAND (op0, 0))
            {
                TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
                TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
                                                      TREE_OPERAND (cond, 1));
            }
            else if (TREE_CODE (op1) == NOP_EXPR
                     && decl == TREE_OPERAND (op1, 0))
            {
                TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
                TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
                                                      TREE_OPERAND (cond, 0));
            }

            if (decl == TREE_OPERAND (cond, 0))
                cond_ok = true;
            else if (decl == TREE_OPERAND (cond, 1))
            {
                TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
                TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
                TREE_OPERAND (cond, 0) = decl;
                cond_ok = true;
            }
        }

        if (!cond_ok)
        {
            error ("%Hinvalid controlling predicate", &elocus);
            fail = true;
        }
    }

    if (incr == NULL_TREE)
    {
        error ("%Hmissing increment expression", &elocus);
        fail = true;
    }
    else
    {
        bool incr_ok = false;

        if (EXPR_HAS_LOCATION (incr))
            elocus = EXPR_LOCATION (incr);

        /* Check all the valid increment expressions: v++, v--, ++v, --v,
           v = v + incr, v = incr + v and v = v - incr.  */
        switch (TREE_CODE (incr))
        {
        case POSTINCREMENT_EXPR:
        case PREINCREMENT_EXPR:
        case POSTDECREMENT_EXPR:
        case PREDECREMENT_EXPR:
            incr_ok = (TREE_OPERAND (incr, 0) == decl);
            break;

        case MODIFY_EXPR:
            if (TREE_OPERAND (incr, 0) != decl)
                break;
            if (TREE_OPERAND (incr, 1) == decl)
                break;
            if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
                    && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
                        || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
                incr_ok = true;
            else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
                     && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
                incr_ok = true;
            else
            {
                tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl);
                if (t != error_mark_node)
                {
                    incr_ok = true;
                    t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
                    incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
                }
            }
            break;

        default:
            break;
        }
        if (!incr_ok)
        {
            error ("%Hinvalid increment expression", &elocus);
            fail = true;
        }
    }

    if (fail)
        return NULL;
    else
    {
        tree t = make_node (OMP_FOR);

        TREE_TYPE (t) = void_type_node;
        OMP_FOR_INIT (t) = init;
        OMP_FOR_COND (t) = cond;
        OMP_FOR_INCR (t) = incr;
        OMP_FOR_BODY (t) = body;
        OMP_FOR_PRE_BODY (t) = pre_body;

        SET_EXPR_LOCATION (t, locus);
        return add_stmt (t);
    }
}
예제 #16
0
static bool
forward_propagate_addr_expr_1 (tree name, tree def_rhs,
			       gimple_stmt_iterator *use_stmt_gsi,
			       bool single_use_p)
{
  tree lhs, rhs, rhs2, array_ref;
  tree *rhsp, *lhsp;
  gimple use_stmt = gsi_stmt (*use_stmt_gsi);
  enum tree_code rhs_code;
  bool res = true;

  gcc_assert (TREE_CODE (def_rhs) == ADDR_EXPR);

  lhs = gimple_assign_lhs (use_stmt);
  rhs_code = gimple_assign_rhs_code (use_stmt);
  rhs = gimple_assign_rhs1 (use_stmt);

  /* Trivial cases.  The use statement could be a trivial copy or a
     useless conversion.  Recurse to the uses of the lhs as copyprop does
     not copy through different variant pointers and FRE does not catch
     all useless conversions.  Treat the case of a single-use name and
     a conversion to def_rhs type separate, though.  */
  if (TREE_CODE (lhs) == SSA_NAME
      && ((rhs_code == SSA_NAME && rhs == name)
	  || CONVERT_EXPR_CODE_P (rhs_code)))
    {
      /* Only recurse if we don't deal with a single use or we cannot
	 do the propagation to the current statement.  In particular
	 we can end up with a conversion needed for a non-invariant
	 address which we cannot do in a single statement.  */
      if (!single_use_p
	  || (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs))
	      && (!is_gimple_min_invariant (def_rhs)
		  || (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
		      && POINTER_TYPE_P (TREE_TYPE (def_rhs))
		      && (TYPE_PRECISION (TREE_TYPE (lhs))
			  > TYPE_PRECISION (TREE_TYPE (def_rhs)))))))
	return forward_propagate_addr_expr (lhs, def_rhs);

      gimple_assign_set_rhs1 (use_stmt, unshare_expr (def_rhs));
      if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))
	gimple_assign_set_rhs_code (use_stmt, TREE_CODE (def_rhs));
      else
	gimple_assign_set_rhs_code (use_stmt, NOP_EXPR);
      return true;
    }

  /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
     ADDR_EXPR will not appear on the LHS.  */
  lhsp = gimple_assign_lhs_ptr (use_stmt);
  while (handled_component_p (*lhsp))
    lhsp = &TREE_OPERAND (*lhsp, 0);
  lhs = *lhsp;

  /* Now see if the LHS node is an INDIRECT_REF using NAME.  If so,
     propagate the ADDR_EXPR into the use of NAME and fold the result.  */
  if (TREE_CODE (lhs) == INDIRECT_REF
      && TREE_OPERAND (lhs, 0) == name)
    {
      if (may_propagate_address_into_dereference (def_rhs, lhs)
	  && (lhsp != gimple_assign_lhs_ptr (use_stmt)
	      || useless_type_conversion_p
	           (TREE_TYPE (TREE_OPERAND (def_rhs, 0)), TREE_TYPE (rhs))))
	{
	  *lhsp = unshare_expr (TREE_OPERAND (def_rhs, 0));
	  fold_stmt_inplace (use_stmt);
	  tidy_after_forward_propagate_addr (use_stmt);

	  /* Continue propagating into the RHS if this was not the only use.  */
	  if (single_use_p)
	    return true;
	}
      else
	/* We can have a struct assignment dereferencing our name twice.
	   Note that we didn't propagate into the lhs to not falsely
	   claim we did when propagating into the rhs.  */
	res = false;
    }

  /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
     nodes from the RHS.  */
  rhsp = gimple_assign_rhs1_ptr (use_stmt);
  while (handled_component_p (*rhsp)
	 || TREE_CODE (*rhsp) == ADDR_EXPR)
    rhsp = &TREE_OPERAND (*rhsp, 0);
  rhs = *rhsp;

  /* Now see if the RHS node is an INDIRECT_REF using NAME.  If so,
     propagate the ADDR_EXPR into the use of NAME and fold the result.  */
  if (TREE_CODE (rhs) == INDIRECT_REF
      && TREE_OPERAND (rhs, 0) == name
      && may_propagate_address_into_dereference (def_rhs, rhs))
    {
      *rhsp = unshare_expr (TREE_OPERAND (def_rhs, 0));
      fold_stmt_inplace (use_stmt);
      tidy_after_forward_propagate_addr (use_stmt);
      return res;
    }

  /* Now see if the RHS node is an INDIRECT_REF using NAME.  If so,
     propagate the ADDR_EXPR into the use of NAME and try to
     create a VCE and fold the result.  */
  if (TREE_CODE (rhs) == INDIRECT_REF
      && TREE_OPERAND (rhs, 0) == name
      && TYPE_SIZE (TREE_TYPE (rhs))
      && TYPE_SIZE (TREE_TYPE (TREE_OPERAND (def_rhs, 0)))
      /* Function decls should not be used for VCE either as it could be a
         function descriptor that we want and not the actual function code.  */
      && TREE_CODE (TREE_OPERAND (def_rhs, 0)) != FUNCTION_DECL
      /* We should not convert volatile loads to non volatile loads. */
      && !TYPE_VOLATILE (TREE_TYPE (rhs))
      && !TYPE_VOLATILE (TREE_TYPE (TREE_OPERAND (def_rhs, 0)))
      && operand_equal_p (TYPE_SIZE (TREE_TYPE (rhs)),
			  TYPE_SIZE (TREE_TYPE (TREE_OPERAND (def_rhs, 0))), 0)
      /* Make sure we only do TBAA compatible replacements.  */
      && get_alias_set (TREE_OPERAND (def_rhs, 0)) == get_alias_set (rhs))
   {
     tree def_rhs_base, new_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
     new_rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), new_rhs);
     if (TREE_CODE (new_rhs) != VIEW_CONVERT_EXPR)
       {
	 /* If we have folded the VIEW_CONVERT_EXPR then the result is only
	    valid if we can replace the whole rhs of the use statement.  */
	 if (rhs != gimple_assign_rhs1 (use_stmt))
	   return false;
	 new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs, true, NULL,
					     true, GSI_NEW_STMT);
	 gimple_assign_set_rhs1 (use_stmt, new_rhs);
	 tidy_after_forward_propagate_addr (use_stmt);
	 return res;
       }
     /* If the defining rhs comes from an indirect reference, then do not
        convert into a VIEW_CONVERT_EXPR.  */
     def_rhs_base = TREE_OPERAND (def_rhs, 0);
     while (handled_component_p (def_rhs_base))
       def_rhs_base = TREE_OPERAND (def_rhs_base, 0);
     if (!INDIRECT_REF_P (def_rhs_base))
       {
	 /* We may have arbitrary VIEW_CONVERT_EXPRs in a nested component
	    reference.  Place it there and fold the thing.  */
	 *rhsp = new_rhs;
	 fold_stmt_inplace (use_stmt);
	 tidy_after_forward_propagate_addr (use_stmt);
	 return res;
       }
   }

  /* If the use of the ADDR_EXPR is not a POINTER_PLUS_EXPR, there
     is nothing to do. */
  if (gimple_assign_rhs_code (use_stmt) != POINTER_PLUS_EXPR
      || gimple_assign_rhs1 (use_stmt) != name)
    return false;

  /* The remaining cases are all for turning pointer arithmetic into
     array indexing.  They only apply when we have the address of
     element zero in an array.  If that is not the case then there
     is nothing to do.  */
  array_ref = TREE_OPERAND (def_rhs, 0);
  if (TREE_CODE (array_ref) != ARRAY_REF
      || TREE_CODE (TREE_TYPE (TREE_OPERAND (array_ref, 0))) != ARRAY_TYPE
      || TREE_CODE (TREE_OPERAND (array_ref, 1)) != INTEGER_CST)
    return false;

  rhs2 = gimple_assign_rhs2 (use_stmt);
  /* Try to optimize &x[C1] p+ C2 where C2 is a multiple of the size
     of the elements in X into &x[C1 + C2/element size].  */
  if (TREE_CODE (rhs2) == INTEGER_CST)
    {
      tree new_rhs = maybe_fold_stmt_addition (gimple_location (use_stmt),
	  				       TREE_TYPE (def_rhs),
					       def_rhs, rhs2);
      if (new_rhs)
	{
	  tree type = TREE_TYPE (gimple_assign_lhs (use_stmt));
	  new_rhs = unshare_expr (new_rhs);
	  if (!useless_type_conversion_p (type, TREE_TYPE (new_rhs)))
	    {
	      if (!is_gimple_min_invariant (new_rhs))
		new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs,
						    true, NULL_TREE,
						    true, GSI_SAME_STMT);
	      new_rhs = fold_convert (type, new_rhs);
	    }
	  gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
	  use_stmt = gsi_stmt (*use_stmt_gsi);
	  update_stmt (use_stmt);
	  tidy_after_forward_propagate_addr (use_stmt);
	  return true;
	}
    }

  /* Try to optimize &x[0] p+ OFFSET where OFFSET is defined by
     converting a multiplication of an index by the size of the
     array elements, then the result is converted into the proper
     type for the arithmetic.  */
  if (TREE_CODE (rhs2) == SSA_NAME
      && integer_zerop (TREE_OPERAND (array_ref, 1))
      && useless_type_conversion_p (TREE_TYPE (name), TREE_TYPE (def_rhs))
      /* Avoid problems with IVopts creating PLUS_EXPRs with a
	 different type than their operands.  */
      && useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))
    return forward_propagate_addr_into_variable_array_index (rhs2, def_rhs,
							     use_stmt_gsi);
  return false;
}
예제 #17
0
파일: tree-browser.c 프로젝트: 3F/gcc
void
browse_tree (tree begin)
{
  tree head;
  TB_CODE tbc = TB_UNUSED_COMMAND;
  ssize_t rd;
  char *input = NULL;
  long input_size = 0;

  fprintf (TB_OUT_FILE, "\nTree Browser\n");

#define TB_SET_HEAD(N) do {                                           \
  vec_safe_push (TB_history_stack, N);                                \
  head = N;                                                           \
  if (TB_verbose)                                                     \
    if (head)                                                         \
      {                                                               \
	print_generic_expr (TB_OUT_FILE, head, 0);                    \
	fprintf (TB_OUT_FILE, "\n");                                  \
      }                                                               \
} while (0)

  TB_SET_HEAD (begin);

  /* Store in a hashtable information about previous and upper statements.  */
  {
    TB_up_ht = new hash_table<tree_upper_hasher> (1023);
    TB_update_up (head);
  }

  while (24)
    {
      fprintf (TB_OUT_FILE, "TB> ");
      rd = TB_getline (&input, &input_size, TB_IN_FILE);

      if (rd == -1)
	/* EOF.  */
	goto ret;

      if (rd != 1)
	/* Get a new command.  Otherwise the user just pressed enter, and thus
	   she expects the last command to be reexecuted.  */
	tbc = TB_get_command (input);

      switch (tbc)
	{
	case TB_UPDATE_UP:
	  TB_update_up (head);
	  break;

	case TB_MAX:
	  if (head && (INTEGRAL_TYPE_P (head)
		       || TREE_CODE (head) == REAL_TYPE
		       || TREE_CODE (head) == FIXED_POINT_TYPE))
	    TB_SET_HEAD (TYPE_MAX_VALUE (head));
	  else
	    TB_WF;
	  break;

	case TB_MIN:
	  if (head && (INTEGRAL_TYPE_P (head)
		       || TREE_CODE (head) == REAL_TYPE
		       || TREE_CODE (head) == FIXED_POINT_TYPE))
	    TB_SET_HEAD (TYPE_MIN_VALUE (head));
	  else
	    TB_WF;
	  break;

	case TB_ELT:
	  if (head && TREE_CODE (head) == TREE_VEC)
	    {
	      /* This command takes another argument: the element number:
		 for example "elt 1".  */
	      TB_NIY;
	    }
	  else if (head && TREE_CODE (head) == VECTOR_CST)
	    {
	      /* This command takes another argument: the element number:
                 for example "elt 1".  */
              TB_NIY;
	    }
	  else
	    TB_WF;
	  break;

	case TB_VALUE:
	  if (head && TREE_CODE (head) == TREE_LIST)
	    TB_SET_HEAD (TREE_VALUE (head));
	  else
	    TB_WF;
	  break;

	case TB_PURPOSE:
	  if (head && TREE_CODE (head) == TREE_LIST)
	    TB_SET_HEAD (TREE_PURPOSE (head));
	  else
	    TB_WF;
	  break;

	case TB_IMAG:
	  if (head && TREE_CODE (head) == COMPLEX_CST)
	    TB_SET_HEAD (TREE_IMAGPART (head));
	  else
	    TB_WF;
	  break;

	case TB_REAL:
	  if (head && TREE_CODE (head) == COMPLEX_CST)
	    TB_SET_HEAD (TREE_REALPART (head));
	  else
	    TB_WF;
	  break;

	case TB_BLOCK:
	  if (head && TREE_CODE (head) == BIND_EXPR)
	    TB_SET_HEAD (TREE_OPERAND (head, 2));
	  else
	    TB_WF;
	  break;

	case TB_SUBBLOCKS:
	  if (head && TREE_CODE (head) == BLOCK)
	    TB_SET_HEAD (BLOCK_SUBBLOCKS (head));
	  else
	    TB_WF;
	  break;

	case TB_SUPERCONTEXT:
	  if (head && TREE_CODE (head) == BLOCK)
	    TB_SET_HEAD (BLOCK_SUPERCONTEXT (head));
	  else
	    TB_WF;
	  break;

	case TB_VARS:
	  if (head && TREE_CODE (head) == BLOCK)
	    TB_SET_HEAD (BLOCK_VARS (head));
	  else if (head && TREE_CODE (head) == BIND_EXPR)
	    TB_SET_HEAD (TREE_OPERAND (head, 0));
	  else
	    TB_WF;
	  break;

	case TB_REFERENCE_TO_THIS:
	  if (head && TYPE_P (head))
	    TB_SET_HEAD (TYPE_REFERENCE_TO (head));
	  else
	    TB_WF;
	  break;

	case TB_POINTER_TO_THIS:
	  if (head && TYPE_P (head))
	    TB_SET_HEAD (TYPE_POINTER_TO (head));
	  else
	    TB_WF;
	  break;

	case TB_BASETYPE:
	  if (head && TREE_CODE (head) == OFFSET_TYPE)
	    TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head));
	  else
	    TB_WF;
	  break;

	case TB_ARG_TYPES:
	  if (head && (TREE_CODE (head) == FUNCTION_TYPE
		       || TREE_CODE (head) == METHOD_TYPE))
	    TB_SET_HEAD (TYPE_ARG_TYPES (head));
	  else
	    TB_WF;
	  break;

	case TB_METHOD_BASE_TYPE:
	  if (head && (TREE_CODE (head) == FUNCTION_TYPE
		       || TREE_CODE (head) == METHOD_TYPE)
	      && TYPE_METHOD_BASETYPE (head))
	    TB_SET_HEAD (TYPE_METHOD_BASETYPE (head));
	  else
	    TB_WF;
	  break;

	case TB_FIELDS:
	  if (head && (TREE_CODE (head) == RECORD_TYPE
		       || TREE_CODE (head) == UNION_TYPE
		       || TREE_CODE (head) == QUAL_UNION_TYPE))
	    TB_SET_HEAD (TYPE_FIELDS (head));
	  else
	    TB_WF;
	  break;

	case TB_DOMAIN:
	  if (head && TREE_CODE (head) == ARRAY_TYPE)
	    TB_SET_HEAD (TYPE_DOMAIN (head));
	  else
	    TB_WF;
	  break;

	case TB_VALUES:
	  if (head && TREE_CODE (head) == ENUMERAL_TYPE)
	    TB_SET_HEAD (TYPE_VALUES (head));
	  else
	    TB_WF;
	  break;

	case TB_ARG_TYPE:
	  if (head && TREE_CODE (head) == PARM_DECL)
	    TB_SET_HEAD (DECL_ARG_TYPE (head));
	  else
	    TB_WF;
	  break;

	case TB_INITIAL:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_INITIAL (head));
	  else
	    TB_WF;
	  break;

	case TB_RESULT:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_RESULT_FLD (head));
	  else
	    TB_WF;
	  break;

	case TB_ARGUMENTS:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_ARGUMENTS (head));
	  else
	    TB_WF;
	  break;

	case TB_ABSTRACT_ORIGIN:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head));
	  else if (head && TREE_CODE (head) == BLOCK)
	    TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head));
	  else
	    TB_WF;
	  break;

	case TB_ATTRIBUTES:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_ATTRIBUTES (head));
	  else if (head && TYPE_P (head))
	    TB_SET_HEAD (TYPE_ATTRIBUTES (head));
	  else
	    TB_WF;
	  break;

	case TB_CONTEXT:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_CONTEXT (head));
	  else if (head && TYPE_P (head)
		   && TYPE_CONTEXT (head))
	    TB_SET_HEAD (TYPE_CONTEXT (head));
	  else
	    TB_WF;
	  break;

	case TB_OFFSET:
	  if (head && TREE_CODE (head) == FIELD_DECL)
	    TB_SET_HEAD (DECL_FIELD_OFFSET (head));
	  else
	    TB_WF;
	  break;

	case TB_BIT_OFFSET:
	  if (head && TREE_CODE (head) == FIELD_DECL)
	    TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head));
	  else
	    TB_WF;
          break;

	case TB_UNIT_SIZE:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_SIZE_UNIT (head));
	  else if (head && TYPE_P (head))
	    TB_SET_HEAD (TYPE_SIZE_UNIT (head));
	  else
	    TB_WF;
	  break;

	case TB_SIZE:
	  if (head && DECL_P (head))
	    TB_SET_HEAD (DECL_SIZE (head));
	  else if (head && TYPE_P (head))
	    TB_SET_HEAD (TYPE_SIZE (head));
	  else
	    TB_WF;
	  break;

	case TB_TYPE:
	  if (head && TREE_TYPE (head))
	    TB_SET_HEAD (TREE_TYPE (head));
	  else
	    TB_WF;
	  break;

	case TB_DECL_SAVED_TREE:
	  if (head && TREE_CODE (head) == FUNCTION_DECL
	      && DECL_SAVED_TREE (head))
	    TB_SET_HEAD (DECL_SAVED_TREE (head));
	  else
	    TB_WF;
	  break;

	case TB_BODY:
	  if (head && TREE_CODE (head) == BIND_EXPR)
	    TB_SET_HEAD (TREE_OPERAND (head, 1));
	  else
	    TB_WF;
	  break;

	case TB_CHILD_0:
	  if (head && EXPR_P (head) && TREE_OPERAND (head, 0))
	    TB_SET_HEAD (TREE_OPERAND (head, 0));
	  else
	    TB_WF;
	  break;

	case TB_CHILD_1:
          if (head && EXPR_P (head) && TREE_OPERAND (head, 1))
	    TB_SET_HEAD (TREE_OPERAND (head, 1));
	  else
	    TB_WF;
          break;

	case TB_CHILD_2:
          if (head && EXPR_P (head) && TREE_OPERAND (head, 2))
	    TB_SET_HEAD (TREE_OPERAND (head, 2));
	  else
	    TB_WF;
	  break;

	case TB_CHILD_3:
	  if (head && EXPR_P (head) && TREE_OPERAND (head, 3))
	    TB_SET_HEAD (TREE_OPERAND (head, 3));
	  else
	    TB_WF;
          break;

	case TB_PRINT:
	  if (head)
	    debug_tree (head);
	  else
	    TB_WF;
	  break;

	case TB_PRETTY_PRINT:
	  if (head)
	    {
	      print_generic_stmt (TB_OUT_FILE, head, 0);
	      fprintf (TB_OUT_FILE, "\n");
	    }
	  else
	    TB_WF;
	  break;

	case TB_SEARCH_NAME:

	  break;

	case TB_SEARCH_CODE:
	  {
	    enum tree_code code;
	    char *arg_text;

	    arg_text = strchr (input, ' ');
	    if (arg_text == NULL)
	      {
		fprintf (TB_OUT_FILE, "First argument is missing.  This isn't a valid search command.  \n");
		break;
	      }
	    code = TB_get_tree_code (arg_text + 1);

	    /* Search in the subtree a node with the given code.  */
	    {
	      tree res;

	      res = walk_tree (&head, find_node_with_code, &code, NULL);
	      if (res == NULL_TREE)
		{
		  fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n");
		}
	      else
		{
		  fprintf (TB_OUT_FILE, "Achoo!  I got this node in the tree.\n");
		  TB_SET_HEAD (res);
		}
	    }
	    break;
	  }

#define TB_MOVE_HEAD(FCT) do {       \
  if (head)                          \
    {                                \
      tree t;                        \
      t = FCT (head);                \
      if (t)                         \
        TB_SET_HEAD (t);             \
      else                           \
	TB_WF;                       \
    }                                \
  else                               \
    TB_WF;                           \
} while (0)

	case TB_FIRST:
	  TB_MOVE_HEAD (TB_first_in_bind);
          break;

        case TB_LAST:
          TB_MOVE_HEAD (TB_last_in_bind);
          break;

	case TB_UP:
	  TB_MOVE_HEAD (TB_up_expr);
	  break;

	case TB_PREV:
	  TB_MOVE_HEAD (TB_prev_expr);
	  break;

	case TB_NEXT:
	  TB_MOVE_HEAD (TB_next_expr);
	  break;

	case TB_HPREV:
	  /* This command is a little bit special, since it deals with history
	     stack.  For this reason it should keep the "head = ..." statement
	     and not use TB_MOVE_HEAD.  */
	  if (head)
	    {
	      tree t;
	      t = TB_history_prev ();
	      if (t)
		{
		  head = t;
		  if (TB_verbose)
		    {
		      print_generic_expr (TB_OUT_FILE, head, 0);
		      fprintf (TB_OUT_FILE, "\n");
		    }
		}
	      else
		TB_WF;
	    }
	  else
	    TB_WF;
	  break;

	case TB_CHAIN:
	  /* Don't go further if it's the last node in this chain.  */
	  if (head && TREE_CODE (head) == BLOCK)
	    TB_SET_HEAD (BLOCK_CHAIN (head));
	  else if (head && TREE_CHAIN (head))
	    TB_SET_HEAD (TREE_CHAIN (head));
	  else
	    TB_WF;
	  break;

	case TB_FUN:
	  /* Go up to the current function declaration.  */
	  TB_SET_HEAD (current_function_decl);
	  fprintf (TB_OUT_FILE, "Current function declaration.\n");
	  break;

	case TB_HELP:
	  /* Display a help message.  */
	  {
	    int i;
	    fprintf (TB_OUT_FILE, "Possible commands are:\n\n");
	    for (i = 0; i < TB_UNUSED_COMMAND; i++)
	      {
		fprintf (TB_OUT_FILE, "%20s  -  %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i));
	      }
	  }
	  break;

	case TB_VERBOSE:
	  if (TB_verbose == 0)
	    {
	      TB_verbose = 1;
	      fprintf (TB_OUT_FILE, "Verbose on.\n");
	    }
	  else
	    {
	      TB_verbose = 0;
	      fprintf (TB_OUT_FILE, "Verbose off.\n");
	    }
	  break;

	case TB_EXIT:
	case TB_QUIT:
	  /* Just exit from this function.  */
	  goto ret;

	default:
	  TB_NIY;
	}
    }

 ret:;
  delete TB_up_ht;
  TB_up_ht = NULL;
  return;
}
예제 #18
0
tree
build_array_notation_ref (location_t loc, tree array, tree start_index, 
			  tree length, tree stride, tree type)
{
  tree array_ntn_tree = NULL_TREE;
  size_t stride_rank = 0, length_rank = 0, start_rank = 0;
  
  if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
    {
      error_at (loc,
		"start-index of array notation triplet is not an integer");
      return error_mark_node;
    }
  if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
    {
      error_at (loc, "length of array notation triplet is not an integer");
      return error_mark_node;
    }

  /* The stride is an optional field.  */
  if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
    {
      error_at (loc, "stride of array notation triplet is not an integer");
      return error_mark_node;
    }  
  if (!stride)
    {
      if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length) 
	  && tree_int_cst_lt (length, start_index))
	stride = build_int_cst (TREE_TYPE (start_index), -1);
      else
	stride = build_int_cst (TREE_TYPE (start_index), 1);
    }	      

  if (!find_rank (loc, start_index, start_index, false, &start_rank))
    return error_mark_node;
  if (!find_rank (loc, length, length, false, &length_rank))
    return error_mark_node;
  if (!find_rank (loc, stride, stride, false, &stride_rank))
    return error_mark_node;

  if (start_rank != 0)
    {
      error_at (loc, "rank of an array notation triplet's start-index is not "
		"zero");
      return error_mark_node;
    }
  if (length_rank != 0)
    {
      error_at (loc, "rank of an array notation triplet's length is not zero");
      return error_mark_node;
    }
  if (stride_rank != 0)
    {
      error_at (loc, "rank of array notation triplet's stride is not zero");
      return error_mark_node;
    }  
  array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
			   NULL_TREE, NULL_TREE);
  ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
  ARRAY_NOTATION_START (array_ntn_tree) = start_index;
  ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
  ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
  TREE_TYPE (array_ntn_tree) = type;
  
  return array_ntn_tree;
}
예제 #19
0
파일: optabs-tree.c 프로젝트: ewang1986/gcc
/* Return the optab used for computing the operation given by the tree code,
   CODE and the tree EXP.  This function is not always usable (for example, it
   cannot give complete results for multiplication or division) but probably
   ought to be relied on more widely throughout the expander.  */
optab
optab_for_tree_code (enum tree_code code, const_tree type,
		     enum optab_subtype subtype)
{
  bool trapv;
  switch (code)
    {
    case BIT_AND_EXPR:
      return and_optab;

    case BIT_IOR_EXPR:
      return ior_optab;

    case BIT_NOT_EXPR:
      return one_cmpl_optab;

    case BIT_XOR_EXPR:
      return xor_optab;

    case MULT_HIGHPART_EXPR:
      return TYPE_UNSIGNED (type) ? umul_highpart_optab : smul_highpart_optab;

    case TRUNC_MOD_EXPR:
    case CEIL_MOD_EXPR:
    case FLOOR_MOD_EXPR:
    case ROUND_MOD_EXPR:
      return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;

    case RDIV_EXPR:
    case TRUNC_DIV_EXPR:
    case CEIL_DIV_EXPR:
    case FLOOR_DIV_EXPR:
    case ROUND_DIV_EXPR:
    case EXACT_DIV_EXPR:
      if (TYPE_SATURATING (type))
	return TYPE_UNSIGNED (type) ? usdiv_optab : ssdiv_optab;
      return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;

    case LSHIFT_EXPR:
      if (TREE_CODE (type) == VECTOR_TYPE)
	{
	  if (subtype == optab_vector)
	    return TYPE_SATURATING (type) ? unknown_optab : vashl_optab;

	  gcc_assert (subtype == optab_scalar);
	}
      if (TYPE_SATURATING (type))
	return TYPE_UNSIGNED (type) ? usashl_optab : ssashl_optab;
      return ashl_optab;

    case RSHIFT_EXPR:
      if (TREE_CODE (type) == VECTOR_TYPE)
	{
	  if (subtype == optab_vector)
	    return TYPE_UNSIGNED (type) ? vlshr_optab : vashr_optab;

	  gcc_assert (subtype == optab_scalar);
	}
      return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;

    case LROTATE_EXPR:
      if (TREE_CODE (type) == VECTOR_TYPE)
	{
	  if (subtype == optab_vector)
	    return vrotl_optab;

	  gcc_assert (subtype == optab_scalar);
	}
      return rotl_optab;

    case RROTATE_EXPR:
      if (TREE_CODE (type) == VECTOR_TYPE)
	{
	  if (subtype == optab_vector)
	    return vrotr_optab;

	  gcc_assert (subtype == optab_scalar);
	}
      return rotr_optab;

    case MAX_EXPR:
      return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;

    case MIN_EXPR:
      return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;

    case REALIGN_LOAD_EXPR:
      return vec_realign_load_optab;

    case WIDEN_SUM_EXPR:
      return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab;

    case DOT_PROD_EXPR:
      return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;

    case SAD_EXPR:
      return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;

    case WIDEN_MULT_PLUS_EXPR:
      return (TYPE_UNSIGNED (type)
	      ? (TYPE_SATURATING (type)
		 ? usmadd_widen_optab : umadd_widen_optab)
	      : (TYPE_SATURATING (type)
		 ? ssmadd_widen_optab : smadd_widen_optab));

    case WIDEN_MULT_MINUS_EXPR:
      return (TYPE_UNSIGNED (type)
	      ? (TYPE_SATURATING (type)
		 ? usmsub_widen_optab : umsub_widen_optab)
	      : (TYPE_SATURATING (type)
		 ? ssmsub_widen_optab : smsub_widen_optab));

    case FMA_EXPR:
      return fma_optab;

    case REDUC_MAX_EXPR:
      return TYPE_UNSIGNED (type)
	     ? reduc_umax_scal_optab : reduc_smax_scal_optab;

    case REDUC_MIN_EXPR:
      return TYPE_UNSIGNED (type)
	     ? reduc_umin_scal_optab : reduc_smin_scal_optab;

    case REDUC_PLUS_EXPR:
      return reduc_plus_scal_optab;

    case VEC_WIDEN_MULT_HI_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;

    case VEC_WIDEN_MULT_LO_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;

    case VEC_WIDEN_MULT_EVEN_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_widen_umult_even_optab : vec_widen_smult_even_optab;

    case VEC_WIDEN_MULT_ODD_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;

    case VEC_WIDEN_LSHIFT_HI_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_widen_ushiftl_hi_optab : vec_widen_sshiftl_hi_optab;

    case VEC_WIDEN_LSHIFT_LO_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_widen_ushiftl_lo_optab : vec_widen_sshiftl_lo_optab;

    case VEC_UNPACK_HI_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_unpacku_hi_optab : vec_unpacks_hi_optab;

    case VEC_UNPACK_LO_EXPR:
      return TYPE_UNSIGNED (type) ?
	vec_unpacku_lo_optab : vec_unpacks_lo_optab;

    case VEC_UNPACK_FLOAT_HI_EXPR:
      /* The signedness is determined from input operand.  */
      return TYPE_UNSIGNED (type) ?
	vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab;

    case VEC_UNPACK_FLOAT_LO_EXPR:
      /* The signedness is determined from input operand.  */
      return TYPE_UNSIGNED (type) ?
	vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab;

    case VEC_PACK_TRUNC_EXPR:
      return vec_pack_trunc_optab;

    case VEC_PACK_SAT_EXPR:
      return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;

    case VEC_PACK_FIX_TRUNC_EXPR:
      /* The signedness is determined from output operand.  */
      return TYPE_UNSIGNED (type) ?
	vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab;

    default:
      break;
    }

  trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
  switch (code)
    {
    case POINTER_PLUS_EXPR:
    case PLUS_EXPR:
      if (TYPE_SATURATING (type))
	return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
      return trapv ? addv_optab : add_optab;

    case MINUS_EXPR:
      if (TYPE_SATURATING (type))
	return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
      return trapv ? subv_optab : sub_optab;

    case MULT_EXPR:
      if (TYPE_SATURATING (type))
	return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
      return trapv ? smulv_optab : smul_optab;

    case NEGATE_EXPR:
      if (TYPE_SATURATING (type))
	return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
      return trapv ? negv_optab : neg_optab;

    case ABS_EXPR:
      return trapv ? absv_optab : abs_optab;

    default:
      return unknown_optab;
    }
}
예제 #20
0
파일: avr-c.c 프로젝트: ShubhamDevVerma/gcc
static tree
avr_resolve_overloaded_builtin (unsigned int iloc, tree fndecl, void *vargs)
{
  tree type0, type1, fold = NULL_TREE;
  enum avr_builtin_id id = AVR_BUILTIN_COUNT;
  location_t loc = (location_t) iloc;
  vec<tree, va_gc> &args = * (vec<tree, va_gc>*) vargs;

  switch (DECL_FUNCTION_CODE (fndecl))
    {
    default:
      break;

    case AVR_BUILTIN_ABSFX:
      if (args.length() != 1)
        {
          error_at (loc, "%qs expects 1 argument but %d given",
                    "absfx", (int) args.length());

          fold = error_mark_node;
          break;
        }

      type0 = TREE_TYPE (args[0]);

      if (!FIXED_POINT_TYPE_P (type0))
        {
          error_at (loc, "%qs expects a fixed-point value as argument",
                    "absfx");

          fold = error_mark_node;
        }

      switch (TYPE_MODE (type0))
        {
        case QQmode: id = AVR_BUILTIN_ABSHR; break;
        case HQmode: id = AVR_BUILTIN_ABSR; break;
        case SQmode: id = AVR_BUILTIN_ABSLR; break;
        case DQmode: id = AVR_BUILTIN_ABSLLR; break;

        case HAmode: id = AVR_BUILTIN_ABSHK; break;
        case SAmode: id = AVR_BUILTIN_ABSK; break;
        case DAmode: id = AVR_BUILTIN_ABSLK; break;
        case TAmode: id = AVR_BUILTIN_ABSLLK; break;

        case UQQmode:
        case UHQmode:
        case USQmode:
        case UDQmode:
        case UHAmode:
        case USAmode:
        case UDAmode:
        case UTAmode:
          warning_at (loc, 0, "using %qs with unsigned type has no effect",
                      "absfx");
          return args[0];

        default:
          error_at (loc, "no matching fixed-point overload found for %qs",
                    "absfx");

          fold = error_mark_node;
          break;
        }

      fold = targetm.builtin_decl (id, true);

      if (fold != error_mark_node)
        fold = build_function_call_vec (loc, vNULL, fold, &args, NULL);

      break; // absfx

    case AVR_BUILTIN_ROUNDFX:
      if (args.length() != 2)
        {
          error_at (loc, "%qs expects 2 arguments but %d given",
                    "roundfx", (int) args.length());

          fold = error_mark_node;
          break;
        }

      type0 = TREE_TYPE (args[0]);
      type1 = TREE_TYPE (args[1]);

      if (!FIXED_POINT_TYPE_P (type0))
        {
          error_at (loc, "%qs expects a fixed-point value as first argument",
                    "roundfx");

          fold = error_mark_node;
        }

      if (!INTEGRAL_TYPE_P (type1))
        {
          error_at (loc, "%qs expects an integer value as second argument",
                    "roundfx");

          fold = error_mark_node;
        }

      switch (TYPE_MODE (type0))
        {
        case QQmode: id = AVR_BUILTIN_ROUNDHR; break;
        case HQmode: id = AVR_BUILTIN_ROUNDR; break;
        case SQmode: id = AVR_BUILTIN_ROUNDLR; break;
        case DQmode: id = AVR_BUILTIN_ROUNDLLR; break;

        case UQQmode: id = AVR_BUILTIN_ROUNDUHR; break;
        case UHQmode: id = AVR_BUILTIN_ROUNDUR; break;
        case USQmode: id = AVR_BUILTIN_ROUNDULR; break;
        case UDQmode: id = AVR_BUILTIN_ROUNDULLR; break;

        case HAmode: id = AVR_BUILTIN_ROUNDHK; break;
        case SAmode: id = AVR_BUILTIN_ROUNDK; break;
        case DAmode: id = AVR_BUILTIN_ROUNDLK; break;
        case TAmode: id = AVR_BUILTIN_ROUNDLLK; break;

        case UHAmode: id = AVR_BUILTIN_ROUNDUHK; break;
        case USAmode: id = AVR_BUILTIN_ROUNDUK; break;
        case UDAmode: id = AVR_BUILTIN_ROUNDULK; break;
        case UTAmode: id = AVR_BUILTIN_ROUNDULLK; break;

        default:
          error_at (loc, "no matching fixed-point overload found for %qs",
                    "roundfx");

          fold = error_mark_node;
          break;
        }

      fold = targetm.builtin_decl (id, true);

      if (fold != error_mark_node)
        fold = build_function_call_vec (loc, vNULL, fold, &args, NULL);

      break; // roundfx

    case AVR_BUILTIN_COUNTLSFX:
      if (args.length() != 1)
        {
          error_at (loc, "%qs expects 1 argument but %d given",
                    "countlsfx", (int) args.length());

          fold = error_mark_node;
          break;
        }

      type0 = TREE_TYPE (args[0]);

      if (!FIXED_POINT_TYPE_P (type0))
        {
          error_at (loc, "%qs expects a fixed-point value as first argument",
                    "countlsfx");

          fold = error_mark_node;
        }

      switch (TYPE_MODE (type0))
        {
        case QQmode: id = AVR_BUILTIN_COUNTLSHR; break;
        case HQmode: id = AVR_BUILTIN_COUNTLSR; break;
        case SQmode: id = AVR_BUILTIN_COUNTLSLR; break;
        case DQmode: id = AVR_BUILTIN_COUNTLSLLR; break;

        case UQQmode: id = AVR_BUILTIN_COUNTLSUHR; break;
        case UHQmode: id = AVR_BUILTIN_COUNTLSUR; break;
        case USQmode: id = AVR_BUILTIN_COUNTLSULR; break;
        case UDQmode: id = AVR_BUILTIN_COUNTLSULLR; break;

        case HAmode: id = AVR_BUILTIN_COUNTLSHK; break;
        case SAmode: id = AVR_BUILTIN_COUNTLSK; break;
        case DAmode: id = AVR_BUILTIN_COUNTLSLK; break;
        case TAmode: id = AVR_BUILTIN_COUNTLSLLK; break;

        case UHAmode: id = AVR_BUILTIN_COUNTLSUHK; break;
        case USAmode: id = AVR_BUILTIN_COUNTLSUK; break;
        case UDAmode: id = AVR_BUILTIN_COUNTLSULK; break;
        case UTAmode: id = AVR_BUILTIN_COUNTLSULLK; break;

        default:
          error_at (loc, "no matching fixed-point overload found for %qs",
                    "countlsfx");

          fold = error_mark_node;
          break;
        }

      fold = targetm.builtin_decl (id, true);

      if (fold != error_mark_node)
        fold = build_function_call_vec (loc, vNULL, fold, &args, NULL);

      break; // countlsfx
    }

  return fold;
}
예제 #21
0
static tree
merge_types (tree type1, tree type2)
{
  if (type1 == type2)
    return type1;
  if (type1 == TYPE_UNKNOWN || type2 == TYPE_UNKNOWN
      || type1 == TYPE_RETURN_ADDR || type2 == TYPE_RETURN_ADDR)
    return TYPE_UNKNOWN;
  if (TREE_CODE (type1) == POINTER_TYPE && TREE_CODE (type2) == POINTER_TYPE)
    {
      int depth1, depth2;
      tree tt1, tt2;
      /* ptr_type_node is only used for a null reference,
	 which is compatible with any reference type. */
      if (type1 == ptr_type_node || type2 == object_ptr_type_node)
	return type2;
      if (type2 == ptr_type_node || type1 == object_ptr_type_node)
	return type1;

      tt1 = TREE_TYPE (type1);
      tt2 = TREE_TYPE (type2);

      /* If tt{1,2} haven't been properly loaded, now is a good time
         to do it. */
      if (!TYPE_SIZE (tt1))
	{
	  load_class (tt1, 1);
	  safe_layout_class (tt1);
	}

      if (!TYPE_SIZE (tt2))
	{
	  load_class (tt2, 1);
	  safe_layout_class (tt2);
	}

      if (TYPE_ARRAY_P (tt1) || TYPE_ARRAY_P (tt2))
	{
	  if (TYPE_ARRAY_P (tt1) == TYPE_ARRAY_P (tt2))
	    {
	      tree el_type1 = TYPE_ARRAY_ELEMENT (tt1);
	      tree el_type2 = TYPE_ARRAY_ELEMENT (tt2);
	      tree el_type = NULL_TREE;
	      if (el_type1 == el_type2)
		el_type = el_type1;
	      else if (TREE_CODE (el_type1) == POINTER_TYPE
		       && TREE_CODE (el_type2) == POINTER_TYPE)
		el_type = merge_types (el_type1, el_type2);
	      if (el_type != NULL_TREE)
		{
		  HOST_WIDE_INT len1 = java_array_type_length (tt1);
		  HOST_WIDE_INT len2 = java_array_type_length (tt2);
		  if (len1 != len2)
		    len1 = -1;
		  else if (el_type1 == el_type2)
		    return type1;
		  return promote_type (build_java_array_type (el_type, len1));
		}
	    }
	  return object_ptr_type_node;
	}

      if (CLASS_INTERFACE (TYPE_NAME (tt1)))
	{
	  /* FIXME: should see if two interfaces have a common
	     superinterface.  */
	  if (CLASS_INTERFACE (TYPE_NAME (tt2)))
	    {
	      /* This is a kludge, but matches what Sun's verifier does.
		 It can be tricked, but is safe as long as type errors
		 (i.e. interface method calls) are caught at run-time. */
	      return object_ptr_type_node;
	    }
	  else
	    {
	      if (can_widen_reference_to (tt2, tt1))
		return type1;
	      else
		return object_ptr_type_node;
	    }
	}
      else if (CLASS_INTERFACE (TYPE_NAME (tt2)))
	{
	  if (can_widen_reference_to (tt1, tt2))
	    return type2;
	  else
	    return object_ptr_type_node;
	}

      type1 = tt1;
      type2 = tt2;

      depth1 = class_depth (type1);
      depth2 = class_depth (type2);
      for ( ; depth1 > depth2;  depth1--)
	type1 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type1), 0));
      for ( ; depth2 > depth1;  depth2--)
	type2 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type2), 0));
      while (type1 != type2)
	{
	  type1 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type1), 0));
	  type2 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type2), 0));
	}
      return promote_type (type1);
    }
  if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2)
      && TYPE_PRECISION (type1) <= 32 && TYPE_PRECISION (type2) <= 32)
    return int_type_node;
  return TYPE_UNKNOWN;
}
예제 #22
0
static tree
fold_const_call_1 (built_in_function fn, tree type, tree arg)
{
  machine_mode mode = TYPE_MODE (type);
  machine_mode arg_mode = TYPE_MODE (TREE_TYPE (arg));

  if (integer_cst_p (arg))
    {
      if (SCALAR_INT_MODE_P (mode))
	{
	  wide_int result;
	  if (fold_const_call_ss (&result, fn, arg, TYPE_PRECISION (type),
				  TREE_TYPE (arg)))
	    return wide_int_to_tree (type, result);
	}
      return NULL_TREE;
    }

  if (real_cst_p (arg))
    {
      gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg_mode));
      if (mode == arg_mode)
	{
	  /* real -> real.  */
	  REAL_VALUE_TYPE result;
	  if (fold_const_call_ss (&result, fn, TREE_REAL_CST_PTR (arg),
				  REAL_MODE_FORMAT (mode)))
	    return build_real (type, result);
	}
      else if (COMPLEX_MODE_P (mode)
	       && GET_MODE_INNER (mode) == arg_mode)
	{
	  /* real -> complex real.  */
	  REAL_VALUE_TYPE result_real, result_imag;
	  if (fold_const_call_cs (&result_real, &result_imag, fn,
				  TREE_REAL_CST_PTR (arg),
				  REAL_MODE_FORMAT (arg_mode)))
	    return build_complex (type,
				  build_real (TREE_TYPE (type), result_real),
				  build_real (TREE_TYPE (type), result_imag));
	}
      else if (INTEGRAL_TYPE_P (type))
	{
	  /* real -> int.  */
	  wide_int result;
	  if (fold_const_call_ss (&result, fn,
				  TREE_REAL_CST_PTR (arg),
				  TYPE_PRECISION (type),
				  REAL_MODE_FORMAT (arg_mode)))
	    return wide_int_to_tree (type, result);
	}
      return NULL_TREE;
    }

  if (complex_cst_p (arg))
    {
      gcc_checking_assert (COMPLEX_MODE_P (arg_mode));
      machine_mode inner_mode = GET_MODE_INNER (arg_mode);
      tree argr = TREE_REALPART (arg);
      tree argi = TREE_IMAGPART (arg);
      if (mode == arg_mode
	  && real_cst_p (argr)
	  && real_cst_p (argi))
	{
	  /* complex real -> complex real.  */
	  REAL_VALUE_TYPE result_real, result_imag;
	  if (fold_const_call_cc (&result_real, &result_imag, fn,
				  TREE_REAL_CST_PTR (argr),
				  TREE_REAL_CST_PTR (argi),
				  REAL_MODE_FORMAT (inner_mode)))
	    return build_complex (type,
				  build_real (TREE_TYPE (type), result_real),
				  build_real (TREE_TYPE (type), result_imag));
	}
      if (mode == inner_mode
	  && real_cst_p (argr)
	  && real_cst_p (argi))
	{
	  /* complex real -> real.  */
	  REAL_VALUE_TYPE result;
	  if (fold_const_call_sc (&result, fn,
				  TREE_REAL_CST_PTR (argr),
				  TREE_REAL_CST_PTR (argi),
				  REAL_MODE_FORMAT (inner_mode)))
	    return build_real (type, result);
	}
      return NULL_TREE;
    }

  return NULL_TREE;
}
예제 #23
0
static bool
ifcombine_iforif (basic_block inner_cond_bb, basic_block outer_cond_bb)
{
  gimple inner_cond, outer_cond;
  tree name1, name2, bits1, bits2;

  inner_cond = last_stmt (inner_cond_bb);
  if (!inner_cond
      || gimple_code (inner_cond) != GIMPLE_COND)
    return false;

  outer_cond = last_stmt (outer_cond_bb);
  if (!outer_cond
      || gimple_code (outer_cond) != GIMPLE_COND)
    return false;

  /* See if we have two bit tests of the same name in both tests.
     In that case remove the outer test and change the inner one to
     test for name & (bits1 | bits2) != 0.  */
  if (recognize_bits_test (inner_cond, &name1, &bits1)
      && recognize_bits_test (outer_cond, &name2, &bits2))
    {
      gimple_stmt_iterator gsi;
      tree t;

      /* Find the common name which is bit-tested.  */
      if (name1 == name2)
	;
      else if (bits1 == bits2)
	{
	  t = name2;
	  name2 = bits2;
	  bits2 = t;
	  t = name1;
	  name1 = bits1;
	  bits1 = t;
	}
      else if (name1 == bits2)
	{
	  t = name2;
	  name2 = bits2;
	  bits2 = t;
	}
      else if (bits1 == name2)
	{
	  t = name1;
	  name1 = bits1;
	  bits1 = t;
	}
      else
	return false;

      /* As we strip non-widening conversions in finding a common
         name that is tested make sure to end up with an integral
	 type for building the bit operations.  */
      if (TYPE_PRECISION (TREE_TYPE (bits1))
	  >= TYPE_PRECISION (TREE_TYPE (bits2)))
	{
	  bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
	  name1 = fold_convert (TREE_TYPE (bits1), name1);
	  bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
	  bits2 = fold_convert (TREE_TYPE (bits1), bits2);
	}
      else
	{
	  bits2 = fold_convert (unsigned_type_for (TREE_TYPE (bits2)), bits2);
	  name1 = fold_convert (TREE_TYPE (bits2), name1);
	  bits1 = fold_convert (unsigned_type_for (TREE_TYPE (bits1)), bits1);
	  bits1 = fold_convert (TREE_TYPE (bits2), bits1);
	}

      /* Do it.  */
      gsi = gsi_for_stmt (inner_cond);
      t = fold_build2 (BIT_IOR_EXPR, TREE_TYPE (name1), bits1, bits2);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (name1), name1, t);
      t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
				    true, GSI_SAME_STMT);
      t = fold_build2 (NE_EXPR, boolean_type_node, t,
		       build_int_cst (TREE_TYPE (t), 0));
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing bits or bits test to ");
	  print_generic_expr (dump_file, name1, 0);
	  fprintf (dump_file, " & T != 0\nwith temporary T = ");
	  print_generic_expr (dump_file, bits1, 0);
	  fprintf (dump_file, " | ");
	  print_generic_expr (dump_file, bits2, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  /* See if we have two comparisons that we can merge into one.
     This happens for C++ operator overloading where for example
     GE_EXPR is implemented as GT_EXPR || EQ_EXPR.  */
  else if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison
	   && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison
	   && operand_equal_p (gimple_cond_lhs (inner_cond),
			       gimple_cond_lhs (outer_cond), 0)
	   && operand_equal_p (gimple_cond_rhs (inner_cond),
			       gimple_cond_rhs (outer_cond), 0))
    {
      enum tree_code code1 = gimple_cond_code (inner_cond);
      enum tree_code code2 = gimple_cond_code (outer_cond);
      enum tree_code code;
      tree t;

#define CHK(a,b) ((code1 == a ## _EXPR && code2 == b ## _EXPR) \
		  || (code2 == a ## _EXPR && code1 == b ## _EXPR))
      /* Merge the two condition codes if possible.  */
      if (code1 == code2)
	code = code1;
      else if (CHK (EQ, LT))
	code = LE_EXPR;
      else if (CHK (EQ, GT))
	code = GE_EXPR;
      else if (CHK (LT, LE))
	code = LE_EXPR;
      else if (CHK (GT, GE))
	code = GE_EXPR;
      else if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (inner_cond)))
	       || flag_unsafe_math_optimizations)
	{
	  if (CHK (LT, GT))
	    code = NE_EXPR;
	  else if (CHK (LT, NE))
	    code = NE_EXPR;
	  else if (CHK (GT, NE))
	    code = NE_EXPR;
	  else
	    return false;
	}
      /* We could check for combinations leading to trivial true/false.  */
      else
	return false;
#undef CHK

      /* Do it.  */
      t = fold_build2 (code, boolean_type_node, gimple_cond_lhs (outer_cond),
		       gimple_cond_rhs (outer_cond));
      t = canonicalize_cond_expr_cond (t);
      if (!t)
	return false;
      gimple_cond_set_condition_from_tree (inner_cond, t);
      update_stmt (inner_cond);

      /* Leave CFG optimization to cfg_cleanup.  */
      gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node);
      update_stmt (outer_cond);

      if (dump_file)
	{
	  fprintf (dump_file, "optimizing two comparisons to ");
	  print_generic_expr (dump_file, t, 0);
	  fprintf (dump_file, "\n");
	}

      return true;
    }

  return false;
}
예제 #24
0
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;
	  }
	}
      }
    }
}
예제 #25
0
파일: c-omp.c 프로젝트: ymgcmstk/gcc
tree
c_finish_omp_atomic (location_t loc, enum tree_code code,
		     enum tree_code opcode, tree lhs, tree rhs,
		     tree v, tree lhs1, tree rhs1, bool swapped, bool seq_cst)
{
  tree x, type, addr, pre = NULL_TREE;

  if (lhs == error_mark_node || rhs == error_mark_node
      || v == error_mark_node || lhs1 == error_mark_node
      || rhs1 == error_mark_node)
    return error_mark_node;

  /* ??? According to one reading of the OpenMP spec, complex type are
     supported, but there are no atomic stores for any architecture.
     But at least icc 9.0 doesn't support complex types here either.
     And lets not even talk about vector types...  */
  type = TREE_TYPE (lhs);
  if (!INTEGRAL_TYPE_P (type)
      && !POINTER_TYPE_P (type)
      && !SCALAR_FLOAT_TYPE_P (type))
    {
      error_at (loc, "invalid expression type for %<#pragma omp atomic%>");
      return error_mark_node;
    }

  if (opcode == RDIV_EXPR)
    opcode = TRUNC_DIV_EXPR;

  /* ??? Validate that rhs does not overlap lhs.  */

  /* Take and save the address of the lhs.  From then on we'll reference it
     via indirection.  */
  addr = build_unary_op (loc, ADDR_EXPR, lhs, 0);
  if (addr == error_mark_node)
    return error_mark_node;
  addr = save_expr (addr);
  if (TREE_CODE (addr) != SAVE_EXPR
      && (TREE_CODE (addr) != ADDR_EXPR
	  || !VAR_P (TREE_OPERAND (addr, 0))))
    {
      /* Make sure LHS is simple enough so that goa_lhs_expr_p can recognize
	 it even after unsharing function body.  */
      tree var = create_tmp_var_raw (TREE_TYPE (addr));
      DECL_CONTEXT (var) = current_function_decl;
      addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL);
    }
  lhs = build_indirect_ref (loc, addr, RO_NULL);

  if (code == OMP_ATOMIC_READ)
    {
      x = build1 (OMP_ATOMIC_READ, type, addr);
      SET_EXPR_LOCATION (x, loc);
      OMP_ATOMIC_SEQ_CST (x) = seq_cst;
      return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
				loc, x, NULL_TREE);
    }

  /* There are lots of warnings, errors, and conversions that need to happen
     in the course of interpreting a statement.  Use the normal mechanisms
     to do this, and then take it apart again.  */
  if (swapped)
    {
      rhs = build_binary_op (loc, opcode, rhs, lhs, 1);
      opcode = NOP_EXPR;
    }
  bool save = in_late_binary_op;
  in_late_binary_op = true;
  x = build_modify_expr (loc, lhs, NULL_TREE, opcode, loc, rhs, NULL_TREE);
  in_late_binary_op = save;
  if (x == error_mark_node)
    return error_mark_node;
  if (TREE_CODE (x) == COMPOUND_EXPR)
    {
      pre = TREE_OPERAND (x, 0);
      gcc_assert (TREE_CODE (pre) == SAVE_EXPR);
      x = TREE_OPERAND (x, 1);
    }
  gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
  rhs = TREE_OPERAND (x, 1);

  /* Punt the actual generation of atomic operations to common code.  */
  if (code == OMP_ATOMIC)
    type = void_type_node;
  x = build2 (code, type, addr, rhs);
  SET_EXPR_LOCATION (x, loc);
  OMP_ATOMIC_SEQ_CST (x) = seq_cst;

  /* Generally it is hard to prove lhs1 and lhs are the same memory
     location, just diagnose different variables.  */
  if (rhs1
      && VAR_P (rhs1)
      && VAR_P (lhs)
      && rhs1 != lhs)
    {
      if (code == OMP_ATOMIC)
	error_at (loc, "%<#pragma omp atomic update%> uses two different variables for memory");
      else
	error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory");
      return error_mark_node;
    }

  if (code != OMP_ATOMIC)
    {
      /* Generally it is hard to prove lhs1 and lhs are the same memory
	 location, just diagnose different variables.  */
      if (lhs1 && VAR_P (lhs1) && VAR_P (lhs))
	{
	  if (lhs1 != lhs)
	    {
	      error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory");
	      return error_mark_node;
	    }
	}
      x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
			     loc, x, NULL_TREE);
      if (rhs1 && rhs1 != lhs)
	{
	  tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
	  if (rhs1addr == error_mark_node)
	    return error_mark_node;
	  x = omit_one_operand_loc (loc, type, x, rhs1addr);
	}
      if (lhs1 && lhs1 != lhs)
	{
	  tree lhs1addr = build_unary_op (loc, ADDR_EXPR, lhs1, 0);
	  if (lhs1addr == error_mark_node)
	    return error_mark_node;
	  if (code == OMP_ATOMIC_CAPTURE_OLD)
	    x = omit_one_operand_loc (loc, type, x, lhs1addr);
	  else
	    {
	      x = save_expr (x);
	      x = omit_two_operands_loc (loc, type, x, x, lhs1addr);
	    }
	}
    }
  else if (rhs1 && rhs1 != lhs)
    {
      tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
      if (rhs1addr == error_mark_node)
	return error_mark_node;
      x = omit_one_operand_loc (loc, type, x, rhs1addr);
    }

  if (pre)
    x = omit_one_operand_loc (loc, type, x, pre);
  return x;
}
예제 #26
0
/* Verify the bytecodes of the current method, with the instructions
   starting at BYTE_OPS and LENGTH in number, from the class file pointed to
   by JCF.
   Return 1 on success, 0 on failure.  */
int
verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
{
  tree label;
  int wide = 0;
  int op_code;
  int PC;
  int oldpc = 0; /* PC of start of instruction. */
  int prevpc = 0;  /* If >= 0, PC of previous instruction. */
  const char *message = 0;
  char *pmessage;
  int i;
  int index;
  unsigned char *p;
  struct eh_range *prev_eh_ranges = NULL_EH_RANGE;
  struct eh_range *eh_ranges;
  tree return_type = TREE_TYPE (TREE_TYPE (current_function_decl));
  struct pc_index *starts;
  int eh_count;

  jint int_value = -1;

  pending_blocks = NULL_TREE;

  current_subr = NULL_TREE;

  /* Handle the exception table.  */
  method_init_exceptions ();
  JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length);
  eh_count = JCF_readu2 (jcf);

  /* We read the exception handlers in order of increasing start PC.
     To do this we first read and sort the start PCs.  */
  starts = xmalloc (eh_count * sizeof (struct pc_index));
  for (i = 0; i < eh_count; ++i)
    {
      starts[i].start_pc = GET_u2 (jcf->read_ptr + 8 * i);
      starts[i].index = i;
    }
  qsort (starts, eh_count, sizeof (struct pc_index), start_pc_cmp);

  for (i = 0; i < eh_count; ++i)
    {
      int start_pc, end_pc, handler_pc, catch_type;

      p = jcf->read_ptr + 8 * starts[i].index;

      start_pc = GET_u2 (p);
      end_pc = GET_u2 (p+2);
      handler_pc = GET_u2 (p+4);
      catch_type = GET_u2 (p+6);

      if (start_pc < 0 || start_pc >= length
	  || end_pc < 0 || end_pc > length || start_pc >= end_pc
	  || handler_pc < 0 || handler_pc >= length
	  || ! (instruction_bits[start_pc] & BCODE_INSTRUCTION_START)
	  || (end_pc < length &&
	     ! (instruction_bits[end_pc] & BCODE_INSTRUCTION_START))
	  || ! (instruction_bits[handler_pc] & BCODE_INSTRUCTION_START))
	{
	  error ("bad pc in exception_table");
	  free (starts);
	  return 0;
	}

      add_handler (start_pc, end_pc,
		   lookup_label (handler_pc),
		   catch_type == 0 ? NULL_TREE
		   : get_class_constant (jcf, catch_type));

      instruction_bits[handler_pc] |= BCODE_EXCEPTION_TARGET;
    }

  free (starts);
  handle_nested_ranges ();

  for (PC = 0;;)
    {
      tree type, tmp;

      if (((PC != INVALID_PC
	   && instruction_bits[PC] & BCODE_TARGET) != 0)
	  || PC == 0)
	{
	  PUSH_PENDING (lookup_label (PC));
	  INVALIDATE_PC;
	}

      /* Check if there are any more pending blocks in the current
	 subroutine.  Because we push pending blocks in a
	 last-in-first-out order, and because we don't push anything
	 from our caller until we are done with this subroutine or
	 anything nested in it, we are done if the top of the
	 pending_blocks stack is not in a subroutine, or it is in our
	 caller. */
      if (current_subr && PC == INVALID_PC)
	{
	  if (pending_blocks == NULL_TREE
	      || (subroutine_nesting (pending_blocks)
		  < subroutine_nesting (current_subr)))
	    {
	      int size
                = DECL_MAX_LOCALS (current_function_decl) + stack_pointer;

	      tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr);
	      tmp = LABEL_RETURN_LABELS (current_subr);
	      
	      /* FIXME: If we exit a subroutine via a throw, we might
		 have returned to an earlier caller.  Obviously a
		 "ret" can only return one level, but a throw may
		 return many levels.  */
	      current_subr = LABEL_SUBR_CONTEXT (current_subr);

	      if (RETURN_MAP_ADJUSTED (ret_map))
		{
		  /* Since we are done with this subroutine, set up
		     the (so far known) return address as pending -
		     with the merged type state.  */
		  for ( ; tmp != NULL_TREE;  tmp = TREE_CHAIN (tmp))
		    {
		      tree return_label = TREE_VALUE (tmp);
		      tree return_state = LABEL_TYPE_STATE (return_label);
		      if (return_state == NULL_TREE)
			{
			  /* This means we had not verified the subroutine
                             earlier, so this is the first jsr to call it.
                             In this case, the type_map of the return
			     address is just the current type_map - and that
			     is handled by the following PUSH_PENDING.  */
			}
		      else
			{
			  /* In this case we have to do a merge.  But first
			     restore the type_map for unused slots to those
			     that were in effect at the jsr.  */
			  for (index = size; --index >= 0; )
			    {
			      type_map[index]
                                = TREE_VEC_ELT (ret_map, index);

			      if (type_map[index] == TYPE_UNUSED)
				type_map[index]
				  = TREE_VEC_ELT (return_state, index);
			    }
			}
		      PUSH_PENDING (return_label);
		    }
		}
	    }
	}

      if (PC == INVALID_PC)
	{
	  label = pending_blocks;

	  if (label == NULL_TREE)
	    break;  /* We're done! */

	  pending_blocks = LABEL_PENDING_CHAIN (label);
	  LABEL_CHANGED (label) = 0;

	  if (LABEL_IN_SUBR (label))
	    current_subr = LABEL_SUBR_START (label);
	  else
	    current_subr = NULL_TREE;

	  /* Restore type_map and stack_pointer from
	     LABEL_TYPE_STATE (label), and continue
	     compiling from there.  */
	  load_type_state (label);

	  PC = LABEL_PC (label);
	}
      else if (PC >= length)
	VERIFICATION_ERROR ("falling through the end of the method");


      oldpc = PC;

      if (! (instruction_bits[PC] & BCODE_INSTRUCTION_START) && ! wide)
	VERIFICATION_ERROR ("PC not at instruction start");

      instruction_bits[PC] |= BCODE_VERIFIED;

      eh_ranges = find_handler (oldpc);

      op_code = byte_ops[PC++];
      switch (op_code)
	{
	  int is_static, is_putting;

	case OPCODE_nop:
	  break;

	case OPCODE_iconst_m1:
	case OPCODE_iconst_0:	case OPCODE_iconst_1:	case OPCODE_iconst_2:
	case OPCODE_iconst_3:	case OPCODE_iconst_4:	case OPCODE_iconst_5:
	  i = op_code - OPCODE_iconst_0;
	  goto push_int;
	push_int:
	  if (byte_ops[PC] == OPCODE_newarray
	      || byte_ops[PC] == OPCODE_anewarray)
	    int_value = i;
	  PUSH_TYPE (int_type_node);  break;

	case OPCODE_lconst_0:	case OPCODE_lconst_1:
	  PUSH_TYPE (long_type_node);  break;

	case OPCODE_fconst_0:	case OPCODE_fconst_1:	case OPCODE_fconst_2:
	  PUSH_TYPE (float_type_node);  break;

	case OPCODE_dconst_0:	case OPCODE_dconst_1:
	  PUSH_TYPE (double_type_node);  break;

	case OPCODE_bipush:
	  i = IMMEDIATE_s1;
	  goto push_int;

	case OPCODE_sipush:
	  i = IMMEDIATE_s2;
	  goto push_int;

	case OPCODE_iload:  type = int_type_node;  goto general_load;
	case OPCODE_lload:  type = long_type_node;  goto general_load;
	case OPCODE_fload:  type = float_type_node;  goto general_load;
	case OPCODE_dload:  type = double_type_node;  goto general_load;
	case OPCODE_aload:  type = ptr_type_node;  goto general_load;
	general_load:
	index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
	wide = 0;
	goto load;
	case OPCODE_iload_0:  type = int_type_node;  index = 0; goto load;
	case OPCODE_iload_1:  type = int_type_node;  index = 1; goto load;
	case OPCODE_iload_2:  type = int_type_node;  index = 2; goto load;
	case OPCODE_iload_3:  type = int_type_node;  index = 3; goto load;
	case OPCODE_lload_0:  type = long_type_node; index = 0; goto load;
	case OPCODE_lload_1:  type = long_type_node; index = 1; goto load;
	case OPCODE_lload_2:  type = long_type_node; index = 2; goto load;
	case OPCODE_lload_3:  type = long_type_node; index = 3; goto load;
	case OPCODE_fload_0:  type = float_type_node; index = 0; goto load;
	case OPCODE_fload_1:  type = float_type_node; index = 1; goto load;
	case OPCODE_fload_2:  type = float_type_node; index = 2; goto load;
	case OPCODE_fload_3:  type = float_type_node; index = 3; goto load;
	case OPCODE_dload_0: type = double_type_node; index = 0; goto load;
	case OPCODE_dload_1: type = double_type_node; index = 1; goto load;
	case OPCODE_dload_2: type = double_type_node; index = 2; goto load;
	case OPCODE_dload_3: type = double_type_node; index = 3; goto load;
	case OPCODE_aload_0:  type = ptr_type_node;  index = 0;  goto load;
	case OPCODE_aload_1:  type = ptr_type_node;  index = 1;  goto load;
	case OPCODE_aload_2:  type = ptr_type_node;  index = 2;  goto load;
	case OPCODE_aload_3:  type = ptr_type_node;  index = 3;  goto load;
	load:
	if (index < 0
	    || (index + TYPE_IS_WIDE (type)
		>= DECL_MAX_LOCALS (current_function_decl)))
	  VERIFICATION_ERROR_WITH_INDEX
	    ("invalid local variable index %d in load");
	tmp = type_map[index];
	if (tmp == TYPE_UNKNOWN)
	  VERIFICATION_ERROR_WITH_INDEX
	    ("loading local variable %d which has unknown type");
	else if (tmp == TYPE_SECOND
	    || (TYPE_IS_WIDE (type)
		&& type_map[index+1] != void_type_node)
	    || (type == ptr_type_node
		? TREE_CODE (tmp) != POINTER_TYPE
		: type == int_type_node
		? (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32)
		: type != tmp))
	  VERIFICATION_ERROR_WITH_INDEX
	    ("loading local variable %d which has invalid type");
	PUSH_TYPE (tmp);
	goto note_used;
	case OPCODE_istore:  type = int_type_node;  goto general_store;
	case OPCODE_lstore:  type = long_type_node;  goto general_store;
	case OPCODE_fstore:  type = float_type_node;  goto general_store;
	case OPCODE_dstore:  type = double_type_node;  goto general_store;
	case OPCODE_astore:  type = object_ptr_type_node;  goto general_store;
	general_store:
	index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
	wide = 0;
	goto store;
	case OPCODE_istore_0:  type = int_type_node; index = 0; goto store;
	case OPCODE_istore_1:  type = int_type_node; index = 1; goto store;
	case OPCODE_istore_2:  type = int_type_node; index = 2; goto store;
	case OPCODE_istore_3:  type = int_type_node; index = 3; goto store;
	case OPCODE_lstore_0:  type = long_type_node; index=0; goto store;
	case OPCODE_lstore_1:  type = long_type_node; index=1; goto store;
	case OPCODE_lstore_2:  type = long_type_node; index=2; goto store;
	case OPCODE_lstore_3:  type = long_type_node; index=3; goto store;
	case OPCODE_fstore_0:  type=float_type_node; index=0; goto store;
	case OPCODE_fstore_1:  type=float_type_node; index=1; goto store;
	case OPCODE_fstore_2:  type=float_type_node; index=2; goto store;
	case OPCODE_fstore_3:  type=float_type_node; index=3; goto store;
	case OPCODE_dstore_0:  type=double_type_node; index=0; goto store;
	case OPCODE_dstore_1:  type=double_type_node; index=1; goto store;
	case OPCODE_dstore_2:  type=double_type_node; index=2; goto store;
	case OPCODE_dstore_3:  type=double_type_node; index=3; goto store;
	case OPCODE_astore_0:  type = ptr_type_node; index = 0; goto store;
	case OPCODE_astore_1:  type = ptr_type_node; index = 1; goto store;
	case OPCODE_astore_2:  type = ptr_type_node; index = 2; goto store;
	case OPCODE_astore_3:  type = ptr_type_node; index = 3; goto store;
	store:
	if (index < 0
	    || (index + TYPE_IS_WIDE (type)
		>= DECL_MAX_LOCALS (current_function_decl)))
	  {
	    VERIFICATION_ERROR_WITH_INDEX
	      ("invalid local variable index %d in store");
	    return 0;
	  }
	POP_TYPE_CONV (type, type, NULL);
	type_map[index] = type;

	/* If a local variable has changed, we need to reconsider exception
        handlers.  */
	prev_eh_ranges = NULL_EH_RANGE;

	/* Allocate decl for this variable now, so we get a temporary
! 	   that survives the whole method. */
	find_local_variable (index, type, oldpc);

        if (TYPE_IS_WIDE (type))
          type_map[index+1] = TYPE_SECOND;

	/* ... fall through to note_used ... */
	note_used:
	  /* For store or load, note that local variable INDEX is used.
	     This is needed to verify try-finally subroutines. */
	  if (current_subr)
	    {
	      tree vec = LABEL_RETURN_TYPE_STATE (current_subr);
	      tree subr_vec = LABEL_TYPE_STATE (current_subr);
	      int len = 1 + TYPE_IS_WIDE (type);
	      while (--len >= 0)
		{
		  if (TREE_VEC_ELT (vec, index) == TYPE_UNUSED)
		    TREE_VEC_ELT (vec, index) = TREE_VEC_ELT (subr_vec, index);
		}
	    }
	break;
	case OPCODE_iadd:
	case OPCODE_iand:
	case OPCODE_idiv:
	case OPCODE_imul:
	case OPCODE_ior:
	case OPCODE_irem:
	case OPCODE_ishl:
	case OPCODE_ishr:
	case OPCODE_isub:
	case OPCODE_iushr:
	case OPCODE_ixor:
	  type = int_type_node;  goto binop;
	case OPCODE_ineg:
	case OPCODE_i2c:
	case OPCODE_i2b:
	case OPCODE_i2s:
	  type = int_type_node;  goto unop;
	case OPCODE_ladd:
	case OPCODE_land:
	case OPCODE_ldiv:
	case OPCODE_lsub:
	case OPCODE_lmul:
	case OPCODE_lrem:
	case OPCODE_lor:
	case OPCODE_lxor:
	  type = long_type_node;  goto binop;
	case OPCODE_lneg:
	  type = long_type_node;  goto unop;
	case OPCODE_fadd:	case OPCODE_fsub:
	case OPCODE_fmul:	case OPCODE_fdiv:	case OPCODE_frem:
	  type = float_type_node;  goto binop;
	case OPCODE_fneg:
	  type = float_type_node;  goto unop;
	case OPCODE_dadd:	case OPCODE_dsub:
	case OPCODE_dmul:	case OPCODE_ddiv:	case OPCODE_drem:
	  type = double_type_node;  goto binop;
	case OPCODE_dneg:
	  type = double_type_node;  goto unop;

	unop:
	  pop_type (type);
	  PUSH_TYPE (type);
	  break;

	binop:
	  pop_type (type);
	  pop_type (type);
	  PUSH_TYPE (type);
	  break;

	case OPCODE_lshl:
	case OPCODE_lshr:
	case OPCODE_lushr:
	  pop_type (int_type_node);
	  pop_type (long_type_node);
	  PUSH_TYPE (long_type_node);
	  break;

	case OPCODE_iinc:
	  index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
	  PC += wide + 1;
	  wide = 0;
	  if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl))
	    VERIFICATION_ERROR ("invalid local variable index in iinc");
	  tmp = type_map[index];
	  if (tmp == NULL_TREE
	      || ! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32)
	    VERIFICATION_ERROR ("invalid local variable type in iinc");
	  break;

	case OPCODE_i2l:
	  pop_type (int_type_node);    PUSH_TYPE (long_type_node);   break;
	case OPCODE_i2f:
	  pop_type (int_type_node);    PUSH_TYPE (float_type_node);  break;
	case OPCODE_i2d:
	  pop_type (int_type_node);    PUSH_TYPE (double_type_node); break;
	case OPCODE_l2i:
	  pop_type (long_type_node);   PUSH_TYPE (int_type_node);    break;
	case OPCODE_l2f:
	  pop_type (long_type_node);   PUSH_TYPE (float_type_node);  break;
	case OPCODE_l2d:
	  pop_type (long_type_node);   PUSH_TYPE (double_type_node); break;
	case OPCODE_f2i:
	  pop_type (float_type_node);  PUSH_TYPE (int_type_node);    break;
	case OPCODE_f2l:
	  pop_type (float_type_node);  PUSH_TYPE (long_type_node);   break;
	case OPCODE_f2d:
	  pop_type (float_type_node);  PUSH_TYPE (double_type_node); break;
	case OPCODE_d2i:
	  pop_type (double_type_node); PUSH_TYPE (int_type_node);    break;
	case OPCODE_d2l:
	  pop_type (double_type_node); PUSH_TYPE (long_type_node);   break;
	case OPCODE_d2f:
	  pop_type (double_type_node); PUSH_TYPE (float_type_node);  break;

	case OPCODE_lcmp:
	  type = long_type_node;  goto compare;
	case OPCODE_fcmpl:
	case OPCODE_fcmpg:
	  type = float_type_node;  goto compare;
	case OPCODE_dcmpl:
	case OPCODE_dcmpg:
	  type = double_type_node;  goto compare;
	compare:
	  pop_type (type);  pop_type (type);
	  PUSH_TYPE (int_type_node);  break;

	case OPCODE_ifeq:
	case OPCODE_ifne:
	case OPCODE_iflt:
	case OPCODE_ifge:
	case OPCODE_ifgt:
	case OPCODE_ifle:
	  pop_type (int_type_node);  goto cond;
	case OPCODE_ifnull:
	case OPCODE_ifnonnull:
	  pop_type (ptr_type_node ); goto cond;
	case OPCODE_if_icmpeq:
	case OPCODE_if_icmpne:
	case OPCODE_if_icmplt:
	case OPCODE_if_icmpge:
	case OPCODE_if_icmpgt:
	case OPCODE_if_icmple:
	  pop_type (int_type_node);  pop_type (int_type_node);  goto cond;
	case OPCODE_if_acmpeq:
	case OPCODE_if_acmpne:
	  pop_type (object_ptr_type_node);  pop_type (object_ptr_type_node);
	  goto cond;

	cond:
	  PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2));
	  break;
          
	case OPCODE_goto:
	  PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2));
	  INVALIDATE_PC;
	  break;

	case OPCODE_wide:
	  switch (byte_ops[PC])
	    {
	    case OPCODE_iload:  case OPCODE_lload:
	    case OPCODE_fload:  case OPCODE_dload:  case OPCODE_aload:
	    case OPCODE_istore:  case OPCODE_lstore:
	    case OPCODE_fstore:  case OPCODE_dstore:  case OPCODE_astore:
	    case OPCODE_iinc:
	    case OPCODE_ret:
	      wide = 1;
	      break;
	    default:
	      VERIFICATION_ERROR ("invalid use of wide instruction");
	    }
	  break;

	case OPCODE_return:   type = void_type_node;   goto ret;
	case OPCODE_ireturn:
	  if ((TREE_CODE (return_type) == BOOLEAN_TYPE
	       || TREE_CODE (return_type) == CHAR_TYPE
	       || TREE_CODE (return_type) == INTEGER_TYPE)
	      && TYPE_PRECISION (return_type) <= 32)
	    type = return_type;
	  else
	    type = NULL_TREE;
	  goto ret;
	case OPCODE_lreturn:  type = long_type_node;   goto ret;
	case OPCODE_freturn:  type = float_type_node;  goto ret;
	case OPCODE_dreturn:  type = double_type_node; goto ret;
	case OPCODE_areturn:
	  if (TREE_CODE (return_type) == POINTER_TYPE)
	    type = return_type;
	  else
	    type = NULL_TREE;
	  goto ret;

	ret:
	  if (type != return_type)
	    VERIFICATION_ERROR ("incorrect ?return opcode");
	  if (type != void_type_node)
	    POP_TYPE (type, "return value has wrong type");
	  INVALIDATE_PC;
	  break;

	case OPCODE_getstatic: is_putting = 0;  is_static = 1;  goto field;
	case OPCODE_putstatic: is_putting = 1;  is_static = 1;  goto field;
	case OPCODE_getfield:  is_putting = 0;  is_static = 0;  goto field;
	case OPCODE_putfield:  is_putting = 1;  is_static = 0;  goto field;
	field:
	  {
	    tree field_signature, field_type;
	    index = IMMEDIATE_u2;

	    if (index <= 0 || index >= JPOOL_SIZE (current_jcf))
	      VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d");

	    if (JPOOL_TAG (current_jcf, index) != CONSTANT_Fieldref)
	      VERIFICATION_ERROR
		("field instruction does not reference a Fieldref");

	    field_signature
              = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);

	    field_type = get_type_from_signature (field_signature);

	    if (is_putting)
	      POP_TYPE (field_type, "incorrect type for field");

	    if (! is_static)
	      {
		int clindex
                  = COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool, index);

		tree self_type = get_class_constant (current_jcf, clindex);

		/* Defer actual checking until next pass. */
		POP_TYPE (self_type, "incorrect type for field reference");
	      }

	    if (! is_putting)
	      PUSH_TYPE (field_type);
	    break;
	  }

	case OPCODE_new:
	  PUSH_TYPE (get_class_constant (jcf, IMMEDIATE_u2));
	  break;

	case OPCODE_dup:     wide = 1; index = 0;  goto dup;
	case OPCODE_dup_x1:  wide = 1; index = 1;  goto dup;
	case OPCODE_dup_x2:  wide = 1; index = 2;  goto dup;
	case OPCODE_dup2:    wide = 2; index = 0;  goto dup;
	case OPCODE_dup2_x1: wide = 2; index = 1;  goto dup;
	case OPCODE_dup2_x2: wide = 2; index = 2;  goto dup;

	dup:
	  if (wide + index > stack_pointer)
	    VERIFICATION_ERROR ("stack underflow - dup* operation");
	  type_stack_dup (wide, index);
	  wide = 0;
	  break;

	case OPCODE_pop:  index = 1;  goto pop;
	case OPCODE_pop2: index = 2;  goto pop;

	pop:
	  if (stack_pointer < index)
	    VERIFICATION_ERROR ("stack underflow");
	  stack_pointer -= index;
	  break;

	case OPCODE_swap:
	  if (stack_pointer < 2)
	    VERIFICATION_ERROR ("stack underflow (in swap)");
	  else
	    {
	      tree type1 = stack_type_map[stack_pointer - 1];
	      tree type2 = stack_type_map[stack_pointer - 2];

	      if (type1 == void_type_node || type2 == void_type_node)
		VERIFICATION_ERROR ("verifier (swap):  double or long value");

	      stack_type_map[stack_pointer - 2] = type1;
	      stack_type_map[stack_pointer - 1] = type2;
	    }
	  break;

	case OPCODE_ldc:   index = IMMEDIATE_u1;  goto ldc;
	case OPCODE_ldc2_w:
	case OPCODE_ldc_w:
	  index = IMMEDIATE_u2;  goto ldc;

	ldc:
	  if (index <= 0 || index >= JPOOL_SIZE (current_jcf))
	    VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d in ldc");

	  int_value = -1;
	  switch (JPOOL_TAG (current_jcf, index) & ~CONSTANT_ResolvedFlag)
	    {
	    case CONSTANT_Integer:  type = int_type_node;  goto check_ldc;
	    case CONSTANT_Float:    type = float_type_node;  goto check_ldc;
	    case CONSTANT_String:   type = string_type_node; goto check_ldc;
	    case CONSTANT_Long:    type = long_type_node;    goto check_ldc;
	    case CONSTANT_Double:  type = double_type_node;  goto check_ldc;
	    check_ldc:
	      if (TYPE_IS_WIDE (type) == (op_code == OPCODE_ldc2_w))
		break;
	      /* ... else fall through ... */
	    default:
	      VERIFICATION_ERROR ("bad constant pool tag in ldc");
	    }
	  if (type == int_type_node)
	    {
	      i = TREE_INT_CST_LOW (get_constant (current_jcf, index));
	      goto push_int;
	    }
	  PUSH_TYPE (type);
	  break;

	case OPCODE_invokevirtual:
	case OPCODE_invokespecial:
	case OPCODE_invokestatic:
	case OPCODE_invokeinterface:
	  {
	    tree sig, method_name, method_type, self_type;
	    int self_is_interface, tag;
	    index = IMMEDIATE_u2;

	    if (index <= 0 || index >= JPOOL_SIZE (current_jcf))
	      VERIFICATION_ERROR_WITH_INDEX
		("bad constant pool index %d for invoke");

	    tag = JPOOL_TAG (current_jcf, index);

	    if (op_code == OPCODE_invokeinterface)
	      {
		if (tag != CONSTANT_InterfaceMethodref)
		  VERIFICATION_ERROR
		    ("invokeinterface does not reference an InterfaceMethodref");
	      }
	    else
	      {
		if (tag != CONSTANT_Methodref)
		  VERIFICATION_ERROR ("invoke does not reference a Methodref");
	      }

	    sig = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);

	    self_type
              = get_class_constant (current_jcf,
                                    COMPONENT_REF_CLASS_INDEX
                                      (&current_jcf->cpool, index));

	    if (! CLASS_LOADED_P (self_type))
	      load_class (self_type, 1);

	    self_is_interface = CLASS_INTERFACE (TYPE_NAME (self_type));
	    method_name = COMPONENT_REF_NAME (&current_jcf->cpool, index);
	    method_type = parse_signature_string ((const unsigned char *) IDENTIFIER_POINTER (sig),
						  IDENTIFIER_LENGTH (sig));

	    if (TREE_CODE (method_type) != FUNCTION_TYPE)
	      VERIFICATION_ERROR ("bad method signature");

	    pmessage = pop_argument_types (TYPE_ARG_TYPES (method_type));
	    if (pmessage != NULL)
	      {
		message = "invalid argument type";
		goto pop_type_error;
	      }

	    /* Can't invoke <clinit>.  */
	    if (ID_CLINIT_P (method_name))
	      VERIFICATION_ERROR ("invoke opcode can't invoke <clinit>");

	    /* Apart from invokespecial, can't invoke <init>.  */
	    if (op_code != OPCODE_invokespecial && ID_INIT_P (method_name))
	      VERIFICATION_ERROR ("invoke opcode can't invoke <init>");

	    if (op_code != OPCODE_invokestatic)
	      POP_TYPE (self_type,
			"stack type not subclass of invoked method's class");

	    switch (op_code)
	      {
	      case OPCODE_invokeinterface:
	        {
		  int nargs    = IMMEDIATE_u1;
		  int notZero  = IMMEDIATE_u1;
		
		  if (!nargs || notZero)
		      VERIFICATION_ERROR 
		        ("invalid argument number in invokeinterface");

		  /* If we verify/resolve the constant pool, as we should,
		     this test (and the one just following) are redundant.  */
		  if (! self_is_interface)
		    VERIFICATION_ERROR
                      ("invokeinterface calls method not in interface");
		  break;

		default:
		  if (self_is_interface)
		    VERIFICATION_ERROR ("method in interface called");
		}
	      }

	    if (TREE_TYPE (method_type) != void_type_node)
	      PUSH_TYPE (TREE_TYPE (method_type));
	    break;
	  }

	case OPCODE_arraylength:
	    /* Type checking actually made during code generation.  */
	    pop_type (ptr_type_node);
	    PUSH_TYPE (int_type_node);
	    break;
	    
        /* Q&D verification *or* more checking done during code generation
	   for byte/boolean/char/short, the value popped is a int coerced
	   into the right type before being stored.  */
	case OPCODE_iastore: type = int_type_node;     goto astore;
	case OPCODE_lastore: type = long_type_node;    goto astore;
	case OPCODE_fastore: type = float_type_node;   goto astore;
	case OPCODE_dastore: type = double_type_node;  goto astore;
	case OPCODE_aastore: type = ptr_type_node;     goto astore;
	case OPCODE_bastore: type = int_type_node; goto astore;
	case OPCODE_castore: type = int_type_node; goto astore;
	case OPCODE_sastore: type = int_type_node; goto astore;

	astore:
	  /* FIXME - need better verification here.  */
	  pop_type (type);	     /* new value */
	  pop_type (int_type_node);  /* index */
	  pop_type (ptr_type_node);  /* array */
	  break;

        /* Q&D verification *or* more checking done during code generation
	   for byte/boolean/char/short, the value pushed is a int.  */
	case OPCODE_iaload: type = int_type_node;     goto aload;
	case OPCODE_laload: type = long_type_node;    goto aload;
	case OPCODE_faload: type = float_type_node;   goto aload;
	case OPCODE_daload: type = double_type_node;  goto aload;
	case OPCODE_aaload: type = ptr_type_node;     goto aload;
	case OPCODE_baload: type = promote_type (byte_type_node);  goto aload;
	case OPCODE_caload: type = promote_type (char_type_node);  goto aload;
	case OPCODE_saload: type = promote_type (short_type_node); goto aload;

        aload:
	  pop_type (int_type_node);
	  tmp = pop_type (ptr_type_node);
	  if (is_array_type_p (tmp))
	    type = TYPE_ARRAY_ELEMENT (TREE_TYPE (tmp));
	  else if (tmp != TYPE_NULL)
	    VERIFICATION_ERROR ("array load from non-array type");
	  PUSH_TYPE (type);
	  break;

	case OPCODE_anewarray:
	  type = get_class_constant (current_jcf, IMMEDIATE_u2);
	  type = promote_type (type);
	  goto newarray;

	case OPCODE_newarray:
	  index = IMMEDIATE_u1;
	  type = decode_newarray_type (index);
	  if (type == NULL_TREE)
	    VERIFICATION_ERROR ("invalid type code in newarray opcode");
	  goto newarray;

	newarray:
	  if (int_value >= 0 && prevpc >= 0)
	    {
	      /* If the previous instruction pushed an int constant,
		 we want to use it. */
	      switch (byte_ops[prevpc])
		{
		case OPCODE_iconst_0: case OPCODE_iconst_1:
		case OPCODE_iconst_2: case OPCODE_iconst_3:
		case OPCODE_iconst_4: case OPCODE_iconst_5:
		case OPCODE_bipush:  case OPCODE_sipush:
		case OPCODE_ldc: case OPCODE_ldc_w:
		  break;
		default:
		  int_value = -1;
		}
	    }
	  else
	    int_value = -1;

	  type = build_java_array_type (type, int_value);
	  pop_type (int_type_node);
	  PUSH_TYPE (type);
	  break;

	case OPCODE_multianewarray:
	  {
	    int ndim, i;
	    index = IMMEDIATE_u2;
	    ndim  = IMMEDIATE_u1;

            if (ndim < 1)
              VERIFICATION_ERROR
                ("number of dimension lower that 1 in multianewarray" );

	    for (i = 0; i < ndim; i++)
	      pop_type (int_type_node);

	    PUSH_TYPE (get_class_constant (current_jcf, index));
	    break;
	  }

	case OPCODE_aconst_null:
	  PUSH_TYPE (ptr_type_node);
	  break;

	case OPCODE_athrow:
	  /* FIXME: athrow also empties the stack.  */
	  POP_TYPE (throwable_type_node, "missing throwable at athrow" );
	  INVALIDATE_PC;
	  break;

	case OPCODE_checkcast:
	  POP_TYPE (object_ptr_type_node,
		    "checkcast operand is not a pointer");
	  type = get_class_constant (current_jcf, IMMEDIATE_u2);
	  PUSH_TYPE (type);
	  break;

	case OPCODE_instanceof:
	  POP_TYPE (object_ptr_type_node,
		    "instanceof operand is not a pointer");
	  get_class_constant (current_jcf, IMMEDIATE_u2);
	  PUSH_TYPE (int_type_node);
	  break;

	case OPCODE_tableswitch:
	  {
	    jint low, high;

	    POP_TYPE (int_type_node, "missing int for tableswitch");

	    while (PC%4)
	      {
	        if (byte_ops[PC++])
		  VERIFICATION_ERROR ("bad alignment in tableswitch pad");
	      }

	    PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
	    low  = IMMEDIATE_s4;
	    high = IMMEDIATE_s4;

	    if (low > high)
	      VERIFICATION_ERROR ("unsorted low/high value in tableswitch");

	    while (low++ <= high)
	      PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));

	    INVALIDATE_PC;
	    break;
	  }

	case OPCODE_lookupswitch:
	  {
	    jint npairs, last = 0, not_registered = 1;

	    POP_TYPE (int_type_node, "missing int for lookupswitch");

	    while (PC%4)
	      {
	        if (byte_ops[PC++])
		  VERIFICATION_ERROR ("bad alignment in lookupswitch pad");
	      }

	    PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
	    npairs = IMMEDIATE_s4;
	    
	    if (npairs < 0)
	      VERIFICATION_ERROR ("invalid number of targets in lookupswitch");

	    while (npairs--)
	      {
	        int match = IMMEDIATE_s4;

		if (not_registered)
		  not_registered = 0;
		else if (last >= match)
		  VERIFICATION_ERROR ("unsorted match value in lookupswitch");

		last = match;
		PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
	      }
	    INVALIDATE_PC;
	    break;
	  }

	case OPCODE_monitorenter: 
	  /* fall thru */
	case OPCODE_monitorexit:
	  pop_type (ptr_type_node);
	  break;

	case OPCODE_goto_w:
	  PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
	  INVALIDATE_PC;
	  break;

	case OPCODE_jsr:
	  {
	    tree target = lookup_label (oldpc + IMMEDIATE_s2);
	    tree return_label = lookup_label (PC);
	    PUSH_TYPE (return_address_type_node);
	    /* The return label chain will be null if this is the first
	       time we've seen this jsr target.  */
            if (LABEL_RETURN_LABEL (target) == NULL_TREE)
	      {
		tree return_type_map;
		int nlocals = DECL_MAX_LOCALS (current_function_decl);
		index = nlocals + DECL_MAX_STACK (current_function_decl);
		return_type_map = make_tree_vec (index);

		while (index > nlocals)
		  TREE_VEC_ELT (return_type_map, --index) = TYPE_UNKNOWN;

		while (index > 0)
		  TREE_VEC_ELT (return_type_map, --index) = TYPE_UNUSED;

		LABEL_RETURN_LABEL (target)
		  = build_decl (LABEL_DECL, NULL_TREE, TREE_TYPE (target));
		LABEL_PC (LABEL_RETURN_LABEL (target)) = INVALID_PC;
		LABEL_RETURN_TYPE_STATE (target) = return_type_map;
		LABEL_IS_SUBR_START (target) = 1;
		LABEL_IN_SUBR (target) = 1;
		LABEL_SUBR_START (target) = target;
		LABEL_SUBR_CONTEXT (target) = current_subr;
	      }
	    else if (! LABEL_IS_SUBR_START (target)
		     || LABEL_SUBR_CONTEXT (target) != current_subr)
	      VERIFICATION_ERROR ("label part of different subroutines");

	    i = merge_type_state (target);
	    if (i != 0)
	      {
		if (i < 0)
		  VERIFICATION_ERROR ("types could not be merged at jsr");
		push_pending_label (target);
	      }
	    current_subr = target;

	    /* Chain return_pc onto LABEL_RETURN_LABELS (target) if needed. */
	    if (! value_member (return_label, LABEL_RETURN_LABELS (target)))
	      {
		LABEL_RETURN_LABELS (target)
		  = tree_cons (NULL_TREE, return_label,
			       LABEL_RETURN_LABELS (target));
	      }

	    if (LABEL_VERIFIED (target))
	      {
		tree return_map = LABEL_RETURN_TYPE_STATE (target);
		int len = TREE_VEC_LENGTH (return_map);
		stack_pointer = len - DECL_MAX_LOCALS (current_function_decl);
		while (--len >= 0)
		  {
		    if (TREE_VEC_ELT (return_map, len) != TYPE_UNUSED)
		      type_map[len] = TREE_VEC_ELT (return_map, len);
		  }
		current_subr = LABEL_SUBR_CONTEXT (target);
		if (RETURN_MAP_ADJUSTED (return_map))
		  PUSH_PENDING (return_label);
	      }

	    INVALIDATE_PC;
	  }
	  break;

	case OPCODE_ret:
	  if (current_subr == NULL_TREE)
	    VERIFICATION_ERROR ("ret instruction not in a jsr subroutine");
	  else
	    {
	      tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr);
	      int size
                = DECL_MAX_LOCALS (current_function_decl) + stack_pointer;
	      index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
	      wide = 0;
	      INVALIDATE_PC;
	      if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl)
		  || type_map[index] != TYPE_RETURN_ADDR)
		VERIFICATION_ERROR ("invalid ret index");

	      /* The next chunk of code is similar to an inlined version of
               merge_type_state (LABEL_RETURN_LABEL (current_subr)).
	       The main differences are that LABEL_RETURN_LABEL is
	       pre-allocated by the jsr (but we don't know the size then);
	       and that we have to handle TYPE_UNUSED.  */

	      if (! RETURN_MAP_ADJUSTED (ret_map))
		{
                  /* First return from this subroutine - fix stack
                  pointer.  */
		  TREE_VEC_LENGTH (ret_map) = size;
		  for (index = size;  --index >= 0; )
		    {
		      if (TREE_VEC_ELT (ret_map, index) != TYPE_UNUSED)
			TREE_VEC_ELT (ret_map, index) = type_map[index];
		    }
		  RETURN_MAP_ADJUSTED (ret_map) = 1;
		}
	      else
		{
		  if (TREE_VEC_LENGTH (ret_map) != size)
		    VERIFICATION_ERROR ("inconsistent stack size on ret");
		  for (index = 0;  index < size;  index++)
		    {
		      tree type = TREE_VEC_ELT (ret_map, index);
		      if (type != TYPE_UNUSED)
			{
			  type = merge_types (type, type_map[index]);
			  TREE_VEC_ELT (ret_map, index) = type;
			  if (type == TYPE_UNKNOWN)
			    {
			      if (index >= size - stack_pointer)
				VERIFICATION_ERROR
				  ("inconsistent types on ret from jsr");
			    }
			  else if (TYPE_IS_WIDE (type))
			    index++;
			}
		    }
		}
            }
          break;

        case OPCODE_jsr_w:        
        case OPCODE_ret_w:
        default:
          error ("unknown opcode %d@pc=%d during verification", op_code, PC-1);
          return 0;
        }

      prevpc = oldpc;

      /* The following test is true if we have entered or exited an exception
	 handler range *or* we have done a store to a local variable.
	 In either case we need to consider any exception handlers that
	 might "follow" this instruction.  */

      if (eh_ranges != prev_eh_ranges)
	{
	  int save_stack_pointer = stack_pointer;
	  int index = DECL_MAX_LOCALS (current_function_decl);
	  tree save_type = type_map[index];
	  tree save_current_subr = current_subr;
	  struct eh_range *ranges = find_handler (oldpc);
	  stack_pointer = 1;

	  for ( ; ranges != NULL_EH_RANGE; ranges = ranges->outer)
	    {
	      tree chain = ranges->handlers;

	      /* We need to determine if the handler is part of current_subr.
		 The are two cases:  (1) The exception catch range
		 is entirely within current_subr.  In that case the handler
		 is also part of current_subr.
		 (2) Some of the catch range is not in current_subr.
		 In that case, the handler is *not* part of current_subr.

		 Figuring out which is the case is not necessarily obvious,
		 in the presence of clever code generators (and obfuscators).
		 We make a simplifying assumption that in case (2) we
		 have that the current_subr is entirely within the catch range.
		 In that case we can assume if that if a caller (the jsr) of
		 a subroutine is within the catch range, then the handler is
		 *not* part of the subroutine, and vice versa.  */

	      current_subr = save_current_subr;
	      for ( ; current_subr != NULL_TREE;
		    current_subr = LABEL_SUBR_CONTEXT (current_subr))
		{
		  tree return_labels = LABEL_RETURN_LABELS (current_subr);
		  /* There could be multiple return_labels, but
		     we only need to check one.  */
		  int return_pc = LABEL_PC (TREE_VALUE (return_labels));
		  if (return_pc <= ranges->start_pc
		      || return_pc > ranges->end_pc)
		    break;
		}

	      for ( ; chain != NULL_TREE; chain = TREE_CHAIN (chain))
		{
		  tree handler = TREE_VALUE (chain);
		  tree type = TREE_PURPOSE (chain);

		  if (type == NULL_TREE)  /* a finally handler */
		    type = throwable_type_node;

		  type_map[index] = promote_type (type);

		  PUSH_PENDING (handler);
		}
	    }
	  stack_pointer = save_stack_pointer;
	  current_subr = save_current_subr;
	  type_map[index] = save_type;
	  prev_eh_ranges = eh_ranges;
	}
    }

  return 1;

 pop_type_error:
  error ("verification error at PC=%d", oldpc);
  if (message != NULL)
    error ("%s", message);
  error ("%s", pmessage);
  free (pmessage);
  return 0;

 stack_overflow:
  message = "stack overflow";
  goto verify_error;

 bad_pc:
  message = "program counter out of range";
  goto verify_error;

 error_with_index:
  error ("verification error at PC=%d", oldpc);
  error (message, index);
  return 0;

 verify_error:
  error ("verification error at PC=%d", oldpc);
  error ("%s", message);
  return 0;
}
예제 #27
0
void
print_node (FILE *file, const char *prefix, tree node, int indent)
{
    int hash;
    struct bucket *b;
    machine_mode mode;
    enum tree_code_class tclass;
    int len;
    int i;
    expanded_location xloc;
    enum tree_code code;

    if (node == 0)
        return;

    code = TREE_CODE (node);
    tclass = TREE_CODE_CLASS (code);

    /* Don't get too deep in nesting.  If the user wants to see deeper,
       it is easy to use the address of a lowest-level node
       as an argument in another call to debug_tree.  */

    if (indent > 24)
    {
        print_node_brief (file, prefix, node, indent);
        return;
    }

    if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration))
    {
        print_node_brief (file, prefix, node, indent);
        return;
    }

    /* It is unsafe to look at any other fields of an ERROR_MARK node.  */
    if (code == ERROR_MARK)
    {
        print_node_brief (file, prefix, node, indent);
        return;
    }

    /* Allow this function to be called if the table is not there.  */
    if (table)
    {
        hash = ((uintptr_t) node) % HASH_SIZE;

        /* If node is in the table, just mention its address.  */
        for (b = table[hash]; b; b = b->next)
            if (b->node == node)
            {
                print_node_brief (file, prefix, node, indent);
                return;
            }

        /* Add this node to the table.  */
        b = XNEW (struct bucket);
        b->node = node;
        b->next = table[hash];
        table[hash] = b;
    }

    /* Indent to the specified column, since this is the long form.  */
    indent_to (file, indent);

    /* Print the slot this node is in, and its code, and address.  */
    fprintf (file, "%s <%s", prefix, get_tree_code_name (code));
    dump_addr (file, " ", node);

    /* Print the name, if any.  */
    if (tclass == tcc_declaration)
    {
        if (DECL_NAME (node))
            fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node)));
        else if (code == LABEL_DECL
                 && LABEL_DECL_UID (node) != -1)
        {
            if (dump_flags & TDF_NOUID)
                fprintf (file, " L.xxxx");
            else
                fprintf (file, " L.%d", (int) LABEL_DECL_UID (node));
        }
        else
        {
            if (dump_flags & TDF_NOUID)
                fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D');
            else
                fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D',
                         DECL_UID (node));
        }
    }
    else if (tclass == tcc_type)
    {
        if (TYPE_NAME (node))
        {
            if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
                fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node)));
            else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
                     && DECL_NAME (TYPE_NAME (node)))
                fprintf (file, " %s",
                         IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))));
        }
    }
    if (code == IDENTIFIER_NODE)
        fprintf (file, " %s", IDENTIFIER_POINTER (node));

    if (code == INTEGER_CST)
    {
        if (indent <= 4)
            print_node_brief (file, "type", TREE_TYPE (node), indent + 4);
    }
    else if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
    {
        print_node (file, "type", TREE_TYPE (node), indent + 4);
        if (TREE_TYPE (node))
            indent_to (file, indent + 3);
    }

    if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node))
        fputs (" side-effects", file);

    if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node))
        fputs (" readonly", file);
    if (TYPE_P (node) && TYPE_ATOMIC (node))
        fputs (" atomic", file);
    if (!TYPE_P (node) && TREE_CONSTANT (node))
        fputs (" constant", file);
    else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node))
        fputs (" sizes-gimplified", file);

    if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node)))
        fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node));

    if (TREE_ADDRESSABLE (node))
        fputs (" addressable", file);
    if (TREE_THIS_VOLATILE (node))
        fputs (" volatile", file);
    if (TREE_ASM_WRITTEN (node))
        fputs (" asm_written", file);
    if (TREE_USED (node))
        fputs (" used", file);
    if (TREE_NOTHROW (node))
        fputs (" nothrow", file);
    if (TREE_PUBLIC (node))
        fputs (" public", file);
    if (TREE_PRIVATE (node))
        fputs (" private", file);
    if (TREE_PROTECTED (node))
        fputs (" protected", file);
    if (TREE_STATIC (node))
        fputs (code == CALL_EXPR ? " must-tail-call" : " static", file);
    if (TREE_DEPRECATED (node))
        fputs (" deprecated", file);
    if (TREE_VISITED (node))
        fputs (" visited", file);

    if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME)
    {
        if (TREE_LANG_FLAG_0 (node))
            fputs (" tree_0", file);
        if (TREE_LANG_FLAG_1 (node))
            fputs (" tree_1", file);
        if (TREE_LANG_FLAG_2 (node))
            fputs (" tree_2", file);
        if (TREE_LANG_FLAG_3 (node))
            fputs (" tree_3", file);
        if (TREE_LANG_FLAG_4 (node))
            fputs (" tree_4", file);
        if (TREE_LANG_FLAG_5 (node))
            fputs (" tree_5", file);
        if (TREE_LANG_FLAG_6 (node))
            fputs (" tree_6", file);
    }

    /* DECL_ nodes have additional attributes.  */

    switch (TREE_CODE_CLASS (code))
    {
    case tcc_declaration:
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
        {
            if (DECL_UNSIGNED (node))
                fputs (" unsigned", file);
            if (DECL_IGNORED_P (node))
                fputs (" ignored", file);
            if (DECL_ABSTRACT_P (node))
                fputs (" abstract", file);
            if (DECL_EXTERNAL (node))
                fputs (" external", file);
            if (DECL_NONLOCAL (node))
                fputs (" nonlocal", file);
        }
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
        {
            if (DECL_WEAK (node))
                fputs (" weak", file);
            if (DECL_IN_SYSTEM_HEADER (node))
                fputs (" in_system_header", file);
        }
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)
                && code != LABEL_DECL
                && code != FUNCTION_DECL
                && DECL_REGISTER (node))
            fputs (" regdecl", file);

        if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node))
            fputs (" suppress-debug", file);

        if (code == FUNCTION_DECL
                && DECL_FUNCTION_SPECIFIC_TARGET (node))
            fputs (" function-specific-target", file);
        if (code == FUNCTION_DECL
                && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node))
            fputs (" function-specific-opt", file);
        if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node))
            fputs (" autoinline", file);
        if (code == FUNCTION_DECL && DECL_BUILT_IN (node))
            fputs (" built-in", file);
        if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node))
            fputs (" static-chain", file);
        if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node))
            fputs (" tm-clone", file);

        if (code == FIELD_DECL && DECL_PACKED (node))
            fputs (" packed", file);
        if (code == FIELD_DECL && DECL_BIT_FIELD (node))
            fputs (" bit-field", file);
        if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node))
            fputs (" nonaddressable", file);

        if (code == LABEL_DECL && EH_LANDING_PAD_NR (node))
            fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node));

        if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node))
            fputs (" in-text-section", file);
        if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node))
            fputs (" in-constant-pool", file);
        if (code == VAR_DECL && DECL_COMMON (node))
            fputs (" common", file);
        if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node))
        {
            fputs (" ", file);
            fputs (tls_model_names[DECL_TLS_MODEL (node)], file);
        }

        if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
        {
            if (DECL_VIRTUAL_P (node))
                fputs (" virtual", file);
            if (DECL_PRESERVE_P (node))
                fputs (" preserve", file);
            if (DECL_LANG_FLAG_0 (node))
                fputs (" decl_0", file);
            if (DECL_LANG_FLAG_1 (node))
                fputs (" decl_1", file);
            if (DECL_LANG_FLAG_2 (node))
                fputs (" decl_2", file);
            if (DECL_LANG_FLAG_3 (node))
                fputs (" decl_3", file);
            if (DECL_LANG_FLAG_4 (node))
                fputs (" decl_4", file);
            if (DECL_LANG_FLAG_5 (node))
                fputs (" decl_5", file);
            if (DECL_LANG_FLAG_6 (node))
                fputs (" decl_6", file);
            if (DECL_LANG_FLAG_7 (node))
                fputs (" decl_7", file);

            mode = DECL_MODE (node);
            fprintf (file, " %s", GET_MODE_NAME (mode));
        }

        if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
                && DECL_BY_REFERENCE (node))
            fputs (" passed-by-reference", file);

        if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)  && DECL_DEFER_OUTPUT (node))
            fputs (" defer-output", file);


        xloc = expand_location (DECL_SOURCE_LOCATION (node));
        fprintf (file, " file %s line %d col %d", xloc.file, xloc.line,
                 xloc.column);

        if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
        {
            print_node (file, "size", DECL_SIZE (node), indent + 4);
            print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4);

            if (code != FUNCTION_DECL || DECL_BUILT_IN (node))
                indent_to (file, indent + 3);

            if (DECL_USER_ALIGN (node))
                fprintf (file, " user");

            fprintf (file, " align %d", DECL_ALIGN (node));
            if (code == FIELD_DECL)
                fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
                         DECL_OFFSET_ALIGN (node));

            if (code == FUNCTION_DECL && DECL_BUILT_IN (node))
            {
                if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD)
                    fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node));
                else
                    fprintf (file, " built-in %s:%s",
                             built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)],
                             built_in_names[(int) DECL_FUNCTION_CODE (node)]);
            }
        }
        if (code == FIELD_DECL)
        {
            print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4);
            print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node),
                        indent + 4);
            if (DECL_BIT_FIELD_TYPE (node))
                print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node),
                            indent + 4);
        }

        print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4);

        if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
        {
            print_node_brief (file, "attributes",
                              DECL_ATTRIBUTES (node), indent + 4);
            if (code != PARM_DECL)
                print_node_brief (file, "initial", DECL_INITIAL (node),
                                  indent + 4);
        }
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
        {
            print_node_brief (file, "abstract_origin",
                              DECL_ABSTRACT_ORIGIN (node), indent + 4);
        }
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
        {
            print_node (file, "result", DECL_RESULT_FLD (node), indent + 4);
        }

        lang_hooks.print_decl (file, node, indent);

        if (DECL_RTL_SET_P (node))
        {
            indent_to (file, indent + 4);
            print_rtl (file, DECL_RTL (node));
        }

        if (code == PARM_DECL)
        {
            print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4);

            if (DECL_INCOMING_RTL (node) != 0)
            {
                indent_to (file, indent + 4);
                fprintf (file, "incoming-rtl ");
                print_rtl (file, DECL_INCOMING_RTL (node));
            }
        }
        else if (code == FUNCTION_DECL
                 && DECL_STRUCT_FUNCTION (node) != 0)
        {
            print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4);
            indent_to (file, indent + 4);
            dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node));
        }

        if ((code == VAR_DECL || code == PARM_DECL)
                && DECL_HAS_VALUE_EXPR_P (node))
            print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4);

        /* Print the decl chain only if decl is at second level.  */
        if (indent == 4)
            print_node (file, "chain", TREE_CHAIN (node), indent + 4);
        else
            print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4);
        break;

    case tcc_type:
        if (TYPE_UNSIGNED (node))
            fputs (" unsigned", file);

        if (TYPE_NO_FORCE_BLK (node))
            fputs (" no-force-blk", file);

        if (TYPE_STRING_FLAG (node))
            fputs (" string-flag", file);

        if (TYPE_NEEDS_CONSTRUCTING (node))
            fputs (" needs-constructing", file);

        if ((code == RECORD_TYPE
                || code == UNION_TYPE
                || code == QUAL_UNION_TYPE
                || code == ARRAY_TYPE)
                && TYPE_REVERSE_STORAGE_ORDER (node))
            fputs (" reverse-storage-order", file);

        /* The transparent-union flag is used for different things in
        different nodes.  */
        if ((code == UNION_TYPE || code == RECORD_TYPE)
                && TYPE_TRANSPARENT_AGGR (node))
            fputs (" transparent-aggr", file);
        else if (code == ARRAY_TYPE
                 && TYPE_NONALIASED_COMPONENT (node))
            fputs (" nonaliased-component", file);

        if (TYPE_PACKED (node))
            fputs (" packed", file);

        if (TYPE_RESTRICT (node))
            fputs (" restrict", file);

        if (TYPE_LANG_FLAG_0 (node))
            fputs (" type_0", file);
        if (TYPE_LANG_FLAG_1 (node))
            fputs (" type_1", file);
        if (TYPE_LANG_FLAG_2 (node))
            fputs (" type_2", file);
        if (TYPE_LANG_FLAG_3 (node))
            fputs (" type_3", file);
        if (TYPE_LANG_FLAG_4 (node))
            fputs (" type_4", file);
        if (TYPE_LANG_FLAG_5 (node))
            fputs (" type_5", file);
        if (TYPE_LANG_FLAG_6 (node))
            fputs (" type_6", file);
        if (TYPE_LANG_FLAG_7 (node))
            fputs (" type_7", file);

        mode = TYPE_MODE (node);
        fprintf (file, " %s", GET_MODE_NAME (mode));

        print_node (file, "size", TYPE_SIZE (node), indent + 4);
        print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4);
        indent_to (file, indent + 3);

        if (TYPE_USER_ALIGN (node))
            fprintf (file, " user");

        fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC,
                 TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node),
                 (HOST_WIDE_INT) TYPE_ALIAS_SET (node));

        if (TYPE_STRUCTURAL_EQUALITY_P (node))
            fprintf (file, " structural equality");
        else
            dump_addr (file, " canonical type ", TYPE_CANONICAL (node));

        print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);

        if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE
                || code == FIXED_POINT_TYPE)
        {
            fprintf (file, " precision %d", TYPE_PRECISION (node));
            print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4);
            print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4);
        }

        if (code == ENUMERAL_TYPE)
            print_node (file, "values", TYPE_VALUES (node), indent + 4);
        else if (code == ARRAY_TYPE)
            print_node (file, "domain", TYPE_DOMAIN (node), indent + 4);
        else if (code == VECTOR_TYPE)
            fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node));
        else if (code == RECORD_TYPE
                 || code == UNION_TYPE
                 || code == QUAL_UNION_TYPE)
            print_node (file, "fields", TYPE_FIELDS (node), indent + 4);
        else if (code == FUNCTION_TYPE
                 || code == METHOD_TYPE)
        {
            if (TYPE_METHOD_BASETYPE (node))
                print_node_brief (file, "method basetype",
                                  TYPE_METHOD_BASETYPE (node), indent + 4);
            print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4);
        }
        else if (code == OFFSET_TYPE)
            print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node),
                              indent + 4);

        if (TYPE_CONTEXT (node))
            print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4);

        lang_hooks.print_type (file, node, indent);

        if (TYPE_POINTER_TO (node) || TREE_CHAIN (node))
            indent_to (file, indent + 3);

        print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node),
                          indent + 4);
        print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node),
                          indent + 4);
        print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4);
        break;

    case tcc_expression:
    case tcc_comparison:
    case tcc_unary:
    case tcc_binary:
    case tcc_reference:
    case tcc_statement:
    case tcc_vl_exp:
        if (code == BIND_EXPR)
        {
            print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4);
            print_node (file, "body", TREE_OPERAND (node, 1), indent + 4);
            print_node (file, "block", TREE_OPERAND (node, 2), indent + 4);
            break;
        }
        if (code == CALL_EXPR)
        {
            call_expr_arg_iterator iter;
            tree arg;
            print_node (file, "fn", CALL_EXPR_FN (node), indent + 4);
            print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node),
                        indent + 4);
            i = 0;
            FOR_EACH_CALL_EXPR_ARG (arg, iter, node)
            {
                char temp[10];
                sprintf (temp, "arg %d", i);
                print_node (file, temp, arg, indent + 4);
                i++;
            }
        }
예제 #28
0
파일: c-omp.c 프로젝트: ymgcmstk/gcc
static tree
check_omp_for_incr_expr (location_t loc, tree exp, tree decl)
{
  tree t;

  if (!INTEGRAL_TYPE_P (TREE_TYPE (exp))
      || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl)))
    return error_mark_node;

  if (exp == decl)
    return build_int_cst (TREE_TYPE (exp), 0);

  switch (TREE_CODE (exp))
    {
    CASE_CONVERT:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_convert_loc (loc, TREE_TYPE (exp), t);
      break;
    case MINUS_EXPR:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, MINUS_EXPR,
			    TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
      break;
    case PLUS_EXPR:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, PLUS_EXPR,
			    TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 1), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, PLUS_EXPR,
			    TREE_TYPE (exp), TREE_OPERAND (exp, 0), t);
      break;
    case COMPOUND_EXPR:
      {
	/* cp_build_modify_expr forces preevaluation of the RHS to make
	   sure that it is evaluated before the lvalue-rvalue conversion
	   is applied to the LHS.  Reconstruct the original expression.  */
	tree op0 = TREE_OPERAND (exp, 0);
	if (TREE_CODE (op0) == TARGET_EXPR
	    && !VOID_TYPE_P (TREE_TYPE (op0)))
	  {
	    tree op1 = TREE_OPERAND (exp, 1);
	    tree temp = TARGET_EXPR_SLOT (op0);
	    if (BINARY_CLASS_P (op1)
		&& TREE_OPERAND (op1, 1) == temp)
	      {
		op1 = copy_node (op1);
		TREE_OPERAND (op1, 1) = TARGET_EXPR_INITIAL (op0);
		return check_omp_for_incr_expr (loc, op1, decl);
	      }
	  }
	break;
      }
    default:
      break;
    }

  return error_mark_node;
}
예제 #29
0
bool
useless_type_conversion_p (tree outer_type, tree inner_type)
{
  /* Do the following before stripping toplevel qualifiers.  */
  if (POINTER_TYPE_P (inner_type)
      && POINTER_TYPE_P (outer_type))
    {
      /* Do not lose casts between pointers to different address spaces.  */
      if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
	  != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
	return false;
      /* Do not lose casts to function pointer types.  */
      if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
	   || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
	  && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
	       || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
	return false;
    }

  /* From now on qualifiers on value types do not matter.  */
  inner_type = TYPE_MAIN_VARIANT (inner_type);
  outer_type = TYPE_MAIN_VARIANT (outer_type);

  if (inner_type == outer_type)
    return true;

  /* Changes in machine mode are never useless conversions because the RTL
     middle-end expects explicit conversions between modes.  */
  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type))
    return false;

  /* If both the inner and outer types are integral types, then the
     conversion is not necessary if they have the same mode and
     signedness and precision, and both or neither are boolean.  */
  if (INTEGRAL_TYPE_P (inner_type)
      && INTEGRAL_TYPE_P (outer_type))
    {
      /* Preserve changes in signedness or precision.  */
      if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
	  || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
	return false;

      /* Preserve conversions to/from BOOLEAN_TYPE if types are not
	 of precision one.  */
      if (((TREE_CODE (inner_type) == BOOLEAN_TYPE)
	   != (TREE_CODE (outer_type) == BOOLEAN_TYPE))
	  && TYPE_PRECISION (outer_type) != 1)
	return false;

      /* We don't need to preserve changes in the types minimum or
	 maximum value in general as these do not generate code
	 unless the types precisions are different.  */
      return true;
    }

  /* Scalar floating point types with the same mode are compatible.  */
  else if (SCALAR_FLOAT_TYPE_P (inner_type)
	   && SCALAR_FLOAT_TYPE_P (outer_type))
    return true;

  /* Fixed point types with the same mode are compatible.  */
  else if (FIXED_POINT_TYPE_P (inner_type)
	   && FIXED_POINT_TYPE_P (outer_type))
    return true;

  /* We need to take special care recursing to pointed-to types.  */
  else if (POINTER_TYPE_P (inner_type)
	   && POINTER_TYPE_P (outer_type))
    {
      /* We do not care for const qualification of the pointed-to types
	 as const qualification has no semantic value to the middle-end.  */

      /* Otherwise pointers/references are equivalent.  */
      return true;
    }

  /* Recurse for complex types.  */
  else if (TREE_CODE (inner_type) == COMPLEX_TYPE
	   && TREE_CODE (outer_type) == COMPLEX_TYPE)
    return useless_type_conversion_p (TREE_TYPE (outer_type),
				      TREE_TYPE (inner_type));

  /* Recurse for vector types with the same number of subparts.  */
  else if (TREE_CODE (inner_type) == VECTOR_TYPE
	   && TREE_CODE (outer_type) == VECTOR_TYPE
	   && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
    return useless_type_conversion_p (TREE_TYPE (outer_type),
				      TREE_TYPE (inner_type));

  else if (TREE_CODE (inner_type) == ARRAY_TYPE
	   && TREE_CODE (outer_type) == ARRAY_TYPE)
    {
      /* Preserve various attributes.  */
      if (TYPE_REVERSE_STORAGE_ORDER (inner_type)
	  != TYPE_REVERSE_STORAGE_ORDER (outer_type))
	return false;
      if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type))
	return false;

      /* Conversions from array types with unknown extent to
	 array types with known extent are not useless.  */
      if (!TYPE_DOMAIN (inner_type) && TYPE_DOMAIN (outer_type))
	return false;

      /* Nor are conversions from array types with non-constant size to
         array types with constant size or to different size.  */
      if (TYPE_SIZE (outer_type)
	  && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST
	  && (!TYPE_SIZE (inner_type)
	      || TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST
	      || !tree_int_cst_equal (TYPE_SIZE (outer_type),
				      TYPE_SIZE (inner_type))))
	return false;

      /* Check conversions between arrays with partially known extents.
	 If the array min/max values are constant they have to match.
	 Otherwise allow conversions to unknown and variable extents.
	 In particular this declares conversions that may change the
	 mode to BLKmode as useless.  */
      if (TYPE_DOMAIN (inner_type)
	  && TYPE_DOMAIN (outer_type)
	  && TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type))
	{
	  tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type));
	  tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type));
	  tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type));
	  tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type));

	  /* After gimplification a variable min/max value carries no
	     additional information compared to a NULL value.  All that
	     matters has been lowered to be part of the IL.  */
	  if (inner_min && TREE_CODE (inner_min) != INTEGER_CST)
	    inner_min = NULL_TREE;
	  if (outer_min && TREE_CODE (outer_min) != INTEGER_CST)
	    outer_min = NULL_TREE;
	  if (inner_max && TREE_CODE (inner_max) != INTEGER_CST)
	    inner_max = NULL_TREE;
	  if (outer_max && TREE_CODE (outer_max) != INTEGER_CST)
	    outer_max = NULL_TREE;

	  /* Conversions NULL / variable <- cst are useless, but not
	     the other way around.  */
	  if (outer_min
	      && (!inner_min
		  || !tree_int_cst_equal (inner_min, outer_min)))
	    return false;
	  if (outer_max
	      && (!inner_max
		  || !tree_int_cst_equal (inner_max, outer_max)))
	    return false;
	}

      /* Recurse on the element check.  */
      return useless_type_conversion_p (TREE_TYPE (outer_type),
					TREE_TYPE (inner_type));
    }

  else if ((TREE_CODE (inner_type) == FUNCTION_TYPE
	    || TREE_CODE (inner_type) == METHOD_TYPE)
	   && TREE_CODE (inner_type) == TREE_CODE (outer_type))
    {
      tree outer_parm, inner_parm;

      /* If the return types are not compatible bail out.  */
      if (!useless_type_conversion_p (TREE_TYPE (outer_type),
				      TREE_TYPE (inner_type)))
	return false;

      /* Method types should belong to a compatible base class.  */
      if (TREE_CODE (inner_type) == METHOD_TYPE
	  && !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type),
					 TYPE_METHOD_BASETYPE (inner_type)))
	return false;

      /* A conversion to an unprototyped argument list is ok.  */
      if (!prototype_p (outer_type))
	return true;

      /* If the unqualified argument types are compatible the conversion
	 is useless.  */
      if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type))
	return true;

      for (outer_parm = TYPE_ARG_TYPES (outer_type),
	   inner_parm = TYPE_ARG_TYPES (inner_type);
	   outer_parm && inner_parm;
	   outer_parm = TREE_CHAIN (outer_parm),
	   inner_parm = TREE_CHAIN (inner_parm))
	if (!useless_type_conversion_p
	       (TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)),
		TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm))))
	  return false;

      /* If there is a mismatch in the number of arguments the functions
	 are not compatible.  */
      if (outer_parm || inner_parm)
	return false;

      /* Defer to the target if necessary.  */
      if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type))
	return comp_type_attributes (outer_type, inner_type) != 0;

      return true;
    }

  /* For aggregates we rely on TYPE_CANONICAL exclusively and require
     explicit conversions for types involving to be structurally
     compared types.  */
  else if (AGGREGATE_TYPE_P (inner_type)
	   && TREE_CODE (inner_type) == TREE_CODE (outer_type))
    return TYPE_CANONICAL (inner_type)
	   && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type);

  else if (TREE_CODE (inner_type) == OFFSET_TYPE
	   && TREE_CODE (outer_type) == OFFSET_TYPE)
    return useless_type_conversion_p (TREE_TYPE (outer_type),
				      TREE_TYPE (inner_type))
	   && useless_type_conversion_p
	        (TYPE_OFFSET_BASETYPE (outer_type),
		 TYPE_OFFSET_BASETYPE (inner_type));

  return false;
}
예제 #30
0
파일: c-omp.c 프로젝트: ymgcmstk/gcc
tree
c_finish_omp_for (location_t locus, enum tree_code code, tree declv,
		  tree orig_declv, tree initv, tree condv, tree incrv,
		  tree body, tree pre_body)
{
  location_t elocus;
  bool fail = false;
  int i;

  if ((code == CILK_SIMD || code == CILK_FOR)
      && !c_check_cilk_loop (locus, TREE_VEC_ELT (declv, 0)))
    fail = true;

  gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv));
  gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv));
  gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv));
  for (i = 0; i < TREE_VEC_LENGTH (declv); i++)
    {
      tree decl = TREE_VEC_ELT (declv, i);
      tree init = TREE_VEC_ELT (initv, i);
      tree cond = TREE_VEC_ELT (condv, i);
      tree incr = TREE_VEC_ELT (incrv, i);

      elocus = locus;
      if (EXPR_HAS_LOCATION (init))
	elocus = EXPR_LOCATION (init);

      /* Validate the iteration variable.  */
      if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
	  && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
	{
	  error_at (elocus, "invalid type for iteration variable %qE", decl);
	  fail = true;
	}

      /* In the case of "for (int i = 0...)", init will be a decl.  It should
	 have a DECL_INITIAL that we can turn into an assignment.  */
      if (init == decl)
	{
	  elocus = DECL_SOURCE_LOCATION (decl);

	  init = DECL_INITIAL (decl);
	  if (init == NULL)
	    {
	      error_at (elocus, "%qE is not initialized", decl);
	      init = integer_zero_node;
	      fail = true;
	    }
	  DECL_INITIAL (decl) = NULL_TREE;

	  init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR,
	      			    /* FIXME diagnostics: This should
				       be the location of the INIT.  */
	      			    elocus,
				    init,
				    NULL_TREE);
	}
      if (init != error_mark_node)
	{
	  gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
	  gcc_assert (TREE_OPERAND (init, 0) == decl);
	}

      if (cond == NULL_TREE)
	{
	  error_at (elocus, "missing controlling predicate");
	  fail = true;
	}
      else
	{
	  bool cond_ok = false;

	  if (EXPR_HAS_LOCATION (cond))
	    elocus = EXPR_LOCATION (cond);

	  if (TREE_CODE (cond) == LT_EXPR
	      || TREE_CODE (cond) == LE_EXPR
	      || TREE_CODE (cond) == GT_EXPR
	      || TREE_CODE (cond) == GE_EXPR
	      || TREE_CODE (cond) == NE_EXPR
	      || TREE_CODE (cond) == EQ_EXPR)
	    {
	      tree op0 = TREE_OPERAND (cond, 0);
	      tree op1 = TREE_OPERAND (cond, 1);

	      /* 2.5.1.  The comparison in the condition is computed in
		 the type of DECL, otherwise the behavior is undefined.

		 For example:
		 long n; int i;
		 i < n;

		 according to ISO will be evaluated as:
		 (long)i < n;

		 We want to force:
		 i < (int)n;  */
	      if (TREE_CODE (op0) == NOP_EXPR
		  && decl == TREE_OPERAND (op0, 0))
		{
		  TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
		  TREE_OPERAND (cond, 1)
		    = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl),
				   TREE_OPERAND (cond, 1));
		}
	      else if (TREE_CODE (op1) == NOP_EXPR
		       && decl == TREE_OPERAND (op1, 0))
		{
		  TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
		  TREE_OPERAND (cond, 0)
		    = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl),
				   TREE_OPERAND (cond, 0));
		}

	      if (decl == TREE_OPERAND (cond, 0))
		cond_ok = true;
	      else if (decl == TREE_OPERAND (cond, 1))
		{
		  TREE_SET_CODE (cond,
				 swap_tree_comparison (TREE_CODE (cond)));
		  TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
		  TREE_OPERAND (cond, 0) = decl;
		  cond_ok = true;
		}

	      if (TREE_CODE (cond) == NE_EXPR
		  || TREE_CODE (cond) == EQ_EXPR)
		{
		  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
		    {
		      if (code != CILK_SIMD && code != CILK_FOR)
			cond_ok = false;
		    }
		  else if (operand_equal_p (TREE_OPERAND (cond, 1),
					    TYPE_MIN_VALUE (TREE_TYPE (decl)),
					    0))
		    TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR
					 ? GT_EXPR : LE_EXPR);
		  else if (operand_equal_p (TREE_OPERAND (cond, 1),
					    TYPE_MAX_VALUE (TREE_TYPE (decl)),
					    0))
		    TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR
					 ? LT_EXPR : GE_EXPR);
		  else if (code != CILK_SIMD && code != CILK_FOR)
		    cond_ok = false;
		}
	    }

	  if (!cond_ok)
	    {
	      error_at (elocus, "invalid controlling predicate");
	      fail = true;
	    }
	}

      if (incr == NULL_TREE)
	{
	  error_at (elocus, "missing increment expression");
	  fail = true;
	}
      else
	{
	  bool incr_ok = false;

	  if (EXPR_HAS_LOCATION (incr))
	    elocus = EXPR_LOCATION (incr);

	  /* Check all the valid increment expressions: v++, v--, ++v, --v,
	     v = v + incr, v = incr + v and v = v - incr.  */
	  switch (TREE_CODE (incr))
	    {
	    case POSTINCREMENT_EXPR:
	    case PREINCREMENT_EXPR:
	    case POSTDECREMENT_EXPR:
	    case PREDECREMENT_EXPR:
	      if (TREE_OPERAND (incr, 0) != decl)
		break;

	      incr_ok = true;
	      incr = c_omp_for_incr_canonicalize_ptr (elocus, decl, incr);
	      break;

	    case COMPOUND_EXPR:
	      if (TREE_CODE (TREE_OPERAND (incr, 0)) != SAVE_EXPR
		  || TREE_CODE (TREE_OPERAND (incr, 1)) != MODIFY_EXPR)
		break;
	      incr = TREE_OPERAND (incr, 1);
	      /* FALLTHRU */
	    case MODIFY_EXPR:
	      if (TREE_OPERAND (incr, 0) != decl)
		break;
	      if (TREE_OPERAND (incr, 1) == decl)
		break;
	      if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
		  && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
		      || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
		incr_ok = true;
	      else if ((TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
			|| (TREE_CODE (TREE_OPERAND (incr, 1))
			    == POINTER_PLUS_EXPR))
		       && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
		incr_ok = true;
	      else
		{
		  tree t = check_omp_for_incr_expr (elocus,
						    TREE_OPERAND (incr, 1),
						    decl);
		  if (t != error_mark_node)
		    {
		      incr_ok = true;
		      t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
		      incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
		    }
		}
	      break;

	    default:
	      break;
	    }
	  if (!incr_ok)
	    {
	      error_at (elocus, "invalid increment expression");
	      fail = true;
	    }
	}

      TREE_VEC_ELT (initv, i) = init;
      TREE_VEC_ELT (incrv, i) = incr;
    }

  if (fail)
    return NULL;
  else
    {
      tree t = make_node (code);

      TREE_TYPE (t) = void_type_node;
      OMP_FOR_INIT (t) = initv;
      OMP_FOR_COND (t) = condv;
      OMP_FOR_INCR (t) = incrv;
      OMP_FOR_BODY (t) = body;
      OMP_FOR_PRE_BODY (t) = pre_body;
      if (code == OMP_FOR)
	OMP_FOR_ORIG_DECLS (t) = orig_declv;

      SET_EXPR_LOCATION (t, locus);
      return add_stmt (t);
    }
}