123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915 |
- /* Gimple decl, type, and expression support functions.
- Copyright (C) 2007-2015 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 "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "predict.h"
- #include "hard-reg-set.h"
- #include "input.h"
- #include "function.h"
- #include "basic-block.h"
- #include "tree-ssa-alias.h"
- #include "internal-fn.h"
- #include "tree-eh.h"
- #include "gimple-expr.h"
- #include "is-a.h"
- #include "gimple.h"
- #include "stringpool.h"
- #include "gimplify.h"
- #include "stor-layout.h"
- #include "demangle.h"
- #include "gimple-ssa.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;
- }
- /* Strip off a legitimate source ending from the input string NAME of
- length LEN. Rather than having to know the names used by all of
- our front ends, we strip off an ending of a period followed by
- up to five characters. (Java uses ".class".) */
- static inline void
- remove_suffix (char *name, int len)
- {
- int i;
- for (i = 2; i < 8 && len > i; i++)
- {
- if (name[len - i] == '.')
- {
- name[len - i] = '\0';
- break;
- }
- }
- }
- /* Create a new temporary name with PREFIX. Return an identifier. */
- static GTY(()) unsigned int tmp_var_id_num;
- tree
- create_tmp_var_name (const char *prefix)
- {
- char *tmp_name;
- if (prefix)
- {
- char *preftmp = ASTRDUP (prefix);
- remove_suffix (preftmp, strlen (preftmp));
- clean_symbol_name (preftmp);
- prefix = preftmp;
- }
- ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix ? prefix : "T", tmp_var_id_num++);
- return get_identifier (tmp_name);
- }
- /* Create a new temporary variable declaration of type TYPE.
- Do NOT push it into the current binding. */
- tree
- create_tmp_var_raw (tree type, const char *prefix)
- {
- tree tmp_var;
- tmp_var = build_decl (input_location,
- VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL,
- type);
- /* The variable was declared by the compiler. */
- DECL_ARTIFICIAL (tmp_var) = 1;
- /* And we don't want debug info for it. */
- DECL_IGNORED_P (tmp_var) = 1;
- /* Make the variable writable. */
- TREE_READONLY (tmp_var) = 0;
- DECL_EXTERNAL (tmp_var) = 0;
- TREE_STATIC (tmp_var) = 0;
- TREE_USED (tmp_var) = 1;
- return tmp_var;
- }
- /* Create a new temporary variable declaration of type TYPE. DO push the
- variable into the current binding. Further, assume that this is called
- only from gimplification or optimization, at which point the creation of
- certain types are bugs. */
- tree
- create_tmp_var (tree type, const char *prefix)
- {
- tree tmp_var;
- /* We don't allow types that are addressable (meaning we can't make copies),
- or incomplete. We also used to reject every variable size objects here,
- but now support those for which a constant upper bound can be obtained.
- The processing for variable sizes is performed in gimple_add_tmp_var,
- point at which it really matters and possibly reached via paths not going
- through this function, e.g. after direct calls to create_tmp_var_raw. */
- gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type));
- tmp_var = create_tmp_var_raw (type, prefix);
- gimple_add_tmp_var (tmp_var);
- return tmp_var;
- }
- /* Create a new temporary variable declaration of type TYPE by calling
- create_tmp_var and if TYPE is a vector or a complex number, mark the new
- temporary as gimple register. */
- tree
- create_tmp_reg (tree type, const char *prefix)
- {
- tree tmp;
- tmp = create_tmp_var (type, prefix);
- if (TREE_CODE (type) == COMPLEX_TYPE
- || TREE_CODE (type) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (tmp) = 1;
- return tmp;
- }
- /* Create a new temporary variable declaration of type TYPE by calling
- create_tmp_var and if TYPE is a vector or a complex number, mark the new
- temporary as gimple register. */
- tree
- create_tmp_reg_fn (struct function *fn, tree type, const char *prefix)
- {
- tree tmp;
- tmp = create_tmp_var_raw (type, prefix);
- gimple_add_tmp_var_fn (fn, tmp);
- if (TREE_CODE (type) == COMPLEX_TYPE
- || TREE_CODE (type) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (tmp) = 1;
- return tmp;
- }
- /* ----- 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)))));
- }
- /* Mark X addressable. Unlike the langhook we expect X to be in gimple
- form and we don't do any syntax checking. */
- void
- mark_addressable (tree x)
- {
- while (handled_component_p (x))
- x = TREE_OPERAND (x, 0);
- if (TREE_CODE (x) == MEM_REF
- && TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR)
- x = TREE_OPERAND (TREE_OPERAND (x, 0), 0);
- if (TREE_CODE (x) != VAR_DECL
- && TREE_CODE (x) != PARM_DECL
- && TREE_CODE (x) != RESULT_DECL)
- return;
- TREE_ADDRESSABLE (x) = 1;
- /* Also mark the artificial SSA_NAME that points to the partition of X. */
- if (TREE_CODE (x) == VAR_DECL
- && !DECL_EXTERNAL (x)
- && !TREE_STATIC (x)
- && cfun->gimple_df != NULL
- && cfun->gimple_df->decls_to_pointers != NULL)
- {
- tree *namep = cfun->gimple_df->decls_to_pointers->get (x);
- if (namep)
- TREE_ADDRESSABLE (*namep) = 1;
- }
- }
- /* Returns true iff T is a valid RHS for an assignment to a renamed
- user -- or front-end generated artificial -- variable. */
- bool
- is_gimple_reg_rhs (tree t)
- {
- return get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS;
- }
- #include "gt-gimple-expr.h"
|