Beispiel #1
0
function_instance *
function_instance::get_function_instance_by_decl (unsigned lineno,
                                                  tree decl) const
{
  int func_name_idx = afdo_string_table->get_index_by_decl (decl);
  if (func_name_idx != -1)
    {
      callsite_map::const_iterator ret
          = callsites.find (std::make_pair (lineno, func_name_idx));
      if (ret != callsites.end ())
        return ret->second;
    }
  func_name_idx
      = afdo_string_table->get_index (lang_hooks.dwarf_name (decl, 0));
  if (func_name_idx != -1)
    {
      callsite_map::const_iterator ret
          = callsites.find (std::make_pair (lineno, func_name_idx));
      if (ret != callsites.end ())
        return ret->second;
    }
  if (DECL_ABSTRACT_ORIGIN (decl))
    return get_function_instance_by_decl (lineno, DECL_ABSTRACT_ORIGIN (decl));

  return NULL;
}
Beispiel #2
0
int
string_table::get_index_by_decl (tree decl) const
{
  char *name
      = get_original_name (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
  int ret = get_index (name);
  free (name);
  if (ret != -1)
    return ret;
  ret = get_index (lang_hooks.dwarf_name (decl, 0));
  if (ret != -1)
    return ret;
  if (DECL_ABSTRACT_ORIGIN (decl) && DECL_ABSTRACT_ORIGIN (decl) != decl)
    return get_index_by_decl (DECL_ABSTRACT_ORIGIN (decl));

  return -1;
}
void
set_decl_origin_self (tree decl)
{
  if (DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE)
    {
      DECL_ABSTRACT_ORIGIN (decl) = decl;
      if (TREE_CODE (decl) == FUNCTION_DECL)
	{
	  tree arg;

	  for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
	    DECL_ABSTRACT_ORIGIN (arg) = arg;
	  if (DECL_INITIAL (decl) != NULL_TREE
	      && DECL_INITIAL (decl) != error_mark_node)
	    set_block_origin_self (DECL_INITIAL (decl));
	}
    }
}
static void print_function(const_tree caller, const_tree callee)
{
	expanded_location xloc;
	const char *caller_name, *callee_name;

	gcc_assert(callee != NULL_TREE);
	if (DECL_ABSTRACT_ORIGIN(callee) != NULL_TREE)
		return;
	callee_name = DECL_NAME_POINTER(callee);

	gcc_assert(caller != NULL_TREE);
	caller_name = DECL_NAME_POINTER(caller);

	xloc = expand_location(DECL_SOURCE_LOCATION(caller));
	fprintf(stderr, "DUMP_CFG:%s:%s:%s\n", caller_name, callee_name, xloc.file);
}
Beispiel #5
0
static void
update_cloned_parm (tree parm, tree cloned_parm, bool first)
{
  DECL_ABSTRACT_ORIGIN (cloned_parm) = parm;

  /* We may have taken its address.  */
  TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm);

  /* The definition might have different constness.  */
  TREE_READONLY (cloned_parm) = TREE_READONLY (parm);

  TREE_USED (cloned_parm) = !first || TREE_USED (parm);

  /* The name may have changed from the declaration.  */
  DECL_NAME (cloned_parm) = DECL_NAME (parm);
  DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm);
  TREE_TYPE (cloned_parm) = TREE_TYPE (parm);
}
Beispiel #6
0
void
print_node (FILE *file, const char *prefix, tree node, int indent)
{
    int hash;
    struct bucket *b;
    machine_mode mode;
    enum tree_code_class tclass;
    int len;
    int i;
    expanded_location xloc;
    enum tree_code code;

    if (node == 0)
        return;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /* DECL_ nodes have additional attributes.  */

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

        lang_hooks.print_decl (file, node, indent);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        lang_hooks.print_type (file, node, indent);

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

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

    case tcc_expression:
    case tcc_comparison:
    case tcc_unary:
    case tcc_binary:
    case tcc_reference:
    case tcc_statement:
    case tcc_vl_exp:
        if (code == BIND_EXPR)
        {
            print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4);
            print_node (file, "body", TREE_OPERAND (node, 1), indent + 4);
            print_node (file, "block", TREE_OPERAND (node, 2), indent + 4);
            break;
        }
        if (code == CALL_EXPR)
        {
            call_expr_arg_iterator iter;
            tree arg;
            print_node (file, "fn", CALL_EXPR_FN (node), indent + 4);
            print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node),
                        indent + 4);
            i = 0;
            FOR_EACH_CALL_EXPR_ARG (arg, iter, node)
            {
                char temp[10];
                sprintf (temp, "arg %d", i);
                print_node (file, temp, arg, indent + 4);
                i++;
            }
        }
Beispiel #7
0
static void
tree_nrv (void)
{
  tree result = DECL_RESULT (current_function_decl);
  tree result_type = TREE_TYPE (result);
  tree found = NULL;
  basic_block bb;
  block_stmt_iterator bsi;
  struct nrv_data data;

  /* If this function does not return an aggregate type in memory, then
     there is nothing to do.  */
  if (!aggregate_value_p (result, current_function_decl))
    return;

  /* Look through each block for assignments to the RESULT_DECL.  */
  FOR_EACH_BB (bb)
    {
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
	{
	  tree stmt = bsi_stmt (bsi);
	  tree ret_expr;

	  if (TREE_CODE (stmt) == RETURN_EXPR)
	    {
	      /* In a function with an aggregate return value, the
		 gimplifier has changed all non-empty RETURN_EXPRs to
		 return the RESULT_DECL.  */
	      ret_expr = TREE_OPERAND (stmt, 0);
	      if (ret_expr)
		gcc_assert (ret_expr == result);
	    }
	  else if (TREE_CODE (stmt) == MODIFY_EXPR
		   && TREE_OPERAND (stmt, 0) == result)
	    {
	      ret_expr = TREE_OPERAND (stmt, 1);

	      /* Now verify that this return statement uses the same value
		 as any previously encountered return statement.  */
	      if (found != NULL)
		{
		  /* If we found a return statement using a different variable
		     than previous return statements, then we can not perform
		     NRV optimizations.  */
		  if (found != ret_expr)
		    return;
		}
	      else
		found = ret_expr;

	      /* The returned value must be a local automatic variable of the
		 same type and alignment as the function's result.  */
	      if (TREE_CODE (found) != VAR_DECL
		  || TREE_THIS_VOLATILE (found)
		  || DECL_CONTEXT (found) != current_function_decl
		  || TREE_STATIC (found)
		  || TREE_ADDRESSABLE (found)
		  || DECL_ALIGN (found) > DECL_ALIGN (result)
		  || !lang_hooks.types_compatible_p (TREE_TYPE (found), 
						     result_type))
		return;
	    }
	}
    }

  if (!found)
    return;

  /* If dumping details, then note once and only the NRV replacement.  */
  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "NRV Replaced: ");
      print_generic_expr (dump_file, found, dump_flags);
      fprintf (dump_file, "  with: ");
      print_generic_expr (dump_file, result, dump_flags);
      fprintf (dump_file, "\n");
    }

  /* At this point we know that all the return statements return the
     same local which has suitable attributes for NRV.   Copy debugging
     information from FOUND to RESULT.  */
  DECL_NAME (result) = DECL_NAME (found);
  DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
  DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
  TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);

  /* Now walk through the function changing all references to VAR to be
     RESULT.  */
  data.var = found;
  data.result = result;
  FOR_EACH_BB (bb)
    {
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
	{
	  tree *tp = bsi_stmt_ptr (bsi);
	  /* If this is a copy from VAR to RESULT, remove it.  */
	  if (TREE_CODE (*tp) == MODIFY_EXPR
	      && TREE_OPERAND (*tp, 0) == result
	      && TREE_OPERAND (*tp, 1) == found)
	    bsi_remove (&bsi);
	  else
	    {
	      walk_tree (tp, finalize_nrv_r, &data, 0);
	      bsi_next (&bsi);
	    }
	}
    }

  /* FOUND is no longer used.  Ensure it gets removed.  */
  var_ann (found)->used = 0;
}
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);
	  }
      }
Beispiel #9
0
void
browse_tree (tree begin)
{
  tree head;
  TB_CODE tbc = TB_UNUSED_COMMAND;
  ssize_t rd;
  char *input = NULL;
  long input_size = 0;

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

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

  TB_SET_HEAD (begin);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	case TB_SEARCH_NAME:

	  break;

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

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

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

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

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

	case TB_FIRST:
	  TB_MOVE_HEAD (TB_first_in_bind);
          break;

        case TB_LAST:
          TB_MOVE_HEAD (TB_last_in_bind);
          break;

	case TB_UP:
	  TB_MOVE_HEAD (TB_up_expr);
	  break;

	case TB_PREV:
	  TB_MOVE_HEAD (TB_prev_expr);
	  break;

	case TB_NEXT:
	  TB_MOVE_HEAD (TB_next_expr);
	  break;

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

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

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

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

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

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

	default:
	  TB_NIY;
	}
    }

 ret:;
  delete TB_up_ht;
  TB_up_ht = NULL;
  return;
}
Beispiel #10
0
bool
maybe_clone_body (tree fn)
{
  tree clone;
  bool first = true;
/* APPLE LOCAL begin ARM structor thunks */
  tree clone_to_call;
  struct clone_info info;
/* APPLE LOCAL end ARM structor thunks */

  /* We only clone constructors and destructors.  */
  if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
    return 0;

  /* Emit the DWARF1 abstract instance.  */
  (*debug_hooks->deferred_inline_function) (fn);

/* APPLE LOCAL begin ARM structor thunks */
  /* Figure out whether we can use the 'thunk' implementation,
     and if so on which clones. */
  info.next_clone = 0;
  info.which_thunks_ok = compute_use_thunks (fn);
/* APPLE LOCAL end ARM structor thunks */

  /* We know that any clones immediately follow FN in the TYPE_METHODS
     list.  */
  push_to_top_level ();
  FOR_EACH_CLONE (clone, fn)
    {
      tree parm;
      tree clone_parm;
      int parmno;
      splay_tree decl_map;

      /* Update CLONE's source position information to match FN's.  */
      DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
      DECL_INLINE (clone) = DECL_INLINE (fn);
      DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
      /* LLVM LOCAL begin inlinehint attribute */
      DECL_EXPLICIT_INLINE_P (clone) = DECL_EXPLICIT_INLINE_P (fn);
      /* LLVM LOCAL end inlinehint attribute */
      DECL_COMDAT (clone) = DECL_COMDAT (fn);
      DECL_WEAK (clone) = DECL_WEAK (fn);
      DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
      DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
      DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
      DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
      DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
      DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
      TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
      DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
      DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);

      /* Adjust the parameter names and locations.  */
      parm = DECL_ARGUMENTS (fn);
      clone_parm = DECL_ARGUMENTS (clone);
      /* Update the `this' parameter, which is always first.  */
      update_cloned_parm (parm, clone_parm, first);
      parm = TREE_CHAIN (parm);
      clone_parm = TREE_CHAIN (clone_parm);
      if (DECL_HAS_IN_CHARGE_PARM_P (fn))
	parm = TREE_CHAIN (parm);
      if (DECL_HAS_VTT_PARM_P (fn))
	parm = TREE_CHAIN (parm);
      if (DECL_HAS_VTT_PARM_P (clone))
	clone_parm = TREE_CHAIN (clone_parm);
      for (; parm;
	   parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
	/* Update this parameter.  */
	update_cloned_parm (parm, clone_parm, first);

      /* Start processing the function.  */
      start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);

      /* Remap the parameters.  */
      decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
      for (parmno = 0,
	     parm = DECL_ARGUMENTS (fn),
	     clone_parm = DECL_ARGUMENTS (clone);
	   parm;
	   ++parmno,
	     parm = TREE_CHAIN (parm))
	{
	  /* Map the in-charge parameter to an appropriate constant.  */
	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
	    {
	      tree in_charge;
	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
	      splay_tree_insert (decl_map,
				 (splay_tree_key) parm,
				 (splay_tree_value) in_charge);
	      /* APPLE LOCAL ARM structor thunks */
	      info.in_charge_value [info.next_clone] = in_charge;
	    }
	  else if (DECL_ARTIFICIAL (parm)
		   && DECL_NAME (parm) == vtt_parm_identifier)
	    {
	      /* For a subobject constructor or destructor, the next
		 argument is the VTT parameter.  Remap the VTT_PARM
		 from the CLONE to this parameter.  */
	      if (DECL_HAS_VTT_PARM_P (clone))
		{
		  DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
		  splay_tree_insert (decl_map,
				     (splay_tree_key) parm,
				     (splay_tree_value) clone_parm);
		  clone_parm = TREE_CHAIN (clone_parm);
		}
	      /* Otherwise, map the VTT parameter to `NULL'.  */
	      else
		{
		  splay_tree_insert (decl_map,
				     (splay_tree_key) parm,
				     (splay_tree_value) null_pointer_node);
		}
	    }
	  /* Map other parameters to their equivalents in the cloned
	     function.  */
	  else
	    {
	      splay_tree_insert (decl_map,
				 (splay_tree_key) parm,
				 (splay_tree_value) clone_parm);
	      clone_parm = TREE_CHAIN (clone_parm);
	    }
	}

      if (targetm.cxx.cdtor_returns_this ())
	{
	  parm = DECL_RESULT (fn);
	  clone_parm = DECL_RESULT (clone);
	  splay_tree_insert (decl_map, (splay_tree_key) parm,
			     (splay_tree_value) clone_parm);
	}
      /* APPLE LOCAL begin ARM structor thunks */
      clone_to_call = find_earlier_clone (&info);
      if (clone_to_call)
	/* Bodies are identical; replace later one with call to an
	   earlier one. */
	thunk_body (clone, fn, clone_to_call);
      else
	/* Clone the body.  */
	clone_body (clone, fn, decl_map);
      /* APPLE LOCAL end ARM structor thunks */

      /* The clone can throw iff the original function can throw.  */
      cp_function_chain->can_throw = !TREE_NOTHROW (fn);

      /* Now, expand this function into RTL, if appropriate.  */
      finish_function (0);
      BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
      expand_or_defer_fn (clone);
      first = false;
      /* APPLE LOCAL begin ARM structor thunks */
      info.clones [info.next_clone] = clone;
      info.next_clone++;
      /* APPLE LOCAL end ARM structor thunks */
    }
Beispiel #11
0
/* FN is a constructor or destructor, and there are FUNCTION_DECLs
   cloned from it nearby.  Instead of cloning this body, leave it
   alone and create tiny one-call bodies for the cloned
   FUNCTION_DECLs.  These clones are sibcall candidates, and their
   resulting code will be very thunk-esque.  */
static void
thunk_body (tree clone, tree fn, tree clone_to_call)
{
  tree bind, block, call, fn_parm, fn_parm_typelist;
  int parmno, vtt_parmno;
  tree clone_parm, parmlist;

  for (vtt_parmno = -1, parmno = 0, fn_parm = DECL_ARGUMENTS (fn);
       fn_parm;
       ++parmno, fn_parm = TREE_CHAIN (fn_parm))
    {
      if (DECL_ARTIFICIAL (fn_parm) && DECL_NAME (fn_parm) == vtt_parm_identifier)
	{
	  vtt_parmno = parmno;	/* Compensate for removed in_charge parameter.  */
	  break;
	}
    }
  /* Currently, we are not supposed to have a vtt argument. */
  gcc_assert(vtt_parmno == -1);

  /* Walk parameter lists together, creating parameter list for call to original function.  */
  for (parmno = 0,
	 parmlist = NULL,
	 fn_parm = DECL_ARGUMENTS (fn),
	 fn_parm_typelist = TYPE_ARG_TYPES (TREE_TYPE (fn)),
	 clone_parm = DECL_ARGUMENTS (clone);
       fn_parm;
       ++parmno,
	 fn_parm = TREE_CHAIN (fn_parm))
    {
      if (parmno == vtt_parmno && ! DECL_HAS_VTT_PARM_P (clone))
	{
	  tree typed_null_pointer_node = copy_node (null_pointer_node);
	  gcc_assert (fn_parm_typelist);
	  /* Clobber actual parameter with formal parameter type.  */
	  TREE_TYPE (typed_null_pointer_node) = TREE_VALUE (fn_parm_typelist);
	  parmlist = tree_cons (NULL, typed_null_pointer_node, parmlist);
	}
      else if (parmno == 1 && DECL_HAS_IN_CHARGE_PARM_P (fn))
	{
	  /* Just skip it. */
	}
      /* Map other parameters to their equivalents in the cloned
	 function.  */
      else
	{
	  gcc_assert (clone_parm);
	  DECL_ABSTRACT_ORIGIN (clone_parm) = NULL;
	  parmlist = tree_cons (NULL, clone_parm, parmlist);
	  clone_parm = TREE_CHAIN (clone_parm);
	}
      if (fn_parm_typelist)
	fn_parm_typelist = TREE_CHAIN (fn_parm_typelist);
    }

    /* We built this list backwards; fix now.  */
    parmlist = nreverse (parmlist);

    TREE_USED (clone_to_call) = 1;
    call = build_cxx_call (clone_to_call, parmlist);

    for (parmlist = TREE_OPERAND (call, 1); parmlist; parmlist = TREE_CHAIN (parmlist))
      {
	fn_parm = TREE_VALUE (parmlist);
	/* Remove the EMPTY_CLASS_EXPR because it upsets estimate_num_insns().  */
	if (TREE_CODE (fn_parm) == COMPOUND_EXPR)
	  {
	    gcc_assert (TREE_CODE (TREE_OPERAND (fn_parm, 1)) == EMPTY_CLASS_EXPR);
	    TREE_VALUE (parmlist) = TREE_OPERAND (fn_parm, 0);
	  }
      }
    block = make_node (BLOCK);
    if (targetm.cxx.cdtor_returns_this ())
      {
	tree clone_result = DECL_RESULT (clone);
	tree modify = build2 (MODIFY_EXPR, TREE_TYPE (clone_result), clone_result, call);
	add_stmt (modify);
	BLOCK_VARS (block) = clone_result;
      }
    else
      {
	add_stmt (call);
      }
    bind = c_build_bind_expr (block, cur_stmt_list);
    DECL_SAVED_TREE (clone) = push_stmt_list ();
    add_stmt (bind);
}
Beispiel #12
0
static unsigned int
tree_nrv (void)
{
  tree result = DECL_RESULT (current_function_decl);
  tree result_type = TREE_TYPE (result);
  tree found = NULL;
  basic_block bb;
  gimple_stmt_iterator gsi;
  struct nrv_data data;

  /* If this function does not return an aggregate type in memory, then
     there is nothing to do.  */
  if (!aggregate_value_p (result, current_function_decl))
    return 0;

  /* If a GIMPLE type is returned in memory, finalize_nrv_r might create
     non-GIMPLE.  */
  if (is_gimple_reg_type (result_type))
    return 0;

  /* Look through each block for assignments to the RESULT_DECL.  */
  FOR_EACH_BB (bb)
    {
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
	{
	  gimple stmt = gsi_stmt (gsi);
	  tree ret_val;

	  if (gimple_code (stmt) == GIMPLE_RETURN)
	    {
	      /* In a function with an aggregate return value, the
		 gimplifier has changed all non-empty RETURN_EXPRs to
		 return the RESULT_DECL.  */
	      ret_val = gimple_return_retval (stmt);
	      if (ret_val)
		gcc_assert (ret_val == result);
	    }
	  else if (is_gimple_assign (stmt)
		   && gimple_assign_lhs (stmt) == result)
	    {
              tree rhs;

	      if (!gimple_assign_copy_p (stmt))
		return 0;

	      rhs = gimple_assign_rhs1 (stmt);

	      /* Now verify that this return statement uses the same value
		 as any previously encountered return statement.  */
	      if (found != NULL)
		{
		  /* If we found a return statement using a different variable
		     than previous return statements, then we can not perform
		     NRV optimizations.  */
		  if (found != rhs)
		    return 0;
		}
	      else
		found = rhs;

	      /* The returned value must be a local automatic variable of the
		 same type and alignment as the function's result.  */
	      if (TREE_CODE (found) != VAR_DECL
		  || TREE_THIS_VOLATILE (found)
		  || DECL_CONTEXT (found) != current_function_decl
		  || TREE_STATIC (found)
		  || TREE_ADDRESSABLE (found)
		  || DECL_ALIGN (found) > DECL_ALIGN (result)
		  || !useless_type_conversion_p (result_type,
					        TREE_TYPE (found)))
		return 0;
	    }
	  else if (is_gimple_assign (stmt))
	    {
	      tree addr = get_base_address (gimple_assign_lhs (stmt));
	       /* If there's any MODIFY of component of RESULT, 
		  then bail out.  */
	      if (addr && addr == result)
		return 0;
	    }
	}
    }

  if (!found)
    return 0;

  /* If dumping details, then note once and only the NRV replacement.  */
  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "NRV Replaced: ");
      print_generic_expr (dump_file, found, dump_flags);
      fprintf (dump_file, "  with: ");
      print_generic_expr (dump_file, result, dump_flags);
      fprintf (dump_file, "\n");
    }

  /* At this point we know that all the return statements return the
     same local which has suitable attributes for NRV.   Copy debugging
     information from FOUND to RESULT.  */
  DECL_NAME (result) = DECL_NAME (found);
  DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
  DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
  TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);

  /* Now walk through the function changing all references to VAR to be
     RESULT.  */
  data.var = found;
  data.result = result;
  FOR_EACH_BB (bb)
    {
      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
	{
	  gimple stmt = gsi_stmt (gsi);
	  /* If this is a copy from VAR to RESULT, remove it.  */
	  if (gimple_assign_copy_p (stmt)
	      && gimple_assign_lhs (stmt) == result
	      && gimple_assign_rhs1 (stmt) == found)
	    gsi_remove (&gsi, true);
	  else
	    {
	      struct walk_stmt_info wi;
	      memset (&wi, 0, sizeof (wi));
	      wi.info = &data;
	      walk_gimple_op (stmt, finalize_nrv_r, &wi);
	      gsi_next (&gsi);
	    }
	}
    }

  /* FOUND is no longer used.  Ensure it gets removed.  */
  var_ann (found)->used = 0;
  return 0;
}