gimple.h: Move some prototypes to gimple-expr.h and add to include list.
* gimple.h: Move some prototypes to gimple-expr.h and add to include list. (extract_ops_from_tree, gimple_call_addr_fndecl, is_gimple_reg_type): Move to gimple-expr.h. * gimple-expr.h: New file. Relocate some prototypes from gimple.h. (types_compatible_p, is_gimple_reg_type, is_gimple_variable, is_gimple_id, virtual_operand_p, is_gimple_addressable, is_gimple_constant, extract_ops_from_tree, gimple_call_addr_fndecl): Relocate here. * gimple.c (extract_ops_from_tree_1, gimple_cond_get_ops_from_tree, gimple_set_body, gimple_body, gimple_has_body_p, is_gimple_lvalue, is_gimple_condexpr, is_gimple_addressable, is_gimple_constant, is_gimple_address, is_gimple_invariant_address, is_gimple_ip_invariant_address, is_gimple_min_invariant, is_gimple_ip_invariant, is_gimple_variable, is_gimple_id, virtual_operand_p, is_gimple_reg, is_gimple_val, is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr, gimple_decl_printable_name, useless_type_conversion_p, types_compatible_p, gimple_can_coalesce_p, copy_var_decl): Move to gimple-expr.[ch]. * gimple-expr.c: New File. (useless_type_conversion_p, gimple_set_body, gimple_body, gimple_has_body_p, gimple_decl_printable_name, copy_var_decl, gimple_can_coalesce_p, extract_ops_from_tree_1, gimple_cond_get_ops_from_tree, is_gimple_lvalue, is_gimple_condexpr, is_gimple_address, is_gimple_invariant_address, is_gimple_ip_invariant_address, is_gimple_min_invariant, is_gimple_ip_invariant, is_gimple_reg, is_gimple_val, is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr): Relocate here. * Makefile.in (OBJS): Add gimple-expr.o. From-SVN: r204412
This commit is contained in:
parent
c180e49596
commit
2a0603f189
@ -1,3 +1,37 @@
|
|||||||
|
2013-11-05 Andrew MacLeod <amacleod@redhat.com>
|
||||||
|
|
||||||
|
* gimple.h: Move some prototypes to gimple-expr.h and add to include
|
||||||
|
list.
|
||||||
|
(extract_ops_from_tree, gimple_call_addr_fndecl, is_gimple_reg_type):
|
||||||
|
Move to gimple-expr.h.
|
||||||
|
* gimple-expr.h: New file. Relocate some prototypes from gimple.h.
|
||||||
|
(types_compatible_p, is_gimple_reg_type, is_gimple_variable,
|
||||||
|
is_gimple_id, virtual_operand_p, is_gimple_addressable,
|
||||||
|
is_gimple_constant, extract_ops_from_tree, gimple_call_addr_fndecl):
|
||||||
|
Relocate here.
|
||||||
|
* gimple.c (extract_ops_from_tree_1, gimple_cond_get_ops_from_tree,
|
||||||
|
gimple_set_body, gimple_body, gimple_has_body_p, is_gimple_lvalue,
|
||||||
|
is_gimple_condexpr, is_gimple_addressable, is_gimple_constant,
|
||||||
|
is_gimple_address, is_gimple_invariant_address,
|
||||||
|
is_gimple_ip_invariant_address, is_gimple_min_invariant,
|
||||||
|
is_gimple_ip_invariant, is_gimple_variable, is_gimple_id,
|
||||||
|
virtual_operand_p, is_gimple_reg, is_gimple_val, is_gimple_asm_val,
|
||||||
|
is_gimple_min_lval, is_gimple_call_addr, is_gimple_mem_ref_addr,
|
||||||
|
gimple_decl_printable_name, useless_type_conversion_p,
|
||||||
|
types_compatible_p, gimple_can_coalesce_p, copy_var_decl): Move to
|
||||||
|
gimple-expr.[ch].
|
||||||
|
* gimple-expr.c: New File.
|
||||||
|
(useless_type_conversion_p, gimple_set_body, gimple_body,
|
||||||
|
gimple_has_body_p, gimple_decl_printable_name, copy_var_decl,
|
||||||
|
gimple_can_coalesce_p, extract_ops_from_tree_1,
|
||||||
|
gimple_cond_get_ops_from_tree, is_gimple_lvalue, is_gimple_condexpr,
|
||||||
|
is_gimple_address, is_gimple_invariant_address,
|
||||||
|
is_gimple_ip_invariant_address, is_gimple_min_invariant,
|
||||||
|
is_gimple_ip_invariant, is_gimple_reg, is_gimple_val,
|
||||||
|
is_gimple_asm_val, is_gimple_min_lval, is_gimple_call_addr,
|
||||||
|
is_gimple_mem_ref_addr): Relocate here.
|
||||||
|
* Makefile.in (OBJS): Add gimple-expr.o.
|
||||||
|
|
||||||
2013-11-05 David Malcolm <dmalcolm@redhat.com>
|
2013-11-05 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
* gengtype-parse.c (struct_field_seq): Support empty structs.
|
* gengtype-parse.c (struct_field_seq): Support empty structs.
|
||||||
|
@ -1230,6 +1230,7 @@ OBJS = \
|
|||||||
ggc-common.o \
|
ggc-common.o \
|
||||||
gimple.o \
|
gimple.o \
|
||||||
gimple-builder.o \
|
gimple-builder.o \
|
||||||
|
gimple-expr.o \
|
||||||
gimple-iterator.o \
|
gimple-iterator.o \
|
||||||
gimple-fold.o \
|
gimple-fold.o \
|
||||||
gimple-low.o \
|
gimple-low.o \
|
||||||
|
721
gcc/gimple-expr.c
Normal file
721
gcc/gimple-expr.c
Normal file
@ -0,0 +1,721 @@
|
|||||||
|
/* Gimple decl, type, and expression support functions.
|
||||||
|
|
||||||
|
Copyright (C) 2007-2013 Free Software Foundation, Inc.
|
||||||
|
Contributed by Aldy Hernandez <aldyh@redhat.com>
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GCC; see the file COPYING3. If not see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "coretypes.h"
|
||||||
|
#include "tm.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "gimple.h"
|
||||||
|
#include "demangle.h"
|
||||||
|
|
||||||
|
/* ----- Type related ----- */
|
||||||
|
|
||||||
|
/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
|
||||||
|
useless type conversion, otherwise return false.
|
||||||
|
|
||||||
|
This function implicitly defines the middle-end type system. With
|
||||||
|
the notion of 'a < b' meaning that useless_type_conversion_p (a, b)
|
||||||
|
holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds,
|
||||||
|
the following invariants shall be fulfilled:
|
||||||
|
|
||||||
|
1) useless_type_conversion_p is transitive.
|
||||||
|
If a < b and b < c then a < c.
|
||||||
|
|
||||||
|
2) useless_type_conversion_p is not symmetric.
|
||||||
|
From a < b does not follow a > b.
|
||||||
|
|
||||||
|
3) Types define the available set of operations applicable to values.
|
||||||
|
A type conversion is useless if the operations for the target type
|
||||||
|
is a subset of the operations for the source type. For example
|
||||||
|
casts to void* are useless, casts from void* are not (void* can't
|
||||||
|
be dereferenced or offsetted, but copied, hence its set of operations
|
||||||
|
is a strict subset of that of all other data pointer types). Casts
|
||||||
|
to const T* are useless (can't be written to), casts from const T*
|
||||||
|
to T* are not. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
useless_type_conversion_p (tree outer_type, tree inner_type)
|
||||||
|
{
|
||||||
|
/* Do the following before stripping toplevel qualifiers. */
|
||||||
|
if (POINTER_TYPE_P (inner_type)
|
||||||
|
&& POINTER_TYPE_P (outer_type))
|
||||||
|
{
|
||||||
|
/* Do not lose casts between pointers to different address spaces. */
|
||||||
|
if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
|
||||||
|
!= TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From now on qualifiers on value types do not matter. */
|
||||||
|
inner_type = TYPE_MAIN_VARIANT (inner_type);
|
||||||
|
outer_type = TYPE_MAIN_VARIANT (outer_type);
|
||||||
|
|
||||||
|
if (inner_type == outer_type)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If we know the canonical types, compare them. */
|
||||||
|
if (TYPE_CANONICAL (inner_type)
|
||||||
|
&& TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Changes in machine mode are never useless conversions unless we
|
||||||
|
deal with aggregate types in which case we defer to later checks. */
|
||||||
|
if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
|
||||||
|
&& !AGGREGATE_TYPE_P (inner_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If both the inner and outer types are integral types, then the
|
||||||
|
conversion is not necessary if they have the same mode and
|
||||||
|
signedness and precision, and both or neither are boolean. */
|
||||||
|
if (INTEGRAL_TYPE_P (inner_type)
|
||||||
|
&& INTEGRAL_TYPE_P (outer_type))
|
||||||
|
{
|
||||||
|
/* Preserve changes in signedness or precision. */
|
||||||
|
if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
|
||||||
|
|| TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Preserve conversions to/from BOOLEAN_TYPE if types are not
|
||||||
|
of precision one. */
|
||||||
|
if (((TREE_CODE (inner_type) == BOOLEAN_TYPE)
|
||||||
|
!= (TREE_CODE (outer_type) == BOOLEAN_TYPE))
|
||||||
|
&& TYPE_PRECISION (outer_type) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We don't need to preserve changes in the types minimum or
|
||||||
|
maximum value in general as these do not generate code
|
||||||
|
unless the types precisions are different. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scalar floating point types with the same mode are compatible. */
|
||||||
|
else if (SCALAR_FLOAT_TYPE_P (inner_type)
|
||||||
|
&& SCALAR_FLOAT_TYPE_P (outer_type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Fixed point types with the same mode are compatible. */
|
||||||
|
else if (FIXED_POINT_TYPE_P (inner_type)
|
||||||
|
&& FIXED_POINT_TYPE_P (outer_type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* We need to take special care recursing to pointed-to types. */
|
||||||
|
else if (POINTER_TYPE_P (inner_type)
|
||||||
|
&& POINTER_TYPE_P (outer_type))
|
||||||
|
{
|
||||||
|
/* Do not lose casts to function pointer types. */
|
||||||
|
if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
|
||||||
|
|| TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
|
||||||
|
&& !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
|
||||||
|
|| TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We do not care for const qualification of the pointed-to types
|
||||||
|
as const qualification has no semantic value to the middle-end. */
|
||||||
|
|
||||||
|
/* Otherwise pointers/references are equivalent. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recurse for complex types. */
|
||||||
|
else if (TREE_CODE (inner_type) == COMPLEX_TYPE
|
||||||
|
&& TREE_CODE (outer_type) == COMPLEX_TYPE)
|
||||||
|
return useless_type_conversion_p (TREE_TYPE (outer_type),
|
||||||
|
TREE_TYPE (inner_type));
|
||||||
|
|
||||||
|
/* Recurse for vector types with the same number of subparts. */
|
||||||
|
else if (TREE_CODE (inner_type) == VECTOR_TYPE
|
||||||
|
&& TREE_CODE (outer_type) == VECTOR_TYPE
|
||||||
|
&& TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
|
||||||
|
return useless_type_conversion_p (TREE_TYPE (outer_type),
|
||||||
|
TREE_TYPE (inner_type));
|
||||||
|
|
||||||
|
else if (TREE_CODE (inner_type) == ARRAY_TYPE
|
||||||
|
&& TREE_CODE (outer_type) == ARRAY_TYPE)
|
||||||
|
{
|
||||||
|
/* Preserve string attributes. */
|
||||||
|
if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Conversions from array types with unknown extent to
|
||||||
|
array types with known extent are not useless. */
|
||||||
|
if (!TYPE_DOMAIN (inner_type)
|
||||||
|
&& TYPE_DOMAIN (outer_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Nor are conversions from array types with non-constant size to
|
||||||
|
array types with constant size or to different size. */
|
||||||
|
if (TYPE_SIZE (outer_type)
|
||||||
|
&& TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST
|
||||||
|
&& (!TYPE_SIZE (inner_type)
|
||||||
|
|| TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST
|
||||||
|
|| !tree_int_cst_equal (TYPE_SIZE (outer_type),
|
||||||
|
TYPE_SIZE (inner_type))))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check conversions between arrays with partially known extents.
|
||||||
|
If the array min/max values are constant they have to match.
|
||||||
|
Otherwise allow conversions to unknown and variable extents.
|
||||||
|
In particular this declares conversions that may change the
|
||||||
|
mode to BLKmode as useless. */
|
||||||
|
if (TYPE_DOMAIN (inner_type)
|
||||||
|
&& TYPE_DOMAIN (outer_type)
|
||||||
|
&& TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type))
|
||||||
|
{
|
||||||
|
tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type));
|
||||||
|
tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type));
|
||||||
|
tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type));
|
||||||
|
tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type));
|
||||||
|
|
||||||
|
/* After gimplification a variable min/max value carries no
|
||||||
|
additional information compared to a NULL value. All that
|
||||||
|
matters has been lowered to be part of the IL. */
|
||||||
|
if (inner_min && TREE_CODE (inner_min) != INTEGER_CST)
|
||||||
|
inner_min = NULL_TREE;
|
||||||
|
if (outer_min && TREE_CODE (outer_min) != INTEGER_CST)
|
||||||
|
outer_min = NULL_TREE;
|
||||||
|
if (inner_max && TREE_CODE (inner_max) != INTEGER_CST)
|
||||||
|
inner_max = NULL_TREE;
|
||||||
|
if (outer_max && TREE_CODE (outer_max) != INTEGER_CST)
|
||||||
|
outer_max = NULL_TREE;
|
||||||
|
|
||||||
|
/* Conversions NULL / variable <- cst are useless, but not
|
||||||
|
the other way around. */
|
||||||
|
if (outer_min
|
||||||
|
&& (!inner_min
|
||||||
|
|| !tree_int_cst_equal (inner_min, outer_min)))
|
||||||
|
return false;
|
||||||
|
if (outer_max
|
||||||
|
&& (!inner_max
|
||||||
|
|| !tree_int_cst_equal (inner_max, outer_max)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recurse on the element check. */
|
||||||
|
return useless_type_conversion_p (TREE_TYPE (outer_type),
|
||||||
|
TREE_TYPE (inner_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((TREE_CODE (inner_type) == FUNCTION_TYPE
|
||||||
|
|| TREE_CODE (inner_type) == METHOD_TYPE)
|
||||||
|
&& TREE_CODE (inner_type) == TREE_CODE (outer_type))
|
||||||
|
{
|
||||||
|
tree outer_parm, inner_parm;
|
||||||
|
|
||||||
|
/* If the return types are not compatible bail out. */
|
||||||
|
if (!useless_type_conversion_p (TREE_TYPE (outer_type),
|
||||||
|
TREE_TYPE (inner_type)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Method types should belong to a compatible base class. */
|
||||||
|
if (TREE_CODE (inner_type) == METHOD_TYPE
|
||||||
|
&& !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type),
|
||||||
|
TYPE_METHOD_BASETYPE (inner_type)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* A conversion to an unprototyped argument list is ok. */
|
||||||
|
if (!prototype_p (outer_type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If the unqualified argument types are compatible the conversion
|
||||||
|
is useless. */
|
||||||
|
if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (outer_parm = TYPE_ARG_TYPES (outer_type),
|
||||||
|
inner_parm = TYPE_ARG_TYPES (inner_type);
|
||||||
|
outer_parm && inner_parm;
|
||||||
|
outer_parm = TREE_CHAIN (outer_parm),
|
||||||
|
inner_parm = TREE_CHAIN (inner_parm))
|
||||||
|
if (!useless_type_conversion_p
|
||||||
|
(TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)),
|
||||||
|
TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm))))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If there is a mismatch in the number of arguments the functions
|
||||||
|
are not compatible. */
|
||||||
|
if (outer_parm || inner_parm)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Defer to the target if necessary. */
|
||||||
|
if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type))
|
||||||
|
return comp_type_attributes (outer_type, inner_type) != 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For aggregates we rely on TYPE_CANONICAL exclusively and require
|
||||||
|
explicit conversions for types involving to be structurally
|
||||||
|
compared types. */
|
||||||
|
else if (AGGREGATE_TYPE_P (inner_type)
|
||||||
|
&& TREE_CODE (inner_type) == TREE_CODE (outer_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Decl related ----- */
|
||||||
|
|
||||||
|
/* Set sequence SEQ to be the GIMPLE body for function FN. */
|
||||||
|
|
||||||
|
void
|
||||||
|
gimple_set_body (tree fndecl, gimple_seq seq)
|
||||||
|
{
|
||||||
|
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
|
||||||
|
if (fn == NULL)
|
||||||
|
{
|
||||||
|
/* If FNDECL still does not have a function structure associated
|
||||||
|
with it, then it does not make sense for it to receive a
|
||||||
|
GIMPLE body. */
|
||||||
|
gcc_assert (seq == NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fn->gimple_body = seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the body of GIMPLE statements for function FN. After the
|
||||||
|
CFG pass, the function body doesn't exist anymore because it has
|
||||||
|
been split up into basic blocks. In this case, it returns
|
||||||
|
NULL. */
|
||||||
|
|
||||||
|
gimple_seq
|
||||||
|
gimple_body (tree fndecl)
|
||||||
|
{
|
||||||
|
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
|
||||||
|
return fn ? fn->gimple_body : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true when FNDECL has Gimple body either in unlowered
|
||||||
|
or CFG form. */
|
||||||
|
bool
|
||||||
|
gimple_has_body_p (tree fndecl)
|
||||||
|
{
|
||||||
|
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
|
||||||
|
return (gimple_body (fndecl) || (fn && fn->cfg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a printable name for symbol DECL. */
|
||||||
|
|
||||||
|
const char *
|
||||||
|
gimple_decl_printable_name (tree decl, int verbosity)
|
||||||
|
{
|
||||||
|
if (!DECL_NAME (decl))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (DECL_ASSEMBLER_NAME_SET_P (decl))
|
||||||
|
{
|
||||||
|
const char *str, *mangled_str;
|
||||||
|
int dmgl_opts = DMGL_NO_OPTS;
|
||||||
|
|
||||||
|
if (verbosity >= 2)
|
||||||
|
{
|
||||||
|
dmgl_opts = DMGL_VERBOSE
|
||||||
|
| DMGL_ANSI
|
||||||
|
| DMGL_GNU_V3
|
||||||
|
| DMGL_RET_POSTFIX;
|
||||||
|
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||||
|
dmgl_opts |= DMGL_PARAMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
||||||
|
str = cplus_demangle_v3 (mangled_str, dmgl_opts);
|
||||||
|
return (str) ? str : mangled_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IDENTIFIER_POINTER (DECL_NAME (decl));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new VAR_DECL and copy information from VAR to it. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
copy_var_decl (tree var, tree name, tree type)
|
||||||
|
{
|
||||||
|
tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type);
|
||||||
|
|
||||||
|
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
|
||||||
|
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
|
||||||
|
DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
|
||||||
|
DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
|
||||||
|
DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
|
||||||
|
DECL_CONTEXT (copy) = DECL_CONTEXT (var);
|
||||||
|
TREE_NO_WARNING (copy) = TREE_NO_WARNING (var);
|
||||||
|
TREE_USED (copy) = 1;
|
||||||
|
DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
|
||||||
|
DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for
|
||||||
|
coalescing together, false otherwise.
|
||||||
|
|
||||||
|
This must stay consistent with var_map_base_init in tree-ssa-live.c. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
gimple_can_coalesce_p (tree name1, tree name2)
|
||||||
|
{
|
||||||
|
/* First check the SSA_NAME's associated DECL. We only want to
|
||||||
|
coalesce if they have the same DECL or both have no associated DECL. */
|
||||||
|
tree var1 = SSA_NAME_VAR (name1);
|
||||||
|
tree var2 = SSA_NAME_VAR (name2);
|
||||||
|
var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE;
|
||||||
|
var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE;
|
||||||
|
if (var1 != var2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Now check the types. If the types are the same, then we should
|
||||||
|
try to coalesce V1 and V2. */
|
||||||
|
tree t1 = TREE_TYPE (name1);
|
||||||
|
tree t2 = TREE_TYPE (name2);
|
||||||
|
if (t1 == t2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If the types are not the same, check for a canonical type match. This
|
||||||
|
(for example) allows coalescing when the types are fundamentally the
|
||||||
|
same, but just have different names.
|
||||||
|
|
||||||
|
Note pointer types with different address spaces may have the same
|
||||||
|
canonical type. Those are rejected for coalescing by the
|
||||||
|
types_compatible_p check. */
|
||||||
|
if (TYPE_CANONICAL (t1)
|
||||||
|
&& TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)
|
||||||
|
&& types_compatible_p (t1, t2))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Expression related ----- */
|
||||||
|
|
||||||
|
/* Extract the operands and code for expression EXPR into *SUBCODE_P,
|
||||||
|
*OP1_P, *OP2_P and *OP3_P respectively. */
|
||||||
|
|
||||||
|
void
|
||||||
|
extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p,
|
||||||
|
tree *op2_p, tree *op3_p)
|
||||||
|
{
|
||||||
|
enum gimple_rhs_class grhs_class;
|
||||||
|
|
||||||
|
*subcode_p = TREE_CODE (expr);
|
||||||
|
grhs_class = get_gimple_rhs_class (*subcode_p);
|
||||||
|
|
||||||
|
if (grhs_class == GIMPLE_TERNARY_RHS)
|
||||||
|
{
|
||||||
|
*op1_p = TREE_OPERAND (expr, 0);
|
||||||
|
*op2_p = TREE_OPERAND (expr, 1);
|
||||||
|
*op3_p = TREE_OPERAND (expr, 2);
|
||||||
|
}
|
||||||
|
else if (grhs_class == GIMPLE_BINARY_RHS)
|
||||||
|
{
|
||||||
|
*op1_p = TREE_OPERAND (expr, 0);
|
||||||
|
*op2_p = TREE_OPERAND (expr, 1);
|
||||||
|
*op3_p = NULL_TREE;
|
||||||
|
}
|
||||||
|
else if (grhs_class == GIMPLE_UNARY_RHS)
|
||||||
|
{
|
||||||
|
*op1_p = TREE_OPERAND (expr, 0);
|
||||||
|
*op2_p = NULL_TREE;
|
||||||
|
*op3_p = NULL_TREE;
|
||||||
|
}
|
||||||
|
else if (grhs_class == GIMPLE_SINGLE_RHS)
|
||||||
|
{
|
||||||
|
*op1_p = expr;
|
||||||
|
*op2_p = NULL_TREE;
|
||||||
|
*op3_p = NULL_TREE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gcc_unreachable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND. */
|
||||||
|
|
||||||
|
void
|
||||||
|
gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
|
||||||
|
tree *lhs_p, tree *rhs_p)
|
||||||
|
{
|
||||||
|
gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
|
||||||
|
|| TREE_CODE (cond) == TRUTH_NOT_EXPR
|
||||||
|
|| is_gimple_min_invariant (cond)
|
||||||
|
|| SSA_VAR_P (cond));
|
||||||
|
|
||||||
|
extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
|
||||||
|
|
||||||
|
/* Canonicalize conditionals of the form 'if (!VAL)'. */
|
||||||
|
if (*code_p == TRUTH_NOT_EXPR)
|
||||||
|
{
|
||||||
|
*code_p = EQ_EXPR;
|
||||||
|
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
|
||||||
|
*rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
|
||||||
|
}
|
||||||
|
/* Canonicalize conditionals of the form 'if (VAL)' */
|
||||||
|
else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
|
||||||
|
{
|
||||||
|
*code_p = NE_EXPR;
|
||||||
|
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
|
||||||
|
*rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a valid LHS for a GIMPLE assignment expression. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_lvalue (tree t)
|
||||||
|
{
|
||||||
|
return (is_gimple_addressable (t)
|
||||||
|
|| TREE_CODE (t) == WITH_SIZE_EXPR
|
||||||
|
/* These are complex lvalues, but don't have addresses, so they
|
||||||
|
go here. */
|
||||||
|
|| TREE_CODE (t) == BIT_FIELD_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a GIMPLE condition. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_condexpr (tree t)
|
||||||
|
{
|
||||||
|
return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
|
||||||
|
&& !tree_could_throw_p (t)
|
||||||
|
&& is_gimple_val (TREE_OPERAND (t, 0))
|
||||||
|
&& is_gimple_val (TREE_OPERAND (t, 1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a gimple address. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_address (const_tree t)
|
||||||
|
{
|
||||||
|
tree op;
|
||||||
|
|
||||||
|
if (TREE_CODE (t) != ADDR_EXPR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
op = TREE_OPERAND (t, 0);
|
||||||
|
while (handled_component_p (op))
|
||||||
|
{
|
||||||
|
if ((TREE_CODE (op) == ARRAY_REF
|
||||||
|
|| TREE_CODE (op) == ARRAY_RANGE_REF)
|
||||||
|
&& !is_gimple_val (TREE_OPERAND (op, 1)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
op = TREE_OPERAND (op, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (TREE_CODE (op))
|
||||||
|
{
|
||||||
|
case PARM_DECL:
|
||||||
|
case RESULT_DECL:
|
||||||
|
case LABEL_DECL:
|
||||||
|
case FUNCTION_DECL:
|
||||||
|
case VAR_DECL:
|
||||||
|
case CONST_DECL:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a gimple invariant address. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_invariant_address (const_tree t)
|
||||||
|
{
|
||||||
|
const_tree op;
|
||||||
|
|
||||||
|
if (TREE_CODE (t) != ADDR_EXPR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
op = strip_invariant_refs (TREE_OPERAND (t, 0));
|
||||||
|
if (!op)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TREE_CODE (op) == MEM_REF)
|
||||||
|
{
|
||||||
|
const_tree op0 = TREE_OPERAND (op, 0);
|
||||||
|
return (TREE_CODE (op0) == ADDR_EXPR
|
||||||
|
&& (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
|
||||||
|
|| decl_address_invariant_p (TREE_OPERAND (op0, 0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a gimple invariant address at IPA level
|
||||||
|
(so addresses of variables on stack are not allowed). */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_ip_invariant_address (const_tree t)
|
||||||
|
{
|
||||||
|
const_tree op;
|
||||||
|
|
||||||
|
if (TREE_CODE (t) != ADDR_EXPR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
op = strip_invariant_refs (TREE_OPERAND (t, 0));
|
||||||
|
if (!op)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TREE_CODE (op) == MEM_REF)
|
||||||
|
{
|
||||||
|
const_tree op0 = TREE_OPERAND (op, 0);
|
||||||
|
return (TREE_CODE (op0) == ADDR_EXPR
|
||||||
|
&& (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
|
||||||
|
|| decl_address_ip_invariant_p (TREE_OPERAND (op0, 0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
|
||||||
|
form of function invariant. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_min_invariant (const_tree t)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (t) == ADDR_EXPR)
|
||||||
|
return is_gimple_invariant_address (t);
|
||||||
|
|
||||||
|
return is_gimple_constant (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a GIMPLE interprocedural invariant. It's a restricted
|
||||||
|
form of gimple minimal invariant. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_ip_invariant (const_tree t)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (t) == ADDR_EXPR)
|
||||||
|
return is_gimple_ip_invariant_address (t);
|
||||||
|
|
||||||
|
return is_gimple_constant (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a non-aggregate register variable. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_reg (tree t)
|
||||||
|
{
|
||||||
|
if (virtual_operand_p (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TREE_CODE (t) == SSA_NAME)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!is_gimple_variable (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!is_gimple_reg_type (TREE_TYPE (t)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* A volatile decl is not acceptable because we can't reuse it as
|
||||||
|
needed. We need to copy it into a temp first. */
|
||||||
|
if (TREE_THIS_VOLATILE (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We define "registers" as things that can be renamed as needed,
|
||||||
|
which with our infrastructure does not apply to memory. */
|
||||||
|
if (needs_to_live_in_memory (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Hard register variables are an interesting case. For those that
|
||||||
|
are call-clobbered, we don't know where all the calls are, since
|
||||||
|
we don't (want to) take into account which operations will turn
|
||||||
|
into libcalls at the rtl level. For those that are call-saved,
|
||||||
|
we don't currently model the fact that calls may in fact change
|
||||||
|
global hard registers, nor do we examine ASM_CLOBBERS at the tree
|
||||||
|
level, and so miss variable changes that might imply. All around,
|
||||||
|
it seems safest to not do too much optimization with these at the
|
||||||
|
tree level at all. We'll have to rely on the rtl optimizers to
|
||||||
|
clean this up, as there we've got all the appropriate bits exposed. */
|
||||||
|
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Complex and vector values must have been put into SSA-like form.
|
||||||
|
That is, no assignments to the individual components. */
|
||||||
|
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
|
||||||
|
|| TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
|
||||||
|
return DECL_GIMPLE_REG_P (t);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_val (tree t)
|
||||||
|
{
|
||||||
|
/* Make loads from volatiles and memory vars explicit. */
|
||||||
|
if (is_gimple_variable (t)
|
||||||
|
&& is_gimple_reg_type (TREE_TYPE (t))
|
||||||
|
&& !is_gimple_reg (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (is_gimple_variable (t) || is_gimple_min_invariant (t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Similarly, but accept hard registers as inputs to asm statements. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_asm_val (tree t)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return is_gimple_val (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a GIMPLE minimal lvalue. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_min_lval (tree t)
|
||||||
|
{
|
||||||
|
if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
|
||||||
|
return false;
|
||||||
|
return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a valid function operand of a CALL_EXPR. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_call_addr (tree t)
|
||||||
|
{
|
||||||
|
return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a valid address operand of a MEM_REF. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_gimple_mem_ref_addr (tree t)
|
||||||
|
{
|
||||||
|
return (is_gimple_reg (t)
|
||||||
|
|| TREE_CODE (t) == INTEGER_CST
|
||||||
|
|| (TREE_CODE (t) == ADDR_EXPR
|
||||||
|
&& (CONSTANT_CLASS_P (TREE_OPERAND (t, 0))
|
||||||
|
|| decl_address_invariant_p (TREE_OPERAND (t, 0)))));
|
||||||
|
}
|
171
gcc/gimple-expr.h
Normal file
171
gcc/gimple-expr.h
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/* Header file for gimple decl, type and expressions.
|
||||||
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GCC.
|
||||||
|
|
||||||
|
GCC is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GCC; see the file COPYING3. If not see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef GCC_GIMPLE_EXPR_H
|
||||||
|
#define GCC_GIMPLE_EXPR_H
|
||||||
|
|
||||||
|
extern bool useless_type_conversion_p (tree, tree);
|
||||||
|
|
||||||
|
extern void gimple_set_body (tree, gimple_seq);
|
||||||
|
extern gimple_seq gimple_body (tree);
|
||||||
|
extern bool gimple_has_body_p (tree);
|
||||||
|
extern const char *gimple_decl_printable_name (tree, int);
|
||||||
|
extern tree copy_var_decl (tree, tree, tree);
|
||||||
|
extern bool gimple_can_coalesce_p (tree, tree);
|
||||||
|
|
||||||
|
extern void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *,
|
||||||
|
tree *);
|
||||||
|
extern void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *,
|
||||||
|
tree *);
|
||||||
|
extern bool is_gimple_lvalue (tree);
|
||||||
|
extern bool is_gimple_condexpr (tree);
|
||||||
|
extern bool is_gimple_address (const_tree);
|
||||||
|
extern bool is_gimple_invariant_address (const_tree);
|
||||||
|
extern bool is_gimple_ip_invariant_address (const_tree);
|
||||||
|
extern bool is_gimple_min_invariant (const_tree);
|
||||||
|
extern bool is_gimple_ip_invariant (const_tree);
|
||||||
|
extern bool is_gimple_reg (tree);
|
||||||
|
extern bool is_gimple_val (tree);
|
||||||
|
extern bool is_gimple_asm_val (tree);
|
||||||
|
extern bool is_gimple_min_lval (tree);
|
||||||
|
extern bool is_gimple_call_addr (tree);
|
||||||
|
extern bool is_gimple_mem_ref_addr (tree);
|
||||||
|
|
||||||
|
/* Return true if a conversion from either type of TYPE1 and TYPE2
|
||||||
|
to the other is not required. Otherwise return false. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
types_compatible_p (tree type1, tree type2)
|
||||||
|
{
|
||||||
|
return (type1 == type2
|
||||||
|
|| (useless_type_conversion_p (type1, type2)
|
||||||
|
&& useless_type_conversion_p (type2, type1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if TYPE is a suitable type for a scalar register variable. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_gimple_reg_type (tree type)
|
||||||
|
{
|
||||||
|
return !AGGREGATE_TYPE_P (type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a variable. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_gimple_variable (tree t)
|
||||||
|
{
|
||||||
|
return (TREE_CODE (t) == VAR_DECL
|
||||||
|
|| TREE_CODE (t) == PARM_DECL
|
||||||
|
|| TREE_CODE (t) == RESULT_DECL
|
||||||
|
|| TREE_CODE (t) == SSA_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a GIMPLE identifier (something with an address). */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_gimple_id (tree t)
|
||||||
|
{
|
||||||
|
return (is_gimple_variable (t)
|
||||||
|
|| TREE_CODE (t) == FUNCTION_DECL
|
||||||
|
|| TREE_CODE (t) == LABEL_DECL
|
||||||
|
|| TREE_CODE (t) == CONST_DECL
|
||||||
|
/* Allow string constants, since they are addressable. */
|
||||||
|
|| TREE_CODE (t) == STRING_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if OP, an SSA name or a DECL is a virtual operand. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
virtual_operand_p (tree op)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (op) == SSA_NAME)
|
||||||
|
{
|
||||||
|
op = SSA_NAME_VAR (op);
|
||||||
|
if (!op)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TREE_CODE (op) == VAR_DECL)
|
||||||
|
return VAR_DECL_IS_VIRTUAL_OPERAND (op);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is something whose address can be taken. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_gimple_addressable (tree t)
|
||||||
|
{
|
||||||
|
return (is_gimple_id (t) || handled_component_p (t)
|
||||||
|
|| TREE_CODE (t) == MEM_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if T is a valid gimple constant. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_gimple_constant (const_tree t)
|
||||||
|
{
|
||||||
|
switch (TREE_CODE (t))
|
||||||
|
{
|
||||||
|
case INTEGER_CST:
|
||||||
|
case REAL_CST:
|
||||||
|
case FIXED_CST:
|
||||||
|
case STRING_CST:
|
||||||
|
case COMPLEX_CST:
|
||||||
|
case VECTOR_CST:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A wrapper around extract_ops_from_tree_1, for callers which expect
|
||||||
|
to see only a maximum of two operands. */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0,
|
||||||
|
tree *op1)
|
||||||
|
{
|
||||||
|
tree op2;
|
||||||
|
extract_ops_from_tree_1 (expr, code, op0, op1, &op2);
|
||||||
|
gcc_assert (op2 == NULL_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL
|
||||||
|
associated with the callee if known. Otherwise return NULL_TREE. */
|
||||||
|
|
||||||
|
static inline tree
|
||||||
|
gimple_call_addr_fndecl (const_tree fn)
|
||||||
|
{
|
||||||
|
if (fn && TREE_CODE (fn) == ADDR_EXPR)
|
||||||
|
{
|
||||||
|
tree fndecl = TREE_OPERAND (fn, 0);
|
||||||
|
if (TREE_CODE (fndecl) == MEM_REF
|
||||||
|
&& TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR
|
||||||
|
&& integer_zerop (TREE_OPERAND (fndecl, 1)))
|
||||||
|
fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0);
|
||||||
|
if (TREE_CODE (fndecl) == FUNCTION_DECL)
|
||||||
|
return fndecl;
|
||||||
|
}
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GCC_GIMPLE_EXPR_H */
|
776
gcc/gimple.c
776
gcc/gimple.c
@ -386,47 +386,6 @@ gimple_call_get_nobnd_arg_index (const_gimple gs, unsigned index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Extract the operands and code for expression EXPR into *SUBCODE_P,
|
|
||||||
*OP1_P, *OP2_P and *OP3_P respectively. */
|
|
||||||
|
|
||||||
void
|
|
||||||
extract_ops_from_tree_1 (tree expr, enum tree_code *subcode_p, tree *op1_p,
|
|
||||||
tree *op2_p, tree *op3_p)
|
|
||||||
{
|
|
||||||
enum gimple_rhs_class grhs_class;
|
|
||||||
|
|
||||||
*subcode_p = TREE_CODE (expr);
|
|
||||||
grhs_class = get_gimple_rhs_class (*subcode_p);
|
|
||||||
|
|
||||||
if (grhs_class == GIMPLE_TERNARY_RHS)
|
|
||||||
{
|
|
||||||
*op1_p = TREE_OPERAND (expr, 0);
|
|
||||||
*op2_p = TREE_OPERAND (expr, 1);
|
|
||||||
*op3_p = TREE_OPERAND (expr, 2);
|
|
||||||
}
|
|
||||||
else if (grhs_class == GIMPLE_BINARY_RHS)
|
|
||||||
{
|
|
||||||
*op1_p = TREE_OPERAND (expr, 0);
|
|
||||||
*op2_p = TREE_OPERAND (expr, 1);
|
|
||||||
*op3_p = NULL_TREE;
|
|
||||||
}
|
|
||||||
else if (grhs_class == GIMPLE_UNARY_RHS)
|
|
||||||
{
|
|
||||||
*op1_p = TREE_OPERAND (expr, 0);
|
|
||||||
*op2_p = NULL_TREE;
|
|
||||||
*op3_p = NULL_TREE;
|
|
||||||
}
|
|
||||||
else if (grhs_class == GIMPLE_SINGLE_RHS)
|
|
||||||
{
|
|
||||||
*op1_p = expr;
|
|
||||||
*op2_p = NULL_TREE;
|
|
||||||
*op3_p = NULL_TREE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gcc_unreachable ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Build a GIMPLE_ASSIGN statement.
|
/* Build a GIMPLE_ASSIGN statement.
|
||||||
|
|
||||||
LHS of the assignment.
|
LHS of the assignment.
|
||||||
@ -526,37 +485,6 @@ gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs,
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Extract operands for a GIMPLE_COND statement out of COND_EXPR tree COND. */
|
|
||||||
|
|
||||||
void
|
|
||||||
gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
|
|
||||||
tree *lhs_p, tree *rhs_p)
|
|
||||||
{
|
|
||||||
gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
|
|
||||||
|| TREE_CODE (cond) == TRUTH_NOT_EXPR
|
|
||||||
|| is_gimple_min_invariant (cond)
|
|
||||||
|| SSA_VAR_P (cond));
|
|
||||||
|
|
||||||
extract_ops_from_tree (cond, code_p, lhs_p, rhs_p);
|
|
||||||
|
|
||||||
/* Canonicalize conditionals of the form 'if (!VAL)'. */
|
|
||||||
if (*code_p == TRUTH_NOT_EXPR)
|
|
||||||
{
|
|
||||||
*code_p = EQ_EXPR;
|
|
||||||
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
|
|
||||||
*rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
|
|
||||||
}
|
|
||||||
/* Canonicalize conditionals of the form 'if (VAL)' */
|
|
||||||
else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
|
|
||||||
{
|
|
||||||
*code_p = NE_EXPR;
|
|
||||||
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
|
|
||||||
*rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Build a GIMPLE_COND statement from the conditional expression tree
|
/* Build a GIMPLE_COND statement from the conditional expression tree
|
||||||
COND. T_LABEL and F_LABEL are as in gimple_build_cond. */
|
COND. T_LABEL and F_LABEL are as in gimple_build_cond. */
|
||||||
|
|
||||||
@ -1906,45 +1834,6 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set sequence SEQ to be the GIMPLE body for function FN. */
|
|
||||||
|
|
||||||
void
|
|
||||||
gimple_set_body (tree fndecl, gimple_seq seq)
|
|
||||||
{
|
|
||||||
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
|
|
||||||
if (fn == NULL)
|
|
||||||
{
|
|
||||||
/* If FNDECL still does not have a function structure associated
|
|
||||||
with it, then it does not make sense for it to receive a
|
|
||||||
GIMPLE body. */
|
|
||||||
gcc_assert (seq == NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fn->gimple_body = seq;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the body of GIMPLE statements for function FN. After the
|
|
||||||
CFG pass, the function body doesn't exist anymore because it has
|
|
||||||
been split up into basic blocks. In this case, it returns
|
|
||||||
NULL. */
|
|
||||||
|
|
||||||
gimple_seq
|
|
||||||
gimple_body (tree fndecl)
|
|
||||||
{
|
|
||||||
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
|
|
||||||
return fn ? fn->gimple_body : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true when FNDECL has Gimple body either in unlowered
|
|
||||||
or CFG form. */
|
|
||||||
bool
|
|
||||||
gimple_has_body_p (tree fndecl)
|
|
||||||
{
|
|
||||||
struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
|
|
||||||
return (gimple_body (fndecl) || (fn && fn->cfg));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if calls C1 and C2 are known to go to the same function. */
|
/* Return true if calls C1 and C2 are known to go to the same function. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -2602,325 +2491,6 @@ const unsigned char gimple_rhs_class_table[] = {
|
|||||||
#undef DEFTREECODE
|
#undef DEFTREECODE
|
||||||
#undef END_OF_BASE_TREE_CODES
|
#undef END_OF_BASE_TREE_CODES
|
||||||
|
|
||||||
/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi. */
|
|
||||||
|
|
||||||
/* Validation of GIMPLE expressions. */
|
|
||||||
|
|
||||||
/* Return true if T is a valid LHS for a GIMPLE assignment expression. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_lvalue (tree t)
|
|
||||||
{
|
|
||||||
return (is_gimple_addressable (t)
|
|
||||||
|| TREE_CODE (t) == WITH_SIZE_EXPR
|
|
||||||
/* These are complex lvalues, but don't have addresses, so they
|
|
||||||
go here. */
|
|
||||||
|| TREE_CODE (t) == BIT_FIELD_REF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a GIMPLE condition. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_condexpr (tree t)
|
|
||||||
{
|
|
||||||
return (is_gimple_val (t) || (COMPARISON_CLASS_P (t)
|
|
||||||
&& !tree_could_throw_p (t)
|
|
||||||
&& is_gimple_val (TREE_OPERAND (t, 0))
|
|
||||||
&& is_gimple_val (TREE_OPERAND (t, 1))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is something whose address can be taken. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_addressable (tree t)
|
|
||||||
{
|
|
||||||
return (is_gimple_id (t) || handled_component_p (t)
|
|
||||||
|| TREE_CODE (t) == MEM_REF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a valid gimple constant. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_constant (const_tree t)
|
|
||||||
{
|
|
||||||
switch (TREE_CODE (t))
|
|
||||||
{
|
|
||||||
case INTEGER_CST:
|
|
||||||
case REAL_CST:
|
|
||||||
case FIXED_CST:
|
|
||||||
case STRING_CST:
|
|
||||||
case COMPLEX_CST:
|
|
||||||
case VECTOR_CST:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a gimple address. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_address (const_tree t)
|
|
||||||
{
|
|
||||||
tree op;
|
|
||||||
|
|
||||||
if (TREE_CODE (t) != ADDR_EXPR)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
op = TREE_OPERAND (t, 0);
|
|
||||||
while (handled_component_p (op))
|
|
||||||
{
|
|
||||||
if ((TREE_CODE (op) == ARRAY_REF
|
|
||||||
|| TREE_CODE (op) == ARRAY_RANGE_REF)
|
|
||||||
&& !is_gimple_val (TREE_OPERAND (op, 1)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
op = TREE_OPERAND (op, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
switch (TREE_CODE (op))
|
|
||||||
{
|
|
||||||
case PARM_DECL:
|
|
||||||
case RESULT_DECL:
|
|
||||||
case LABEL_DECL:
|
|
||||||
case FUNCTION_DECL:
|
|
||||||
case VAR_DECL:
|
|
||||||
case CONST_DECL:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a gimple invariant address. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_invariant_address (const_tree t)
|
|
||||||
{
|
|
||||||
const_tree op;
|
|
||||||
|
|
||||||
if (TREE_CODE (t) != ADDR_EXPR)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
op = strip_invariant_refs (TREE_OPERAND (t, 0));
|
|
||||||
if (!op)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (TREE_CODE (op) == MEM_REF)
|
|
||||||
{
|
|
||||||
const_tree op0 = TREE_OPERAND (op, 0);
|
|
||||||
return (TREE_CODE (op0) == ADDR_EXPR
|
|
||||||
&& (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
|
|
||||||
|| decl_address_invariant_p (TREE_OPERAND (op0, 0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a gimple invariant address at IPA level
|
|
||||||
(so addresses of variables on stack are not allowed). */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_ip_invariant_address (const_tree t)
|
|
||||||
{
|
|
||||||
const_tree op;
|
|
||||||
|
|
||||||
if (TREE_CODE (t) != ADDR_EXPR)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
op = strip_invariant_refs (TREE_OPERAND (t, 0));
|
|
||||||
if (!op)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (TREE_CODE (op) == MEM_REF)
|
|
||||||
{
|
|
||||||
const_tree op0 = TREE_OPERAND (op, 0);
|
|
||||||
return (TREE_CODE (op0) == ADDR_EXPR
|
|
||||||
&& (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
|
|
||||||
|| decl_address_ip_invariant_p (TREE_OPERAND (op0, 0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
|
|
||||||
form of function invariant. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_min_invariant (const_tree t)
|
|
||||||
{
|
|
||||||
if (TREE_CODE (t) == ADDR_EXPR)
|
|
||||||
return is_gimple_invariant_address (t);
|
|
||||||
|
|
||||||
return is_gimple_constant (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a GIMPLE interprocedural invariant. It's a restricted
|
|
||||||
form of gimple minimal invariant. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_ip_invariant (const_tree t)
|
|
||||||
{
|
|
||||||
if (TREE_CODE (t) == ADDR_EXPR)
|
|
||||||
return is_gimple_ip_invariant_address (t);
|
|
||||||
|
|
||||||
return is_gimple_constant (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a variable. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_variable (tree t)
|
|
||||||
{
|
|
||||||
return (TREE_CODE (t) == VAR_DECL
|
|
||||||
|| TREE_CODE (t) == PARM_DECL
|
|
||||||
|| TREE_CODE (t) == RESULT_DECL
|
|
||||||
|| TREE_CODE (t) == SSA_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a GIMPLE identifier (something with an address). */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_id (tree t)
|
|
||||||
{
|
|
||||||
return (is_gimple_variable (t)
|
|
||||||
|| TREE_CODE (t) == FUNCTION_DECL
|
|
||||||
|| TREE_CODE (t) == LABEL_DECL
|
|
||||||
|| TREE_CODE (t) == CONST_DECL
|
|
||||||
/* Allow string constants, since they are addressable. */
|
|
||||||
|| TREE_CODE (t) == STRING_CST);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if OP, an SSA name or a DECL is a virtual operand. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
virtual_operand_p (tree op)
|
|
||||||
{
|
|
||||||
if (TREE_CODE (op) == SSA_NAME)
|
|
||||||
{
|
|
||||||
op = SSA_NAME_VAR (op);
|
|
||||||
if (!op)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TREE_CODE (op) == VAR_DECL)
|
|
||||||
return VAR_DECL_IS_VIRTUAL_OPERAND (op);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return true if T is a non-aggregate register variable. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_reg (tree t)
|
|
||||||
{
|
|
||||||
if (virtual_operand_p (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (TREE_CODE (t) == SSA_NAME)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!is_gimple_variable (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!is_gimple_reg_type (TREE_TYPE (t)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* A volatile decl is not acceptable because we can't reuse it as
|
|
||||||
needed. We need to copy it into a temp first. */
|
|
||||||
if (TREE_THIS_VOLATILE (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* We define "registers" as things that can be renamed as needed,
|
|
||||||
which with our infrastructure does not apply to memory. */
|
|
||||||
if (needs_to_live_in_memory (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Hard register variables are an interesting case. For those that
|
|
||||||
are call-clobbered, we don't know where all the calls are, since
|
|
||||||
we don't (want to) take into account which operations will turn
|
|
||||||
into libcalls at the rtl level. For those that are call-saved,
|
|
||||||
we don't currently model the fact that calls may in fact change
|
|
||||||
global hard registers, nor do we examine ASM_CLOBBERS at the tree
|
|
||||||
level, and so miss variable changes that might imply. All around,
|
|
||||||
it seems safest to not do too much optimization with these at the
|
|
||||||
tree level at all. We'll have to rely on the rtl optimizers to
|
|
||||||
clean this up, as there we've got all the appropriate bits exposed. */
|
|
||||||
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Complex and vector values must have been put into SSA-like form.
|
|
||||||
That is, no assignments to the individual components. */
|
|
||||||
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
|
|
||||||
|| TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
|
|
||||||
return DECL_GIMPLE_REG_P (t);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_val (tree t)
|
|
||||||
{
|
|
||||||
/* Make loads from volatiles and memory vars explicit. */
|
|
||||||
if (is_gimple_variable (t)
|
|
||||||
&& is_gimple_reg_type (TREE_TYPE (t))
|
|
||||||
&& !is_gimple_reg (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (is_gimple_variable (t) || is_gimple_min_invariant (t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Similarly, but accept hard registers as inputs to asm statements. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_asm_val (tree t)
|
|
||||||
{
|
|
||||||
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return is_gimple_val (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a GIMPLE minimal lvalue. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_min_lval (tree t)
|
|
||||||
{
|
|
||||||
if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
|
|
||||||
return false;
|
|
||||||
return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a valid function operand of a CALL_EXPR. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_call_addr (tree t)
|
|
||||||
{
|
|
||||||
return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if T is a valid address operand of a MEM_REF. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_gimple_mem_ref_addr (tree t)
|
|
||||||
{
|
|
||||||
return (is_gimple_reg (t)
|
|
||||||
|| TREE_CODE (t) == INTEGER_CST
|
|
||||||
|| (TREE_CODE (t) == ADDR_EXPR
|
|
||||||
&& (CONSTANT_CLASS_P (TREE_OPERAND (t, 0))
|
|
||||||
|| decl_address_invariant_p (TREE_OPERAND (t, 0)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Given a memory reference expression T, return its base address.
|
/* Given a memory reference expression T, return its base address.
|
||||||
The base address of a memory reference expression is the main
|
The base address of a memory reference expression is the main
|
||||||
object being referenced. For instance, the base address for
|
object being referenced. For instance, the base address for
|
||||||
@ -3642,37 +3212,6 @@ gimple_ior_addresses_taken (bitmap addresses_taken, gimple stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a printable name for symbol DECL. */
|
|
||||||
|
|
||||||
const char *
|
|
||||||
gimple_decl_printable_name (tree decl, int verbosity)
|
|
||||||
{
|
|
||||||
if (!DECL_NAME (decl))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (DECL_ASSEMBLER_NAME_SET_P (decl))
|
|
||||||
{
|
|
||||||
const char *str, *mangled_str;
|
|
||||||
int dmgl_opts = DMGL_NO_OPTS;
|
|
||||||
|
|
||||||
if (verbosity >= 2)
|
|
||||||
{
|
|
||||||
dmgl_opts = DMGL_VERBOSE
|
|
||||||
| DMGL_ANSI
|
|
||||||
| DMGL_GNU_V3
|
|
||||||
| DMGL_RET_POSTFIX;
|
|
||||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
|
||||||
dmgl_opts |= DMGL_PARAMS;
|
|
||||||
}
|
|
||||||
|
|
||||||
mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
|
||||||
str = cplus_demangle_v3 (mangled_str, dmgl_opts);
|
|
||||||
return (str) ? str : mangled_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IDENTIFIER_POINTER (DECL_NAME (decl));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return TRUE iff stmt is a call to a built-in function. */
|
/* Return TRUE iff stmt is a call to a built-in function. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -3763,261 +3302,6 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
|
|
||||||
useless type conversion, otherwise return false.
|
|
||||||
|
|
||||||
This function implicitly defines the middle-end type system. With
|
|
||||||
the notion of 'a < b' meaning that useless_type_conversion_p (a, b)
|
|
||||||
holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds,
|
|
||||||
the following invariants shall be fulfilled:
|
|
||||||
|
|
||||||
1) useless_type_conversion_p is transitive.
|
|
||||||
If a < b and b < c then a < c.
|
|
||||||
|
|
||||||
2) useless_type_conversion_p is not symmetric.
|
|
||||||
From a < b does not follow a > b.
|
|
||||||
|
|
||||||
3) Types define the available set of operations applicable to values.
|
|
||||||
A type conversion is useless if the operations for the target type
|
|
||||||
is a subset of the operations for the source type. For example
|
|
||||||
casts to void* are useless, casts from void* are not (void* can't
|
|
||||||
be dereferenced or offsetted, but copied, hence its set of operations
|
|
||||||
is a strict subset of that of all other data pointer types). Casts
|
|
||||||
to const T* are useless (can't be written to), casts from const T*
|
|
||||||
to T* are not. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
useless_type_conversion_p (tree outer_type, tree inner_type)
|
|
||||||
{
|
|
||||||
/* Do the following before stripping toplevel qualifiers. */
|
|
||||||
if (POINTER_TYPE_P (inner_type)
|
|
||||||
&& POINTER_TYPE_P (outer_type))
|
|
||||||
{
|
|
||||||
/* Do not lose casts between pointers to different address spaces. */
|
|
||||||
if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
|
|
||||||
!= TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* From now on qualifiers on value types do not matter. */
|
|
||||||
inner_type = TYPE_MAIN_VARIANT (inner_type);
|
|
||||||
outer_type = TYPE_MAIN_VARIANT (outer_type);
|
|
||||||
|
|
||||||
if (inner_type == outer_type)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* If we know the canonical types, compare them. */
|
|
||||||
if (TYPE_CANONICAL (inner_type)
|
|
||||||
&& TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* Changes in machine mode are never useless conversions unless we
|
|
||||||
deal with aggregate types in which case we defer to later checks. */
|
|
||||||
if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
|
|
||||||
&& !AGGREGATE_TYPE_P (inner_type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* If both the inner and outer types are integral types, then the
|
|
||||||
conversion is not necessary if they have the same mode and
|
|
||||||
signedness and precision, and both or neither are boolean. */
|
|
||||||
if (INTEGRAL_TYPE_P (inner_type)
|
|
||||||
&& INTEGRAL_TYPE_P (outer_type))
|
|
||||||
{
|
|
||||||
/* Preserve changes in signedness or precision. */
|
|
||||||
if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
|
|
||||||
|| TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Preserve conversions to/from BOOLEAN_TYPE if types are not
|
|
||||||
of precision one. */
|
|
||||||
if (((TREE_CODE (inner_type) == BOOLEAN_TYPE)
|
|
||||||
!= (TREE_CODE (outer_type) == BOOLEAN_TYPE))
|
|
||||||
&& TYPE_PRECISION (outer_type) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* We don't need to preserve changes in the types minimum or
|
|
||||||
maximum value in general as these do not generate code
|
|
||||||
unless the types precisions are different. */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scalar floating point types with the same mode are compatible. */
|
|
||||||
else if (SCALAR_FLOAT_TYPE_P (inner_type)
|
|
||||||
&& SCALAR_FLOAT_TYPE_P (outer_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* Fixed point types with the same mode are compatible. */
|
|
||||||
else if (FIXED_POINT_TYPE_P (inner_type)
|
|
||||||
&& FIXED_POINT_TYPE_P (outer_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* We need to take special care recursing to pointed-to types. */
|
|
||||||
else if (POINTER_TYPE_P (inner_type)
|
|
||||||
&& POINTER_TYPE_P (outer_type))
|
|
||||||
{
|
|
||||||
/* Do not lose casts to function pointer types. */
|
|
||||||
if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
|
|
||||||
|| TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
|
|
||||||
&& !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
|
|
||||||
|| TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* We do not care for const qualification of the pointed-to types
|
|
||||||
as const qualification has no semantic value to the middle-end. */
|
|
||||||
|
|
||||||
/* Otherwise pointers/references are equivalent. */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recurse for complex types. */
|
|
||||||
else if (TREE_CODE (inner_type) == COMPLEX_TYPE
|
|
||||||
&& TREE_CODE (outer_type) == COMPLEX_TYPE)
|
|
||||||
return useless_type_conversion_p (TREE_TYPE (outer_type),
|
|
||||||
TREE_TYPE (inner_type));
|
|
||||||
|
|
||||||
/* Recurse for vector types with the same number of subparts. */
|
|
||||||
else if (TREE_CODE (inner_type) == VECTOR_TYPE
|
|
||||||
&& TREE_CODE (outer_type) == VECTOR_TYPE
|
|
||||||
&& TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
|
|
||||||
return useless_type_conversion_p (TREE_TYPE (outer_type),
|
|
||||||
TREE_TYPE (inner_type));
|
|
||||||
|
|
||||||
else if (TREE_CODE (inner_type) == ARRAY_TYPE
|
|
||||||
&& TREE_CODE (outer_type) == ARRAY_TYPE)
|
|
||||||
{
|
|
||||||
/* Preserve string attributes. */
|
|
||||||
if (TYPE_STRING_FLAG (inner_type) != TYPE_STRING_FLAG (outer_type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Conversions from array types with unknown extent to
|
|
||||||
array types with known extent are not useless. */
|
|
||||||
if (!TYPE_DOMAIN (inner_type)
|
|
||||||
&& TYPE_DOMAIN (outer_type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Nor are conversions from array types with non-constant size to
|
|
||||||
array types with constant size or to different size. */
|
|
||||||
if (TYPE_SIZE (outer_type)
|
|
||||||
&& TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST
|
|
||||||
&& (!TYPE_SIZE (inner_type)
|
|
||||||
|| TREE_CODE (TYPE_SIZE (inner_type)) != INTEGER_CST
|
|
||||||
|| !tree_int_cst_equal (TYPE_SIZE (outer_type),
|
|
||||||
TYPE_SIZE (inner_type))))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Check conversions between arrays with partially known extents.
|
|
||||||
If the array min/max values are constant they have to match.
|
|
||||||
Otherwise allow conversions to unknown and variable extents.
|
|
||||||
In particular this declares conversions that may change the
|
|
||||||
mode to BLKmode as useless. */
|
|
||||||
if (TYPE_DOMAIN (inner_type)
|
|
||||||
&& TYPE_DOMAIN (outer_type)
|
|
||||||
&& TYPE_DOMAIN (inner_type) != TYPE_DOMAIN (outer_type))
|
|
||||||
{
|
|
||||||
tree inner_min = TYPE_MIN_VALUE (TYPE_DOMAIN (inner_type));
|
|
||||||
tree outer_min = TYPE_MIN_VALUE (TYPE_DOMAIN (outer_type));
|
|
||||||
tree inner_max = TYPE_MAX_VALUE (TYPE_DOMAIN (inner_type));
|
|
||||||
tree outer_max = TYPE_MAX_VALUE (TYPE_DOMAIN (outer_type));
|
|
||||||
|
|
||||||
/* After gimplification a variable min/max value carries no
|
|
||||||
additional information compared to a NULL value. All that
|
|
||||||
matters has been lowered to be part of the IL. */
|
|
||||||
if (inner_min && TREE_CODE (inner_min) != INTEGER_CST)
|
|
||||||
inner_min = NULL_TREE;
|
|
||||||
if (outer_min && TREE_CODE (outer_min) != INTEGER_CST)
|
|
||||||
outer_min = NULL_TREE;
|
|
||||||
if (inner_max && TREE_CODE (inner_max) != INTEGER_CST)
|
|
||||||
inner_max = NULL_TREE;
|
|
||||||
if (outer_max && TREE_CODE (outer_max) != INTEGER_CST)
|
|
||||||
outer_max = NULL_TREE;
|
|
||||||
|
|
||||||
/* Conversions NULL / variable <- cst are useless, but not
|
|
||||||
the other way around. */
|
|
||||||
if (outer_min
|
|
||||||
&& (!inner_min
|
|
||||||
|| !tree_int_cst_equal (inner_min, outer_min)))
|
|
||||||
return false;
|
|
||||||
if (outer_max
|
|
||||||
&& (!inner_max
|
|
||||||
|| !tree_int_cst_equal (inner_max, outer_max)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recurse on the element check. */
|
|
||||||
return useless_type_conversion_p (TREE_TYPE (outer_type),
|
|
||||||
TREE_TYPE (inner_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ((TREE_CODE (inner_type) == FUNCTION_TYPE
|
|
||||||
|| TREE_CODE (inner_type) == METHOD_TYPE)
|
|
||||||
&& TREE_CODE (inner_type) == TREE_CODE (outer_type))
|
|
||||||
{
|
|
||||||
tree outer_parm, inner_parm;
|
|
||||||
|
|
||||||
/* If the return types are not compatible bail out. */
|
|
||||||
if (!useless_type_conversion_p (TREE_TYPE (outer_type),
|
|
||||||
TREE_TYPE (inner_type)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Method types should belong to a compatible base class. */
|
|
||||||
if (TREE_CODE (inner_type) == METHOD_TYPE
|
|
||||||
&& !useless_type_conversion_p (TYPE_METHOD_BASETYPE (outer_type),
|
|
||||||
TYPE_METHOD_BASETYPE (inner_type)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* A conversion to an unprototyped argument list is ok. */
|
|
||||||
if (!prototype_p (outer_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* If the unqualified argument types are compatible the conversion
|
|
||||||
is useless. */
|
|
||||||
if (TYPE_ARG_TYPES (outer_type) == TYPE_ARG_TYPES (inner_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (outer_parm = TYPE_ARG_TYPES (outer_type),
|
|
||||||
inner_parm = TYPE_ARG_TYPES (inner_type);
|
|
||||||
outer_parm && inner_parm;
|
|
||||||
outer_parm = TREE_CHAIN (outer_parm),
|
|
||||||
inner_parm = TREE_CHAIN (inner_parm))
|
|
||||||
if (!useless_type_conversion_p
|
|
||||||
(TYPE_MAIN_VARIANT (TREE_VALUE (outer_parm)),
|
|
||||||
TYPE_MAIN_VARIANT (TREE_VALUE (inner_parm))))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* If there is a mismatch in the number of arguments the functions
|
|
||||||
are not compatible. */
|
|
||||||
if (outer_parm || inner_parm)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Defer to the target if necessary. */
|
|
||||||
if (TYPE_ATTRIBUTES (inner_type) || TYPE_ATTRIBUTES (outer_type))
|
|
||||||
return comp_type_attributes (outer_type, inner_type) != 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For aggregates we rely on TYPE_CANONICAL exclusively and require
|
|
||||||
explicit conversions for types involving to be structurally
|
|
||||||
compared types. */
|
|
||||||
else if (AGGREGATE_TYPE_P (inner_type)
|
|
||||||
&& TREE_CODE (inner_type) == TREE_CODE (outer_type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if a conversion from either type of TYPE1 and TYPE2
|
|
||||||
to the other is not required. Otherwise return false. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
types_compatible_p (tree type1, tree type2)
|
|
||||||
{
|
|
||||||
return (type1 == type2
|
|
||||||
|| (useless_type_conversion_p (type1, type2)
|
|
||||||
&& useless_type_conversion_p (type2, type1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dump bitmap SET (assumed to contain VAR_DECLs) to FILE. */
|
/* Dump bitmap SET (assumed to contain VAR_DECLs) to FILE. */
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -4042,45 +3326,6 @@ dump_decl_set (FILE *file, bitmap set)
|
|||||||
fprintf (file, "NIL");
|
fprintf (file, "NIL");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for
|
|
||||||
coalescing together, false otherwise.
|
|
||||||
|
|
||||||
This must stay consistent with var_map_base_init in tree-ssa-live.c. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
gimple_can_coalesce_p (tree name1, tree name2)
|
|
||||||
{
|
|
||||||
/* First check the SSA_NAME's associated DECL. We only want to
|
|
||||||
coalesce if they have the same DECL or both have no associated DECL. */
|
|
||||||
tree var1 = SSA_NAME_VAR (name1);
|
|
||||||
tree var2 = SSA_NAME_VAR (name2);
|
|
||||||
var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : NULL_TREE;
|
|
||||||
var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : NULL_TREE;
|
|
||||||
if (var1 != var2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Now check the types. If the types are the same, then we should
|
|
||||||
try to coalesce V1 and V2. */
|
|
||||||
tree t1 = TREE_TYPE (name1);
|
|
||||||
tree t2 = TREE_TYPE (name2);
|
|
||||||
if (t1 == t2)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* If the types are not the same, check for a canonical type match. This
|
|
||||||
(for example) allows coalescing when the types are fundamentally the
|
|
||||||
same, but just have different names.
|
|
||||||
|
|
||||||
Note pointer types with different address spaces may have the same
|
|
||||||
canonical type. Those are rejected for coalescing by the
|
|
||||||
types_compatible_p check. */
|
|
||||||
if (TYPE_CANONICAL (t1)
|
|
||||||
&& TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)
|
|
||||||
&& types_compatible_p (t1, t2))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true when CALL is a call stmt that definitely doesn't
|
/* Return true when CALL is a call stmt that definitely doesn't
|
||||||
free any memory or makes it unavailable otherwise. */
|
free any memory or makes it unavailable otherwise. */
|
||||||
bool
|
bool
|
||||||
@ -4102,24 +3347,3 @@ nonfreeing_call_p (gimple call)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new VAR_DECL and copy information from VAR to it. */
|
|
||||||
|
|
||||||
tree
|
|
||||||
copy_var_decl (tree var, tree name, tree type)
|
|
||||||
{
|
|
||||||
tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type);
|
|
||||||
|
|
||||||
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
|
|
||||||
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
|
|
||||||
DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
|
|
||||||
DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
|
|
||||||
DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
|
|
||||||
DECL_CONTEXT (copy) = DECL_CONTEXT (var);
|
|
||||||
TREE_NO_WARNING (copy) = TREE_NO_WARNING (var);
|
|
||||||
TREE_USED (copy) = 1;
|
|
||||||
DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
|
|
||||||
DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var);
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
92
gcc/gimple.h
92
gcc/gimple.h
@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
#include "internal-fn.h"
|
#include "internal-fn.h"
|
||||||
#include "gimple-fold.h"
|
#include "gimple-fold.h"
|
||||||
#include "tree-eh.h"
|
#include "tree-eh.h"
|
||||||
|
#include "gimple-expr.h"
|
||||||
|
|
||||||
typedef gimple gimple_seq_node;
|
typedef gimple gimple_seq_node;
|
||||||
|
|
||||||
@ -745,8 +746,6 @@ gimple gimple_build_return (tree);
|
|||||||
gimple gimple_build_assign_stat (tree, tree MEM_STAT_DECL);
|
gimple gimple_build_assign_stat (tree, tree MEM_STAT_DECL);
|
||||||
#define gimple_build_assign(l,r) gimple_build_assign_stat (l, r MEM_STAT_INFO)
|
#define gimple_build_assign(l,r) gimple_build_assign_stat (l, r MEM_STAT_INFO)
|
||||||
|
|
||||||
void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *, tree *);
|
|
||||||
|
|
||||||
gimple
|
gimple
|
||||||
gimple_build_assign_with_ops (enum tree_code, tree,
|
gimple_build_assign_with_ops (enum tree_code, tree,
|
||||||
tree, tree CXX_MEM_STAT_INFO);
|
tree, tree CXX_MEM_STAT_INFO);
|
||||||
@ -809,9 +808,6 @@ gimple gimple_build_predict (enum br_predictor, enum prediction);
|
|||||||
enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
|
enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
|
||||||
void sort_case_labels (vec<tree> );
|
void sort_case_labels (vec<tree> );
|
||||||
void preprocess_case_label_vec_for_gimple (vec<tree> , tree, tree *);
|
void preprocess_case_label_vec_for_gimple (vec<tree> , tree, tree *);
|
||||||
void gimple_set_body (tree, gimple_seq);
|
|
||||||
gimple_seq gimple_body (tree);
|
|
||||||
bool gimple_has_body_p (tree);
|
|
||||||
gimple_seq gimple_seq_alloc (void);
|
gimple_seq gimple_seq_alloc (void);
|
||||||
void gimple_seq_free (gimple_seq);
|
void gimple_seq_free (gimple_seq);
|
||||||
void gimple_seq_add_seq (gimple_seq *, gimple_seq);
|
void gimple_seq_add_seq (gimple_seq *, gimple_seq);
|
||||||
@ -832,7 +828,6 @@ tree gimple_get_lhs (const_gimple);
|
|||||||
void gimple_set_lhs (gimple, tree);
|
void gimple_set_lhs (gimple, tree);
|
||||||
void gimple_replace_lhs (gimple, tree);
|
void gimple_replace_lhs (gimple, tree);
|
||||||
gimple gimple_copy (gimple);
|
gimple gimple_copy (gimple);
|
||||||
void gimple_cond_get_ops_from_tree (tree, enum tree_code *, tree *, tree *);
|
|
||||||
gimple gimple_build_cond_from_tree (tree, tree, tree);
|
gimple gimple_build_cond_from_tree (tree, tree, tree);
|
||||||
void gimple_cond_set_condition_from_tree (gimple, tree);
|
void gimple_cond_set_condition_from_tree (gimple, tree);
|
||||||
bool gimple_has_side_effects (const_gimple);
|
bool gimple_has_side_effects (const_gimple);
|
||||||
@ -844,48 +839,6 @@ bool empty_body_p (gimple_seq);
|
|||||||
unsigned get_gimple_rhs_num_ops (enum tree_code);
|
unsigned get_gimple_rhs_num_ops (enum tree_code);
|
||||||
#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
|
#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
|
||||||
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
|
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
|
||||||
const char *gimple_decl_printable_name (tree, int);
|
|
||||||
|
|
||||||
/* Returns true iff T is a virtual ssa name decl. */
|
|
||||||
extern bool virtual_operand_p (tree);
|
|
||||||
/* Returns true iff T is a scalar register variable. */
|
|
||||||
extern bool is_gimple_reg (tree);
|
|
||||||
/* Returns true iff T is any sort of variable. */
|
|
||||||
extern bool is_gimple_variable (tree);
|
|
||||||
/* Returns true iff T is any sort of symbol. */
|
|
||||||
extern bool is_gimple_id (tree);
|
|
||||||
/* Returns true iff T is a variable or an INDIRECT_REF (of a variable). */
|
|
||||||
extern bool is_gimple_min_lval (tree);
|
|
||||||
/* Returns true iff T is something whose address can be taken. */
|
|
||||||
extern bool is_gimple_addressable (tree);
|
|
||||||
/* Returns true iff T is any valid GIMPLE lvalue. */
|
|
||||||
extern bool is_gimple_lvalue (tree);
|
|
||||||
|
|
||||||
/* Returns true iff T is a GIMPLE address. */
|
|
||||||
bool is_gimple_address (const_tree);
|
|
||||||
/* Returns true iff T is a GIMPLE invariant address. */
|
|
||||||
bool is_gimple_invariant_address (const_tree);
|
|
||||||
/* Returns true iff T is a GIMPLE invariant address at interprocedural
|
|
||||||
level. */
|
|
||||||
bool is_gimple_ip_invariant_address (const_tree);
|
|
||||||
/* Returns true iff T is a valid GIMPLE constant. */
|
|
||||||
bool is_gimple_constant (const_tree);
|
|
||||||
/* Returns true iff T is a GIMPLE restricted function invariant. */
|
|
||||||
extern bool is_gimple_min_invariant (const_tree);
|
|
||||||
/* Returns true iff T is a GIMPLE restricted interprecodural invariant. */
|
|
||||||
extern bool is_gimple_ip_invariant (const_tree);
|
|
||||||
/* Returns true iff T is a GIMPLE rvalue. */
|
|
||||||
extern bool is_gimple_val (tree);
|
|
||||||
/* Returns true iff T is a GIMPLE asm statement input. */
|
|
||||||
extern bool is_gimple_asm_val (tree);
|
|
||||||
/* Returns true iff T is a valid address operand of a MEM_REF. */
|
|
||||||
bool is_gimple_mem_ref_addr (tree);
|
|
||||||
|
|
||||||
/* Returns true iff T is a valid if-statement condition. */
|
|
||||||
extern bool is_gimple_condexpr (tree);
|
|
||||||
|
|
||||||
/* Returns true iff T is a valid call address expression. */
|
|
||||||
extern bool is_gimple_call_addr (tree);
|
|
||||||
|
|
||||||
/* Return TRUE iff stmt is a call to a built-in function. */
|
/* Return TRUE iff stmt is a call to a built-in function. */
|
||||||
extern bool is_gimple_builtin_call (gimple stmt);
|
extern bool is_gimple_builtin_call (gimple stmt);
|
||||||
@ -906,8 +859,6 @@ extern bool gimple_ior_addresses_taken (bitmap, gimple);
|
|||||||
extern bool gimple_call_builtin_p (gimple, enum built_in_class);
|
extern bool gimple_call_builtin_p (gimple, enum built_in_class);
|
||||||
extern bool gimple_call_builtin_p (gimple, enum built_in_function);
|
extern bool gimple_call_builtin_p (gimple, enum built_in_function);
|
||||||
extern bool gimple_asm_clobbers_memory_p (const_gimple);
|
extern bool gimple_asm_clobbers_memory_p (const_gimple);
|
||||||
extern bool useless_type_conversion_p (tree, tree);
|
|
||||||
extern bool types_compatible_p (tree, tree);
|
|
||||||
|
|
||||||
/* In gimplify.c */
|
/* In gimplify.c */
|
||||||
extern tree create_tmp_var_raw (tree, const char *);
|
extern tree create_tmp_var_raw (tree, const char *);
|
||||||
@ -1086,9 +1037,7 @@ extern tree gimple_boolify (tree);
|
|||||||
extern gimple_predicate rhs_predicate_for (tree);
|
extern gimple_predicate rhs_predicate_for (tree);
|
||||||
extern tree canonicalize_cond_expr_cond (tree);
|
extern tree canonicalize_cond_expr_cond (tree);
|
||||||
extern void dump_decl_set (FILE *, bitmap);
|
extern void dump_decl_set (FILE *, bitmap);
|
||||||
extern bool gimple_can_coalesce_p (tree, tree);
|
|
||||||
extern bool nonfreeing_call_p (gimple);
|
extern bool nonfreeing_call_p (gimple);
|
||||||
extern tree copy_var_decl (tree, tree, tree);
|
|
||||||
|
|
||||||
/* In trans-mem.c. */
|
/* In trans-mem.c. */
|
||||||
extern void diagnose_tm_safe_errors (tree);
|
extern void diagnose_tm_safe_errors (tree);
|
||||||
@ -2042,18 +1991,6 @@ gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code,
|
|||||||
gimple_assign_set_rhs_with_ops_1 (gsi, code, op1, op2, NULL);
|
gimple_assign_set_rhs_with_ops_1 (gsi, code, op1, op2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A wrapper around extract_ops_from_tree_1, for callers which expect
|
|
||||||
to see only a maximum of two operands. */
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
extract_ops_from_tree (tree expr, enum tree_code *code, tree *op0,
|
|
||||||
tree *op1)
|
|
||||||
{
|
|
||||||
tree op2;
|
|
||||||
extract_ops_from_tree_1 (expr, code, op0, op1, &op2);
|
|
||||||
gcc_assert (op2 == NULL_TREE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns true if GS is a nontemporal move. */
|
/* Returns true if GS is a nontemporal move. */
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@ -2316,25 +2253,6 @@ gimple_call_set_internal_fn (gimple gs, enum internal_fn fn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL
|
|
||||||
associated with the callee if known. Otherwise return NULL_TREE. */
|
|
||||||
|
|
||||||
static inline tree
|
|
||||||
gimple_call_addr_fndecl (const_tree fn)
|
|
||||||
{
|
|
||||||
if (fn && TREE_CODE (fn) == ADDR_EXPR)
|
|
||||||
{
|
|
||||||
tree fndecl = TREE_OPERAND (fn, 0);
|
|
||||||
if (TREE_CODE (fndecl) == MEM_REF
|
|
||||||
&& TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR
|
|
||||||
&& integer_zerop (TREE_OPERAND (fndecl, 1)))
|
|
||||||
fndecl = TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0);
|
|
||||||
if (TREE_CODE (fndecl) == FUNCTION_DECL)
|
|
||||||
return fndecl;
|
|
||||||
}
|
|
||||||
return NULL_TREE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it.
|
/* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it.
|
||||||
Otherwise return NULL. This function is analogous to
|
Otherwise return NULL. This function is analogous to
|
||||||
get_callee_fndecl in tree land. */
|
get_callee_fndecl in tree land. */
|
||||||
@ -5385,14 +5303,6 @@ gimple_expr_type (const_gimple stmt)
|
|||||||
return void_type_node;
|
return void_type_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if TYPE is a suitable type for a scalar register variable. */
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
is_gimple_reg_type (tree type)
|
|
||||||
{
|
|
||||||
return !AGGREGATE_TYPE_P (type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a new iterator pointing to GIMPLE_SEQ's first statement. */
|
/* Return a new iterator pointing to GIMPLE_SEQ's first statement. */
|
||||||
|
|
||||||
static inline gimple_stmt_iterator
|
static inline gimple_stmt_iterator
|
||||||
|
Loading…
Reference in New Issue
Block a user