diff options
Diffstat (limited to 'gcc/gimple-expr.c')
-rw-r--r-- | gcc/gimple-expr.c | 938 |
1 files changed, 0 insertions, 938 deletions
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c deleted file mode 100644 index 05b1274..0000000 --- a/gcc/gimple-expr.c +++ /dev/null @@ -1,938 +0,0 @@ -/* Gimple decl, type, and expression support functions. - - Copyright (C) 2007-2022 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 "backend.h" -#include "tree.h" -#include "gimple.h" -#include "stringpool.h" -#include "gimple-ssa.h" -#include "fold-const.h" -#include "tree-eh.h" -#include "gimplify.h" -#include "stor-layout.h" -#include "demangle.h" -#include "hash-set.h" -#include "rtl.h" -#include "tree-pass.h" -#include "stringpool.h" -#include "attribs.h" -#include "target.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; - /* 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; - } - - /* 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; - - /* Changes in machine mode are never useless conversions because the RTL - middle-end expects explicit conversions between modes. */ - if (TYPE_MODE (inner_type) != TYPE_MODE (outer_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 TYPE_SATURATING (inner_type) == TYPE_SATURATING (outer_type); - - /* We need to take special care recursing to pointed-to types. */ - else if (POINTER_TYPE_P (inner_type) - && POINTER_TYPE_P (outer_type)) - { - /* 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) - return (known_eq (TYPE_VECTOR_SUBPARTS (inner_type), - TYPE_VECTOR_SUBPARTS (outer_type)) - && useless_type_conversion_p (TREE_TYPE (outer_type), - TREE_TYPE (inner_type)) - && targetm.compatible_vector_types_p (inner_type, outer_type)); - - else if (TREE_CODE (inner_type) == ARRAY_TYPE - && TREE_CODE (outer_type) == ARRAY_TYPE) - { - /* Preserve various attributes. */ - if (TYPE_REVERSE_STORAGE_ORDER (inner_type) - != TYPE_REVERSE_STORAGE_ORDER (outer_type)) - return false; - 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 TYPE_CANONICAL (inner_type) - && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type); - - else if (TREE_CODE (inner_type) == OFFSET_TYPE - && TREE_CODE (outer_type) == OFFSET_TYPE) - return useless_type_conversion_p (TREE_TYPE (outer_type), - TREE_TYPE (inner_type)) - && useless_type_conversion_p - (TYPE_OFFSET_BASETYPE (outer_type), - TYPE_OFFSET_BASETYPE (inner_type)); - - 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 && !(fn->curr_properties & PROP_rtl))); -} - -/* Return a printable name for symbol DECL. */ - -const char * -gimple_decl_printable_name (tree decl, int verbosity) -{ - if (!DECL_NAME (decl)) - return NULL; - - if (HAS_DECL_ASSEMBLER_NAME_P (decl) && DECL_ASSEMBLER_NAME_SET_P (decl)) - { - 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; - } - - const char *mangled_str - = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME_RAW (decl)); - const char *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_NOT_GIMPLE_REG_P (copy) = DECL_NOT_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_USED (copy) = 1; - DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; - DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var); - if (DECL_USER_ALIGN (var)) - { - SET_DECL_ALIGN (copy, DECL_ALIGN (var)); - DECL_USER_ALIGN (copy) = 1; - } - - copy_warning (copy, var); - return copy; -} - -/* 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 four characters. (like ".cpp".) */ - -static inline void -remove_suffix (char *name, int len) -{ - int i; - - for (i = 2; i < 7 && 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; - /* And we don't want even the fancy names of those printed in - -fdump-final-insns= dumps. */ - DECL_NAMELESS (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) -{ - return create_tmp_var (type, prefix); -} - -/* 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); - - 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 (tree expr, enum tree_code *subcode_p, tree *op1_p, - tree *op2_p, tree *op3_p) -{ - *subcode_p = TREE_CODE (expr); - switch (get_gimple_rhs_class (*subcode_p)) - { - case GIMPLE_TERNARY_RHS: - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); - *op3_p = TREE_OPERAND (expr, 2); - break; - } - case GIMPLE_BINARY_RHS: - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = TREE_OPERAND (expr, 1); - *op3_p = NULL_TREE; - break; - } - case GIMPLE_UNARY_RHS: - { - *op1_p = TREE_OPERAND (expr, 0); - *op2_p = NULL_TREE; - *op3_p = NULL_TREE; - break; - } - case GIMPLE_SINGLE_RHS: - { - *op1_p = expr; - *op2_p = NULL_TREE; - *op3_p = NULL_TREE; - break; - } - default: - 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 (COMPARISON_CLASS_P (cond) - || TREE_CODE (cond) == TRUTH_NOT_EXPR - || is_gimple_min_invariant (cond) - || SSA_VAR_P (cond)); - gcc_checking_assert (!tree_could_throw_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); -} - -/* Helper for is_gimple_condexpr and is_gimple_condexpr_for_cond. */ - -static bool -is_gimple_condexpr_1 (tree t, bool allow_traps) -{ - return (is_gimple_val (t) || (COMPARISON_CLASS_P (t) - && (allow_traps || !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 condition. */ - -bool -is_gimple_condexpr (tree t) -{ - return is_gimple_condexpr_1 (t, true); -} - -/* Like is_gimple_condexpr, but does not allow T to trap. */ - -bool -is_gimple_condexpr_for_cond (tree t) -{ - return is_gimple_condexpr_1 (t, 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) == TARGET_MEM_REF - || 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; - - /* Variables can be marked as having partial definitions, avoid - putting them into SSA form. */ - return !DECL_NOT_GIMPLE_REG_P (t); -} - - -/* 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))))); -} - -/* Hold trees marked addressable during expand. */ - -static hash_set<tree> *mark_addressable_queue; - -/* Mark X as addressable or queue it up if called during expand. We - don't want to apply it immediately during expand because decls are - made addressable at that point due to RTL-only concerns, such as - uses of memcpy for block moves, and TREE_ADDRESSABLE changes - is_gimple_reg, which might make it seem like a variable that used - to be a gimple_reg shouldn't have been an SSA name. So we queue up - this flag setting and only apply it when we're done with GIMPLE and - only RTL issues matter. */ - -static void -mark_addressable_1 (tree x) -{ - if (!currently_expanding_to_rtl) - { - TREE_ADDRESSABLE (x) = 1; - return; - } - - if (!mark_addressable_queue) - mark_addressable_queue = new hash_set<tree>(); - mark_addressable_queue->add (x); -} - -/* Adaptor for mark_addressable_1 for use in hash_set traversal. */ - -bool -mark_addressable_2 (tree const &x, void * ATTRIBUTE_UNUSED = NULL) -{ - mark_addressable_1 (x); - return false; -} - -/* Mark all queued trees as addressable, and empty the queue. To be - called right after clearing CURRENTLY_EXPANDING_TO_RTL. */ - -void -flush_mark_addressable_queue () -{ - gcc_assert (!currently_expanding_to_rtl); - if (mark_addressable_queue) - { - mark_addressable_queue->traverse<void*, mark_addressable_2> (NULL); - delete mark_addressable_queue; - mark_addressable_queue = NULL; - } -} - -/* 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) -{ - if (TREE_CODE (x) == WITH_SIZE_EXPR) - x = TREE_OPERAND (x, 0); - 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 (!VAR_P (x) - && TREE_CODE (x) != PARM_DECL - && TREE_CODE (x) != RESULT_DECL) - return; - mark_addressable_1 (x); - - /* 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) - mark_addressable_1 (*namep); - } -} - -/* 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" |