Beispiel #1
0
static tree
fold_cplus_constants (const_tree c)
{
  tree folded_elems, elems = CONST_CAST_TREE (c);
  int vec_len, i;

  if (elems == NULL_TREE || elems == error_mark_node)
    return elems;

  vec_len = TREE_VEC_LENGTH (elems);

  /* First check if there is at least one element that needs
     folding. If there is none, we just return ELEMS. Otherwise create
     and return a new tree vector that contains the folded versions of
     ELEMS. This is to avoid allocating memory if we don't need
     to.  */
  for (i = 0; i < vec_len; ++i)
    {
      if (template_arg_needs_folding (TREE_VEC_ELT (elems, i)))
	break;
    }
  if (i == vec_len)
    return elems;

  folded_elems = make_tree_vec (vec_len);
  for (i = 0; i < vec_len; ++i)
    {
      tree elem = TREE_VEC_ELT (elems, i);
      TREE_VEC_ELT (folded_elems, i) =  
	(elem && !TYPE_P (elem)) ? cplus_expand_constant (elem) : elem;

    }
  return folded_elems;
}
Beispiel #2
0
bool
c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh)
{
  hash_set<tree> pset;
  struct c_omp_check_loop_iv_data data;
  int i;

  data.declv = declv;
  data.fail = false;
  data.stmt_loc = EXPR_LOCATION (stmt);
  data.lh = lh;
  data.ppset = &pset;
  for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
    {
      tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i);
      gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
      tree decl = TREE_OPERAND (init, 0);
      tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i);
      gcc_assert (COMPARISON_CLASS_P (cond));
      gcc_assert (TREE_OPERAND (cond, 0) == decl);
      tree incr = TREE_VEC_ELT (OMP_FOR_INCR (stmt), i);
      data.expr_loc = EXPR_LOCATION (TREE_OPERAND (init, 1));
      data.kind = 0;
      walk_tree_1 (&TREE_OPERAND (init, 1),
		   c_omp_check_loop_iv_r, &data, &pset, lh);
      /* Don't warn for C++ random access iterators here, the
	 expression then involves the subtraction and always refers
	 to the original value.  The C++ FE needs to warn on those
	 earlier.  */
      if (decl == TREE_VEC_ELT (declv, i))
	{
	  data.expr_loc = EXPR_LOCATION (cond);
	  data.kind = 1;
	  walk_tree_1 (&TREE_OPERAND (cond, 1),
		       c_omp_check_loop_iv_r, &data, &pset, lh);
	}
      if (TREE_CODE (incr) == MODIFY_EXPR)
	{
	  gcc_assert (TREE_OPERAND (incr, 0) == decl);
	  incr = TREE_OPERAND (incr, 1);
	  data.kind = 2;
	  if (TREE_CODE (incr) == PLUS_EXPR
	      && TREE_OPERAND (incr, 1) == decl)
	    {
	      data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 0));
	      walk_tree_1 (&TREE_OPERAND (incr, 0),
			   c_omp_check_loop_iv_r, &data, &pset, lh);
	    }
	  else
	    {
	      data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 1));
	      walk_tree_1 (&TREE_OPERAND (incr, 1),
			   c_omp_check_loop_iv_r, &data, &pset, lh);
	    }
	}
    }
  return !data.fail;
}
static void
compression_table_add (tree type)
{
  if (compression_next == TREE_VEC_LENGTH (compression_table))
    {
      tree new_table = make_tree_vec (2*compression_next);
      int i;

      for (i = 0; i < compression_next; i++)
	TREE_VEC_ELT (new_table, i) = TREE_VEC_ELT (compression_table, i);

      compression_table = new_table;
    }
  TREE_VEC_ELT (compression_table, compression_next++) = type;
}
static int
find_compression_array_template_match (tree string)
{
  int i;
  for (i = 0; i < compression_next; i++)
    if (TREE_VEC_ELT (compression_table, i) == string) 
      return i;
  return -1;
}
static void
write_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
  int i;

  /* Note that the number of slots for EXPR has already been emitted
     in EXPR's header (see streamer_write_tree_header).  */
  for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
    stream_write_tree (ob, TREE_VEC_ELT (expr, i), ref_p);
}
Beispiel #6
0
tree
cxx_omp_clause_dtor (tree clause, tree decl)
{
  tree info = CP_OMP_CLAUSE_INFO (clause);
  tree ret = NULL;

  if (info)
    ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 1), decl, NULL);

  return ret;
}
Beispiel #7
0
tree
cxx_omp_clause_default_ctor (tree clause, tree decl, tree /*outer*/)
{
  tree info = CP_OMP_CLAUSE_INFO (clause);
  tree ret = NULL;

  if (info)
    ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), decl, NULL);

  return ret;
}
Beispiel #8
0
static void
lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
				struct data_in *data_in, tree expr)
{
  int i;

  /* Note that TREE_VEC_LENGTH was read by streamer_alloc_tree to
     instantiate EXPR.  */
  for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
    TREE_VEC_ELT (expr, i) = stream_read_tree (ib, data_in);
}
static int
find_compression_record_match (tree type, tree *next_current)
{
  int i, match = -1;
  tree current, saved_current = NULL_TREE;

  current = TYPE_PACKAGE_LIST (type);
      
  for (i = 0; i < compression_next; i++)
    {
      tree compression_entry = TREE_VEC_ELT (compression_table, i);
      if (current && compression_entry == TREE_PURPOSE (current))
        {
	  match = i;
	  saved_current = current;
	  current = TREE_CHAIN (current);
	}
      else
	/* We don't want to match an element that appears in the middle
	   of a package name, so skip forward to the next complete type name.
	   IDENTIFIER_NODEs (except for a "6JArray") are partial package
	   names while RECORD_TYPEs represent complete type names. */
	while (i < compression_next 
	       && TREE_CODE (compression_entry) == IDENTIFIER_NODE
	       && compression_entry != atms)
	  compression_entry = TREE_VEC_ELT (compression_table, ++i);
    }

  if (!next_current)
    return match;

  /* If we have a match, set next_current to the item next to the last
     matched value. */
  if (match >= 0)
    *next_current = TREE_CHAIN (saved_current);
  /* We had no match: we'll have to start from the beginning. */
  if (match < 0)
    *next_current = TYPE_PACKAGE_LIST (type);

  return match;
}
static inline void
pp_cxx_template_parameter_list (cxx_pretty_printer *pp, tree t)
{
  const int n = TREE_VEC_LENGTH (t);
  int i;
  for (i = 0; i < n; ++i)
    {
      if (i)
	pp_cxx_separate_with (pp, ',');
      pp_cxx_template_parameter (pp, TREE_VEC_ELT (t, i));
    }
}
Beispiel #11
0
tree
cxx_omp_clause_assign_op (tree clause, tree dst, tree src)
{
  tree info = CP_OMP_CLAUSE_INFO (clause);
  tree ret = NULL;

  if (info)
    ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 2), dst, src);
  if (ret == NULL)
    ret = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);

  return ret;
}
Beispiel #12
0
tree
cxx_omp_clause_copy_ctor (tree clause, tree dst, tree src)
{
  tree info = CP_OMP_CLAUSE_INFO (clause);
  tree ret = NULL;

  if (info)
    ret = cxx_omp_clause_apply_fn (TREE_VEC_ELT (info, 0), dst, src);
  if (ret == NULL)
    ret = build2 (MODIFY_EXPR, void_type_node, dst, src);

  return ret;
}
Beispiel #13
0
static bool
ok_to_generate_alias_set_for_type (tree t)
{
    if (TYPE_PTRMEMFUNC_P (t))
        return true;
    if (AGGREGATE_TYPE_P (t))
    {
        if ((TREE_CODE (t) == RECORD_TYPE) || (TREE_CODE (t) == UNION_TYPE))
        {
            tree fields;
            /* Backend-created structs are safe.  */
            if (! CLASS_TYPE_P (t))
                return true;
            /* PODs are safe.  */
            if (! CLASSTYPE_NON_POD_P(t))
                return true;
            /* Classes with virtual baseclasses are not.  */
            if (TYPE_USES_VIRTUAL_BASECLASSES (t))
                return false;
            /* Recursively check the base classes.  */
            if (TYPE_BINFO (t) != NULL && TYPE_BINFO_BASETYPES (t) != NULL)
            {
                int i;
                for (i = 0; i < TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (t)); i++)
                {
                    tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
                    if (!ok_to_generate_alias_set_for_type (BINFO_TYPE (binfo)))
                        return false;
                }
            }
            /* Check all the fields.  */
            for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
            {
                if (TREE_CODE (fields) != FIELD_DECL)
                    continue;
                if (! ok_to_generate_alias_set_for_type (TREE_TYPE (fields)))
                    return false;
            }
            return true;
        }
        else if (TREE_CODE (t) == ARRAY_TYPE)
            return ok_to_generate_alias_set_for_type (TREE_TYPE (t));
        else
            /* This should never happen, we dealt with all the aggregate
               types that can appear in C++ above.  */
            abort ();
    }
    else
        return true;
}
Beispiel #14
0
int
merge_type_state (tree label)
{
  int nlocals = DECL_MAX_LOCALS (current_function_decl);
  int cur_length = stack_pointer + nlocals;
  tree vec = LABEL_TYPE_STATE (label);
  tree return_map;
  if (vec == NULL_TREE)
    {
      vec = make_tree_vec (cur_length);
      LABEL_TYPE_STATE (label) = vec;

      while (--cur_length >= 0)
	TREE_VEC_ELT (vec, cur_length) = type_map[cur_length];
      return 1;
    }
  else
    {
      int i;
      int changed = 0;
      if (LABEL_IS_SUBR_START (label) && LABEL_VERIFIED (label)
	  && current_subr != label)
	return_map = LABEL_RETURN_TYPE_STATE (label);
      else
	return_map = NULL_TREE;
      if (TREE_VEC_LENGTH (vec) != cur_length)
	{
	  return -1;
	}
      for (i = 0; i < cur_length; i++)
	{
	  tree old_type = TREE_VEC_ELT (vec, i);
	  tree new_type = merge_types (old_type, type_map[i]);
	  if (TREE_VEC_ELT (vec, i) != new_type)
	    {
	      /* If there has been a change, note that since we must re-verify.
		 However, if the label is the start of a subroutine,
		 we don't care about local variables that are neither
		 set nor used in the subroutine. */
	      if (return_map == NULL_TREE || i >= nlocals
		  || TREE_VEC_ELT (return_map, i) != TYPE_UNUSED
		  || (TYPE_IS_WIDE (new_type)
		      && TREE_VEC_ELT (return_map, i+1) != TYPE_UNUSED))
		changed = 1;
	    }
	  TREE_VEC_ELT (vec, i) = new_type;
	  if (new_type == TYPE_UNKNOWN)
	    {
	      if (i >= nlocals)
		return -1;
	    }
	  else if (TYPE_IS_WIDE (new_type))
	    i++;
	}
      return changed;
    }
}
static int
entry_match_pointer_p (tree type, int i)
{
  tree t = TREE_VEC_ELT (compression_table, i);
  
  while (TREE_CODE (type) == POINTER_TYPE
	 && TREE_CODE (t) == POINTER_TYPE)
    {
      t = TREE_TYPE (t);
      type = TREE_TYPE (type);
    }
  return (TREE_CODE (type) == RECORD_TYPE
	  && TREE_CODE (t) == RECORD_TYPE
	  && t == type);
}
static void
pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t)
{
  int i;
  if (t == NULL)
    return;
  for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
    {
      tree arg = TREE_VEC_ELT (t, i);
      if (i != 0)
	pp_cxx_separate_with (pp, ',');
      if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL
			   && TYPE_P (DECL_TEMPLATE_RESULT (arg))))
	pp_cxx_type_id (pp, arg);
      else
	pp_cxx_expression (pp, arg);
    }
}
Beispiel #17
0
static tree
c_omp_check_loop_iv_r (tree *tp, int *walk_subtrees, void *data)
{
  struct c_omp_check_loop_iv_data *d
    = (struct c_omp_check_loop_iv_data *) data;
  if (DECL_P (*tp))
    {
      int i;
      for (i = 0; i < TREE_VEC_LENGTH (d->declv); i++)
	if (*tp == TREE_VEC_ELT (d->declv, i))
	  {
	    location_t loc = d->expr_loc;
	    if (loc == UNKNOWN_LOCATION)
	      loc = d->stmt_loc;
	    switch (d->kind)
	      {
	      case 0:
		error_at (loc, "initializer expression refers to "
			       "iteration variable %qD", *tp);
		break;
	      case 1:
		error_at (loc, "condition expression refers to "
			       "iteration variable %qD", *tp);
		break;
	      case 2:
		error_at (loc, "increment expression refers to "
			       "iteration variable %qD", *tp);
		break;
	      }
	    d->fail = true;
	  }
    }
  /* Don't walk dtors added by C++ wrap_cleanups_r.  */
  else if (TREE_CODE (*tp) == TRY_CATCH_EXPR
	   && TRY_CATCH_IS_CLEANUP (*tp))
    {
      *walk_subtrees = 0;
      return walk_tree_1 (&TREE_OPERAND (*tp, 0), c_omp_check_loop_iv_r, data,
			  d->ppset, d->lh);
    }

  return NULL_TREE;
}
Beispiel #18
0
static tree
synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
                           void *client)
{
  tree raises = empty_except_spec;
  tree fields = TYPE_FIELDS (type);
  int i, n_bases = CLASSTYPE_N_BASECLASSES (type);
  tree binfos = TYPE_BINFO_BASETYPES (type);

  for (i = 0; i != n_bases; i++)
    {
      tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
      tree fn = (*extractor) (base, client);
      if (fn)
        {
          tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
          
          raises = merge_exception_specifiers (raises, fn_raises);
        }
    }
  for (; fields; fields = TREE_CHAIN (fields))
    {
      tree type = TREE_TYPE (fields);
      tree fn;
      
      if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
        continue;
      while (TREE_CODE (type) == ARRAY_TYPE)
  	type = TREE_TYPE (type);
      if (!CLASS_TYPE_P (type))
        continue;
      
      fn = (*extractor) (type, client);
      if (fn)
        {
          tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
          
          raises = merge_exception_specifiers (raises, fn_raises);
        }
    }
  return raises;
}
static void
dequeue_and_dump (dump_info_p di)
{
  dump_queue_p dq;
  splay_tree_node stn;
  dump_node_info_p dni;
  tree t;
  unsigned int index;
  enum tree_code code;
  enum tree_code_class code_class;
  const char* code_name;

  /* Get the next node from the queue.  */
  dq = di->queue;
  stn = dq->node;
  t = (tree) stn->key;
  dni = (dump_node_info_p) stn->value;
  index = dni->index;

  /* Remove the node from the queue, and put it on the free list.  */
  di->queue = dq->next;
  if (!di->queue)
    di->queue_end = 0;
  dq->next = di->free_list;
  di->free_list = dq;

  /* Print the node index.  */
  dump_index (di, index);
  /* And the type of node this is.  */
  if (dni->binfo_p)
    code_name = "binfo";
  else
    code_name = tree_code_name[(int) TREE_CODE (t)];
  fprintf (di->stream, "%-16s ", code_name);
  di->column = 25;

  /* Figure out what kind of node this is.  */
  code = TREE_CODE (t);
  code_class = TREE_CODE_CLASS (code);

  /* Although BINFOs are TREE_VECs, we dump them specially so as to be
     more informative.  */
  if (dni->binfo_p)
    {
      unsigned ix;
      tree base;
      VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t);

      dump_child ("type", BINFO_TYPE (t));

      if (BINFO_VIRTUAL_P (t))
	dump_string_field (di, "spec", "virt");

      dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
      for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
	{
	  tree access = (accesses ? VEC_index (tree, accesses, ix)
			 : access_public_node);
	  const char *string = NULL;

	  if (access == access_public_node)
	    string = "pub";
	  else if (access == access_protected_node)
	    string = "prot";
	  else if (access == access_private_node)
	    string = "priv";
	  else
	    gcc_unreachable ();

	  dump_string_field (di, "accs", string);
	  queue_and_dump_index (di, "binf", base, DUMP_BINFO);
	}

      goto done;
    }

  /* We can knock off a bunch of expression nodes in exactly the same
     way.  */
  if (IS_EXPR_CODE_CLASS (code_class))
    {
      /* If we're dumping children, dump them now.  */
      queue_and_dump_type (di, t);

      switch (code_class)
	{
	case tcc_unary:
	  dump_child ("op 0", TREE_OPERAND (t, 0));
	  break;

	case tcc_binary:
	case tcc_comparison:
	  dump_child ("op 0", TREE_OPERAND (t, 0));
	  dump_child ("op 1", TREE_OPERAND (t, 1));
	  break;

	case tcc_expression:
	case tcc_reference:
	case tcc_statement:
	case tcc_vl_exp:
	  /* These nodes are handled explicitly below.  */
	  break;

	default:
	  gcc_unreachable ();
	}
    }
  else if (DECL_P (t))
    {
      expanded_location xloc;
      /* All declarations have names.  */
      if (DECL_NAME (t))
	dump_child ("name", DECL_NAME (t));
      if (DECL_ASSEMBLER_NAME_SET_P (t)
	  && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
	dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
      if (DECL_ABSTRACT_ORIGIN (t))
        dump_child ("orig", DECL_ABSTRACT_ORIGIN (t));
      /* And types.  */
      queue_and_dump_type (di, t);
      dump_child ("scpe", DECL_CONTEXT (t));
      /* And a source position.  */
      xloc = expand_location (DECL_SOURCE_LOCATION (t));
      if (xloc.file)
	{
	  const char *filename = lbasename (xloc.file);

	  dump_maybe_newline (di);
	  fprintf (di->stream, "srcp: %s:%-6d ", filename,
		   xloc.line);
	  di->column += 6 + strlen (filename) + 8;
	}
      /* And any declaration can be compiler-generated.  */
      if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON)
	  && DECL_ARTIFICIAL (t))
	dump_string_field (di, "note", "artificial");
      if (DECL_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
	dump_child ("chain", DECL_CHAIN (t));
    }
  else if (code_class == tcc_type)
    {
      /* All types have qualifiers.  */
      int quals = lang_hooks.tree_dump.type_quals (t);

      if (quals != TYPE_UNQUALIFIED)
	{
	  fprintf (di->stream, "qual: %c%c%c     ",
		   (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
		   (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
		   (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
	  di->column += 14;
	}

      /* All types have associated declarations.  */
      dump_child ("name", TYPE_NAME (t));

      /* All types have a main variant.  */
      if (TYPE_MAIN_VARIANT (t) != t)
	dump_child ("unql", TYPE_MAIN_VARIANT (t));

      /* And sizes.  */
      dump_child ("size", TYPE_SIZE (t));

      /* All types have alignments.  */
      dump_int (di, "algn", TYPE_ALIGN (t));
    }
  else if (code_class == tcc_constant)
    /* All constants can have types.  */
    queue_and_dump_type (di, t);

  /* Give the language-specific code a chance to print something.  If
     it's completely taken care of things, don't bother printing
     anything more ourselves.  */
  if (lang_hooks.tree_dump.dump_tree (di, t))
    goto done;

  /* Now handle the various kinds of nodes.  */
  switch (code)
    {
      int i;

    case IDENTIFIER_NODE:
      dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
      dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
      break;

    case TREE_LIST:
      dump_child ("purp", TREE_PURPOSE (t));
      dump_child ("valu", TREE_VALUE (t));
      dump_child ("chan", TREE_CHAIN (t));
      break;

    case STATEMENT_LIST:
      {
	tree_stmt_iterator it;
	for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
	  {
	    char buffer[32];
	    sprintf (buffer, "%u", i);
	    dump_child (buffer, tsi_stmt (it));
	  }
      }
      break;

    case TREE_VEC:
      dump_int (di, "lngt", TREE_VEC_LENGTH (t));
      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
	{
	  char buffer[32];
	  sprintf (buffer, "%u", i);
	  dump_child (buffer, TREE_VEC_ELT (t, i));
	}
      break;

    case INTEGER_TYPE:
    case ENUMERAL_TYPE:
      dump_int (di, "prec", TYPE_PRECISION (t));
      dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
      dump_child ("min", TYPE_MIN_VALUE (t));
      dump_child ("max", TYPE_MAX_VALUE (t));

      if (code == ENUMERAL_TYPE)
	dump_child ("csts", TYPE_VALUES (t));
      break;

    case REAL_TYPE:
      dump_int (di, "prec", TYPE_PRECISION (t));
      break;

    case FIXED_POINT_TYPE:
      dump_int (di, "prec", TYPE_PRECISION (t));
      dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
      dump_string_field (di, "saturating",
			 TYPE_SATURATING (t) ? "saturating": "non-saturating");
      break;

    case POINTER_TYPE:
      dump_child ("ptd", TREE_TYPE (t));
      break;

    case REFERENCE_TYPE:
      dump_child ("refd", TREE_TYPE (t));
      break;

    case METHOD_TYPE:
      dump_child ("clas", TYPE_METHOD_BASETYPE (t));
      /* Fall through.  */

    case FUNCTION_TYPE:
      dump_child ("retn", TREE_TYPE (t));
      dump_child ("prms", TYPE_ARG_TYPES (t));
      break;

    case ARRAY_TYPE:
      dump_child ("elts", TREE_TYPE (t));
      dump_child ("domn", TYPE_DOMAIN (t));
      break;

    case RECORD_TYPE:
    case UNION_TYPE:
      if (TREE_CODE (t) == RECORD_TYPE)
	dump_string_field (di, "tag", "struct");
      else
	dump_string_field (di, "tag", "union");

      dump_child ("flds", TYPE_FIELDS (t));
      dump_child ("fncs", TYPE_METHODS (t));
      queue_and_dump_index (di, "binf", TYPE_BINFO (t),
			    DUMP_BINFO);
      break;

    case CONST_DECL:
      dump_child ("cnst", DECL_INITIAL (t));
      break;

    case DEBUG_EXPR_DECL:
      dump_int (di, "-uid", DEBUG_TEMP_UID (t));
      /* Fall through.  */

    case VAR_DECL:
    case PARM_DECL:
    case FIELD_DECL:
    case RESULT_DECL:
      if (TREE_CODE (t) == PARM_DECL)
	dump_child ("argt", DECL_ARG_TYPE (t));
      else
	dump_child ("init", DECL_INITIAL (t));
      dump_child ("size", DECL_SIZE (t));
      dump_int (di, "algn", DECL_ALIGN (t));

      if (TREE_CODE (t) == FIELD_DECL)
	{
	  if (DECL_FIELD_OFFSET (t))
	    dump_child ("bpos", bit_position (t));
	}
      else if (TREE_CODE (t) == VAR_DECL
	       || TREE_CODE (t) == PARM_DECL)
	{
	  dump_int (di, "used", TREE_USED (t));
	  if (DECL_REGISTER (t))
	    dump_string_field (di, "spec", "register");
	}
      break;

    case FUNCTION_DECL:
      dump_child ("args", DECL_ARGUMENTS (t));
      if (DECL_EXTERNAL (t))
	dump_string_field (di, "body", "undefined");
      if (TREE_PUBLIC (t))
	dump_string_field (di, "link", "extern");
      else
	dump_string_field (di, "link", "static");
      if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t))
	dump_child ("body", DECL_SAVED_TREE (t));
      break;

    case INTEGER_CST:
      if (TREE_INT_CST_HIGH (t))
	dump_int (di, "high", TREE_INT_CST_HIGH (t));
      dump_int (di, "low", TREE_INT_CST_LOW (t));
      break;

    case STRING_CST:
      fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
      dump_int (di, "lngt", TREE_STRING_LENGTH (t));
      break;

    case REAL_CST:
      dump_real (di, "valu", TREE_REAL_CST_PTR (t));
      break;

    case FIXED_CST:
      dump_fixed (di, "valu", TREE_FIXED_CST_PTR (t));
      break;

    case TRUTH_NOT_EXPR:
    case ADDR_EXPR:
    case INDIRECT_REF:
    case CLEANUP_POINT_EXPR:
    case SAVE_EXPR:
    case REALPART_EXPR:
    case IMAGPART_EXPR:
      /* These nodes are unary, but do not have code class `1'.  */
      dump_child ("op 0", TREE_OPERAND (t, 0));
      break;

    case TRUTH_ANDIF_EXPR:
    case TRUTH_ORIF_EXPR:
    case INIT_EXPR:
    case MODIFY_EXPR:
    case COMPOUND_EXPR:
    case PREDECREMENT_EXPR:
    case PREINCREMENT_EXPR:
    case POSTDECREMENT_EXPR:
    case POSTINCREMENT_EXPR:
      /* These nodes are binary, but do not have code class `2'.  */
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      break;

    case COMPONENT_REF:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      dump_child ("op 2", TREE_OPERAND (t, 2));
      break;

    case ARRAY_REF:
    case ARRAY_RANGE_REF:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      dump_child ("op 2", TREE_OPERAND (t, 2));
      dump_child ("op 3", TREE_OPERAND (t, 3));
      break;

    case COND_EXPR:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      dump_child ("op 2", TREE_OPERAND (t, 2));
      break;

    case TRY_FINALLY_EXPR:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      break;

    case CALL_EXPR:
      {
	int i = 0;
	tree arg;
	call_expr_arg_iterator iter;
	dump_child ("fn", CALL_EXPR_FN (t));
	FOR_EACH_CALL_EXPR_ARG (arg, iter, t)
	  {
	    char buffer[32];
	    sprintf (buffer, "%u", i);
	    dump_child (buffer, arg);
	    i++;
	  }
      }
      break;

    case CONSTRUCTOR:
      {
	unsigned HOST_WIDE_INT cnt;
	tree index, value;
	dump_int (di, "lngt", VEC_length (constructor_elt,
					  CONSTRUCTOR_ELTS (t)));
	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value)
	  {
	    dump_child ("idx", index);
	    dump_child ("val", value);
	  }
      }
static tree
gfc_trans_omp_do (gfc_code *code, stmtblock_t *pblock,
		  gfc_omp_clauses *do_clauses, tree par_clauses)
{
  gfc_se se;
  tree dovar, stmt, from, to, step, type, init, cond, incr;
  tree count = NULL_TREE, cycle_label, tmp, omp_clauses;
  stmtblock_t block;
  stmtblock_t body;
  gfc_omp_clauses *clauses = code->ext.omp_clauses;
  int i, collapse = clauses->collapse;
  tree dovar_init = NULL_TREE;

  if (collapse <= 0)
    collapse = 1;

  code = code->block->next;
  gcc_assert (code->op == EXEC_DO);

  init = make_tree_vec (collapse);
  cond = make_tree_vec (collapse);
  incr = make_tree_vec (collapse);

  if (pblock == NULL)
    {
      gfc_start_block (&block);
      pblock = &block;
    }

  omp_clauses = gfc_trans_omp_clauses (pblock, do_clauses, code->loc);

  for (i = 0; i < collapse; i++)
    {
      int simple = 0;
      int dovar_found = 0;
      tree dovar_decl;

      if (clauses)
	{
	  gfc_namelist *n;
	  for (n = clauses->lists[OMP_LIST_LASTPRIVATE]; n != NULL;
	       n = n->next)
	    if (code->ext.iterator->var->symtree->n.sym == n->sym)
	      break;
	  if (n != NULL)
	    dovar_found = 1;
	  else if (n == NULL)
	    for (n = clauses->lists[OMP_LIST_PRIVATE]; n != NULL; n = n->next)
	      if (code->ext.iterator->var->symtree->n.sym == n->sym)
		break;
	  if (n != NULL)
	    dovar_found++;
	}

      /* Evaluate all the expressions in the iterator.  */
      gfc_init_se (&se, NULL);
      gfc_conv_expr_lhs (&se, code->ext.iterator->var);
      gfc_add_block_to_block (pblock, &se.pre);
      dovar = se.expr;
      type = TREE_TYPE (dovar);
      gcc_assert (TREE_CODE (type) == INTEGER_TYPE);

      gfc_init_se (&se, NULL);
      gfc_conv_expr_val (&se, code->ext.iterator->start);
      gfc_add_block_to_block (pblock, &se.pre);
      from = gfc_evaluate_now (se.expr, pblock);

      gfc_init_se (&se, NULL);
      gfc_conv_expr_val (&se, code->ext.iterator->end);
      gfc_add_block_to_block (pblock, &se.pre);
      to = gfc_evaluate_now (se.expr, pblock);

      gfc_init_se (&se, NULL);
      gfc_conv_expr_val (&se, code->ext.iterator->step);
      gfc_add_block_to_block (pblock, &se.pre);
      step = gfc_evaluate_now (se.expr, pblock);
      dovar_decl = dovar;

      /* Special case simple loops.  */
      if (TREE_CODE (dovar) == VAR_DECL)
	{
	  if (integer_onep (step))
	    simple = 1;
	  else if (tree_int_cst_equal (step, integer_minus_one_node))
	    simple = -1;
	}
      else
	dovar_decl
	  = gfc_trans_omp_variable (code->ext.iterator->var->symtree->n.sym);

      /* Loop body.  */
      if (simple)
	{
	  TREE_VEC_ELT (init, i) = build2_v (MODIFY_EXPR, dovar, from);
	  TREE_VEC_ELT (cond, i) = fold_build2 (simple > 0 ? LE_EXPR : GE_EXPR,
						boolean_type_node, dovar, to);
	  TREE_VEC_ELT (incr, i) = fold_build2 (PLUS_EXPR, type, dovar, step);
	  TREE_VEC_ELT (incr, i) = fold_build2 (MODIFY_EXPR, type, dovar,
						TREE_VEC_ELT (incr, i));
	}
      else
	{
	  /* STEP is not 1 or -1.  Use:
	     for (count = 0; count < (to + step - from) / step; count++)
	       {
		 dovar = from + count * step;
		 body;
	       cycle_label:;
	       }  */
	  tmp = fold_build2 (MINUS_EXPR, type, step, from);
	  tmp = fold_build2 (PLUS_EXPR, type, to, tmp);
	  tmp = fold_build2 (TRUNC_DIV_EXPR, type, tmp, step);
	  tmp = gfc_evaluate_now (tmp, pblock);
	  count = gfc_create_var (type, "count");
	  TREE_VEC_ELT (init, i) = build2_v (MODIFY_EXPR, count,
					     build_int_cst (type, 0));
	  TREE_VEC_ELT (cond, i) = fold_build2 (LT_EXPR, boolean_type_node,
						count, tmp);
	  TREE_VEC_ELT (incr, i) = fold_build2 (PLUS_EXPR, type, count,
						build_int_cst (type, 1));
	  TREE_VEC_ELT (incr, i) = fold_build2 (MODIFY_EXPR, type,
						count, TREE_VEC_ELT (incr, i));

	  /* Initialize DOVAR.  */
	  tmp = fold_build2 (MULT_EXPR, type, count, step);
	  tmp = fold_build2 (PLUS_EXPR, type, from, tmp);
	  dovar_init = tree_cons (dovar, tmp, dovar_init);
	}

      if (!dovar_found)
	{
	  tmp = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
	  OMP_CLAUSE_DECL (tmp) = dovar_decl;
	  omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
	}
      else if (dovar_found == 2)
	{
	  tree c = NULL;

	  tmp = NULL;
	  if (!simple)
	    {
	      /* If dovar is lastprivate, but different counter is used,
		 dovar += step needs to be added to
		 OMP_CLAUSE_LASTPRIVATE_STMT, otherwise the copied dovar
		 will have the value on entry of the last loop, rather
		 than value after iterator increment.  */
	      tmp = gfc_evaluate_now (step, pblock);
	      tmp = fold_build2 (PLUS_EXPR, type, dovar, tmp);
	      tmp = fold_build2 (MODIFY_EXPR, type, dovar, tmp);
	      for (c = omp_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
		    && OMP_CLAUSE_DECL (c) == dovar_decl)
		  {
		    OMP_CLAUSE_LASTPRIVATE_STMT (c) = tmp;
		    break;
		  }
	    }
	  if (c == NULL && par_clauses != NULL)
	    {
	      for (c = par_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
		    && OMP_CLAUSE_DECL (c) == dovar_decl)
		  {
		    tree l = build_omp_clause (input_location,
					       OMP_CLAUSE_LASTPRIVATE);
		    OMP_CLAUSE_DECL (l) = dovar_decl;
		    OMP_CLAUSE_CHAIN (l) = omp_clauses;
		    OMP_CLAUSE_LASTPRIVATE_STMT (l) = tmp;
		    omp_clauses = l;
		    OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_SHARED);
		    break;
		  }
	    }
	  gcc_assert (simple || c != NULL);
	}
      if (!simple)
	{
	  tmp = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
	  OMP_CLAUSE_DECL (tmp) = count;
	  omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
	}

      if (i + 1 < collapse)
	code = code->block->next;
    }

  if (pblock != &block)
    {
      pushlevel (0);
      gfc_start_block (&block);
    }

  gfc_start_block (&body);

  dovar_init = nreverse (dovar_init);
  while (dovar_init)
    {
      gfc_add_modify (&body, TREE_PURPOSE (dovar_init),
			   TREE_VALUE (dovar_init));
      dovar_init = TREE_CHAIN (dovar_init);
    }

  /* Cycle statement is implemented with a goto.  Exit statement must not be
     present for this loop.  */
  cycle_label = gfc_build_label_decl (NULL_TREE);

  /* Put these labels where they can be found later. We put the
     labels in a TREE_LIST node (because TREE_CHAIN is already
     used). cycle_label goes in TREE_PURPOSE (backend_decl), exit
     label in TREE_VALUE (backend_decl).  */

  code->block->backend_decl = tree_cons (cycle_label, NULL, NULL);

  /* Main loop body.  */
  tmp = gfc_trans_omp_code (code->block->next, true);
  gfc_add_expr_to_block (&body, tmp);

  /* Label for cycle statements (if needed).  */
  if (TREE_USED (cycle_label))
    {
      tmp = build1_v (LABEL_EXPR, cycle_label);
      gfc_add_expr_to_block (&body, tmp);
    }

  /* End of loop body.  */
  stmt = make_node (OMP_FOR);

  TREE_TYPE (stmt) = void_type_node;
  OMP_FOR_BODY (stmt) = gfc_finish_block (&body);
  OMP_FOR_CLAUSES (stmt) = omp_clauses;
  OMP_FOR_INIT (stmt) = init;
  OMP_FOR_COND (stmt) = cond;
  OMP_FOR_INCR (stmt) = incr;
  gfc_add_expr_to_block (&block, stmt);

  return gfc_finish_block (&block);
}
Beispiel #21
0
static void
do_build_copy_constructor (tree fndecl)
{
  tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
  tree t;

  parm = convert_from_reference (parm);

  if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)
      && is_empty_class (current_class_type))
    /* Don't copy the padding byte; it might not have been allocated
       if *this is a base subobject.  */;
  else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
    {
      t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
      finish_expr_stmt (t);
    }
  else
    {
      tree fields = TYPE_FIELDS (current_class_type);
      int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
      tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
      tree member_init_list = NULL_TREE;
      int cvquals = cp_type_quals (TREE_TYPE (parm));
      int i;

      /* Initialize all the base-classes with the parameter converted
	 to their type so that we get their copy constructor and not
	 another constructor that takes current_class_type.  We must
	 deal with the binfo's directly as a direct base might be
	 inaccessible due to ambiguity.  */
      for (t = CLASSTYPE_VBASECLASSES (current_class_type); t;
	   t = TREE_CHAIN (t))
	{
	  tree binfo = TREE_VALUE (t);
	  
	  member_init_list 
	    = tree_cons (binfo,
			 build_tree_list (NULL_TREE,
					  build_base_path (PLUS_EXPR, parm,
							   binfo, 1)),
			 member_init_list);
	}

      for (i = 0; i < n_bases; ++i)
	{
	  tree binfo = TREE_VEC_ELT (binfos, i);
	  if (TREE_VIA_VIRTUAL (binfo))
	    continue; 

	  member_init_list 
	    = tree_cons (binfo,
			 build_tree_list (NULL_TREE,
					  build_base_path (PLUS_EXPR, parm,
							   binfo, 1)),
			 member_init_list);
	}

      for (; fields; fields = TREE_CHAIN (fields))
	{
	  tree init = parm;
	  tree field = fields;
	  tree expr_type;

	  if (TREE_CODE (field) != FIELD_DECL)
	    continue;

	  expr_type = TREE_TYPE (field);
	  if (DECL_NAME (field))
	    {
	      if (VFIELD_NAME_P (DECL_NAME (field)))
		continue;

	      /* True for duplicate members.  */
	      if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
		continue;
	    }
	  else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
	    /* Just use the field; anonymous types can't have
	       nontrivial copy ctors or assignment ops.  */;
	  else
	    continue;

	  /* Compute the type of "init->field".  If the copy-constructor
	     parameter is, for example, "const S&", and the type of
	     the field is "T", then the type will usually be "const
	     T".  (There are no cv-qualified variants of reference
	     types.)  */
	  if (TREE_CODE (expr_type) != REFERENCE_TYPE)
	    {
	      int quals = cvquals;
	      
	      if (DECL_MUTABLE_P (field))
		quals &= ~TYPE_QUAL_CONST;
	      expr_type = cp_build_qualified_type (expr_type, quals);
	    }
	  
	  init = build (COMPONENT_REF, expr_type, init, field);
	  init = build_tree_list (NULL_TREE, init);

	  member_init_list = tree_cons (field, init, member_init_list);
	}
      finish_mem_initializers (member_init_list);
    }
}
Beispiel #22
0
tree
cilk_for_number_of_iterations (tree cilk_for)
{
  tree t, v, n1, n2, step, type, init, cond, incr, itype;
  enum tree_code cond_code;
  location_t loc = EXPR_LOCATION (cilk_for);

  init = TREE_VEC_ELT (OMP_FOR_INIT (cilk_for), 0);
  v = TREE_OPERAND (init, 0);
  cond = TREE_VEC_ELT (OMP_FOR_COND (cilk_for), 0);
  incr = TREE_VEC_ELT (OMP_FOR_INCR (cilk_for), 0);
  type = TREE_TYPE (v);

  gcc_assert (TREE_CODE (TREE_TYPE (v)) == INTEGER_TYPE
	      || TREE_CODE (TREE_TYPE (v)) == POINTER_TYPE);
  n1 = TREE_OPERAND (init, 1);
  cond_code = TREE_CODE (cond);
  n2 = TREE_OPERAND (cond, 1);
  switch (cond_code)
    {
    case LT_EXPR:
    case GT_EXPR:
    case NE_EXPR:
      break;
    case LE_EXPR:
      if (POINTER_TYPE_P (TREE_TYPE (n2)))
	n2 = fold_build_pointer_plus_hwi_loc (loc, n2, 1);
      else
	n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (n2), n2,
			      build_int_cst (TREE_TYPE (n2), 1));
      cond_code = LT_EXPR;
      break;
    case GE_EXPR:
      if (POINTER_TYPE_P (TREE_TYPE (n2)))
	n2 = fold_build_pointer_plus_hwi_loc (loc, n2, -1);
      else
	n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (n2), n2,
			      build_int_cst (TREE_TYPE (n2), 1));
      cond_code = GT_EXPR;
      break;
    default:
      gcc_unreachable ();
    }

  step = NULL_TREE;
  switch (TREE_CODE (incr))
    {
    case PREINCREMENT_EXPR:
    case POSTINCREMENT_EXPR:
      step = build_int_cst (TREE_TYPE (v), 1);
      break;
    case PREDECREMENT_EXPR:
    case POSTDECREMENT_EXPR:
      step = build_int_cst (TREE_TYPE (v), -1);
      break;
    case MODIFY_EXPR:
      t = TREE_OPERAND (incr, 1);
      gcc_assert (TREE_OPERAND (t, 0) == v);
      switch (TREE_CODE (t))
	{
	case PLUS_EXPR:
	  step = TREE_OPERAND (t, 1);
	  break;
	case POINTER_PLUS_EXPR:
	  step = fold_convert (ssizetype, TREE_OPERAND (t, 1));
	  break;
	case MINUS_EXPR:
	  step = TREE_OPERAND (t, 1);
	  step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
	  break;
	default:
	  gcc_unreachable ();
	}
      break;
    default:
      gcc_unreachable ();
    }

  itype = type;
  if (POINTER_TYPE_P (itype))
    itype = signed_type_for (itype);
  if (cond_code == NE_EXPR)
    {
      /* For NE_EXPR, we need to find out if the iterator increases
	 or decreases from whether step is positive or negative.  */
      tree stype = itype;
      if (TYPE_UNSIGNED (stype))
	stype = signed_type_for (stype);
      cond = fold_build2_loc (loc, GE_EXPR, boolean_type_node,
			      fold_convert_loc (loc, stype, step),
			      build_int_cst (stype, 0));
      t = fold_build3_loc (loc, COND_EXPR, itype, cond,
			   build_int_cst (itype, -1),
			   build_int_cst (itype, 1));
    }
  else
    t = build_int_cst (itype, (cond_code == LT_EXPR ? -1 : 1));
  t = fold_build2_loc (loc, PLUS_EXPR, itype,
		       fold_convert_loc (loc, itype, step), t);
  t = fold_build2_loc (loc, PLUS_EXPR, itype, t,
		       fold_convert_loc (loc, itype, n2));
  t = fold_build2_loc (loc, MINUS_EXPR, itype, t,
		       fold_convert_loc (loc, itype, n1));
  if (TYPE_UNSIGNED (itype) && cond_code == GT_EXPR)
    t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype,
			 fold_build1_loc (loc, NEGATE_EXPR, itype, t),
			 fold_build1_loc (loc, NEGATE_EXPR, itype,
					  fold_convert_loc (loc, itype,
							    step)));
  else if (TYPE_UNSIGNED (itype) && cond_code == NE_EXPR)
    {
      tree t1
	= fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t,
			   fold_convert_loc (loc, itype, step));
      tree t2
	= fold_build2_loc (loc, TRUNC_DIV_EXPR, itype,
			   fold_build1_loc (loc, NEGATE_EXPR, itype, t),
			   fold_build1_loc (loc, NEGATE_EXPR, itype,
					    fold_convert_loc (loc, itype,
							      step)));
      t = fold_build3_loc (loc, COND_EXPR, itype, cond, t1, t2);
    }
  else
    t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t,
			 fold_convert_loc (loc, itype, step));
  cond = fold_build2_loc (loc, cond_code, boolean_type_node, n1, n2);
  t = fold_build3_loc (loc, COND_EXPR, itype, cond, t,
		       build_int_cst (itype, 0));
  return t;
}
Beispiel #23
0
static tree
get_pseudo_ti_desc (tree type)
{
  switch (TREE_CODE (type))
    {
    case OFFSET_TYPE:
      return ptm_desc_type_node;
    case POINTER_TYPE:
      return ptr_desc_type_node;
    case ENUMERAL_TYPE:
      return enum_desc_type_node;
    case FUNCTION_TYPE:
      return func_desc_type_node;
    case ARRAY_TYPE:
      return ary_desc_type_node;
    case UNION_TYPE:
    case RECORD_TYPE:
      if (TYPE_PTRMEMFUNC_P (type))
	return ptm_desc_type_node;
      else if (!COMPLETE_TYPE_P (type))
	{
	  if (!at_eof)
	    cxx_incomplete_type_error (NULL_TREE, type);
	  return class_desc_type_node;
	}
      else if (!BINFO_N_BASE_BINFOS (TYPE_BINFO (type)))
	return class_desc_type_node;
      else
	{
	  tree binfo = TYPE_BINFO (type);
	  VEC (tree) *base_accesses = BINFO_BASE_ACCESSES (binfo);
	  tree base_binfo = BINFO_BASE_BINFO (binfo, 0);
	  int num_bases = BINFO_N_BASE_BINFOS (binfo);
	  
	  if (num_bases == 1
	      && VEC_index (tree, base_accesses, 0) == access_public_node
	      && !BINFO_VIRTUAL_P (base_binfo)
	      && integer_zerop (BINFO_OFFSET (base_binfo)))
	    /* single non-virtual public.  */
	    return si_class_desc_type_node;
	  else
	    {
	      tree var_desc;
	      tree array_domain, base_array;
	      
	      if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
		{
		  int ix;
		  tree extend = make_tree_vec (num_bases + 5);
		  
		  for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
		    TREE_VEC_ELT (extend, ix)
		      = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
		  vmi_class_desc_type_node = extend;
		}
	      var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
	      if (var_desc)
		return var_desc;
  
	      /* Create the array of __base_class_type_info entries.
		 G++ 3.2 allocated an array that had one too many
		 entries, and then filled that extra entries with
		 zeros.  */
	      if (abi_version_at_least (2))
		array_domain = build_index_type (size_int (num_bases - 1));
	      else
		array_domain = build_index_type (size_int (num_bases));
	      base_array =
		build_array_type (base_desc_type_node, array_domain);

	      push_nested_namespace (abi_node);
	      var_desc = create_pseudo_type_info
		("__vmi_class_type_info", num_bases,
		 build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
		 build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
		 build_decl (FIELD_DECL, NULL_TREE, base_array),
		 NULL);
	      pop_nested_namespace (abi_node);

	      TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc;
	      return var_desc;
	    }
	}
    default:
      return bltn_desc_type_node;
    }
}
Beispiel #24
0
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);
    }
}
Beispiel #25
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;
}