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>
|
||||
|
||||
* gengtype-parse.c (struct_field_seq): Support empty structs.
|
||||
|
@ -1230,6 +1230,7 @@ OBJS = \
|
||||
ggc-common.o \
|
||||
gimple.o \
|
||||
gimple-builder.o \
|
||||
gimple-expr.o \
|
||||
gimple-iterator.o \
|
||||
gimple-fold.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.
|
||||
|
||||
LHS of the assignment.
|
||||
@ -526,37 +485,6 @@ gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs,
|
||||
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
|
||||
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. */
|
||||
|
||||
bool
|
||||
@ -2602,325 +2491,6 @@ const unsigned char gimple_rhs_class_table[] = {
|
||||
#undef DEFTREECODE
|
||||
#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.
|
||||
The base address of a memory reference expression is the main
|
||||
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. */
|
||||
|
||||
bool
|
||||
@ -3763,261 +3302,6 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
|
||||
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. */
|
||||
|
||||
void
|
||||
@ -4042,45 +3326,6 @@ dump_decl_set (FILE *file, bitmap set)
|
||||
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
|
||||
free any memory or makes it unavailable otherwise. */
|
||||
bool
|
||||
@ -4102,24 +3347,3 @@ nonfreeing_call_p (gimple call)
|
||||
|
||||
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 "gimple-fold.h"
|
||||
#include "tree-eh.h"
|
||||
#include "gimple-expr.h"
|
||||
|
||||
typedef gimple gimple_seq_node;
|
||||
|
||||
@ -745,8 +746,6 @@ gimple gimple_build_return (tree);
|
||||
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)
|
||||
|
||||
void extract_ops_from_tree_1 (tree, enum tree_code *, tree *, tree *, tree *);
|
||||
|
||||
gimple
|
||||
gimple_build_assign_with_ops (enum tree_code, tree,
|
||||
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);
|
||||
void sort_case_labels (vec<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);
|
||||
void gimple_seq_free (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_replace_lhs (gimple, tree);
|
||||
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);
|
||||
void gimple_cond_set_condition_from_tree (gimple, tree);
|
||||
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);
|
||||
#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
|
||||
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. */
|
||||
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_function);
|
||||
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 */
|
||||
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 tree canonicalize_cond_expr_cond (tree);
|
||||
extern void dump_decl_set (FILE *, bitmap);
|
||||
extern bool gimple_can_coalesce_p (tree, tree);
|
||||
extern bool nonfreeing_call_p (gimple);
|
||||
extern tree copy_var_decl (tree, tree, tree);
|
||||
|
||||
/* In trans-mem.c. */
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
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.
|
||||
Otherwise return NULL. This function is analogous to
|
||||
get_callee_fndecl in tree land. */
|
||||
@ -5385,14 +5303,6 @@ gimple_expr_type (const_gimple stmt)
|
||||
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. */
|
||||
|
||||
static inline gimple_stmt_iterator
|
||||
|
Loading…
Reference in New Issue
Block a user