예제 #1
0
static bool
tree_estimate_loop_size (struct loop *loop, edge exit, edge edge_to_cancel, struct loop_size *size,
			 int upper_bound)
{
  basic_block *body = get_loop_body (loop);
  gimple_stmt_iterator gsi;
  unsigned int i;
  bool after_exit;
  vec<basic_block> path = get_loop_hot_path (loop);

  size->overall = 0;
  size->eliminated_by_peeling = 0;
  size->last_iteration = 0;
  size->last_iteration_eliminated_by_peeling = 0;
  size->num_pure_calls_on_hot_path = 0;
  size->num_non_pure_calls_on_hot_path = 0;
  size->non_call_stmts_on_hot_path = 0;
  size->num_branches_on_hot_path = 0;
  size->constant_iv = 0;

  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "Estimating sizes for loop %i\n", loop->num);
  for (i = 0; i < loop->num_nodes; i++)
    {
      if (edge_to_cancel && body[i] != edge_to_cancel->src
	  && dominated_by_p (CDI_DOMINATORS, body[i], edge_to_cancel->src))
	after_exit = true;
      else
	after_exit = false;
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, " BB: %i, after_exit: %i\n", body[i]->index, after_exit);

      for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple *stmt = gsi_stmt (gsi);
	  int num = estimate_num_insns (stmt, &eni_size_weights);
	  bool likely_eliminated = false;
	  bool likely_eliminated_last = false;
	  bool likely_eliminated_peeled = false;

	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, "  size: %3i ", num);
	      print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, 0);
	    }

	  /* Look for reasons why we might optimize this stmt away. */

	  if (gimple_has_side_effects (stmt))
	    ;
	  /* Exit conditional.  */
	  else if (exit && body[i] == exit->src
		   && stmt == last_stmt (exit->src))
	    {
	      if (dump_file && (dump_flags & TDF_DETAILS))
	        fprintf (dump_file, "   Exit condition will be eliminated "
			 "in peeled copies.\n");
	      likely_eliminated_peeled = true;
	    }
	  else if (edge_to_cancel && body[i] == edge_to_cancel->src
		   && stmt == last_stmt (edge_to_cancel->src))
	    {
	      if (dump_file && (dump_flags & TDF_DETAILS))
	        fprintf (dump_file, "   Exit condition will be eliminated "
			 "in last copy.\n");
	      likely_eliminated_last = true;
	    }
	  /* Sets of IV variables  */
	  else if (gimple_code (stmt) == GIMPLE_ASSIGN
	      && constant_after_peeling (gimple_assign_lhs (stmt), stmt, loop))
	    {
	      if (dump_file && (dump_flags & TDF_DETAILS))
	        fprintf (dump_file, "   Induction variable computation will"
			 " be folded away.\n");
	      likely_eliminated = true;
	    }
	  /* Assignments of IV variables.  */
	  else if (gimple_code (stmt) == GIMPLE_ASSIGN
		   && TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME
		   && constant_after_peeling (gimple_assign_rhs1 (stmt), stmt, loop)
		   && (gimple_assign_rhs_class (stmt) != GIMPLE_BINARY_RHS
		       || constant_after_peeling (gimple_assign_rhs2 (stmt),
		       				  stmt, loop)))
	    {
	      size->constant_iv = true;
	      if (dump_file && (dump_flags & TDF_DETAILS))
	        fprintf (dump_file, "   Constant expression will be folded away.\n");
	      likely_eliminated = true;
	    }
	  /* Conditionals.  */
	  else if ((gimple_code (stmt) == GIMPLE_COND
		    && constant_after_peeling (gimple_cond_lhs (stmt), stmt, loop)
		    && constant_after_peeling (gimple_cond_rhs (stmt), stmt, loop)
		    /* We don't simplify all constant compares so make sure
		       they are not both constant already.  See PR70288.  */
		    && (! is_gimple_min_invariant (gimple_cond_lhs (stmt))
			|| ! is_gimple_min_invariant (gimple_cond_rhs (stmt))))
		   || (gimple_code (stmt) == GIMPLE_SWITCH
		       && constant_after_peeling (gimple_switch_index (
						    as_a <gswitch *> (stmt)),
						  stmt, loop)
		       && ! is_gimple_min_invariant (gimple_switch_index (
						       as_a <gswitch *> (stmt)))))
	    {
	      if (dump_file && (dump_flags & TDF_DETAILS))
	        fprintf (dump_file, "   Constant conditional.\n");
	      likely_eliminated = true;
	    }

	  size->overall += num;
	  if (likely_eliminated || likely_eliminated_peeled)
	    size->eliminated_by_peeling += num;
	  if (!after_exit)
	    {
	      size->last_iteration += num;
	      if (likely_eliminated || likely_eliminated_last)
		size->last_iteration_eliminated_by_peeling += num;
	    }
	  if ((size->overall * 3 / 2 - size->eliminated_by_peeling
	      - size->last_iteration_eliminated_by_peeling) > upper_bound)
	    {
              free (body);
	      path.release ();
	      return true;
	    }
	}
    }
  while (path.length ())
    {
      basic_block bb = path.pop ();
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple *stmt = gsi_stmt (gsi);
	  if (gimple_code (stmt) == GIMPLE_CALL)
	    {
	      int flags = gimple_call_flags (stmt);
	      tree decl = gimple_call_fndecl (stmt);

	      if (decl && DECL_IS_BUILTIN (decl)
		  && is_inexpensive_builtin (decl))
		;
	      else if (flags & (ECF_PURE | ECF_CONST))
		size->num_pure_calls_on_hot_path++;
	      else
		size->num_non_pure_calls_on_hot_path++;
	      size->num_branches_on_hot_path ++;
	    }
	  else if (gimple_code (stmt) != GIMPLE_CALL
		   && gimple_code (stmt) != GIMPLE_DEBUG)
	    size->non_call_stmts_on_hot_path++;
	  if (((gimple_code (stmt) == GIMPLE_COND
	        && (!constant_after_peeling (gimple_cond_lhs (stmt), stmt, loop)
		    || constant_after_peeling (gimple_cond_rhs (stmt), stmt, loop)))
	       || (gimple_code (stmt) == GIMPLE_SWITCH
		   && !constant_after_peeling (gimple_switch_index (
						 as_a <gswitch *> (stmt)),
					       stmt, loop)))
	      && (!exit || bb != exit->src))
	    size->num_branches_on_hot_path++;
	}
    }
  path.release ();
  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "size: %i-%i, last_iteration: %i-%i\n", size->overall,
    	     size->eliminated_by_peeling, size->last_iteration,
	     size->last_iteration_eliminated_by_peeling);

  free (body);
  return false;
}
예제 #2
0
bool
gimple_simplify (gimple *stmt,
		 code_helper *rcode, tree *ops,
		 gimple_seq *seq,
		 tree (*valueize)(tree), tree (*top_valueize)(tree))
{
  switch (gimple_code (stmt))
    {
    case GIMPLE_ASSIGN:
      {
	enum tree_code code = gimple_assign_rhs_code (stmt);
	tree type = TREE_TYPE (gimple_assign_lhs (stmt));
	switch (gimple_assign_rhs_class (stmt))
	  {
	  case GIMPLE_SINGLE_RHS:
	    if (code == REALPART_EXPR
		|| code == IMAGPART_EXPR
		|| code == VIEW_CONVERT_EXPR)
	      {
		tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
		bool valueized = false;
		op0 = do_valueize (op0, top_valueize, valueized);
		*rcode = code;
		ops[0] = op0;
		return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
			|| valueized);
	      }
	    else if (code == BIT_FIELD_REF)
	      {
		tree rhs1 = gimple_assign_rhs1 (stmt);
		tree op0 = TREE_OPERAND (rhs1, 0);
		bool valueized = false;
		op0 = do_valueize (op0, top_valueize, valueized);
		*rcode = code;
		ops[0] = op0;
		ops[1] = TREE_OPERAND (rhs1, 1);
		ops[2] = TREE_OPERAND (rhs1, 2);
		return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
			|| valueized);
	      }
	    else if (code == SSA_NAME
		     && top_valueize)
	      {
		tree op0 = gimple_assign_rhs1 (stmt);
		tree valueized = top_valueize (op0);
		if (!valueized || op0 == valueized)
		  return false;
		ops[0] = valueized;
		*rcode = TREE_CODE (op0);
		return true;
	      }
	    break;
	  case GIMPLE_UNARY_RHS:
	    {
	      tree rhs1 = gimple_assign_rhs1 (stmt);
	      bool valueized = false;
	      rhs1 = do_valueize (rhs1, top_valueize, valueized);
	      *rcode = code;
	      ops[0] = rhs1;
	      return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
		      || valueized);
	    }
	  case GIMPLE_BINARY_RHS:
	    {
	      tree rhs1 = gimple_assign_rhs1 (stmt);
	      tree rhs2 = gimple_assign_rhs2 (stmt);
	      bool valueized = false;
	      rhs1 = do_valueize (rhs1, top_valueize, valueized);
	      rhs2 = do_valueize (rhs2, top_valueize, valueized);
	      *rcode = code;
	      ops[0] = rhs1;
	      ops[1] = rhs2;
	      return (gimple_resimplify2 (seq, rcode, type, ops, valueize)
		      || valueized);
	    }
	  case GIMPLE_TERNARY_RHS:
	    {
	      bool valueized = false;
	      tree rhs1 = gimple_assign_rhs1 (stmt);
	      /* If this is a [VEC_]COND_EXPR first try to simplify an
		 embedded GENERIC condition.  */
	      if (code == COND_EXPR
		  || code == VEC_COND_EXPR)
		{
		  if (COMPARISON_CLASS_P (rhs1))
		    {
		      tree lhs = TREE_OPERAND (rhs1, 0);
		      tree rhs = TREE_OPERAND (rhs1, 1);
		      lhs = do_valueize (lhs, top_valueize, valueized);
		      rhs = do_valueize (rhs, top_valueize, valueized);
		      code_helper rcode2 = TREE_CODE (rhs1);
		      tree ops2[3] = {};
		      ops2[0] = lhs;
		      ops2[1] = rhs;
		      if ((gimple_resimplify2 (seq, &rcode2, TREE_TYPE (rhs1),
					       ops2, valueize)
			   || valueized)
			  && rcode2.is_tree_code ())
			{
			  valueized = true;
			  if (TREE_CODE_CLASS ((enum tree_code)rcode2)
			      == tcc_comparison)
			    rhs1 = build2 (rcode2, TREE_TYPE (rhs1),
					   ops2[0], ops2[1]);
			  else if (rcode2 == SSA_NAME
				   || rcode2 == INTEGER_CST)
			    rhs1 = ops2[0];
			  else
			    valueized = false;
			}
		    }
		}
	      tree rhs2 = gimple_assign_rhs2 (stmt);
	      tree rhs3 = gimple_assign_rhs3 (stmt);
	      rhs1 = do_valueize (rhs1, top_valueize, valueized);
	      rhs2 = do_valueize (rhs2, top_valueize, valueized);
	      rhs3 = do_valueize (rhs3, top_valueize, valueized);
	      *rcode = code;
	      ops[0] = rhs1;
	      ops[1] = rhs2;
	      ops[2] = rhs3;
	      return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
		      || valueized);
	    }
	  default:
	    gcc_unreachable ();
	  }
	break;
      }

    case GIMPLE_CALL:
      /* ???  This way we can't simplify calls with side-effects.  */
      if (gimple_call_lhs (stmt) != NULL_TREE
	  && gimple_call_num_args (stmt) >= 1
	  && gimple_call_num_args (stmt) <= 3)
	{
	  tree fn = gimple_call_fn (stmt);
	  /* ???  Internal function support missing.  */
	  if (!fn)
	    return false;
	  bool valueized = false;
	  fn = do_valueize (fn, top_valueize, valueized);
	  if (TREE_CODE (fn) != ADDR_EXPR
	      || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
	    return false;

	  tree decl = TREE_OPERAND (fn, 0);
	  if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL
	      || !builtin_decl_implicit (DECL_FUNCTION_CODE (decl))
	      || !gimple_builtin_call_types_compatible_p (stmt, decl))
	    return false;

	  tree type = TREE_TYPE (gimple_call_lhs (stmt));
	  *rcode = DECL_FUNCTION_CODE (decl);
	  for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i)
	    {
	      tree arg = gimple_call_arg (stmt, i);
	      ops[i] = do_valueize (arg, top_valueize, valueized);
	    }
	  switch (gimple_call_num_args (stmt))
	    {
	    case 1:
	      return (gimple_resimplify1 (seq, rcode, type, ops, valueize)
		      || valueized);
	    case 2:
	      return (gimple_resimplify2 (seq, rcode, type, ops, valueize)
		      || valueized);
	    case 3:
	      return (gimple_resimplify3 (seq, rcode, type, ops, valueize)
		      || valueized);
	    default:
	     gcc_unreachable ();
	    }
	}
      break;

    case GIMPLE_COND:
      {
	tree lhs = gimple_cond_lhs (stmt);
	tree rhs = gimple_cond_rhs (stmt);
	bool valueized = false;
	lhs = do_valueize (lhs, top_valueize, valueized);
	rhs = do_valueize (rhs, top_valueize, valueized);
	*rcode = gimple_cond_code (stmt);
	ops[0] = lhs;
	ops[1] = rhs;
        return (gimple_resimplify2 (seq, rcode,
				    boolean_type_node, ops, valueize)
		|| valueized);
      }

    default:
      break;
    }

  return false;
}
예제 #3
0
bool
gimple_simplify (gimple stmt,
		 code_helper *rcode, tree *ops,
		 gimple_seq *seq, tree (*valueize)(tree))
{
  switch (gimple_code (stmt))
    {
    case GIMPLE_ASSIGN:
      {
	enum tree_code code = gimple_assign_rhs_code (stmt);
	tree type = TREE_TYPE (gimple_assign_lhs (stmt));
	switch (gimple_assign_rhs_class (stmt))
	  {
	  case GIMPLE_SINGLE_RHS:
	    if (code == REALPART_EXPR
		|| code == IMAGPART_EXPR
		|| code == VIEW_CONVERT_EXPR)
	      {
		tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
		if (valueize && TREE_CODE (op0) == SSA_NAME)
		  {
		    tree tem = valueize (op0);
		    if (tem)
		      op0 = tem;
		  }
		*rcode = code;
		ops[0] = op0;
		return gimple_resimplify1 (seq, rcode, type, ops, valueize);
	      }
	    else if (code == BIT_FIELD_REF)
	      {
		tree rhs1 = gimple_assign_rhs1 (stmt);
		tree op0 = TREE_OPERAND (rhs1, 0);
		if (valueize && TREE_CODE (op0) == SSA_NAME)
		  {
		    tree tem = valueize (op0);
		    if (tem)
		      op0 = tem;
		  }
		*rcode = code;
		ops[0] = op0;
		ops[1] = TREE_OPERAND (rhs1, 1);
		ops[2] = TREE_OPERAND (rhs1, 2);
		return gimple_resimplify3 (seq, rcode, type, ops, valueize);
	      }
	    else if (code == SSA_NAME
		     && valueize)
	      {
		tree op0 = gimple_assign_rhs1 (stmt);
		tree valueized = valueize (op0);
		if (!valueized || op0 == valueized)
		  return false;
		ops[0] = valueized;
		*rcode = TREE_CODE (op0);
		return true;
	      }
	    break;
	  case GIMPLE_UNARY_RHS:
	    {
	      tree rhs1 = gimple_assign_rhs1 (stmt);
	      if (valueize && TREE_CODE (rhs1) == SSA_NAME)
		{
		  tree tem = valueize (rhs1);
		  if (tem)
		    rhs1 = tem;
		}
	      *rcode = code;
	      ops[0] = rhs1;
	      return gimple_resimplify1 (seq, rcode, type, ops, valueize);
	    }
	  case GIMPLE_BINARY_RHS:
	    {
	      tree rhs1 = gimple_assign_rhs1 (stmt);
	      if (valueize && TREE_CODE (rhs1) == SSA_NAME)
		{
		  tree tem = valueize (rhs1);
		  if (tem)
		    rhs1 = tem;
		}
	      tree rhs2 = gimple_assign_rhs2 (stmt);
	      if (valueize && TREE_CODE (rhs2) == SSA_NAME)
		{
		  tree tem = valueize (rhs2);
		  if (tem)
		    rhs2 = tem;
		}
	      *rcode = code;
	      ops[0] = rhs1;
	      ops[1] = rhs2;
	      return gimple_resimplify2 (seq, rcode, type, ops, valueize);
	    }
	  case GIMPLE_TERNARY_RHS:
	    {
	      tree rhs1 = gimple_assign_rhs1 (stmt);
	      if (valueize && TREE_CODE (rhs1) == SSA_NAME)
		{
		  tree tem = valueize (rhs1);
		  if (tem)
		    rhs1 = tem;
		}
	      tree rhs2 = gimple_assign_rhs2 (stmt);
	      if (valueize && TREE_CODE (rhs2) == SSA_NAME)
		{
		  tree tem = valueize (rhs2);
		  if (tem)
		    rhs2 = tem;
		}
	      tree rhs3 = gimple_assign_rhs3 (stmt);
	      if (valueize && TREE_CODE (rhs3) == SSA_NAME)
		{
		  tree tem = valueize (rhs3);
		  if (tem)
		    rhs3 = tem;
		}
	      *rcode = code;
	      ops[0] = rhs1;
	      ops[1] = rhs2;
	      ops[2] = rhs3;
	      return gimple_resimplify3 (seq, rcode, type, ops, valueize);
	    }
	  default:
	    gcc_unreachable ();
	  }
	break;
      }

    case GIMPLE_CALL:
      /* ???  This way we can't simplify calls with side-effects.  */
      if (gimple_call_lhs (stmt) != NULL_TREE)
	{
	  tree fn = gimple_call_fn (stmt);
	  /* ???  Internal function support missing.  */
	  if (!fn)
	    return false;
	  if (valueize && TREE_CODE (fn) == SSA_NAME)
	    {
	      tree tem = valueize (fn);
	      if (tem)
		fn = tem;
	    }
	  if (!fn
	      || TREE_CODE (fn) != ADDR_EXPR
	      || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL
	      || DECL_BUILT_IN_CLASS (TREE_OPERAND (fn, 0)) != BUILT_IN_NORMAL
	      || !builtin_decl_implicit (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0)))
	      || !gimple_builtin_call_types_compatible_p (stmt,
							  TREE_OPERAND (fn, 0)))
	    return false;

	  tree decl = TREE_OPERAND (fn, 0);
	  tree type = TREE_TYPE (gimple_call_lhs (stmt));
	  switch (gimple_call_num_args (stmt))
	    {
	    case 1:
	      {
		tree arg1 = gimple_call_arg (stmt, 0);
		if (valueize && TREE_CODE (arg1) == SSA_NAME)
		  {
		    tree tem = valueize (arg1);
		    if (tem)
		      arg1 = tem;
		  }
		*rcode = DECL_FUNCTION_CODE (decl);
		ops[0] = arg1;
		return gimple_resimplify1 (seq, rcode, type, ops, valueize);
	      }
	    case 2:
	      {
		tree arg1 = gimple_call_arg (stmt, 0);
		if (valueize && TREE_CODE (arg1) == SSA_NAME)
		  {
		    tree tem = valueize (arg1);
		    if (tem)
		      arg1 = tem;
		  }
		tree arg2 = gimple_call_arg (stmt, 1);
		if (valueize && TREE_CODE (arg2) == SSA_NAME)
		  {
		    tree tem = valueize (arg2);
		    if (tem)
		      arg2 = tem;
		  }
		*rcode = DECL_FUNCTION_CODE (decl);
		ops[0] = arg1;
		ops[1] = arg2;
		return gimple_resimplify2 (seq, rcode, type, ops, valueize);
	      }
	    case 3:
	      {
		tree arg1 = gimple_call_arg (stmt, 0);
		if (valueize && TREE_CODE (arg1) == SSA_NAME)
		  {
		    tree tem = valueize (arg1);
		    if (tem)
		      arg1 = tem;
		  }
		tree arg2 = gimple_call_arg (stmt, 1);
		if (valueize && TREE_CODE (arg2) == SSA_NAME)
		  {
		    tree tem = valueize (arg2);
		    if (tem)
		      arg2 = tem;
		  }
		tree arg3 = gimple_call_arg (stmt, 2);
		if (valueize && TREE_CODE (arg3) == SSA_NAME)
		  {
		    tree tem = valueize (arg3);
		    if (tem)
		      arg3 = tem;
		  }
		*rcode = DECL_FUNCTION_CODE (decl);
		ops[0] = arg1;
		ops[1] = arg2;
		ops[2] = arg3;
		return gimple_resimplify3 (seq, rcode, type, ops, valueize);
	      }
	    default:
	      return false;
	    }
	}
      break;

    case GIMPLE_COND:
      {
	tree lhs = gimple_cond_lhs (stmt);
	if (valueize && TREE_CODE (lhs) == SSA_NAME)
	  {
	    tree tem = valueize (lhs);
	    if (tem)
	      lhs = tem;
	  }
	tree rhs = gimple_cond_rhs (stmt);
	if (valueize && TREE_CODE (rhs) == SSA_NAME)
	  {
	    tree tem = valueize (rhs);
	    if (tem)
	      rhs = tem;
	  }
	*rcode = gimple_cond_code (stmt);
	ops[0] = lhs;
	ops[1] = rhs;
        return gimple_resimplify2 (seq, rcode, boolean_type_node, ops, valueize);
      }

    default:
      break;
    }

  return false;
}
예제 #4
0
파일: gimple-walk.c 프로젝트: jtramm/gcc
tree
walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
		struct walk_stmt_info *wi)
{
  hash_set<tree> *pset = (wi) ? wi->pset : NULL;
  unsigned i;
  tree ret = NULL_TREE;

  switch (gimple_code (stmt))
    {
    case GIMPLE_ASSIGN:
      /* Walk the RHS operands.  If the LHS is of a non-renamable type or
         is a register variable, we may use a COMPONENT_REF on the RHS.  */
      if (wi)
	{
	  tree lhs = gimple_assign_lhs (stmt);
	  wi->val_only
	    = (is_gimple_reg_type (TREE_TYPE (lhs)) && !is_gimple_reg (lhs))
	      || gimple_assign_rhs_class (stmt) != GIMPLE_SINGLE_RHS;
	}

      for (i = 1; i < gimple_num_ops (stmt); i++)
	{
	  ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi,
			   pset);
	  if (ret)
	    return ret;
	}

      /* Walk the LHS.  If the RHS is appropriate for a memory, we
	 may use a COMPONENT_REF on the LHS.  */
      if (wi)
	{
          /* If the RHS is of a non-renamable type or is a register variable,
	     we may use a COMPONENT_REF on the LHS.  */
	  tree rhs1 = gimple_assign_rhs1 (stmt);
	  wi->val_only
	    = (is_gimple_reg_type (TREE_TYPE (rhs1)) && !is_gimple_reg (rhs1))
	      || gimple_assign_rhs_class (stmt) != GIMPLE_SINGLE_RHS;
	  wi->is_lhs = true;
	}

      ret = walk_tree (gimple_op_ptr (stmt, 0), callback_op, wi, pset);
      if (ret)
	return ret;

      if (wi)
	{
	  wi->val_only = true;
	  wi->is_lhs = false;
	}
      break;

    case GIMPLE_CALL:
      if (wi)
	{
	  wi->is_lhs = false;
	  wi->val_only = true;
	}

      ret = walk_tree (gimple_call_chain_ptr (as_a <gcall *> (stmt)),
		       callback_op, wi, pset);
      if (ret)
        return ret;

      ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset);
      if (ret)
        return ret;

      for (i = 0; i < gimple_call_num_args (stmt); i++)
	{
	  if (wi)
	    wi->val_only
	      = is_gimple_reg_type (TREE_TYPE (gimple_call_arg (stmt, i)));
	  ret = walk_tree (gimple_call_arg_ptr (stmt, i), callback_op, wi,
			   pset);
	  if (ret)
	    return ret;
	}

      if (gimple_call_lhs (stmt))
	{
	  if (wi)
	    {
	      wi->is_lhs = true;
	      wi->val_only
		= is_gimple_reg_type (TREE_TYPE (gimple_call_lhs (stmt)));
	    }

	  ret = walk_tree (gimple_call_lhs_ptr (stmt), callback_op, wi, pset);
	  if (ret)
	    return ret;
	}

      if (wi)
	{
	  wi->is_lhs = false;
	  wi->val_only = true;
	}
      break;

    case GIMPLE_CATCH:
      ret = walk_tree (gimple_catch_types_ptr (as_a <gcatch *> (stmt)),
		       callback_op, wi, pset);
      if (ret)
	return ret;
      break;

    case GIMPLE_EH_FILTER:
      ret = walk_tree (gimple_eh_filter_types_ptr (stmt), callback_op, wi,
		       pset);
      if (ret)
	return ret;
      break;

    case GIMPLE_ASM:
      ret = walk_gimple_asm (as_a <gasm *> (stmt), callback_op, wi);
      if (ret)
	return ret;
      break;

    case GIMPLE_OMP_CONTINUE:
      {
	gomp_continue *cont_stmt = as_a <gomp_continue *> (stmt);
	ret = walk_tree (gimple_omp_continue_control_def_ptr (cont_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;

	ret = walk_tree (gimple_omp_continue_control_use_ptr (cont_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_OMP_CRITICAL:
      {
	gomp_critical *omp_stmt = as_a <gomp_critical *> (stmt);
	ret = walk_tree (gimple_omp_critical_name_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
	ret = walk_tree (gimple_omp_critical_clauses_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_OMP_ORDERED:
      {
	gomp_ordered *omp_stmt = as_a <gomp_ordered *> (stmt);
	ret = walk_tree (gimple_omp_ordered_clauses_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_OMP_FOR:
      ret = walk_tree (gimple_omp_for_clauses_ptr (stmt), callback_op, wi,
		       pset);
      if (ret)
	return ret;
      for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
	{
	  ret = walk_tree (gimple_omp_for_index_ptr (stmt, i), callback_op,
			   wi, pset);
	  if (ret)
	    return ret;
	  ret = walk_tree (gimple_omp_for_initial_ptr (stmt, i), callback_op,
			   wi, pset);
	  if (ret)
	    return ret;
	  ret = walk_tree (gimple_omp_for_final_ptr (stmt, i), callback_op,
			   wi, pset);
	  if (ret)
	    return ret;
	  ret = walk_tree (gimple_omp_for_incr_ptr (stmt, i), callback_op,
			   wi, pset);
	  if (ret)
	    return ret;
	}
      break;

    case GIMPLE_OMP_PARALLEL:
      {
	gomp_parallel *omp_par_stmt = as_a <gomp_parallel *> (stmt);
	ret = walk_tree (gimple_omp_parallel_clauses_ptr (omp_par_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
	ret = walk_tree (gimple_omp_parallel_child_fn_ptr (omp_par_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
	ret = walk_tree (gimple_omp_parallel_data_arg_ptr (omp_par_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_OMP_TASK:
      ret = walk_tree (gimple_omp_task_clauses_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      ret = walk_tree (gimple_omp_task_child_fn_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      ret = walk_tree (gimple_omp_task_data_arg_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      ret = walk_tree (gimple_omp_task_copy_fn_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      ret = walk_tree (gimple_omp_task_arg_size_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      ret = walk_tree (gimple_omp_task_arg_align_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      break;

    case GIMPLE_OMP_SECTIONS:
      ret = walk_tree (gimple_omp_sections_clauses_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;
      ret = walk_tree (gimple_omp_sections_control_ptr (stmt), callback_op,
		       wi, pset);
      if (ret)
	return ret;

      break;

    case GIMPLE_OMP_SINGLE:
      ret = walk_tree (gimple_omp_single_clauses_ptr (stmt), callback_op, wi,
		       pset);
      if (ret)
	return ret;
      break;

    case GIMPLE_OMP_TARGET:
      {
	gomp_target *omp_stmt = as_a <gomp_target *> (stmt);
	ret = walk_tree (gimple_omp_target_clauses_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
	ret = walk_tree (gimple_omp_target_child_fn_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
	ret = walk_tree (gimple_omp_target_data_arg_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_OMP_TEAMS:
      ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi,
		       pset);
      if (ret)
	return ret;
      break;

    case GIMPLE_OMP_ATOMIC_LOAD:
      {
	gomp_atomic_load *omp_stmt = as_a <gomp_atomic_load *> (stmt);
	ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
	ret = walk_tree (gimple_omp_atomic_load_rhs_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_OMP_ATOMIC_STORE:
      {
	gomp_atomic_store *omp_stmt = as_a <gomp_atomic_store *> (stmt);
	ret = walk_tree (gimple_omp_atomic_store_val_ptr (omp_stmt),
			 callback_op, wi, pset);
	if (ret)
	  return ret;
      }
      break;

    case GIMPLE_TRANSACTION:
      ret = walk_tree (gimple_transaction_label_ptr (
			 as_a <gtransaction *> (stmt)),
		       callback_op, wi, pset);
      if (ret)
	return ret;
      break;

    case GIMPLE_OMP_RETURN:
      ret = walk_tree (gimple_omp_return_lhs_ptr (stmt), callback_op, wi,
		       pset);
      if (ret)
	return ret;
      break;

      /* Tuples that do not have operands.  */
    case GIMPLE_NOP:
    case GIMPLE_RESX:
    case GIMPLE_PREDICT:
      break;

    default:
      {
	enum gimple_statement_structure_enum gss;
	gss = gimple_statement_structure (stmt);
	if (gss == GSS_WITH_OPS || gss == GSS_WITH_MEM_OPS)
	  for (i = 0; i < gimple_num_ops (stmt); i++)
	    {
	      ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, pset);
	      if (ret)
		return ret;
	    }
      }
      break;
    }

  return NULL_TREE;
}