Mercurial > hg > CbC > CbC_gcc
diff gcc/gimple.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | ab0bcb71f44d 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/gimple.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/gimple.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,6 +1,6 @@ /* Gimple IR support functions. - Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2007-2017 Free Software Foundation, Inc. Contributed by Aldy Hernandez <aldyh@redhat.com> This file is part of GCC. @@ -22,38 +22,29 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" -#include "target.h" +#include "backend.h" #include "tree.h" -#include "ggc.h" -#include "hard-reg-set.h" -#include "basic-block.h" #include "gimple.h" +#include "ssa.h" +#include "cgraph.h" #include "diagnostic.h" -#include "tree-flow.h" -#include "value-prof.h" -#include "flags.h" #include "alias.h" -#include "demangle.h" -#include "langhooks.h" - -/* Global type table. FIXME lto, it should be possible to re-use some - of the type hashing routines in tree.c (type_hash_canon, type_hash_lookup, - etc), but those assume that types were built with the various - build_*_type routines which is not the case with the streamer. */ -static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node))) - htab_t gimple_types; -static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node))) - htab_t gimple_canonical_types; -static GTY((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map))) - htab_t type_hash_cache; -static GTY((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map))) - htab_t canonical_type_hash_cache; - -/* Global type comparison cache. This is by TYPE_UID for space efficiency - and thus cannot use and does not need GC. */ -static htab_t gtc_visited; -static struct obstack gtc_ob; +#include "fold-const.h" +#include "calls.h" +#include "stor-layout.h" +#include "internal-fn.h" +#include "tree-eh.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "gimplify.h" +#include "target.h" +#include "builtins.h" +#include "selftest.h" +#include "gimple-pretty-print.h" +#include "stringpool.h" +#include "attribs.h" +#include "asan.h" + /* All the tuples have their operand vector (if present) at the very bottom of the structure. Therefore, the offset required to find the @@ -66,7 +57,7 @@ }; #undef DEFGSSTRUCT -#define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP) sizeof(struct STRUCT), +#define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP) sizeof (struct STRUCT), static const size_t gsstruct_code_size[] = { #include "gsstruct.def" }; @@ -84,7 +75,6 @@ }; #undef DEFGSCODE -#ifdef GATHER_STATISTICS /* Gimple stats. */ int gimple_alloc_counts[(int) gimple_alloc_kind_all]; @@ -95,20 +85,14 @@ "assignments", "phi nodes", "conditionals", - "sequences", "everything else" }; -#endif /* GATHER_STATISTICS */ - -/* A cache of gimple_seq objects. Sequences are created and destroyed - fairly often during gimplification. */ -static GTY ((deletable)) struct gimple_seq_d *gimple_seq_cache; - -/* Private API manipulation functions shared only with some - other files. */ -extern void gimple_set_stored_syms (gimple, bitmap, bitmap_obstack *); -extern void gimple_set_loaded_syms (gimple, bitmap, bitmap_obstack *); +/* Static gimple tuple members. */ +const enum gimple_code gassign::code_; +const enum gimple_code gcall::code_; +const enum gimple_code gcond::code_; + /* Gimple tuple constructors. Note: Any constructor taking a ``gimple_seq'' as a parameter, can @@ -117,9 +101,9 @@ /* Set the code for statement G to CODE. */ static inline void -gimple_set_code (gimple g, enum gimple_code code) +gimple_set_code (gimple *g, enum gimple_code code) { - g->gsbase.code = code; + g->code = code; } /* Return the number of bytes needed to hold a GIMPLE statement with @@ -134,31 +118,31 @@ /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS operands. */ -gimple -gimple_alloc_stat (enum gimple_code code, unsigned num_ops MEM_STAT_DECL) +gimple * +gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL) { size_t size; - gimple stmt; + gimple *stmt; size = gimple_size (code); if (num_ops > 0) size += sizeof (tree) * (num_ops - 1); -#ifdef GATHER_STATISTICS - { - enum gimple_alloc_kind kind = gimple_alloc_kind (code); - gimple_alloc_counts[(int) kind]++; - gimple_alloc_sizes[(int) kind] += size; - } -#endif - - stmt = ggc_alloc_cleared_gimple_statement_d_stat (size PASS_MEM_STAT); + if (GATHER_STATISTICS) + { + enum gimple_alloc_kind kind = gimple_alloc_kind (code); + gimple_alloc_counts[(int) kind]++; + gimple_alloc_sizes[(int) kind] += size; + } + + stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT); gimple_set_code (stmt, code); gimple_set_num_ops (stmt, num_ops); /* Do not call gimple_set_modified here as it has other side effects and this tuple is still not completely built. */ - stmt->gsbase.modified = 1; + stmt->modified = 1; + gimple_init_singleton (stmt); return stmt; } @@ -166,28 +150,28 @@ /* Set SUBCODE to be the code of the expression computed by statement G. */ static inline void -gimple_set_subcode (gimple g, unsigned subcode) +gimple_set_subcode (gimple *g, unsigned subcode) { /* We only have 16 bits for the RHS code. Assert that we are not overflowing it. */ gcc_assert (subcode < (1 << 16)); - g->gsbase.subcode = subcode; + g->subcode = subcode; } /* Build a tuple with operands. CODE is the statement to build (which - must be one of the GIMPLE_WITH_OPS tuples). SUBCODE is the sub-code + must be one of the GIMPLE_WITH_OPS tuples). SUBCODE is the subcode for the new tuple. NUM_OPS is the number of operands to allocate. */ #define gimple_build_with_ops(c, s, n) \ gimple_build_with_ops_stat (c, s, n MEM_STAT_INFO) -static gimple +static gimple * gimple_build_with_ops_stat (enum gimple_code code, unsigned subcode, unsigned num_ops MEM_STAT_DECL) { - gimple s = gimple_alloc_stat (code, num_ops PASS_MEM_STAT); + gimple *s = gimple_alloc (code, num_ops PASS_MEM_STAT); gimple_set_subcode (s, subcode); return s; @@ -196,10 +180,12 @@ /* Build a GIMPLE_RETURN statement returning RETVAL. */ -gimple +greturn * gimple_build_return (tree retval) { - gimple s = gimple_build_with_ops (GIMPLE_RETURN, ERROR_MARK, 1); + greturn *s + = as_a <greturn *> (gimple_build_with_ops (GIMPLE_RETURN, ERROR_MARK, + 2)); if (retval) gimple_return_set_retval (s, retval); return s; @@ -208,7 +194,7 @@ /* Reset alias information on call S. */ void -gimple_call_reset_alias_info (gimple s) +gimple_call_reset_alias_info (gcall *s) { if (gimple_call_flags (s) & ECF_CONST) memset (gimple_call_use_set (s), 0, sizeof (struct pt_solution)); @@ -220,17 +206,21 @@ pt_solution_reset (gimple_call_clobber_set (s)); } -/* Helper for gimple_build_call, gimple_build_call_vec and - gimple_build_call_from_tree. Build the basic components of a - GIMPLE_CALL statement to function FN with NARGS arguments. */ - -static inline gimple +/* Helper for gimple_build_call, gimple_build_call_valist, + gimple_build_call_vec and gimple_build_call_from_tree. Build the basic + components of a GIMPLE_CALL statement to function FN with NARGS + arguments. */ + +static inline gcall * gimple_build_call_1 (tree fn, unsigned nargs) { - gimple s = gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, nargs + 3); + gcall *s + = as_a <gcall *> (gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, + nargs + 3)); if (TREE_CODE (fn) == FUNCTION_DECL) fn = build_fold_addr_expr (fn); gimple_set_op (s, 1, fn); + gimple_call_set_fntype (s, TREE_TYPE (TREE_TYPE (fn))); gimple_call_reset_alias_info (s); return s; } @@ -239,15 +229,15 @@ /* Build a GIMPLE_CALL statement to function FN with the arguments specified in vector ARGS. */ -gimple -gimple_build_call_vec (tree fn, VEC(tree, heap) *args) +gcall * +gimple_build_call_vec (tree fn, vec<tree> args) { unsigned i; - unsigned nargs = VEC_length (tree, args); - gimple call = gimple_build_call_1 (fn, nargs); + unsigned nargs = args.length (); + gcall *call = gimple_build_call_1 (fn, nargs); for (i = 0; i < nargs; i++) - gimple_call_set_arg (call, i, VEC_index (tree, args, i)); + gimple_call_set_arg (call, i, args[i]); return call; } @@ -256,11 +246,11 @@ /* Build a GIMPLE_CALL statement to function FN. NARGS is the number of arguments. The ... are the arguments. */ -gimple +gcall * gimple_build_call (tree fn, unsigned nargs, ...) { va_list ap; - gimple call; + gcall *call; unsigned i; gcc_assert (TREE_CODE (fn) == FUNCTION_DECL || is_gimple_call_addr (fn)); @@ -276,15 +266,90 @@ } +/* Build a GIMPLE_CALL statement to function FN. NARGS is the number of + arguments. AP contains the arguments. */ + +gcall * +gimple_build_call_valist (tree fn, unsigned nargs, va_list ap) +{ + gcall *call; + unsigned i; + + gcc_assert (TREE_CODE (fn) == FUNCTION_DECL || is_gimple_call_addr (fn)); + + call = gimple_build_call_1 (fn, nargs); + + for (i = 0; i < nargs; i++) + gimple_call_set_arg (call, i, va_arg (ap, tree)); + + return call; +} + + +/* Helper for gimple_build_call_internal and gimple_build_call_internal_vec. + Build the basic components of a GIMPLE_CALL statement to internal + function FN with NARGS arguments. */ + +static inline gcall * +gimple_build_call_internal_1 (enum internal_fn fn, unsigned nargs) +{ + gcall *s + = as_a <gcall *> (gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, + nargs + 3)); + s->subcode |= GF_CALL_INTERNAL; + gimple_call_set_internal_fn (s, fn); + gimple_call_reset_alias_info (s); + return s; +} + + +/* Build a GIMPLE_CALL statement to internal function FN. NARGS is + the number of arguments. The ... are the arguments. */ + +gcall * +gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...) +{ + va_list ap; + gcall *call; + unsigned i; + + call = gimple_build_call_internal_1 (fn, nargs); + va_start (ap, nargs); + for (i = 0; i < nargs; i++) + gimple_call_set_arg (call, i, va_arg (ap, tree)); + va_end (ap); + + return call; +} + + +/* Build a GIMPLE_CALL statement to internal function FN with the arguments + specified in vector ARGS. */ + +gcall * +gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args) +{ + unsigned i, nargs; + gcall *call; + + nargs = args.length (); + call = gimple_build_call_internal_1 (fn, nargs); + for (i = 0; i < nargs; i++) + gimple_call_set_arg (call, i, args[i]); + + return call; +} + + /* Build a GIMPLE_CALL statement from CALL_EXPR T. Note that T is assumed to be in GIMPLE form already. Minimal checking is done of this fact. */ -gimple -gimple_build_call_from_tree (tree t) +gcall * +gimple_build_call_from_tree (tree t, tree fnptrtype) { unsigned i, nargs; - gimple call; + gcall *call; tree fndecl = get_callee_fndecl (t); gcc_assert (TREE_CODE (t) == CALL_EXPR); @@ -300,92 +365,74 @@ /* Carry all the CALL_EXPR flags to the new GIMPLE_CALL. */ gimple_call_set_chain (call, CALL_EXPR_STATIC_CHAIN (t)); gimple_call_set_tail (call, CALL_EXPR_TAILCALL (t)); - gimple_call_set_cannot_inline (call, CALL_CANNOT_INLINE_P (t)); + gimple_call_set_must_tail (call, CALL_EXPR_MUST_TAIL_CALL (t)); gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t)); - gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t)); + if (fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (fndecl))) + gimple_call_set_alloca_for_var (call, CALL_ALLOCA_FOR_VAR_P (t)); + else + gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t)); gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (t)); gimple_call_set_nothrow (call, TREE_NOTHROW (t)); + gimple_call_set_by_descriptor (call, CALL_EXPR_BY_DESCRIPTOR (t)); gimple_set_no_warning (call, TREE_NO_WARNING (t)); + gimple_call_set_with_bounds (call, CALL_WITH_BOUNDS_P (t)); + + if (fnptrtype) + { + gimple_call_set_fntype (call, TREE_TYPE (fnptrtype)); + + /* Check if it's an indirect CALL and the type has the + nocf_check attribute. In that case propagate the information + to the gimple CALL insn. */ + if (!fndecl) + { + gcc_assert (POINTER_TYPE_P (fnptrtype)); + tree fntype = TREE_TYPE (fnptrtype); + + if (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (fntype))) + gimple_call_set_nocf_check (call, TRUE); + } + } return call; } -/* 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. RHS of the assignment which can be unary or binary. */ -gimple -gimple_build_assign_stat (tree lhs, tree rhs MEM_STAT_DECL) +gassign * +gimple_build_assign (tree lhs, tree rhs MEM_STAT_DECL) { enum tree_code subcode; tree op1, op2, op3; - extract_ops_from_tree_1 (rhs, &subcode, &op1, &op2, &op3); - return gimple_build_assign_with_ops_stat (subcode, lhs, op1, op2, op3 - PASS_MEM_STAT); + extract_ops_from_tree (rhs, &subcode, &op1, &op2, &op3); + return gimple_build_assign (lhs, subcode, op1, op2, op3 PASS_MEM_STAT); } -/* Build a GIMPLE_ASSIGN statement with sub-code SUBCODE and operands - OP1 and OP2. If OP2 is NULL then SUBCODE must be of class - GIMPLE_UNARY_RHS or GIMPLE_SINGLE_RHS. */ - -gimple -gimple_build_assign_with_ops_stat (enum tree_code subcode, tree lhs, tree op1, - tree op2, tree op3 MEM_STAT_DECL) +/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operands + OP1, OP2 and OP3. */ + +static inline gassign * +gimple_build_assign_1 (tree lhs, enum tree_code subcode, tree op1, + tree op2, tree op3 MEM_STAT_DECL) { unsigned num_ops; - gimple p; + gassign *p; /* Need 1 operand for LHS and 1 or 2 for the RHS (depending on the code). */ num_ops = get_gimple_rhs_num_ops (subcode) + 1; - p = gimple_build_with_ops_stat (GIMPLE_ASSIGN, (unsigned)subcode, num_ops - PASS_MEM_STAT); + p = as_a <gassign *> ( + gimple_build_with_ops_stat (GIMPLE_ASSIGN, (unsigned)subcode, num_ops + PASS_MEM_STAT)); gimple_assign_set_lhs (p, lhs); gimple_assign_set_rhs1 (p, op1); if (op2) @@ -403,22 +450,34 @@ return p; } - -/* Build a new GIMPLE_ASSIGN tuple and append it to the end of *SEQ_P. - - DST/SRC are the destination and source respectively. You can pass - ungimplified trees in DST or SRC, in which case they will be - converted to a gimple operand if necessary. - - This function returns the newly created GIMPLE_ASSIGN tuple. */ - -gimple -gimplify_assign (tree dst, tree src, gimple_seq *seq_p) +/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operands + OP1, OP2 and OP3. */ + +gassign * +gimple_build_assign (tree lhs, enum tree_code subcode, tree op1, + tree op2, tree op3 MEM_STAT_DECL) { - tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src); - gimplify_and_add (t, seq_p); - ggc_free (t); - return gimple_seq_last_stmt (*seq_p); + return gimple_build_assign_1 (lhs, subcode, op1, op2, op3 PASS_MEM_STAT); +} + +/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operands + OP1 and OP2. */ + +gassign * +gimple_build_assign (tree lhs, enum tree_code subcode, tree op1, + tree op2 MEM_STAT_DECL) +{ + return gimple_build_assign_1 (lhs, subcode, op1, op2, NULL_TREE + PASS_MEM_STAT); +} + +/* Build a GIMPLE_ASSIGN statement with subcode SUBCODE and operand OP1. */ + +gassign * +gimple_build_assign (tree lhs, enum tree_code subcode, tree op1 MEM_STAT_DECL) +{ + return gimple_build_assign_1 (lhs, subcode, op1, NULL_TREE, NULL_TREE + PASS_MEM_STAT); } @@ -428,14 +487,14 @@ T_LABEL is the label to jump to if the condition is true. F_LABEL is the label to jump to otherwise. */ -gimple +gcond * gimple_build_cond (enum tree_code pred_code, tree lhs, tree rhs, tree t_label, tree f_label) { - gimple p; + gcond *p; gcc_assert (TREE_CODE_CLASS (pred_code) == tcc_comparison); - p = gimple_build_with_ops (GIMPLE_COND, pred_code, 4); + p = as_a <gcond *> (gimple_build_with_ops (GIMPLE_COND, pred_code, 4)); gimple_cond_set_lhs (p, lhs); gimple_cond_set_rhs (p, rhs); gimple_cond_set_true_label (p, t_label); @@ -443,41 +502,10 @@ 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. */ -gimple +gcond * gimple_build_cond_from_tree (tree cond, tree t_label, tree f_label) { enum tree_code code; @@ -491,7 +519,7 @@ boolean expression tree COND. */ void -gimple_cond_set_condition_from_tree (gimple stmt, tree cond) +gimple_cond_set_condition_from_tree (gcond *stmt, tree cond) { enum tree_code code; tree lhs, rhs; @@ -502,20 +530,22 @@ /* Build a GIMPLE_LABEL statement for LABEL. */ -gimple +glabel * gimple_build_label (tree label) { - gimple p = gimple_build_with_ops (GIMPLE_LABEL, ERROR_MARK, 1); + glabel *p + = as_a <glabel *> (gimple_build_with_ops (GIMPLE_LABEL, ERROR_MARK, 1)); gimple_label_set_label (p, label); return p; } /* Build a GIMPLE_GOTO statement to label DEST. */ -gimple +ggoto * gimple_build_goto (tree dest) { - gimple p = gimple_build_with_ops (GIMPLE_GOTO, ERROR_MARK, 1); + ggoto *p + = as_a <ggoto *> (gimple_build_with_ops (GIMPLE_GOTO, ERROR_MARK, 1)); gimple_goto_set_dest (p, dest); return p; } @@ -523,7 +553,7 @@ /* Build a GIMPLE_NOP statement. */ -gimple +gimple * gimple_build_nop (void) { return gimple_alloc (GIMPLE_NOP, 0); @@ -534,10 +564,10 @@ VARS are the variables in BODY. BLOCK is the containing block. */ -gimple +gbind * gimple_build_bind (tree vars, gimple_seq body, tree block) { - gimple p = gimple_alloc (GIMPLE_BIND, 0); + gbind *p = as_a <gbind *> (gimple_alloc (GIMPLE_BIND, 0)); gimple_bind_set_vars (p, vars); if (body) gimple_bind_set_body (p, body); @@ -554,29 +584,29 @@ NCLOBBERS is the number of clobbered registers. */ -static inline gimple +static inline gasm * gimple_build_asm_1 (const char *string, unsigned ninputs, unsigned noutputs, unsigned nclobbers, unsigned nlabels) { - gimple p; + gasm *p; int size = strlen (string); /* ASMs with labels cannot have outputs. This should have been enforced by the front end. */ gcc_assert (nlabels == 0 || noutputs == 0); - p = gimple_build_with_ops (GIMPLE_ASM, ERROR_MARK, - ninputs + noutputs + nclobbers + nlabels); - - p->gimple_asm.ni = ninputs; - p->gimple_asm.no = noutputs; - p->gimple_asm.nc = nclobbers; - p->gimple_asm.nl = nlabels; - p->gimple_asm.string = ggc_alloc_string (string, size); - -#ifdef GATHER_STATISTICS - gimple_alloc_sizes[(int) gimple_alloc_kind (GIMPLE_ASM)] += size; -#endif + p = as_a <gasm *> ( + gimple_build_with_ops (GIMPLE_ASM, ERROR_MARK, + ninputs + noutputs + nclobbers + nlabels)); + + p->ni = ninputs; + p->no = noutputs; + p->nc = nclobbers; + p->nl = nlabels; + p->string = ggc_alloc_string (string, size); + + if (GATHER_STATISTICS) + gimple_alloc_sizes[(int) gimple_alloc_kind (GIMPLE_ASM)] += size; return p; } @@ -592,31 +622,31 @@ CLOBBERS is a vector of the clobbered register parameters. LABELS is a vector of destination labels. */ -gimple -gimple_build_asm_vec (const char *string, VEC(tree,gc)* inputs, - VEC(tree,gc)* outputs, VEC(tree,gc)* clobbers, - VEC(tree,gc)* labels) +gasm * +gimple_build_asm_vec (const char *string, vec<tree, va_gc> *inputs, + vec<tree, va_gc> *outputs, vec<tree, va_gc> *clobbers, + vec<tree, va_gc> *labels) { - gimple p; + gasm *p; unsigned i; p = gimple_build_asm_1 (string, - VEC_length (tree, inputs), - VEC_length (tree, outputs), - VEC_length (tree, clobbers), - VEC_length (tree, labels)); - - for (i = 0; i < VEC_length (tree, inputs); i++) - gimple_asm_set_input_op (p, i, VEC_index (tree, inputs, i)); - - for (i = 0; i < VEC_length (tree, outputs); i++) - gimple_asm_set_output_op (p, i, VEC_index (tree, outputs, i)); - - for (i = 0; i < VEC_length (tree, clobbers); i++) - gimple_asm_set_clobber_op (p, i, VEC_index (tree, clobbers, i)); - - for (i = 0; i < VEC_length (tree, labels); i++) - gimple_asm_set_label_op (p, i, VEC_index (tree, labels, i)); + vec_safe_length (inputs), + vec_safe_length (outputs), + vec_safe_length (clobbers), + vec_safe_length (labels)); + + for (i = 0; i < vec_safe_length (inputs); i++) + gimple_asm_set_input_op (p, i, (*inputs)[i]); + + for (i = 0; i < vec_safe_length (outputs); i++) + gimple_asm_set_output_op (p, i, (*outputs)[i]); + + for (i = 0; i < vec_safe_length (clobbers); i++) + gimple_asm_set_clobber_op (p, i, (*clobbers)[i]); + + for (i = 0; i < vec_safe_length (labels); i++) + gimple_asm_set_label_op (p, i, (*labels)[i]); return p; } @@ -626,10 +656,10 @@ TYPES are the catch types. HANDLER is the exception handler. */ -gimple +gcatch * gimple_build_catch (tree types, gimple_seq handler) { - gimple p = gimple_alloc (GIMPLE_CATCH, 0); + gcatch *p = as_a <gcatch *> (gimple_alloc (GIMPLE_CATCH, 0)); gimple_catch_set_types (p, types); if (handler) gimple_catch_set_handler (p, handler); @@ -642,10 +672,10 @@ TYPES are the filter's types. FAILURE is the filter's failure action. */ -gimple +geh_filter * gimple_build_eh_filter (tree types, gimple_seq failure) { - gimple p = gimple_alloc (GIMPLE_EH_FILTER, 0); + geh_filter *p = as_a <geh_filter *> (gimple_alloc (GIMPLE_EH_FILTER, 0)); gimple_eh_filter_set_types (p, types); if (failure) gimple_eh_filter_set_failure (p, failure); @@ -655,10 +685,10 @@ /* Build a GIMPLE_EH_MUST_NOT_THROW statement. */ -gimple +geh_mnt * gimple_build_eh_must_not_throw (tree decl) { - gimple p = gimple_alloc (GIMPLE_EH_MUST_NOT_THROW, 0); + geh_mnt *p = as_a <geh_mnt *> (gimple_alloc (GIMPLE_EH_MUST_NOT_THROW, 0)); gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); gcc_assert (flags_from_decl_or_type (decl) & ECF_NORETURN); @@ -667,6 +697,17 @@ return p; } +/* Build a GIMPLE_EH_ELSE statement. */ + +geh_else * +gimple_build_eh_else (gimple_seq n_body, gimple_seq e_body) +{ + geh_else *p = as_a <geh_else *> (gimple_alloc (GIMPLE_EH_ELSE, 0)); + gimple_eh_else_set_n_body (p, n_body); + gimple_eh_else_set_e_body (p, e_body); + return p; +} + /* Build a GIMPLE_TRY statement. EVAL is the expression to evaluate. @@ -674,14 +715,14 @@ KIND is either GIMPLE_TRY_CATCH or GIMPLE_TRY_FINALLY depending on whether this is a try/catch or a try/finally respectively. */ -gimple +gtry * gimple_build_try (gimple_seq eval, gimple_seq cleanup, enum gimple_try_flags kind) { - gimple p; + gtry *p; gcc_assert (kind == GIMPLE_TRY_CATCH || kind == GIMPLE_TRY_FINALLY); - p = gimple_alloc (GIMPLE_TRY, 0); + p = as_a <gtry *> (gimple_alloc (GIMPLE_TRY, 0)); gimple_set_subcode (p, kind); if (eval) gimple_try_set_eval (p, eval); @@ -695,10 +736,10 @@ CLEANUP is the cleanup expression. */ -gimple +gimple * gimple_build_wce (gimple_seq cleanup) { - gimple p = gimple_alloc (GIMPLE_WITH_CLEANUP_EXPR, 0); + gimple *p = gimple_alloc (GIMPLE_WITH_CLEANUP_EXPR, 0); if (cleanup) gimple_wce_set_cleanup (p, cleanup); @@ -708,11 +749,12 @@ /* Build a GIMPLE_RESX statement. */ -gimple +gresx * gimple_build_resx (int region) { - gimple p = gimple_build_with_ops (GIMPLE_RESX, ERROR_MARK, 0); - p->gimple_eh_ctrl.region = region; + gresx *p + = as_a <gresx *> (gimple_build_with_ops (GIMPLE_RESX, ERROR_MARK, 0)); + p->region = region; return p; } @@ -722,70 +764,48 @@ NLABELS is the number of labels in the switch excluding the default. DEFAULT_LABEL is the default label for the switch statement. */ -gimple +gswitch * gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label) { /* nlabels + 1 default label + 1 index. */ - gimple p = gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK, - 1 + (default_label != NULL) + nlabels); + gcc_checking_assert (default_label); + gswitch *p = as_a <gswitch *> (gimple_build_with_ops (GIMPLE_SWITCH, + ERROR_MARK, + 1 + 1 + nlabels)); gimple_switch_set_index (p, index); - if (default_label) - gimple_switch_set_default_label (p, default_label); + gimple_switch_set_default_label (p, default_label); return p; } - -/* Build a GIMPLE_SWITCH statement. - - INDEX is the switch's index. - NLABELS is the number of labels in the switch excluding the DEFAULT_LABEL. - ... are the labels excluding the default. */ - -gimple -gimple_build_switch (unsigned nlabels, tree index, tree default_label, ...) -{ - va_list al; - unsigned i, offset; - gimple p = gimple_build_switch_nlabels (nlabels, index, default_label); - - /* Store the rest of the labels. */ - va_start (al, default_label); - offset = (default_label != NULL); - for (i = 0; i < nlabels; i++) - gimple_switch_set_label (p, i + offset, va_arg (al, tree)); - va_end (al); - - return p; -} - - /* Build a GIMPLE_SWITCH statement. INDEX is the switch's index. DEFAULT_LABEL is the default label ARGS is a vector of labels excluding the default. */ -gimple -gimple_build_switch_vec (tree index, tree default_label, VEC(tree, heap) *args) +gswitch * +gimple_build_switch (tree index, tree default_label, vec<tree> args) { - unsigned i, offset, nlabels = VEC_length (tree, args); - gimple p = gimple_build_switch_nlabels (nlabels, index, default_label); + unsigned i, nlabels = args.length (); + + gswitch *p = gimple_build_switch_nlabels (nlabels, index, default_label); /* Copy the labels from the vector to the switch statement. */ - offset = (default_label != NULL); for (i = 0; i < nlabels; i++) - gimple_switch_set_label (p, i + offset, VEC_index (tree, args, i)); + gimple_switch_set_label (p, i + 1, args[i]); return p; } /* Build a GIMPLE_EH_DISPATCH statement. */ -gimple +geh_dispatch * gimple_build_eh_dispatch (int region) { - gimple p = gimple_build_with_ops (GIMPLE_EH_DISPATCH, ERROR_MARK, 0); - p->gimple_eh_ctrl.region = region; + geh_dispatch *p + = as_a <geh_dispatch *> ( + gimple_build_with_ops (GIMPLE_EH_DISPATCH, ERROR_MARK, 0)); + p->region = region; return p; } @@ -793,20 +813,40 @@ VAR is bound to VALUE; block and location are taken from STMT. */ -gimple -gimple_build_debug_bind_stat (tree var, tree value, gimple stmt MEM_STAT_DECL) +gdebug * +gimple_build_debug_bind (tree var, tree value, gimple *stmt MEM_STAT_DECL) { - gimple p = gimple_build_with_ops_stat (GIMPLE_DEBUG, - (unsigned)GIMPLE_DEBUG_BIND, 2 - PASS_MEM_STAT); - + gdebug *p + = as_a <gdebug *> (gimple_build_with_ops_stat (GIMPLE_DEBUG, + (unsigned)GIMPLE_DEBUG_BIND, 2 + PASS_MEM_STAT)); gimple_debug_bind_set_var (p, var); gimple_debug_bind_set_value (p, value); if (stmt) - { - gimple_set_block (p, gimple_block (stmt)); - gimple_set_location (p, gimple_location (stmt)); - } + gimple_set_location (p, gimple_location (stmt)); + + return p; +} + + +/* Build a new GIMPLE_DEBUG_SOURCE_BIND statement. + + VAR is bound to VALUE; block and location are taken from STMT. */ + +gdebug * +gimple_build_debug_source_bind (tree var, tree value, + gimple *stmt MEM_STAT_DECL) +{ + gdebug *p + = as_a <gdebug *> ( + gimple_build_with_ops_stat (GIMPLE_DEBUG, + (unsigned)GIMPLE_DEBUG_SOURCE_BIND, 2 + PASS_MEM_STAT)); + + gimple_debug_source_bind_set_var (p, var); + gimple_debug_source_bind_set_value (p, value); + if (stmt) + gimple_set_location (p, gimple_location (stmt)); return p; } @@ -815,13 +855,16 @@ /* Build a GIMPLE_OMP_CRITICAL statement. BODY is the sequence of statements for which only one thread can execute. - NAME is optional identifier for this critical block. */ - -gimple -gimple_build_omp_critical (gimple_seq body, tree name) + NAME is optional identifier for this critical block. + CLAUSES are clauses for this critical block. */ + +gomp_critical * +gimple_build_omp_critical (gimple_seq body, tree name, tree clauses) { - gimple p = gimple_alloc (GIMPLE_OMP_CRITICAL, 0); + gomp_critical *p + = as_a <gomp_critical *> (gimple_alloc (GIMPLE_OMP_CRITICAL, 0)); gimple_omp_critical_set_name (p, name); + gimple_omp_critical_set_clauses (p, clauses); if (body) gimple_omp_set_body (p, body); @@ -831,22 +874,23 @@ /* Build a GIMPLE_OMP_FOR statement. BODY is sequence of statements inside the for loop. - CLAUSES, are any of the OMP loop construct's clauses: private, firstprivate, - lastprivate, reductions, ordered, schedule, and nowait. + KIND is the `for' variant. + CLAUSES, are any of the construct's clauses. COLLAPSE is the collapse count. PRE_BODY is the sequence of statements that are loop invariant. */ -gimple -gimple_build_omp_for (gimple_seq body, tree clauses, size_t collapse, +gomp_for * +gimple_build_omp_for (gimple_seq body, int kind, tree clauses, size_t collapse, gimple_seq pre_body) { - gimple p = gimple_alloc (GIMPLE_OMP_FOR, 0); + gomp_for *p = as_a <gomp_for *> (gimple_alloc (GIMPLE_OMP_FOR, 0)); if (body) gimple_omp_set_body (p, body); gimple_omp_for_set_clauses (p, clauses); - p->gimple_omp_for.collapse = collapse; - p->gimple_omp_for.iter - = ggc_alloc_cleared_vec_gimple_omp_for_iter (collapse); + gimple_omp_for_set_kind (p, kind); + p->collapse = collapse; + p->iter = ggc_cleared_vec_alloc<gimple_omp_for_iter> (collapse); + if (pre_body) gimple_omp_for_set_pre_body (p, pre_body); @@ -861,11 +905,12 @@ CHILD_FN is the function created for the parallel threads to execute. DATA_ARG are the shared data argument(s). */ -gimple +gomp_parallel * gimple_build_omp_parallel (gimple_seq body, tree clauses, tree child_fn, tree data_arg) { - gimple p = gimple_alloc (GIMPLE_OMP_PARALLEL, 0); + gomp_parallel *p + = as_a <gomp_parallel *> (gimple_alloc (GIMPLE_OMP_PARALLEL, 0)); if (body) gimple_omp_set_body (p, body); gimple_omp_parallel_set_clauses (p, clauses); @@ -885,12 +930,12 @@ COPY_FN is the optional function for firstprivate initialization. ARG_SIZE and ARG_ALIGN are size and alignment of the data block. */ -gimple +gomp_task * gimple_build_omp_task (gimple_seq body, tree clauses, tree child_fn, tree data_arg, tree copy_fn, tree arg_size, tree arg_align) { - gimple p = gimple_alloc (GIMPLE_OMP_TASK, 0); + gomp_task *p = as_a <gomp_task *> (gimple_alloc (GIMPLE_OMP_TASK, 0)); if (body) gimple_omp_set_body (p, body); gimple_omp_task_set_clauses (p, clauses); @@ -908,10 +953,10 @@ BODY is the sequence of statements in the section. */ -gimple +gimple * gimple_build_omp_section (gimple_seq body) { - gimple p = gimple_alloc (GIMPLE_OMP_SECTION, 0); + gimple *p = gimple_alloc (GIMPLE_OMP_SECTION, 0); if (body) gimple_omp_set_body (p, body); @@ -923,10 +968,39 @@ BODY is the sequence of statements to be executed by just the master. */ -gimple +gimple * gimple_build_omp_master (gimple_seq body) { - gimple p = gimple_alloc (GIMPLE_OMP_MASTER, 0); + gimple *p = gimple_alloc (GIMPLE_OMP_MASTER, 0); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + +/* Build a GIMPLE_OMP_GRID_BODY statement. + + BODY is the sequence of statements to be executed by the kernel. */ + +gimple * +gimple_build_omp_grid_body (gimple_seq body) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_GRID_BODY, 0); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + +/* Build a GIMPLE_OMP_TASKGROUP statement. + + BODY is the sequence of statements to be executed by the taskgroup + construct. */ + +gimple * +gimple_build_omp_taskgroup (gimple_seq body) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_TASKGROUP, 0); if (body) gimple_omp_set_body (p, body); @@ -939,10 +1013,11 @@ CONTROL_DEF is the definition of the control variable. CONTROL_USE is the use of the control variable. */ -gimple +gomp_continue * gimple_build_omp_continue (tree control_def, tree control_use) { - gimple p = gimple_alloc (GIMPLE_OMP_CONTINUE, 0); + gomp_continue *p + = as_a <gomp_continue *> (gimple_alloc (GIMPLE_OMP_CONTINUE, 0)); gimple_omp_continue_set_control_def (p, control_def); gimple_omp_continue_set_control_use (p, control_use); return p; @@ -951,12 +1026,15 @@ /* Build a GIMPLE_OMP_ORDERED statement. BODY is the sequence of statements inside a loop that will executed in - sequence. */ - -gimple -gimple_build_omp_ordered (gimple_seq body) + sequence. + CLAUSES are clauses for this statement. */ + +gomp_ordered * +gimple_build_omp_ordered (gimple_seq body, tree clauses) { - gimple p = gimple_alloc (GIMPLE_OMP_ORDERED, 0); + gomp_ordered *p + = as_a <gomp_ordered *> (gimple_alloc (GIMPLE_OMP_ORDERED, 0)); + gimple_omp_ordered_set_clauses (p, clauses); if (body) gimple_omp_set_body (p, body); @@ -967,10 +1045,10 @@ /* Build a GIMPLE_OMP_RETURN statement. WAIT_P is true if this is a non-waiting return. */ -gimple +gimple * gimple_build_omp_return (bool wait_p) { - gimple p = gimple_alloc (GIMPLE_OMP_RETURN, 0); + gimple *p = gimple_alloc (GIMPLE_OMP_RETURN, 0); if (wait_p) gimple_omp_return_set_nowait (p); @@ -984,10 +1062,11 @@ CLAUSES are any of the OMP sections contsruct's clauses: private, firstprivate, lastprivate, reduction, and nowait. */ -gimple +gomp_sections * gimple_build_omp_sections (gimple_seq body, tree clauses) { - gimple p = gimple_alloc (GIMPLE_OMP_SECTIONS, 0); + gomp_sections *p + = as_a <gomp_sections *> (gimple_alloc (GIMPLE_OMP_SECTIONS, 0)); if (body) gimple_omp_set_body (p, body); gimple_omp_sections_set_clauses (p, clauses); @@ -998,7 +1077,7 @@ /* Build a GIMPLE_OMP_SECTIONS_SWITCH. */ -gimple +gimple * gimple_build_omp_sections_switch (void) { return gimple_alloc (GIMPLE_OMP_SECTIONS_SWITCH, 0); @@ -1011,10 +1090,11 @@ CLAUSES are any of the OMP single construct's clauses: private, firstprivate, copyprivate, nowait. */ -gimple +gomp_single * gimple_build_omp_single (gimple_seq body, tree clauses) { - gimple p = gimple_alloc (GIMPLE_OMP_SINGLE, 0); + gomp_single *p + = as_a <gomp_single *> (gimple_alloc (GIMPLE_OMP_SINGLE, 0)); if (body) gimple_omp_set_body (p, body); gimple_omp_single_set_clauses (p, clauses); @@ -1023,12 +1103,50 @@ } +/* Build a GIMPLE_OMP_TARGET statement. + + BODY is the sequence of statements that will be executed. + KIND is the kind of the region. + CLAUSES are any of the construct's clauses. */ + +gomp_target * +gimple_build_omp_target (gimple_seq body, int kind, tree clauses) +{ + gomp_target *p + = as_a <gomp_target *> (gimple_alloc (GIMPLE_OMP_TARGET, 0)); + if (body) + gimple_omp_set_body (p, body); + gimple_omp_target_set_clauses (p, clauses); + gimple_omp_target_set_kind (p, kind); + + return p; +} + + +/* Build a GIMPLE_OMP_TEAMS statement. + + BODY is the sequence of statements that will be executed. + CLAUSES are any of the OMP teams construct's clauses. */ + +gomp_teams * +gimple_build_omp_teams (gimple_seq body, tree clauses) +{ + gomp_teams *p = as_a <gomp_teams *> (gimple_alloc (GIMPLE_OMP_TEAMS, 0)); + if (body) + gimple_omp_set_body (p, body); + gimple_omp_teams_set_clauses (p, clauses); + + return p; +} + + /* Build a GIMPLE_OMP_ATOMIC_LOAD statement. */ -gimple +gomp_atomic_load * gimple_build_omp_atomic_load (tree lhs, tree rhs) { - gimple p = gimple_alloc (GIMPLE_OMP_ATOMIC_LOAD, 0); + gomp_atomic_load *p + = as_a <gomp_atomic_load *> (gimple_alloc (GIMPLE_OMP_ATOMIC_LOAD, 0)); gimple_omp_atomic_load_set_lhs (p, lhs); gimple_omp_atomic_load_set_rhs (p, rhs); return p; @@ -1038,25 +1156,26 @@ VAL is the value we are storing. */ -gimple +gomp_atomic_store * gimple_build_omp_atomic_store (tree val) { - gimple p = gimple_alloc (GIMPLE_OMP_ATOMIC_STORE, 0); + gomp_atomic_store *p + = as_a <gomp_atomic_store *> (gimple_alloc (GIMPLE_OMP_ATOMIC_STORE, 0)); gimple_omp_atomic_store_set_val (p, val); return p; } -/* Build a GIMPLE_PREDICT statement. PREDICT is one of the predictors from - predict.def, OUTCOME is NOT_TAKEN or TAKEN. */ - -gimple -gimple_build_predict (enum br_predictor predictor, enum prediction outcome) +/* Build a GIMPLE_TRANSACTION statement. */ + +gtransaction * +gimple_build_transaction (gimple_seq body) { - gimple p = gimple_alloc (GIMPLE_PREDICT, 0); - /* Ensure all the predictors fit into the lower bits of the subcode. */ - gcc_assert ((int) END_PREDICTORS <= GF_PREDICT_TAKEN); - gimple_predict_set_predictor (p, predictor); - gimple_predict_set_outcome (p, outcome); + gtransaction *p + = as_a <gtransaction *> (gimple_alloc (GIMPLE_TRANSACTION, 0)); + gimple_transaction_set_body (p, body); + gimple_transaction_set_label_norm (p, 0); + gimple_transaction_set_label_uninst (p, 0); + gimple_transaction_set_label_over (p, 0); return p; } @@ -1064,88 +1183,54 @@ /* Complain of a gimple type mismatch and die. */ void -gimple_check_failed (const_gimple gs, const char *file, int line, +gimple_check_failed (const gimple *gs, const char *file, int line, const char *function, enum gimple_code code, enum tree_code subcode) { internal_error ("gimple check: expected %s(%s), have %s(%s) in %s, at %s:%d", gimple_code_name[code], - tree_code_name[subcode], + get_tree_code_name (subcode), gimple_code_name[gimple_code (gs)], - gs->gsbase.subcode > 0 - ? tree_code_name[gs->gsbase.subcode] + gs->subcode > 0 + ? get_tree_code_name ((enum tree_code) gs->subcode) : "", function, trim_filename (file), line); } #endif /* ENABLE_GIMPLE_CHECKING */ -/* Allocate a new GIMPLE sequence in GC memory and return it. If - there are free sequences in GIMPLE_SEQ_CACHE return one of those - instead. */ - -gimple_seq -gimple_seq_alloc (void) -{ - gimple_seq seq = gimple_seq_cache; - if (seq) - { - gimple_seq_cache = gimple_seq_cache->next_free; - gcc_assert (gimple_seq_cache != seq); - memset (seq, 0, sizeof (*seq)); - } - else - { - seq = ggc_alloc_cleared_gimple_seq_d (); -#ifdef GATHER_STATISTICS - gimple_alloc_counts[(int) gimple_alloc_kind_seq]++; - gimple_alloc_sizes[(int) gimple_alloc_kind_seq] += sizeof (*seq); -#endif - } - - return seq; -} - -/* Return SEQ to the free pool of GIMPLE sequences. */ - -void -gimple_seq_free (gimple_seq seq) -{ - if (seq == NULL) - return; - - gcc_assert (gimple_seq_first (seq) == NULL); - gcc_assert (gimple_seq_last (seq) == NULL); - - /* If this triggers, it's a sign that the same list is being freed - twice. */ - gcc_assert (seq != gimple_seq_cache || gimple_seq_cache == NULL); - - /* Add SEQ to the pool of free sequences. */ - seq->next_free = gimple_seq_cache; - gimple_seq_cache = seq; -} - - /* Link gimple statement GS to the end of the sequence *SEQ_P. If *SEQ_P is NULL, a new sequence is allocated. */ void -gimple_seq_add_stmt (gimple_seq *seq_p, gimple gs) +gimple_seq_add_stmt (gimple_seq *seq_p, gimple *gs) +{ + gimple_stmt_iterator si; + if (gs == NULL) + return; + + si = gsi_last (*seq_p); + gsi_insert_after (&si, gs, GSI_NEW_STMT); +} + +/* Link gimple statement GS to the end of the sequence *SEQ_P. If + *SEQ_P is NULL, a new sequence is allocated. This function is + similar to gimple_seq_add_stmt, but does not scan the operands. + During gimplification, we need to manipulate statement sequences + before the def/use vectors have been constructed. */ + +void +gimple_seq_add_stmt_without_update (gimple_seq *seq_p, gimple *gs) { gimple_stmt_iterator si; if (gs == NULL) return; - if (*seq_p == NULL) - *seq_p = gimple_seq_alloc (); - si = gsi_last (*seq_p); - gsi_insert_after (&si, gs, GSI_NEW_STMT); + gsi_insert_after_without_update (&si, gs, GSI_NEW_STMT); } - /* Append sequence SRC to the end of sequence *DST_P. If *DST_P is NULL, a new sequence is allocated. */ @@ -1153,28 +1238,97 @@ gimple_seq_add_seq (gimple_seq *dst_p, gimple_seq src) { gimple_stmt_iterator si; - if (src == NULL) return; - if (*dst_p == NULL) - *dst_p = gimple_seq_alloc (); - si = gsi_last (*dst_p); gsi_insert_seq_after (&si, src, GSI_NEW_STMT); } +/* Append sequence SRC to the end of sequence *DST_P. If *DST_P is + NULL, a new sequence is allocated. This function is + similar to gimple_seq_add_seq, but does not scan the operands. */ + +void +gimple_seq_add_seq_without_update (gimple_seq *dst_p, gimple_seq src) +{ + gimple_stmt_iterator si; + if (src == NULL) + return; + + si = gsi_last (*dst_p); + gsi_insert_seq_after_without_update (&si, src, GSI_NEW_STMT); +} + +/* Determine whether to assign a location to the statement GS. */ + +static bool +should_carry_location_p (gimple *gs) +{ + /* Don't emit a line note for a label. We particularly don't want to + emit one for the break label, since it doesn't actually correspond + to the beginning of the loop/switch. */ + if (gimple_code (gs) == GIMPLE_LABEL) + return false; + + return true; +} + +/* Set the location for gimple statement GS to LOCATION. */ + +static void +annotate_one_with_location (gimple *gs, location_t location) +{ + if (!gimple_has_location (gs) + && !gimple_do_not_emit_location_p (gs) + && should_carry_location_p (gs)) + gimple_set_location (gs, location); +} + +/* Set LOCATION for all the statements after iterator GSI in sequence + SEQ. If GSI is pointing to the end of the sequence, start with the + first statement in SEQ. */ + +void +annotate_all_with_location_after (gimple_seq seq, gimple_stmt_iterator gsi, + location_t location) +{ + if (gsi_end_p (gsi)) + gsi = gsi_start (seq); + else + gsi_next (&gsi); + + for (; !gsi_end_p (gsi); gsi_next (&gsi)) + annotate_one_with_location (gsi_stmt (gsi), location); +} + +/* Set the location for all the statements in a sequence STMT_P to LOCATION. */ + +void +annotate_all_with_location (gimple_seq stmt_p, location_t location) +{ + gimple_stmt_iterator i; + + if (gimple_seq_empty_p (stmt_p)) + return; + + for (i = gsi_start (stmt_p); !gsi_end_p (i); gsi_next (&i)) + { + gimple *gs = gsi_stmt (i); + annotate_one_with_location (gs, location); + } +} /* Helper function of empty_body_p. Return true if STMT is an empty statement. */ static bool -empty_stmt_p (gimple stmt) +empty_stmt_p (gimple *stmt) { if (gimple_code (stmt) == GIMPLE_NOP) return true; - if (gimple_code (stmt) == GIMPLE_BIND) - return empty_body_p (gimple_bind_body (stmt)); + if (gbind *bind_stmt = dyn_cast <gbind *> (stmt)) + return empty_body_p (gimple_bind_body (bind_stmt)); return false; } @@ -1203,8 +1357,8 @@ gimple_seq_copy (gimple_seq src) { gimple_stmt_iterator gsi; - gimple_seq new_seq = gimple_seq_alloc (); - gimple stmt; + gimple_seq new_seq = NULL; + gimple *stmt; for (gsi = gsi_start (src); !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -1216,601 +1370,77 @@ } -/* Walk all the statements in the sequence SEQ calling walk_gimple_stmt - on each one. WI is as in walk_gimple_stmt. - - If walk_gimple_stmt returns non-NULL, the walk is stopped, the - value is stored in WI->CALLBACK_RESULT and the statement that - produced the value is returned. - - Otherwise, all the statements are walked and NULL returned. */ - -gimple -walk_gimple_seq (gimple_seq seq, walk_stmt_fn callback_stmt, - walk_tree_fn callback_op, struct walk_stmt_info *wi) -{ - gimple_stmt_iterator gsi; - - for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi)) - { - tree ret = walk_gimple_stmt (&gsi, callback_stmt, callback_op, wi); - if (ret) - { - /* If CALLBACK_STMT or CALLBACK_OP return a value, WI must exist - to hold it. */ - gcc_assert (wi); - wi->callback_result = ret; - return gsi_stmt (gsi); - } - } - - if (wi) - wi->callback_result = NULL_TREE; - - return NULL; -} - - -/* Helper function for walk_gimple_stmt. Walk operands of a GIMPLE_ASM. */ - -static tree -walk_gimple_asm (gimple stmt, walk_tree_fn callback_op, - struct walk_stmt_info *wi) -{ - tree ret, op; - unsigned noutputs; - const char **oconstraints; - unsigned i, n; - const char *constraint; - bool allows_mem, allows_reg, is_inout; - - noutputs = gimple_asm_noutputs (stmt); - oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); - - if (wi) - wi->is_lhs = true; - - for (i = 0; i < noutputs; i++) - { - op = gimple_asm_output_op (stmt, i); - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); - oconstraints[i] = constraint; - parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg, - &is_inout); - if (wi) - wi->val_only = (allows_reg || !allows_mem); - ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL); - if (ret) - return ret; - } - - n = gimple_asm_ninputs (stmt); - for (i = 0; i < n; i++) - { - op = gimple_asm_input_op (stmt, i); - constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); - parse_input_constraint (&constraint, 0, 0, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); - if (wi) - { - wi->val_only = (allows_reg || !allows_mem); - /* Although input "m" is not really a LHS, we need a lvalue. */ - wi->is_lhs = !wi->val_only; - } - ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL); - if (ret) - return ret; - } - - if (wi) - { - wi->is_lhs = false; - wi->val_only = true; - } - - n = gimple_asm_nlabels (stmt); - for (i = 0; i < n; i++) - { - op = gimple_asm_label_op (stmt, i); - ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL); - if (ret) - return ret; - } - - return NULL_TREE; -} - - -/* Helper function of WALK_GIMPLE_STMT. Walk every tree operand in - STMT. CALLBACK_OP and WI are as in WALK_GIMPLE_STMT. - - CALLBACK_OP is called on each operand of STMT via walk_tree. - Additional parameters to walk_tree must be stored in WI. For each operand - OP, walk_tree is called as: - - walk_tree (&OP, CALLBACK_OP, WI, WI->PSET) - - If CALLBACK_OP returns non-NULL for an operand, the remaining - operands are not scanned. - - The return value is that returned by the last call to walk_tree, or - NULL_TREE if no CALLBACK_OP is specified. */ - -tree -walk_gimple_op (gimple stmt, walk_tree_fn callback_op, - struct walk_stmt_info *wi) + +/* Return true if calls C1 and C2 are known to go to the same function. */ + +bool +gimple_call_same_target_p (const gimple *c1, const gimple *c2) { - struct pointer_set_t *pset = (wi) ? wi->pset : NULL; - unsigned i; - tree ret = NULL_TREE; - - switch (gimple_code (stmt)) - { - case GIMPLE_ASSIGN: - /* Walk the RHS operands. If the LHS is of a non-renamable type or - is a register variable, we may use a COMPONENT_REF on the RHS. */ - if (wi) - { - tree lhs = gimple_assign_lhs (stmt); - wi->val_only - = (is_gimple_reg_type (TREE_TYPE (lhs)) && !is_gimple_reg (lhs)) - || !gimple_assign_single_p (stmt); - } - - for (i = 1; i < gimple_num_ops (stmt); i++) - { - ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, - pset); - if (ret) - return ret; - } - - /* Walk the LHS. If the RHS is appropriate for a memory, we - may use a COMPONENT_REF on the LHS. */ - if (wi) - { - /* If the RHS has more than 1 operand, it is not appropriate - for the memory. */ - wi->val_only = !is_gimple_mem_rhs (gimple_assign_rhs1 (stmt)) - || !gimple_assign_single_p (stmt); - wi->is_lhs = true; - } - - ret = walk_tree (gimple_op_ptr (stmt, 0), callback_op, wi, pset); - if (ret) - return ret; - - if (wi) - { - wi->val_only = true; - wi->is_lhs = false; - } - break; - - case GIMPLE_CALL: - if (wi) - { - wi->is_lhs = false; - wi->val_only = true; - } - - ret = walk_tree (gimple_call_chain_ptr (stmt), callback_op, wi, pset); - if (ret) - return ret; - - ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset); - if (ret) - return ret; - - for (i = 0; i < gimple_call_num_args (stmt); i++) - { - if (wi) - wi->val_only = is_gimple_reg_type (gimple_call_arg (stmt, i)); - ret = walk_tree (gimple_call_arg_ptr (stmt, i), callback_op, wi, - pset); - if (ret) - return ret; - } - - if (gimple_call_lhs (stmt)) - { - if (wi) - { - wi->is_lhs = true; - wi->val_only = is_gimple_reg_type (gimple_call_lhs (stmt)); - } - - ret = walk_tree (gimple_call_lhs_ptr (stmt), callback_op, wi, pset); - if (ret) - return ret; - } - - if (wi) - { - wi->is_lhs = false; - wi->val_only = true; - } - break; - - case GIMPLE_CATCH: - ret = walk_tree (gimple_catch_types_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - break; - - case GIMPLE_EH_FILTER: - ret = walk_tree (gimple_eh_filter_types_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - break; - - case GIMPLE_ASM: - ret = walk_gimple_asm (stmt, callback_op, wi); - if (ret) - return ret; - break; - - case GIMPLE_OMP_CONTINUE: - ret = walk_tree (gimple_omp_continue_control_def_ptr (stmt), - callback_op, wi, pset); - if (ret) - return ret; - - ret = walk_tree (gimple_omp_continue_control_use_ptr (stmt), - callback_op, wi, pset); - if (ret) - return ret; - break; - - case GIMPLE_OMP_CRITICAL: - ret = walk_tree (gimple_omp_critical_name_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - break; - - case GIMPLE_OMP_FOR: - ret = walk_tree (gimple_omp_for_clauses_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - for (i = 0; i < gimple_omp_for_collapse (stmt); i++) - { - ret = walk_tree (gimple_omp_for_index_ptr (stmt, i), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_for_initial_ptr (stmt, i), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_for_final_ptr (stmt, i), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_for_incr_ptr (stmt, i), callback_op, - wi, pset); - } - if (ret) - return ret; - break; - - case GIMPLE_OMP_PARALLEL: - ret = walk_tree (gimple_omp_parallel_clauses_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_parallel_child_fn_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_parallel_data_arg_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - break; - - case GIMPLE_OMP_TASK: - ret = walk_tree (gimple_omp_task_clauses_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_task_child_fn_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_task_data_arg_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_task_copy_fn_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_task_arg_size_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - ret = walk_tree (gimple_omp_task_arg_align_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - break; - - case GIMPLE_OMP_SECTIONS: - ret = walk_tree (gimple_omp_sections_clauses_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - - ret = walk_tree (gimple_omp_sections_control_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - - break; - - case GIMPLE_OMP_SINGLE: - ret = walk_tree (gimple_omp_single_clauses_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - break; - - case GIMPLE_OMP_ATOMIC_LOAD: - ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - - ret = walk_tree (gimple_omp_atomic_load_rhs_ptr (stmt), callback_op, wi, - pset); - if (ret) - return ret; - break; - - case GIMPLE_OMP_ATOMIC_STORE: - ret = walk_tree (gimple_omp_atomic_store_val_ptr (stmt), callback_op, - wi, pset); - if (ret) - return ret; - break; - - /* Tuples that do not have operands. */ - case GIMPLE_NOP: - case GIMPLE_RESX: - case GIMPLE_OMP_RETURN: - case GIMPLE_PREDICT: - break; - - default: - { - enum gimple_statement_structure_enum gss; - gss = gimple_statement_structure (stmt); - if (gss == GSS_WITH_OPS || gss == GSS_WITH_MEM_OPS) - for (i = 0; i < gimple_num_ops (stmt); i++) - { - ret = walk_tree (gimple_op_ptr (stmt, i), callback_op, wi, pset); - if (ret) - return ret; - } - } - break; - } - - return NULL_TREE; -} - - -/* Walk the current statement in GSI (optionally using traversal state - stored in WI). If WI is NULL, no state is kept during traversal. - The callback CALLBACK_STMT is called. If CALLBACK_STMT indicates - that it has handled all the operands of the statement, its return - value is returned. Otherwise, the return value from CALLBACK_STMT - is discarded and its operands are scanned. - - If CALLBACK_STMT is NULL or it didn't handle the operands, - CALLBACK_OP is called on each operand of the statement via - walk_gimple_op. If walk_gimple_op returns non-NULL for any - operand, the remaining operands are not scanned. In this case, the - return value from CALLBACK_OP is returned. - - In any other case, NULL_TREE is returned. */ - -tree -walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, - walk_tree_fn callback_op, struct walk_stmt_info *wi) -{ - gimple ret; - tree tree_ret; - gimple stmt = gsi_stmt (*gsi); - - if (wi) - wi->gsi = *gsi; - - if (wi && wi->want_locations && gimple_has_location (stmt)) - input_location = gimple_location (stmt); - - ret = NULL; - - /* Invoke the statement callback. Return if the callback handled - all of STMT operands by itself. */ - if (callback_stmt) - { - bool handled_ops = false; - tree_ret = callback_stmt (gsi, &handled_ops, wi); - if (handled_ops) - return tree_ret; - - /* If CALLBACK_STMT did not handle operands, it should not have - a value to return. */ - gcc_assert (tree_ret == NULL); - - /* Re-read stmt in case the callback changed it. */ - stmt = gsi_stmt (*gsi); - } - - /* If CALLBACK_OP is defined, invoke it on every operand of STMT. */ - if (callback_op) - { - tree_ret = walk_gimple_op (stmt, callback_op, wi); - if (tree_ret) - return tree_ret; - } - - /* If STMT can have statements inside (e.g. GIMPLE_BIND), walk them. */ - switch (gimple_code (stmt)) - { - case GIMPLE_BIND: - ret = walk_gimple_seq (gimple_bind_body (stmt), callback_stmt, - callback_op, wi); - if (ret) - return wi->callback_result; - break; - - case GIMPLE_CATCH: - ret = walk_gimple_seq (gimple_catch_handler (stmt), callback_stmt, - callback_op, wi); - if (ret) - return wi->callback_result; - break; - - case GIMPLE_EH_FILTER: - ret = walk_gimple_seq (gimple_eh_filter_failure (stmt), callback_stmt, - callback_op, wi); - if (ret) - return wi->callback_result; - break; - - case GIMPLE_TRY: - ret = walk_gimple_seq (gimple_try_eval (stmt), callback_stmt, callback_op, - wi); - if (ret) - return wi->callback_result; - - ret = walk_gimple_seq (gimple_try_cleanup (stmt), callback_stmt, - callback_op, wi); - if (ret) - return wi->callback_result; - break; - - case GIMPLE_OMP_FOR: - ret = walk_gimple_seq (gimple_omp_for_pre_body (stmt), callback_stmt, - callback_op, wi); - if (ret) - return wi->callback_result; - - /* FALL THROUGH. */ - case GIMPLE_OMP_CRITICAL: - case GIMPLE_OMP_MASTER: - case GIMPLE_OMP_ORDERED: - case GIMPLE_OMP_SECTION: - case GIMPLE_OMP_PARALLEL: - case GIMPLE_OMP_TASK: - case GIMPLE_OMP_SECTIONS: - case GIMPLE_OMP_SINGLE: - ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt, callback_op, - wi); - if (ret) - return wi->callback_result; - break; - - case GIMPLE_WITH_CLEANUP_EXPR: - ret = walk_gimple_seq (gimple_wce_cleanup (stmt), callback_stmt, - callback_op, wi); - if (ret) - return wi->callback_result; - break; - - default: - gcc_assert (!gimple_has_substatements (stmt)); - break; - } - - return NULL; -} - - -/* 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); - } + if (gimple_call_internal_p (c1)) + return (gimple_call_internal_p (c2) + && gimple_call_internal_fn (c1) == gimple_call_internal_fn (c2) + && (!gimple_call_internal_unique_p (as_a <const gcall *> (c1)) + || c1 == c2)); 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 (gimple_call_fn (c1) == gimple_call_fn (c2) + || (gimple_call_fndecl (c1) + && gimple_call_fndecl (c1) == gimple_call_fndecl (c2))); } /* Detect flags from a GIMPLE_CALL. This is just like call_expr_flags, but for gimple tuples. */ int -gimple_call_flags (const_gimple stmt) +gimple_call_flags (const gimple *stmt) { int flags; tree decl = gimple_call_fndecl (stmt); - tree t; if (decl) flags = flags_from_decl_or_type (decl); + else if (gimple_call_internal_p (stmt)) + flags = internal_fn_flags (gimple_call_internal_fn (stmt)); else - { - t = TREE_TYPE (gimple_call_fn (stmt)); - if (t && TREE_CODE (t) == POINTER_TYPE) - flags = flags_from_decl_or_type (TREE_TYPE (t)); - else - flags = 0; - } - - if (stmt->gsbase.subcode & GF_CALL_NOTHROW) + flags = flags_from_decl_or_type (gimple_call_fntype (stmt)); + + if (stmt->subcode & GF_CALL_NOTHROW) flags |= ECF_NOTHROW; + if (stmt->subcode & GF_CALL_BY_DESCRIPTOR) + flags |= ECF_BY_DESCRIPTOR; + return flags; } +/* Return the "fn spec" string for call STMT. */ + +static const_tree +gimple_call_fnspec (const gcall *stmt) +{ + tree type, attr; + + if (gimple_call_internal_p (stmt)) + return internal_fn_fnspec (gimple_call_internal_fn (stmt)); + + type = gimple_call_fntype (stmt); + if (!type) + return NULL_TREE; + + attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); + if (!attr) + return NULL_TREE; + + return TREE_VALUE (TREE_VALUE (attr)); +} + /* Detects argument flags for argument number ARG on call STMT. */ int -gimple_call_arg_flags (const_gimple stmt, unsigned arg) +gimple_call_arg_flags (const gcall *stmt, unsigned arg) { - tree type = TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt))); - tree attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); - if (!attr) - return 0; - - attr = TREE_VALUE (TREE_VALUE (attr)); - if (1 + arg >= (unsigned) TREE_STRING_LENGTH (attr)) + const_tree attr = gimple_call_fnspec (stmt); + + if (!attr || 1 + arg >= (unsigned) TREE_STRING_LENGTH (attr)) return 0; switch (TREE_STRING_POINTER (attr)[1 + arg]) @@ -1840,21 +1470,15 @@ /* Detects return flags for the call STMT. */ int -gimple_call_return_flags (const_gimple stmt) +gimple_call_return_flags (const gcall *stmt) { - tree type; - tree attr = NULL_TREE; + const_tree attr; if (gimple_call_flags (stmt) & ECF_MALLOC) return ERF_NOALIAS; - type = TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt))); - attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); - if (!attr) - return 0; - - attr = TREE_VALUE (TREE_VALUE (attr)); - if (TREE_STRING_LENGTH (attr) < 1) + attr = gimple_call_fnspec (stmt); + if (!attr || TREE_STRING_LENGTH (attr) < 1) return 0; switch (TREE_STRING_POINTER (attr)[0]) @@ -1878,7 +1502,7 @@ /* Return true if GS is a copy assignment. */ bool -gimple_assign_copy_p (gimple gs) +gimple_assign_copy_p (gimple *gs) { return (gimple_assign_single_p (gs) && is_gimple_val (gimple_op (gs, 1))); @@ -1888,7 +1512,7 @@ /* Return true if GS is a SSA_NAME copy assignment. */ bool -gimple_assign_ssa_name_copy_p (gimple gs) +gimple_assign_ssa_name_copy_p (gimple *gs) { return (gimple_assign_single_p (gs) && TREE_CODE (gimple_assign_lhs (gs)) == SSA_NAME @@ -1911,7 +1535,7 @@ treatment of unary NOPs is appropriate. */ bool -gimple_assign_unary_nop_p (gimple gs) +gimple_assign_unary_nop_p (gimple *gs) { return (is_gimple_assign (gs) && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (gs)) @@ -1924,33 +1548,37 @@ /* Set BB to be the basic block holding G. */ void -gimple_set_bb (gimple stmt, basic_block bb) +gimple_set_bb (gimple *stmt, basic_block bb) { - stmt->gsbase.bb = bb; + stmt->bb = bb; + + if (gimple_code (stmt) != GIMPLE_LABEL) + return; /* If the statement is a label, add the label to block-to-labels map so that we can speed up edge creation for GIMPLE_GOTOs. */ - if (cfun->cfg && gimple_code (stmt) == GIMPLE_LABEL) + if (cfun->cfg) { tree t; int uid; - t = gimple_label_label (stmt); + t = gimple_label_label (as_a <glabel *> (stmt)); uid = LABEL_DECL_UID (t); if (uid == -1) { - unsigned old_len = VEC_length (basic_block, label_to_block_map); + unsigned old_len = + vec_safe_length (label_to_block_map_for_fn (cfun)); LABEL_DECL_UID (t) = uid = cfun->cfg->last_label_uid++; if (old_len <= (unsigned) uid) { unsigned new_len = 3 * uid / 2 + 1; - VEC_safe_grow_cleared (basic_block, gc, label_to_block_map, + vec_safe_grow_cleared (label_to_block_map_for_fn (cfun), new_len); } } - VEC_replace (basic_block, label_to_block_map, uid, bb); + (*label_to_block_map_for_fn (cfun))[uid] = bb; } } @@ -1978,8 +1606,8 @@ enum tree_code subcode; tree op1, op2, op3; - extract_ops_from_tree_1 (expr, &subcode, &op1, &op2, &op3); - gimple_assign_set_rhs_with_ops_1 (gsi, subcode, op1, op2, op3); + extract_ops_from_tree (expr, &subcode, &op1, &op2, &op3); + gimple_assign_set_rhs_with_ops (gsi, subcode, op1, op2, op3); } @@ -1990,19 +1618,20 @@ did not have enough operand slots. */ void -gimple_assign_set_rhs_with_ops_1 (gimple_stmt_iterator *gsi, enum tree_code code, - tree op1, tree op2, tree op3) +gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code, + tree op1, tree op2, tree op3) { unsigned new_rhs_ops = get_gimple_rhs_num_ops (code); - gimple stmt = gsi_stmt (*gsi); + gimple *stmt = gsi_stmt (*gsi); /* If the new CODE needs more operands, allocate a new statement. */ if (gimple_num_ops (stmt) < new_rhs_ops + 1) { tree lhs = gimple_assign_lhs (stmt); - gimple new_stmt = gimple_alloc (gimple_code (stmt), new_rhs_ops + 1); + gimple *new_stmt = gimple_alloc (gimple_code (stmt), new_rhs_ops + 1); memcpy (new_stmt, stmt, gimple_size (gimple_code (stmt))); - gsi_replace (gsi, new_stmt, true); + gimple_init_singleton (new_stmt); + gsi_replace (gsi, new_stmt, false); stmt = new_stmt; /* The LHS needs to be reset as this also changes the SSA name @@ -2026,7 +1655,7 @@ statement other than an assignment or a call. */ tree -gimple_get_lhs (const_gimple stmt) +gimple_get_lhs (const gimple *stmt) { enum gimple_code code = gimple_code (stmt); @@ -2043,7 +1672,7 @@ either a GIMPLE_ASSIGN or a GIMPLE_CALL. */ void -gimple_set_lhs (gimple stmt, tree lhs) +gimple_set_lhs (gimple *stmt, tree lhs) { enum gimple_code code = gimple_code (stmt); @@ -2052,57 +1681,26 @@ else if (code == GIMPLE_CALL) gimple_call_set_lhs (stmt, lhs); else - gcc_unreachable(); + gcc_unreachable (); } -/* Replace the LHS of STMT, an assignment, either a GIMPLE_ASSIGN or a - GIMPLE_CALL, with NLHS, in preparation for modifying the RHS to an - expression with a different value. - - This will update any annotations (say debug bind stmts) referring - to the original LHS, so that they use the RHS instead. This is - done even if NLHS and LHS are the same, for it is understood that - the RHS will be modified afterwards, and NLHS will not be assigned - an equivalent value. - - Adjusting any non-annotation uses of the LHS, if needed, is a - responsibility of the caller. - - The effect of this call should be pretty much the same as that of - inserting a copy of STMT before STMT, and then removing the - original stmt, at which time gsi_remove() would have update - annotations, but using this function saves all the inserting, - copying and removing. */ - -void -gimple_replace_lhs (gimple stmt, tree nlhs) -{ - if (MAY_HAVE_DEBUG_STMTS) - { - tree lhs = gimple_get_lhs (stmt); - - gcc_assert (SSA_NAME_DEF_STMT (lhs) == stmt); - - insert_debug_temp_for_var_def (NULL, lhs); - } - - gimple_set_lhs (stmt, nlhs); -} /* Return a deep copy of statement STMT. All the operands from STMT are reallocated and copied using unshare_expr. The DEF, USE, VDEF - and VUSE operand arrays are set to empty in the new copy. */ - -gimple -gimple_copy (gimple stmt) + and VUSE operand arrays are set to empty in the new copy. The new + copy isn't part of any sequence. */ + +gimple * +gimple_copy (gimple *stmt) { enum gimple_code code = gimple_code (stmt); unsigned num_ops = gimple_num_ops (stmt); - gimple copy = gimple_alloc (code, num_ops); + gimple *copy = gimple_alloc (code, num_ops); unsigned i; /* Shallow copy all the fields from STMT. */ memcpy (copy, stmt, gimple_size (code)); + gimple_init_singleton (copy); /* If STMT has sub-statements, deep-copy them as well. */ if (gimple_has_substatements (stmt)) @@ -2113,31 +1711,60 @@ switch (gimple_code (stmt)) { case GIMPLE_BIND: - new_seq = gimple_seq_copy (gimple_bind_body (stmt)); - gimple_bind_set_body (copy, new_seq); - gimple_bind_set_vars (copy, unshare_expr (gimple_bind_vars (stmt))); - gimple_bind_set_block (copy, gimple_bind_block (stmt)); + { + gbind *bind_stmt = as_a <gbind *> (stmt); + gbind *bind_copy = as_a <gbind *> (copy); + new_seq = gimple_seq_copy (gimple_bind_body (bind_stmt)); + gimple_bind_set_body (bind_copy, new_seq); + gimple_bind_set_vars (bind_copy, + unshare_expr (gimple_bind_vars (bind_stmt))); + gimple_bind_set_block (bind_copy, gimple_bind_block (bind_stmt)); + } break; case GIMPLE_CATCH: - new_seq = gimple_seq_copy (gimple_catch_handler (stmt)); - gimple_catch_set_handler (copy, new_seq); - t = unshare_expr (gimple_catch_types (stmt)); - gimple_catch_set_types (copy, t); + { + gcatch *catch_stmt = as_a <gcatch *> (stmt); + gcatch *catch_copy = as_a <gcatch *> (copy); + new_seq = gimple_seq_copy (gimple_catch_handler (catch_stmt)); + gimple_catch_set_handler (catch_copy, new_seq); + t = unshare_expr (gimple_catch_types (catch_stmt)); + gimple_catch_set_types (catch_copy, t); + } break; case GIMPLE_EH_FILTER: - new_seq = gimple_seq_copy (gimple_eh_filter_failure (stmt)); - gimple_eh_filter_set_failure (copy, new_seq); - t = unshare_expr (gimple_eh_filter_types (stmt)); - gimple_eh_filter_set_types (copy, t); + { + geh_filter *eh_filter_stmt = as_a <geh_filter *> (stmt); + geh_filter *eh_filter_copy = as_a <geh_filter *> (copy); + new_seq + = gimple_seq_copy (gimple_eh_filter_failure (eh_filter_stmt)); + gimple_eh_filter_set_failure (eh_filter_copy, new_seq); + t = unshare_expr (gimple_eh_filter_types (eh_filter_stmt)); + gimple_eh_filter_set_types (eh_filter_copy, t); + } + break; + + case GIMPLE_EH_ELSE: + { + geh_else *eh_else_stmt = as_a <geh_else *> (stmt); + geh_else *eh_else_copy = as_a <geh_else *> (copy); + new_seq = gimple_seq_copy (gimple_eh_else_n_body (eh_else_stmt)); + gimple_eh_else_set_n_body (eh_else_copy, new_seq); + new_seq = gimple_seq_copy (gimple_eh_else_e_body (eh_else_stmt)); + gimple_eh_else_set_e_body (eh_else_copy, new_seq); + } break; case GIMPLE_TRY: - new_seq = gimple_seq_copy (gimple_try_eval (stmt)); - gimple_try_set_eval (copy, new_seq); - new_seq = gimple_seq_copy (gimple_try_cleanup (stmt)); - gimple_try_set_cleanup (copy, new_seq); + { + gtry *try_stmt = as_a <gtry *> (stmt); + gtry *try_copy = as_a <gtry *> (copy); + new_seq = gimple_seq_copy (gimple_try_eval (try_stmt)); + gimple_try_set_eval (try_copy, new_seq); + new_seq = gimple_seq_copy (gimple_try_cleanup (try_stmt)); + gimple_try_set_cleanup (try_copy, new_seq); + } break; case GIMPLE_OMP_FOR: @@ -2145,9 +1772,11 @@ gimple_omp_for_set_pre_body (copy, new_seq); t = unshare_expr (gimple_omp_for_clauses (stmt)); gimple_omp_for_set_clauses (copy, t); - copy->gimple_omp_for.iter - = ggc_alloc_vec_gimple_omp_for_iter - (gimple_omp_for_collapse (stmt)); + { + gomp_for *omp_for_copy = as_a <gomp_for *> (copy); + omp_for_copy->iter = ggc_vec_alloc<gimple_omp_for_iter> + ( gimple_omp_for_collapse (stmt)); + } for (i = 0; i < gimple_omp_for_collapse (stmt); i++) { gimple_omp_for_set_cond (copy, i, @@ -2164,12 +1793,16 @@ goto copy_omp_body; case GIMPLE_OMP_PARALLEL: - t = unshare_expr (gimple_omp_parallel_clauses (stmt)); - gimple_omp_parallel_set_clauses (copy, t); - t = unshare_expr (gimple_omp_parallel_child_fn (stmt)); - gimple_omp_parallel_set_child_fn (copy, t); - t = unshare_expr (gimple_omp_parallel_data_arg (stmt)); - gimple_omp_parallel_set_data_arg (copy, t); + { + gomp_parallel *omp_par_stmt = as_a <gomp_parallel *> (stmt); + gomp_parallel *omp_par_copy = as_a <gomp_parallel *> (copy); + t = unshare_expr (gimple_omp_parallel_clauses (omp_par_stmt)); + gimple_omp_parallel_set_clauses (omp_par_copy, t); + t = unshare_expr (gimple_omp_parallel_child_fn (omp_par_stmt)); + gimple_omp_parallel_set_child_fn (omp_par_copy, t); + t = unshare_expr (gimple_omp_parallel_data_arg (omp_par_stmt)); + gimple_omp_parallel_set_data_arg (omp_par_copy, t); + } goto copy_omp_body; case GIMPLE_OMP_TASK: @@ -2188,8 +1821,18 @@ goto copy_omp_body; case GIMPLE_OMP_CRITICAL: - t = unshare_expr (gimple_omp_critical_name (stmt)); - gimple_omp_critical_set_name (copy, t); + t = unshare_expr (gimple_omp_critical_name + (as_a <gomp_critical *> (stmt))); + gimple_omp_critical_set_name (as_a <gomp_critical *> (copy), t); + t = unshare_expr (gimple_omp_critical_clauses + (as_a <gomp_critical *> (stmt))); + gimple_omp_critical_set_clauses (as_a <gomp_critical *> (copy), t); + goto copy_omp_body; + + case GIMPLE_OMP_ORDERED: + t = unshare_expr (gimple_omp_ordered_clauses + (as_a <gomp_ordered *> (stmt))); + gimple_omp_ordered_set_clauses (as_a <gomp_ordered *> (copy), t); goto copy_omp_body; case GIMPLE_OMP_SECTIONS: @@ -2197,17 +1840,51 @@ gimple_omp_sections_set_clauses (copy, t); t = unshare_expr (gimple_omp_sections_control (stmt)); gimple_omp_sections_set_control (copy, t); - /* FALLTHRU */ + goto copy_omp_body; case GIMPLE_OMP_SINGLE: + { + gomp_single *omp_single_copy = as_a <gomp_single *> (copy); + t = unshare_expr (gimple_omp_single_clauses (stmt)); + gimple_omp_single_set_clauses (omp_single_copy, t); + } + goto copy_omp_body; + + case GIMPLE_OMP_TARGET: + { + gomp_target *omp_target_stmt = as_a <gomp_target *> (stmt); + gomp_target *omp_target_copy = as_a <gomp_target *> (copy); + t = unshare_expr (gimple_omp_target_clauses (omp_target_stmt)); + gimple_omp_target_set_clauses (omp_target_copy, t); + t = unshare_expr (gimple_omp_target_data_arg (omp_target_stmt)); + gimple_omp_target_set_data_arg (omp_target_copy, t); + } + goto copy_omp_body; + + case GIMPLE_OMP_TEAMS: + { + gomp_teams *omp_teams_copy = as_a <gomp_teams *> (copy); + t = unshare_expr (gimple_omp_teams_clauses (stmt)); + gimple_omp_teams_set_clauses (omp_teams_copy, t); + } + /* FALLTHRU */ + case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: - case GIMPLE_OMP_ORDERED: + case GIMPLE_OMP_TASKGROUP: + case GIMPLE_OMP_GRID_BODY: copy_omp_body: new_seq = gimple_seq_copy (gimple_omp_body (stmt)); gimple_omp_set_body (copy, new_seq); break; + case GIMPLE_TRANSACTION: + new_seq = gimple_seq_copy (gimple_transaction_body ( + as_a <gtransaction *> (stmt))); + gimple_transaction_set_body (as_a <gtransaction *> (copy), + new_seq); + break; + case GIMPLE_WITH_CLEANUP_EXPR: new_seq = gimple_seq_copy (gimple_wce_cleanup (stmt)); gimple_wce_set_cleanup (copy, new_seq); @@ -2219,23 +1896,19 @@ } /* Make copy of operands. */ - if (num_ops > 0) + for (i = 0; i < num_ops; i++) + gimple_set_op (copy, i, unshare_expr (gimple_op (stmt, i))); + + if (gimple_has_mem_ops (stmt)) { - for (i = 0; i < num_ops; i++) - gimple_set_op (copy, i, unshare_expr (gimple_op (stmt, i))); - - /* Clear out SSA operand vectors on COPY. */ - if (gimple_has_ops (stmt)) - { - gimple_set_def_ops (copy, NULL); - gimple_set_use_ops (copy, NULL); - } - - if (gimple_has_mem_ops (stmt)) - { - gimple_set_vdef (copy, gimple_vdef (stmt)); - gimple_set_vuse (copy, gimple_vuse (stmt)); - } + gimple_set_vdef (copy, gimple_vdef (stmt)); + gimple_set_vuse (copy, gimple_vuse (stmt)); + } + + /* Clear out SSA operand vectors on COPY. */ + if (gimple_has_ops (stmt)) + { + gimple_set_use_ops (copy, NULL); /* SSA operands need to be updated. */ gimple_set_modified (copy, true); @@ -2245,25 +1918,6 @@ } -/* Set the MODIFIED flag to MODIFIEDP, iff the gimple statement G has - a MODIFIED field. */ - -void -gimple_set_modified (gimple s, bool modifiedp) -{ - if (gimple_has_ops (s)) - { - s->gsbase.modified = (unsigned) modifiedp; - - if (modifiedp - && cfun->gimple_df - && is_gimple_call (s) - && gimple_call_noreturn_p (s)) - VEC_safe_push (gimple, gc, MODIFIED_NORETURN_CALLS (cfun), s); - } -} - - /* Return true if statement S has side-effects. We consider a statement to have side effects if: @@ -2271,10 +1925,8 @@ - Any of its operands are marked TREE_THIS_VOLATILE or TREE_SIDE_EFFECTS. */ bool -gimple_has_side_effects (const_gimple s) +gimple_has_side_effects (const gimple *s) { - unsigned i; - if (is_gimple_debug (s)) return false; @@ -2284,106 +1936,21 @@ if (gimple_has_volatile_ops (s)) return true; - if (is_gimple_call (s)) - { - unsigned nargs = gimple_call_num_args (s); - - if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE))) - return true; - else if (gimple_call_flags (s) & ECF_LOOPING_CONST_OR_PURE) - /* An infinite loop is considered a side effect. */ - return true; - - if (gimple_call_lhs (s) - && TREE_SIDE_EFFECTS (gimple_call_lhs (s))) - { - gcc_assert (gimple_has_volatile_ops (s)); - return true; - } - - if (TREE_SIDE_EFFECTS (gimple_call_fn (s))) - return true; - - for (i = 0; i < nargs; i++) - if (TREE_SIDE_EFFECTS (gimple_call_arg (s, i))) - { - gcc_assert (gimple_has_volatile_ops (s)); - return true; - } - - return false; - } - else - { - for (i = 0; i < gimple_num_ops (s); i++) - if (TREE_SIDE_EFFECTS (gimple_op (s, i))) - { - gcc_assert (gimple_has_volatile_ops (s)); - return true; - } - } - - return false; -} - -/* Return true if the RHS of statement S has side effects. - We may use it to determine if it is admissable to replace - an assignment or call with a copy of a previously-computed - value. In such cases, side-effects due the the LHS are - preserved. */ - -bool -gimple_rhs_has_side_effects (const_gimple s) -{ - unsigned i; + if (gimple_code (s) == GIMPLE_ASM + && gimple_asm_volatile_p (as_a <const gasm *> (s))) + return true; if (is_gimple_call (s)) { - unsigned nargs = gimple_call_num_args (s); - - if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE))) - return true; - - /* We cannot use gimple_has_volatile_ops here, - because we must ignore a volatile LHS. */ - if (TREE_SIDE_EFFECTS (gimple_call_fn (s)) - || TREE_THIS_VOLATILE (gimple_call_fn (s))) - { - gcc_assert (gimple_has_volatile_ops (s)); - return true; - } - - for (i = 0; i < nargs; i++) - if (TREE_SIDE_EFFECTS (gimple_call_arg (s, i)) - || TREE_THIS_VOLATILE (gimple_call_arg (s, i))) - return true; + int flags = gimple_call_flags (s); + + /* An infinite loop is considered a side effect. */ + if (!(flags & (ECF_CONST | ECF_PURE)) + || (flags & ECF_LOOPING_CONST_OR_PURE)) + return true; return false; } - else if (is_gimple_assign (s)) - { - /* Skip the first operand, the LHS. */ - for (i = 1; i < gimple_num_ops (s); i++) - if (TREE_SIDE_EFFECTS (gimple_op (s, i)) - || TREE_THIS_VOLATILE (gimple_op (s, i))) - { - gcc_assert (gimple_has_volatile_ops (s)); - return true; - } - } - else if (is_gimple_debug (s)) - return false; - else - { - /* For statements without an LHS, examine all arguments. */ - for (i = 0; i < gimple_num_ops (s); i++) - if (TREE_SIDE_EFFECTS (gimple_op (s, i)) - || TREE_THIS_VOLATILE (gimple_op (s, i))) - { - gcc_assert (gimple_has_volatile_ops (s)); - return true; - } - } return false; } @@ -2394,7 +1961,7 @@ S is a GIMPLE_ASSIGN, the LHS of the assignment is also checked. */ bool -gimple_could_trap_p_1 (gimple s, bool include_mem, bool include_stores) +gimple_could_trap_p_1 (gimple *s, bool include_mem, bool include_stores) { tree t, div = NULL_TREE; enum tree_code op; @@ -2411,7 +1978,7 @@ switch (gimple_code (s)) { case GIMPLE_ASM: - return gimple_asm_volatile_p (s); + return gimple_asm_volatile_p (as_a <gasm *> (s)); case GIMPLE_CALL: t = gimple_call_fndecl (s); @@ -2430,6 +1997,11 @@ && TYPE_OVERFLOW_TRAPS (t)), div)); + case GIMPLE_COND: + t = TREE_TYPE (gimple_cond_lhs (s)); + return operation_could_trap_p (gimple_cond_code (s), + FLOAT_TYPE_P (t), false, NULL_TREE); + default: break; } @@ -2440,7 +2012,7 @@ /* Return true if statement S can trap. */ bool -gimple_could_trap_p (gimple s) +gimple_could_trap_p (gimple *s) { return gimple_could_trap_p_1 (s, true, true); } @@ -2448,7 +2020,7 @@ /* Return true if RHS of a GIMPLE_ASSIGN S can trap. */ bool -gimple_assign_rhs_could_trap_p (gimple s) +gimple_assign_rhs_could_trap_p (gimple *s) { gcc_assert (is_gimple_assign (s)); return gimple_could_trap_p_1 (s, true, false); @@ -2460,9 +2032,14 @@ void dump_gimple_statistics (void) { -#ifdef GATHER_STATISTICS int i, total_tuples = 0, total_bytes = 0; + if (! GATHER_STATISTICS) + { + fprintf (stderr, "No gimple statistics\n"); + return; + } + fprintf (stderr, "\nGIMPLE statements\n"); fprintf (stderr, "Kind Stmts Bytes\n"); fprintf (stderr, "---------------------------------------\n"); @@ -2476,9 +2053,6 @@ fprintf (stderr, "---------------------------------------\n"); fprintf (stderr, "%-20s %7d %10d\n", "Total", total_tuples, total_bytes); fprintf (stderr, "---------------------------------------\n"); -#else - fprintf (stderr, "No gimple statistics\n"); -#endif } @@ -2512,20 +2086,22 @@ || (SYM) == TRUTH_OR_EXPR \ || (SYM) == TRUTH_XOR_EXPR) ? GIMPLE_BINARY_RHS \ : (SYM) == TRUTH_NOT_EXPR ? GIMPLE_UNARY_RHS \ - : ((SYM) == WIDEN_MULT_PLUS_EXPR \ + : ((SYM) == COND_EXPR \ + || (SYM) == WIDEN_MULT_PLUS_EXPR \ || (SYM) == WIDEN_MULT_MINUS_EXPR \ + || (SYM) == DOT_PROD_EXPR \ + || (SYM) == SAD_EXPR \ + || (SYM) == REALIGN_LOAD_EXPR \ + || (SYM) == VEC_COND_EXPR \ + || (SYM) == VEC_PERM_EXPR \ + || (SYM) == BIT_INSERT_EXPR \ || (SYM) == FMA_EXPR) ? GIMPLE_TERNARY_RHS \ - : ((SYM) == COND_EXPR \ - || (SYM) == CONSTRUCTOR \ + : ((SYM) == CONSTRUCTOR \ || (SYM) == OBJ_TYPE_REF \ || (SYM) == ASSERT_EXPR \ || (SYM) == ADDR_EXPR \ || (SYM) == WITH_SIZE_EXPR \ - || (SYM) == SSA_NAME \ - || (SYM) == POLYNOMIAL_CHREC \ - || (SYM) == DOT_PROD_EXPR \ - || (SYM) == VEC_COND_EXPR \ - || (SYM) == REALIGN_LOAD_EXPR) ? GIMPLE_SINGLE_RHS \ + || (SYM) == SSA_NAME) ? GIMPLE_SINGLE_RHS \ : GIMPLE_INVALID_RHS), #define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS, @@ -2536,523 +2112,6 @@ #undef DEFTREECODE #undef END_OF_BASE_TREE_CODES -/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi. */ - -/* Validation of GIMPLE expressions. */ - -/* 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; -} - -/* Returns true iff T is a valid RHS for an assignment to an un-renamed - LHS, or for a call argument. */ - -bool -is_gimple_mem_rhs (tree t) -{ - /* If we're dealing with a renamable type, either source or dest must be - a renamed variable. */ - if (is_gimple_reg_type (TREE_TYPE (t))) - return is_gimple_val (t); - else - return is_gimple_val (t) || is_gimple_lvalue (t); -} - -/* 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_trap_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; - - /* Vector constant constructors are gimple invariant. */ - case CONSTRUCTOR: - if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) - return TREE_CONSTANT (t); - else - return false; - - 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; - } -} - -/* Strip out all handled components that produce invariant - offsets. */ - -static const_tree -strip_invariant_refs (const_tree op) -{ - while (handled_component_p (op)) - { - switch (TREE_CODE (op)) - { - case ARRAY_REF: - case ARRAY_RANGE_REF: - if (!is_gimple_constant (TREE_OPERAND (op, 1)) - || TREE_OPERAND (op, 2) != NULL_TREE - || TREE_OPERAND (op, 3) != NULL_TREE) - return NULL; - break; - - case COMPONENT_REF: - if (TREE_OPERAND (op, 2) != NULL_TREE) - return NULL; - break; - - default:; - } - op = TREE_OPERAND (op, 0); - } - - return op; -} - -/* 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)); - - return op && (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 looks like a valid GIMPLE statement. */ - -bool -is_gimple_stmt (tree t) -{ - const enum tree_code code = TREE_CODE (t); - - switch (code) - { - case NOP_EXPR: - /* The only valid NOP_EXPR is the empty statement. */ - return IS_EMPTY_STMT (t); - - case BIND_EXPR: - case COND_EXPR: - /* These are only valid if they're void. */ - return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t)); - - case SWITCH_EXPR: - case GOTO_EXPR: - case RETURN_EXPR: - case LABEL_EXPR: - case CASE_LABEL_EXPR: - case TRY_CATCH_EXPR: - case TRY_FINALLY_EXPR: - case EH_FILTER_EXPR: - case CATCH_EXPR: - case ASM_EXPR: - case STATEMENT_LIST: - case OMP_PARALLEL: - case OMP_FOR: - case OMP_SECTIONS: - case OMP_SECTION: - case OMP_SINGLE: - case OMP_MASTER: - case OMP_ORDERED: - case OMP_CRITICAL: - case OMP_TASK: - /* These are always void. */ - return true; - - case CALL_EXPR: - case MODIFY_EXPR: - case PREDICT_EXPR: - /* These are valid regardless of their type. */ - return true; - - default: - return false; - } -} - -/* 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 TYPE is a suitable type for a scalar register variable. */ - -bool -is_gimple_reg_type (tree type) -{ - return !AGGREGATE_TYPE_P (type); -} - -/* Return true if T is a non-aggregate register variable. */ - -bool -is_gimple_reg (tree t) -{ - if (TREE_CODE (t) == SSA_NAME) - t = SSA_NAME_VAR (t); - - 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 variable whose address is not needed. */ - -bool -is_gimple_non_addressable (tree t) -{ - if (TREE_CODE (t) == SSA_NAME) - t = SSA_NAME_VAR (t); - - return (is_gimple_variable (t) && ! needs_to_live_in_memory (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))))); -} - -/* If T makes a function call, return the corresponding CALL_EXPR operand. - Otherwise, return NULL_TREE. */ - -tree -get_call_expr_in (tree t) -{ - if (TREE_CODE (t) == MODIFY_EXPR) - t = TREE_OPERAND (t, 1); - if (TREE_CODE (t) == WITH_SIZE_EXPR) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == CALL_EXPR) - return t; - return NULL_TREE; -} - - -/* 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 - 'array[i].fld[j]' is 'array'. You can think of this as stripping - away the offset part from a memory address. - - This function calls handled_component_p to strip away all the inner - parts of the memory reference until it reaches the base object. */ - -tree -get_base_address (tree t) -{ - while (handled_component_p (t)) - t = TREE_OPERAND (t, 0); - - if ((TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == TARGET_MEM_REF) - && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR) - t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); - - if (TREE_CODE (t) == SSA_NAME - || DECL_P (t) - || TREE_CODE (t) == STRING_CST - || TREE_CODE (t) == CONSTRUCTOR - || INDIRECT_REF_P (t) - || TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == TARGET_MEM_REF) - return t; - else - return NULL_TREE; -} - -void -recalculate_side_effects (tree t) -{ - enum tree_code code = TREE_CODE (t); - int len = TREE_OPERAND_LENGTH (t); - int i; - - switch (TREE_CODE_CLASS (code)) - { - case tcc_expression: - switch (code) - { - case INIT_EXPR: - case MODIFY_EXPR: - case VA_ARG_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - /* All of these have side-effects, no matter what their - operands are. */ - return; - - default: - break; - } - /* Fall through. */ - - case tcc_comparison: /* a comparison expression */ - case tcc_unary: /* a unary arithmetic expression */ - case tcc_binary: /* a binary arithmetic expression */ - case tcc_reference: /* a reference */ - case tcc_vl_exp: /* a function call */ - TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); - for (i = 0; i < len; ++i) - { - tree op = TREE_OPERAND (t, i); - if (op && TREE_SIDE_EFFECTS (op)) - TREE_SIDE_EFFECTS (t) = 1; - } - break; - - case tcc_constant: - /* No side-effects. */ - return; - - default: - gcc_unreachable (); - } -} - /* Canonicalize a tree T for use in a COND_EXPR as conditional. Returns a canonicalized tree that is valid for a COND_EXPR or NULL_TREE, if we failed to create one. */ @@ -3062,19 +2121,13 @@ { /* Strip conversions around boolean operations. */ if (CONVERT_EXPR_P (t) - && truth_value_p (TREE_CODE (TREE_OPERAND (t, 0)))) + && (truth_value_p (TREE_CODE (TREE_OPERAND (t, 0))) + || TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) + == BOOLEAN_TYPE)) t = TREE_OPERAND (t, 0); - /* For (bool)x use x != 0. */ - if (CONVERT_EXPR_P (t) - && TREE_CODE (TREE_TYPE (t)) == BOOLEAN_TYPE) - { - tree top0 = TREE_OPERAND (t, 0); - t = build2 (NE_EXPR, TREE_TYPE (t), - top0, build_int_cst (TREE_TYPE (top0), 0)); - } /* For !x use x == 0. */ - else if (TREE_CODE (t) == TRUTH_NOT_EXPR) + if (TREE_CODE (t) == TRUTH_NOT_EXPR) { tree top0 = TREE_OPERAND (t, 0); t = build2 (EQ_EXPR, TREE_TYPE (t), @@ -3090,7 +2143,11 @@ t = build2 (TREE_CODE (top0), TREE_TYPE (t), TREE_OPERAND (top0, 0), TREE_OPERAND (top0, 1)); } - + /* For x ^ y use x != y. */ + else if (TREE_CODE (t) == BIT_XOR_EXPR) + t = build2 (NE_EXPR, TREE_TYPE (t), + TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)); + if (is_gimple_condexpr (t)) return t; @@ -3100,28 +2157,30 @@ /* Build a GIMPLE_CALL identical to STMT but skipping the arguments in the positions marked by the set ARGS_TO_SKIP. */ -gimple -gimple_call_copy_skip_args (gimple stmt, bitmap args_to_skip) +gcall * +gimple_call_copy_skip_args (gcall *stmt, bitmap args_to_skip) { int i; - tree fn = gimple_call_fn (stmt); int nargs = gimple_call_num_args (stmt); - VEC(tree, heap) *vargs = VEC_alloc (tree, heap, nargs); - gimple new_stmt; + auto_vec<tree> vargs (nargs); + gcall *new_stmt; for (i = 0; i < nargs; i++) if (!bitmap_bit_p (args_to_skip, i)) - VEC_quick_push (tree, vargs, gimple_call_arg (stmt, i)); - - new_stmt = gimple_build_call_vec (fn, vargs); - VEC_free (tree, heap, vargs); + vargs.quick_push (gimple_call_arg (stmt, i)); + + if (gimple_call_internal_p (stmt)) + new_stmt = gimple_build_call_internal_vec (gimple_call_internal_fn (stmt), + vargs); + else + new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs); + if (gimple_call_lhs (stmt)) gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); gimple_set_vuse (new_stmt, gimple_vuse (stmt)); gimple_set_vdef (new_stmt, gimple_vdef (stmt)); - gimple_set_block (new_stmt, gimple_block (stmt)); if (gimple_has_location (stmt)) gimple_set_location (new_stmt, gimple_location (stmt)); gimple_call_copy_flags (new_stmt, stmt); @@ -3133,182 +2192,10 @@ } -static hashval_t gimple_type_hash_1 (const void *, enum gtc_mode); - -/* Structure used to maintain a cache of some type pairs compared by - gimple_types_compatible_p when comparing aggregate types. There are - three possible values for SAME_P: - - -2: The pair (T1, T2) has just been inserted in the table. - 0: T1 and T2 are different types. - 1: T1 and T2 are the same type. - - The two elements in the SAME_P array are indexed by the comparison - mode gtc_mode. */ - -struct type_pair_d -{ - unsigned int uid1; - unsigned int uid2; - signed char same_p[2]; -}; -typedef struct type_pair_d *type_pair_t; - -DEF_VEC_P(type_pair_t); -DEF_VEC_ALLOC_P(type_pair_t,heap); - -/* Return a hash value for the type pair pointed-to by P. */ - -static hashval_t -type_pair_hash (const void *p) -{ - const struct type_pair_d *pair = (const struct type_pair_d *) p; - hashval_t val1 = pair->uid1; - hashval_t val2 = pair->uid2; - return (iterative_hash_hashval_t (val2, val1) - ^ iterative_hash_hashval_t (val1, val2)); -} - -/* Compare two type pairs pointed-to by P1 and P2. */ - -static int -type_pair_eq (const void *p1, const void *p2) -{ - const struct type_pair_d *pair1 = (const struct type_pair_d *) p1; - const struct type_pair_d *pair2 = (const struct type_pair_d *) p2; - return ((pair1->uid1 == pair2->uid1 && pair1->uid2 == pair2->uid2) - || (pair1->uid1 == pair2->uid2 && pair1->uid2 == pair2->uid1)); -} - -/* Lookup the pair of types T1 and T2 in *VISITED_P. Insert a new - entry if none existed. */ - -static type_pair_t -lookup_type_pair (tree t1, tree t2, htab_t *visited_p, struct obstack *ob_p) -{ - struct type_pair_d pair; - type_pair_t p; - void **slot; - - if (*visited_p == NULL) - { - *visited_p = htab_create (251, type_pair_hash, type_pair_eq, NULL); - gcc_obstack_init (ob_p); - } - - pair.uid1 = TYPE_UID (t1); - pair.uid2 = TYPE_UID (t2); - slot = htab_find_slot (*visited_p, &pair, INSERT); - - if (*slot) - p = *((type_pair_t *) slot); - else - { - p = XOBNEW (ob_p, struct type_pair_d); - p->uid1 = TYPE_UID (t1); - p->uid2 = TYPE_UID (t2); - p->same_p[0] = -2; - p->same_p[1] = -2; - *slot = (void *) p; - } - - return p; -} - -/* Per pointer state for the SCC finding. The on_sccstack flag - is not strictly required, it is true when there is no hash value - recorded for the type and false otherwise. But querying that - is slower. */ - -struct sccs -{ - unsigned int dfsnum; - unsigned int low; - bool on_sccstack; - union { - hashval_t hash; - signed char same_p; - } u; -}; - -static unsigned int next_dfs_num; -static unsigned int gtc_next_dfs_num; - - -/* GIMPLE type merging cache. A direct-mapped cache based on TYPE_UID. */ - -typedef struct GTY(()) gimple_type_leader_entry_s { - tree type; - tree leader; -} gimple_type_leader_entry; - -#define GIMPLE_TYPE_LEADER_SIZE 16381 -static GTY((length("GIMPLE_TYPE_LEADER_SIZE"))) gimple_type_leader_entry - *gimple_type_leader; - -/* Lookup an existing leader for T and return it or NULL_TREE, if - there is none in the cache. */ - -static tree -gimple_lookup_type_leader (tree t) -{ - gimple_type_leader_entry *leader; - - if (!gimple_type_leader) - return NULL_TREE; - - leader = &gimple_type_leader[TYPE_UID (t) % GIMPLE_TYPE_LEADER_SIZE]; - if (leader->type != t) - return NULL_TREE; - - return leader->leader; -} - -/* Return true if T1 and T2 have the same name. If FOR_COMPLETION_P is - true then if any type has no name return false, otherwise return - true if both types have no names. */ - -static bool -compare_type_names_p (tree t1, tree t2, bool for_completion_p) -{ - tree name1 = TYPE_NAME (t1); - tree name2 = TYPE_NAME (t2); - - /* Consider anonymous types all unique for completion. */ - if (for_completion_p - && (!name1 || !name2)) - return false; - - if (name1 && TREE_CODE (name1) == TYPE_DECL) - { - name1 = DECL_NAME (name1); - if (for_completion_p - && !name1) - return false; - } - gcc_assert (!name1 || TREE_CODE (name1) == IDENTIFIER_NODE); - - if (name2 && TREE_CODE (name2) == TYPE_DECL) - { - name2 = DECL_NAME (name2); - if (for_completion_p - && !name2) - return false; - } - gcc_assert (!name2 || TREE_CODE (name2) == IDENTIFIER_NODE); - - /* Identifiers can be compared with pointer equality rather - than a string comparison. */ - if (name1 == name2) - return true; - - return false; -} /* Return true if the field decls F1 and F2 are at the same offset. - This is intended to be used on GIMPLE types only. In order to - compare GENERIC types, use fields_compatible_p instead. */ + This is intended to be used on GIMPLE types only. */ bool gimple_compare_field_offset (tree f1, tree f2) @@ -3338,8 +2225,8 @@ /* Fortran and C do not always agree on what DECL_OFFSET_ALIGN should be, so handle differing ones specially by decomposing the offset into a byte and bit offset manually. */ - if (host_integerp (DECL_FIELD_OFFSET (f1), 0) - && host_integerp (DECL_FIELD_OFFSET (f2), 0)) + if (tree_fits_shwi_p (DECL_FIELD_OFFSET (f1)) + && tree_fits_shwi_p (DECL_FIELD_OFFSET (f2))) { unsigned HOST_WIDE_INT byte_offset1, byte_offset2; unsigned HOST_WIDE_INT bit_offset1, bit_offset2; @@ -3357,1201 +2244,6 @@ return false; } -/* If the type T1 and the type T2 are a complete and an incomplete - variant of the same type return true. */ - -static bool -gimple_compatible_complete_and_incomplete_subtype_p (tree t1, tree t2) -{ - /* If one pointer points to an incomplete type variant of - the other pointed-to type they are the same. */ - if (TREE_CODE (t1) == TREE_CODE (t2) - && RECORD_OR_UNION_TYPE_P (t1) - && (!COMPLETE_TYPE_P (t1) - || !COMPLETE_TYPE_P (t2)) - && TYPE_QUALS (t1) == TYPE_QUALS (t2) - && compare_type_names_p (TYPE_MAIN_VARIANT (t1), - TYPE_MAIN_VARIANT (t2), true)) - return true; - return false; -} - -static bool -gimple_types_compatible_p_1 (tree, tree, enum gtc_mode, type_pair_t, - VEC(type_pair_t, heap) **, - struct pointer_map_t *, struct obstack *); - -/* DFS visit the edge from the callers type pair with state *STATE to - the pair T1, T2 while operating in FOR_MERGING_P mode. - Update the merging status if it is not part of the SCC containing the - callers pair and return it. - SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */ - -static bool -gtc_visit (tree t1, tree t2, enum gtc_mode mode, - struct sccs *state, - VEC(type_pair_t, heap) **sccstack, - struct pointer_map_t *sccstate, - struct obstack *sccstate_obstack) -{ - struct sccs *cstate = NULL; - type_pair_t p; - void **slot; - - /* Check first for the obvious case of pointer identity. */ - if (t1 == t2) - return true; - - /* Check that we have two types to compare. */ - if (t1 == NULL_TREE || t2 == NULL_TREE) - return false; - - /* If the types have been previously registered and found equal - they still are. */ - if (mode == GTC_MERGE) - { - tree leader1 = gimple_lookup_type_leader (t1); - tree leader2 = gimple_lookup_type_leader (t2); - if (leader1 == t2 - || t1 == leader2 - || (leader1 && leader1 == leader2)) - return true; - } - else if (mode == GTC_DIAG) - { - if (TYPE_CANONICAL (t1) - && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)) - return true; - } - - /* Can't be the same type if the types don't have the same code. */ - if (TREE_CODE (t1) != TREE_CODE (t2)) - return false; - - /* Can't be the same type if they have different CV qualifiers. */ - if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) - return false; - - /* Void types are always the same. */ - if (TREE_CODE (t1) == VOID_TYPE) - return true; - - /* Do some simple checks before doing three hashtable queries. */ - if (INTEGRAL_TYPE_P (t1) - || SCALAR_FLOAT_TYPE_P (t1) - || FIXED_POINT_TYPE_P (t1) - || TREE_CODE (t1) == VECTOR_TYPE - || TREE_CODE (t1) == COMPLEX_TYPE - || TREE_CODE (t1) == OFFSET_TYPE) - { - /* Can't be the same type if they have different alignment, - sign, precision or mode. */ - if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) - || TYPE_PRECISION (t1) != TYPE_PRECISION (t2) - || TYPE_MODE (t1) != TYPE_MODE (t2) - || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) - return false; - - if (TREE_CODE (t1) == INTEGER_TYPE - && (TYPE_IS_SIZETYPE (t1) != TYPE_IS_SIZETYPE (t2) - || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))) - return false; - - /* That's all we need to check for float and fixed-point types. */ - if (SCALAR_FLOAT_TYPE_P (t1) - || FIXED_POINT_TYPE_P (t1)) - return true; - - /* For integral types fall thru to more complex checks. */ - } - - else if (AGGREGATE_TYPE_P (t1) || POINTER_TYPE_P (t1)) - { - /* Can't be the same type if they have different alignment or mode. */ - if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) - || TYPE_MODE (t1) != TYPE_MODE (t2)) - return false; - } - - /* If the hash values of t1 and t2 are different the types can't - possibly be the same. This helps keeping the type-pair hashtable - small, only tracking comparisons for hash collisions. */ - if (gimple_type_hash_1 (t1, mode) != gimple_type_hash_1 (t2, mode)) - return false; - - /* Allocate a new cache entry for this comparison. */ - p = lookup_type_pair (t1, t2, >c_visited, >c_ob); - if (p->same_p[mode] == 0 || p->same_p[mode] == 1) - { - /* We have already decided whether T1 and T2 are the - same, return the cached result. */ - return p->same_p[mode] == 1; - } - - if ((slot = pointer_map_contains (sccstate, p)) != NULL) - cstate = (struct sccs *)*slot; - /* Not yet visited. DFS recurse. */ - if (!cstate) - { - gimple_types_compatible_p_1 (t1, t2, mode, p, - sccstack, sccstate, sccstate_obstack); - cstate = (struct sccs *)* pointer_map_contains (sccstate, p); - state->low = MIN (state->low, cstate->low); - } - /* If the type is still on the SCC stack adjust the parents low. */ - if (cstate->dfsnum < state->dfsnum - && cstate->on_sccstack) - state->low = MIN (cstate->dfsnum, state->low); - - /* Return the current lattice value. We start with an equality - assumption so types part of a SCC will be optimistically - treated equal unless proven otherwise. */ - return cstate->u.same_p; -} - -/* Worker for gimple_types_compatible. - SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */ - -static bool -gimple_types_compatible_p_1 (tree t1, tree t2, enum gtc_mode mode, - type_pair_t p, - VEC(type_pair_t, heap) **sccstack, - struct pointer_map_t *sccstate, - struct obstack *sccstate_obstack) -{ - struct sccs *state; - - gcc_assert (p->same_p[mode] == -2); - - state = XOBNEW (sccstate_obstack, struct sccs); - *pointer_map_insert (sccstate, p) = state; - - VEC_safe_push (type_pair_t, heap, *sccstack, p); - state->dfsnum = gtc_next_dfs_num++; - state->low = state->dfsnum; - state->on_sccstack = true; - /* Start with an equality assumption. As we DFS recurse into child - SCCs this assumption may get revisited. */ - state->u.same_p = 1; - - /* If their attributes are not the same they can't be the same type. */ - if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2))) - goto different_types; - - /* Do type-specific comparisons. */ - switch (TREE_CODE (t1)) - { - case VECTOR_TYPE: - case COMPLEX_TYPE: - if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode, - state, sccstack, sccstate, sccstate_obstack)) - goto different_types; - goto same_types; - - case ARRAY_TYPE: - /* Array types are the same if the element types are the same and - the number of elements are the same. */ - if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode, - state, sccstack, sccstate, sccstate_obstack) - || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2) - || TYPE_NONALIASED_COMPONENT (t1) != TYPE_NONALIASED_COMPONENT (t2)) - goto different_types; - else - { - tree i1 = TYPE_DOMAIN (t1); - tree i2 = TYPE_DOMAIN (t2); - - /* For an incomplete external array, the type domain can be - NULL_TREE. Check this condition also. */ - if (i1 == NULL_TREE && i2 == NULL_TREE) - goto same_types; - else if (i1 == NULL_TREE || i2 == NULL_TREE) - goto different_types; - /* If for a complete array type the possibly gimplified sizes - are different the types are different. */ - else if (((TYPE_SIZE (i1) != NULL) ^ (TYPE_SIZE (i2) != NULL)) - || (TYPE_SIZE (i1) - && TYPE_SIZE (i2) - && !operand_equal_p (TYPE_SIZE (i1), TYPE_SIZE (i2), 0))) - goto different_types; - else - { - tree min1 = TYPE_MIN_VALUE (i1); - tree min2 = TYPE_MIN_VALUE (i2); - tree max1 = TYPE_MAX_VALUE (i1); - tree max2 = TYPE_MAX_VALUE (i2); - - /* The minimum/maximum values have to be the same. */ - if ((min1 == min2 - || (min1 && min2 - && ((TREE_CODE (min1) == PLACEHOLDER_EXPR - && TREE_CODE (min2) == PLACEHOLDER_EXPR) - || operand_equal_p (min1, min2, 0)))) - && (max1 == max2 - || (max1 && max2 - && ((TREE_CODE (max1) == PLACEHOLDER_EXPR - && TREE_CODE (max2) == PLACEHOLDER_EXPR) - || operand_equal_p (max1, max2, 0))))) - goto same_types; - else - goto different_types; - } - } - - case METHOD_TYPE: - /* Method types should belong to the same class. */ - if (!gtc_visit (TYPE_METHOD_BASETYPE (t1), TYPE_METHOD_BASETYPE (t2), - mode, state, sccstack, sccstate, sccstate_obstack)) - goto different_types; - - /* Fallthru */ - - case FUNCTION_TYPE: - /* Function types are the same if the return type and arguments types - are the same. */ - if ((mode != GTC_DIAG - || !gimple_compatible_complete_and_incomplete_subtype_p - (TREE_TYPE (t1), TREE_TYPE (t2))) - && !gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode, - state, sccstack, sccstate, sccstate_obstack)) - goto different_types; - - if (!targetm.comp_type_attributes (t1, t2)) - goto different_types; - - if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) - goto same_types; - else - { - tree parms1, parms2; - - for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2); - parms1 && parms2; - parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2)) - { - if ((mode == GTC_MERGE - || !gimple_compatible_complete_and_incomplete_subtype_p - (TREE_VALUE (parms1), TREE_VALUE (parms2))) - && !gtc_visit (TREE_VALUE (parms1), TREE_VALUE (parms2), mode, - state, sccstack, sccstate, sccstate_obstack)) - goto different_types; - } - - if (parms1 || parms2) - goto different_types; - - goto same_types; - } - - case OFFSET_TYPE: - { - if (!gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode, - state, sccstack, sccstate, sccstate_obstack) - || !gtc_visit (TYPE_OFFSET_BASETYPE (t1), - TYPE_OFFSET_BASETYPE (t2), mode, - state, sccstack, sccstate, sccstate_obstack)) - goto different_types; - - goto same_types; - } - - case POINTER_TYPE: - case REFERENCE_TYPE: - { - /* If the two pointers have different ref-all attributes, - they can't be the same type. */ - if (TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)) - goto different_types; - - /* If one pointer points to an incomplete type variant of - the other pointed-to type they are the same. */ - if (mode == GTC_DIAG - && gimple_compatible_complete_and_incomplete_subtype_p - (TREE_TYPE (t1), TREE_TYPE (t2))) - goto same_types; - - /* Otherwise, pointer and reference types are the same if the - pointed-to types are the same. */ - if (gtc_visit (TREE_TYPE (t1), TREE_TYPE (t2), mode, - state, sccstack, sccstate, sccstate_obstack)) - goto same_types; - - goto different_types; - } - - case NULLPTR_TYPE: - /* There is only one decltype(nullptr). */ - goto same_types; - - case INTEGER_TYPE: - case BOOLEAN_TYPE: - { - tree min1 = TYPE_MIN_VALUE (t1); - tree max1 = TYPE_MAX_VALUE (t1); - tree min2 = TYPE_MIN_VALUE (t2); - tree max2 = TYPE_MAX_VALUE (t2); - bool min_equal_p = false; - bool max_equal_p = false; - - /* If either type has a minimum value, the other type must - have the same. */ - if (min1 == NULL_TREE && min2 == NULL_TREE) - min_equal_p = true; - else if (min1 && min2 && operand_equal_p (min1, min2, 0)) - min_equal_p = true; - - /* Likewise, if either type has a maximum value, the other - type must have the same. */ - if (max1 == NULL_TREE && max2 == NULL_TREE) - max_equal_p = true; - else if (max1 && max2 && operand_equal_p (max1, max2, 0)) - max_equal_p = true; - - if (!min_equal_p || !max_equal_p) - goto different_types; - - goto same_types; - } - - case ENUMERAL_TYPE: - { - /* FIXME lto, we cannot check bounds on enumeral types because - different front ends will produce different values. - In C, enumeral types are integers, while in C++ each element - will have its own symbolic value. We should decide how enums - are to be represented in GIMPLE and have each front end lower - to that. */ - tree v1, v2; - - /* For enumeral types, all the values must be the same. */ - if (TYPE_VALUES (t1) == TYPE_VALUES (t2)) - goto same_types; - - for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2); - v1 && v2; - v1 = TREE_CHAIN (v1), v2 = TREE_CHAIN (v2)) - { - tree c1 = TREE_VALUE (v1); - tree c2 = TREE_VALUE (v2); - - if (TREE_CODE (c1) == CONST_DECL) - c1 = DECL_INITIAL (c1); - - if (TREE_CODE (c2) == CONST_DECL) - c2 = DECL_INITIAL (c2); - - if (tree_int_cst_equal (c1, c2) != 1) - goto different_types; - } - - /* If one enumeration has more values than the other, they - are not the same. */ - if (v1 || v2) - goto different_types; - - goto same_types; - } - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - { - tree f1, f2; - - /* The struct tags shall compare equal. */ - if (mode == GTC_MERGE - && !compare_type_names_p (TYPE_MAIN_VARIANT (t1), - TYPE_MAIN_VARIANT (t2), false)) - goto different_types; - - /* For aggregate types, all the fields must be the same. */ - for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2); - f1 && f2; - f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) - { - /* The fields must have the same name, offset and type. */ - if ((mode == GTC_MERGE - && DECL_NAME (f1) != DECL_NAME (f2)) - || DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2) - || !gimple_compare_field_offset (f1, f2) - || !gtc_visit (TREE_TYPE (f1), TREE_TYPE (f2), mode, - state, sccstack, sccstate, sccstate_obstack)) - goto different_types; - } - - /* If one aggregate has more fields than the other, they - are not the same. */ - if (f1 || f2) - goto different_types; - - goto same_types; - } - - default: - gcc_unreachable (); - } - - /* Common exit path for types that are not compatible. */ -different_types: - state->u.same_p = 0; - goto pop; - - /* Common exit path for types that are compatible. */ -same_types: - gcc_assert (state->u.same_p == 1); - -pop: - if (state->low == state->dfsnum) - { - type_pair_t x; - - /* Pop off the SCC and set its cache values to the final - comparison result. */ - do - { - struct sccs *cstate; - x = VEC_pop (type_pair_t, *sccstack); - cstate = (struct sccs *)*pointer_map_contains (sccstate, x); - cstate->on_sccstack = false; - x->same_p[mode] = state->u.same_p; - } - while (x != p); - } - - return state->u.same_p; -} - -/* Return true iff T1 and T2 are structurally identical. When - FOR_MERGING_P is true the an incomplete type and a complete type - are considered different, otherwise they are considered compatible. */ - -bool -gimple_types_compatible_p (tree t1, tree t2, enum gtc_mode mode) -{ - VEC(type_pair_t, heap) *sccstack = NULL; - struct pointer_map_t *sccstate; - struct obstack sccstate_obstack; - type_pair_t p = NULL; - bool res; - - /* Before starting to set up the SCC machinery handle simple cases. */ - - /* Check first for the obvious case of pointer identity. */ - if (t1 == t2) - return true; - - /* Check that we have two types to compare. */ - if (t1 == NULL_TREE || t2 == NULL_TREE) - return false; - - /* If the types have been previously registered and found equal - they still are. */ - if (mode == GTC_MERGE) - { - tree leader1 = gimple_lookup_type_leader (t1); - tree leader2 = gimple_lookup_type_leader (t2); - if (leader1 == t2 - || t1 == leader2 - || (leader1 && leader1 == leader2)) - return true; - } - else if (mode == GTC_DIAG) - { - if (TYPE_CANONICAL (t1) - && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)) - return true; - } - - /* Can't be the same type if the types don't have the same code. */ - if (TREE_CODE (t1) != TREE_CODE (t2)) - return false; - - /* Can't be the same type if they have different CV qualifiers. */ - if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) - return false; - - /* Void types are always the same. */ - if (TREE_CODE (t1) == VOID_TYPE) - return true; - - /* Do some simple checks before doing three hashtable queries. */ - if (INTEGRAL_TYPE_P (t1) - || SCALAR_FLOAT_TYPE_P (t1) - || FIXED_POINT_TYPE_P (t1) - || TREE_CODE (t1) == VECTOR_TYPE - || TREE_CODE (t1) == COMPLEX_TYPE - || TREE_CODE (t1) == OFFSET_TYPE) - { - /* Can't be the same type if they have different alignment, - sign, precision or mode. */ - if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) - || TYPE_PRECISION (t1) != TYPE_PRECISION (t2) - || TYPE_MODE (t1) != TYPE_MODE (t2) - || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) - return false; - - if (TREE_CODE (t1) == INTEGER_TYPE - && (TYPE_IS_SIZETYPE (t1) != TYPE_IS_SIZETYPE (t2) - || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))) - return false; - - /* That's all we need to check for float and fixed-point types. */ - if (SCALAR_FLOAT_TYPE_P (t1) - || FIXED_POINT_TYPE_P (t1)) - return true; - - /* For integral types fall thru to more complex checks. */ - } - - else if (AGGREGATE_TYPE_P (t1) || POINTER_TYPE_P (t1)) - { - /* Can't be the same type if they have different alignment or mode. */ - if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) - || TYPE_MODE (t1) != TYPE_MODE (t2)) - return false; - } - - /* If the hash values of t1 and t2 are different the types can't - possibly be the same. This helps keeping the type-pair hashtable - small, only tracking comparisons for hash collisions. */ - if (gimple_type_hash_1 (t1, mode) != gimple_type_hash_1 (t2, mode)) - return false; - - /* If we've visited this type pair before (in the case of aggregates - with self-referential types), and we made a decision, return it. */ - p = lookup_type_pair (t1, t2, >c_visited, >c_ob); - if (p->same_p[mode] == 0 || p->same_p[mode] == 1) - { - /* We have already decided whether T1 and T2 are the - same, return the cached result. */ - return p->same_p[mode] == 1; - } - - /* Now set up the SCC machinery for the comparison. */ - gtc_next_dfs_num = 1; - sccstate = pointer_map_create (); - gcc_obstack_init (&sccstate_obstack); - res = gimple_types_compatible_p_1 (t1, t2, mode, p, - &sccstack, sccstate, &sccstate_obstack); - VEC_free (type_pair_t, heap, sccstack); - pointer_map_destroy (sccstate); - obstack_free (&sccstate_obstack, NULL); - - return res; -} - - -static hashval_t -iterative_hash_gimple_type (tree, hashval_t, VEC(tree, heap) **, - struct pointer_map_t *, struct obstack *, - enum gtc_mode); - -/* DFS visit the edge from the callers type with state *STATE to T. - Update the callers type hash V with the hash for T if it is not part - of the SCC containing the callers type and return it. - SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */ - -static hashval_t -visit (tree t, struct sccs *state, hashval_t v, - VEC (tree, heap) **sccstack, - struct pointer_map_t *sccstate, - struct obstack *sccstate_obstack, enum gtc_mode mode) -{ - struct sccs *cstate = NULL; - struct tree_int_map m; - void **slot; - - /* If there is a hash value recorded for this type then it can't - possibly be part of our parent SCC. Simply mix in its hash. */ - m.base.from = t; - if ((slot = htab_find_slot (mode == GTC_MERGE - ? type_hash_cache : canonical_type_hash_cache, - &m, NO_INSERT)) - && *slot) - return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, v); - - if ((slot = pointer_map_contains (sccstate, t)) != NULL) - cstate = (struct sccs *)*slot; - if (!cstate) - { - hashval_t tem; - /* Not yet visited. DFS recurse. */ - tem = iterative_hash_gimple_type (t, v, - sccstack, sccstate, sccstate_obstack, - mode); - if (!cstate) - cstate = (struct sccs *)* pointer_map_contains (sccstate, t); - state->low = MIN (state->low, cstate->low); - /* If the type is no longer on the SCC stack and thus is not part - of the parents SCC mix in its hash value. Otherwise we will - ignore the type for hashing purposes and return the unaltered - hash value. */ - if (!cstate->on_sccstack) - return tem; - } - if (cstate->dfsnum < state->dfsnum - && cstate->on_sccstack) - state->low = MIN (cstate->dfsnum, state->low); - - /* We are part of our parents SCC, skip this type during hashing - and return the unaltered hash value. */ - return v; -} - -/* Hash NAME with the previous hash value V and return it. */ - -static hashval_t -iterative_hash_name (tree name, hashval_t v) -{ - if (!name) - return v; - if (TREE_CODE (name) == TYPE_DECL) - name = DECL_NAME (name); - if (!name) - return v; - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); - return iterative_hash_object (IDENTIFIER_HASH_VALUE (name), v); -} - -/* Returning a hash value for gimple type TYPE combined with VAL. - SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. - - To hash a type we end up hashing in types that are reachable. - Through pointers we can end up with cycles which messes up the - required property that we need to compute the same hash value - for structurally equivalent types. To avoid this we have to - hash all types in a cycle (the SCC) in a commutative way. The - easiest way is to not mix in the hashes of the SCC members at - all. To make this work we have to delay setting the hash - values of the SCC until it is complete. */ - -static hashval_t -iterative_hash_gimple_type (tree type, hashval_t val, - VEC(tree, heap) **sccstack, - struct pointer_map_t *sccstate, - struct obstack *sccstate_obstack, - enum gtc_mode mode) -{ - hashval_t v; - void **slot; - struct sccs *state; - - /* Not visited during this DFS walk. */ - gcc_checking_assert (!pointer_map_contains (sccstate, type)); - state = XOBNEW (sccstate_obstack, struct sccs); - *pointer_map_insert (sccstate, type) = state; - - VEC_safe_push (tree, heap, *sccstack, type); - state->dfsnum = next_dfs_num++; - state->low = state->dfsnum; - state->on_sccstack = true; - - /* Combine a few common features of types so that types are grouped into - smaller sets; when searching for existing matching types to merge, - only existing types having the same features as the new type will be - checked. */ - v = iterative_hash_hashval_t (TREE_CODE (type), 0); - v = iterative_hash_hashval_t (TYPE_QUALS (type), v); - v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v); - - /* Do not hash the types size as this will cause differences in - hash values for the complete vs. the incomplete type variant. */ - - /* Incorporate common features of numerical types. */ - if (INTEGRAL_TYPE_P (type) - || SCALAR_FLOAT_TYPE_P (type) - || FIXED_POINT_TYPE_P (type)) - { - v = iterative_hash_hashval_t (TYPE_PRECISION (type), v); - v = iterative_hash_hashval_t (TYPE_MODE (type), v); - v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); - } - - /* For pointer and reference types, fold in information about the type - pointed to but do not recurse into possibly incomplete types to - avoid hash differences for complete vs. incomplete types. */ - if (POINTER_TYPE_P (type)) - { - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) - { - v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); - v = iterative_hash_name - (TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (type))), v); - } - else - v = visit (TREE_TYPE (type), state, v, - sccstack, sccstate, sccstate_obstack, mode); - } - - /* For integer types hash the types min/max values and the string flag. */ - if (TREE_CODE (type) == INTEGER_TYPE) - { - /* OMP lowering can introduce error_mark_node in place of - random local decls in types. */ - if (TYPE_MIN_VALUE (type) != error_mark_node) - v = iterative_hash_expr (TYPE_MIN_VALUE (type), v); - if (TYPE_MAX_VALUE (type) != error_mark_node) - v = iterative_hash_expr (TYPE_MAX_VALUE (type), v); - v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); - } - - /* For array types hash their domain and the string flag. */ - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type)) - { - v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); - v = visit (TYPE_DOMAIN (type), state, v, - sccstack, sccstate, sccstate_obstack, mode); - } - - /* Recurse for aggregates with a single element type. */ - if (TREE_CODE (type) == ARRAY_TYPE - || TREE_CODE (type) == COMPLEX_TYPE - || TREE_CODE (type) == VECTOR_TYPE) - v = visit (TREE_TYPE (type), state, v, - sccstack, sccstate, sccstate_obstack, mode); - - /* Incorporate function return and argument types. */ - if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) - { - unsigned na; - tree p; - - /* For method types also incorporate their parent class. */ - if (TREE_CODE (type) == METHOD_TYPE) - v = visit (TYPE_METHOD_BASETYPE (type), state, v, - sccstack, sccstate, sccstate_obstack, mode); - - /* For result types allow mismatch in completeness. */ - if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) - { - v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); - v = iterative_hash_name - (TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (type))), v); - } - else - v = visit (TREE_TYPE (type), state, v, - sccstack, sccstate, sccstate_obstack, mode); - - for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p)) - { - /* For argument types allow mismatch in completeness. */ - if (RECORD_OR_UNION_TYPE_P (TREE_VALUE (p))) - { - v = iterative_hash_hashval_t (TREE_CODE (TREE_VALUE (p)), v); - v = iterative_hash_name - (TYPE_NAME (TYPE_MAIN_VARIANT (TREE_VALUE (p))), v); - } - else - v = visit (TREE_VALUE (p), state, v, - sccstack, sccstate, sccstate_obstack, mode); - na++; - } - - v = iterative_hash_hashval_t (na, v); - } - - if (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE) - { - unsigned nf; - tree f; - - if (mode == GTC_MERGE) - v = iterative_hash_name (TYPE_NAME (TYPE_MAIN_VARIANT (type)), v); - - for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) - { - if (mode == GTC_MERGE) - v = iterative_hash_name (DECL_NAME (f), v); - v = visit (TREE_TYPE (f), state, v, - sccstack, sccstate, sccstate_obstack, mode); - nf++; - } - - v = iterative_hash_hashval_t (nf, v); - } - - /* Record hash for us. */ - state->u.hash = v; - - /* See if we found an SCC. */ - if (state->low == state->dfsnum) - { - tree x; - - /* Pop off the SCC and set its hash values. */ - do - { - struct sccs *cstate; - struct tree_int_map *m = ggc_alloc_cleared_tree_int_map (); - x = VEC_pop (tree, *sccstack); - cstate = (struct sccs *)*pointer_map_contains (sccstate, x); - cstate->on_sccstack = false; - m->base.from = x; - m->to = cstate->u.hash; - slot = htab_find_slot (mode == GTC_MERGE - ? type_hash_cache : canonical_type_hash_cache, - m, INSERT); - gcc_assert (!*slot); - *slot = (void *) m; - } - while (x != type); - } - - return iterative_hash_hashval_t (v, val); -} - - -/* Returns a hash value for P (assumed to be a type). The hash value - is computed using some distinguishing features of the type. Note - that we cannot use pointer hashing here as we may be dealing with - two distinct instances of the same type. - - This function should produce the same hash value for two compatible - types according to gimple_types_compatible_p. */ - -static hashval_t -gimple_type_hash_1 (const void *p, enum gtc_mode mode) -{ - const_tree t = (const_tree) p; - VEC(tree, heap) *sccstack = NULL; - struct pointer_map_t *sccstate; - struct obstack sccstate_obstack; - hashval_t val; - void **slot; - struct tree_int_map m; - - if (mode == GTC_MERGE - && type_hash_cache == NULL) - type_hash_cache = htab_create_ggc (512, tree_int_map_hash, - tree_int_map_eq, NULL); - else if (mode == GTC_DIAG - && canonical_type_hash_cache == NULL) - canonical_type_hash_cache = htab_create_ggc (512, tree_int_map_hash, - tree_int_map_eq, NULL); - - m.base.from = CONST_CAST_TREE (t); - if ((slot = htab_find_slot (mode == GTC_MERGE - ? type_hash_cache : canonical_type_hash_cache, - &m, NO_INSERT)) - && *slot) - return iterative_hash_hashval_t (((struct tree_int_map *) *slot)->to, 0); - - /* Perform a DFS walk and pre-hash all reachable types. */ - next_dfs_num = 1; - sccstate = pointer_map_create (); - gcc_obstack_init (&sccstate_obstack); - val = iterative_hash_gimple_type (CONST_CAST_TREE (t), 0, - &sccstack, sccstate, &sccstate_obstack, - mode); - VEC_free (tree, heap, sccstack); - pointer_map_destroy (sccstate); - obstack_free (&sccstate_obstack, NULL); - - return val; -} - -static hashval_t -gimple_type_hash (const void *p) -{ - return gimple_type_hash_1 (p, GTC_MERGE); -} - -static hashval_t -gimple_canonical_type_hash (const void *p) -{ - return gimple_type_hash_1 (p, GTC_DIAG); -} - - -/* Returns nonzero if P1 and P2 are equal. */ - -static int -gimple_type_eq (const void *p1, const void *p2) -{ - const_tree t1 = (const_tree) p1; - const_tree t2 = (const_tree) p2; - return gimple_types_compatible_p (CONST_CAST_TREE (t1), - CONST_CAST_TREE (t2), GTC_MERGE); -} - - -/* Register type T in the global type table gimple_types. - If another type T', compatible with T, already existed in - gimple_types then return T', otherwise return T. This is used by - LTO to merge identical types read from different TUs. */ - -tree -gimple_register_type (tree t) -{ - void **slot; - gimple_type_leader_entry *leader; - tree mv_leader = NULL_TREE; - - gcc_assert (TYPE_P (t)); - - if (!gimple_type_leader) - gimple_type_leader = ggc_alloc_cleared_vec_gimple_type_leader_entry_s - (GIMPLE_TYPE_LEADER_SIZE); - /* If we registered this type before return the cached result. */ - leader = &gimple_type_leader[TYPE_UID (t) % GIMPLE_TYPE_LEADER_SIZE]; - if (leader->type == t) - return leader->leader; - - /* Always register the main variant first. This is important so we - pick up the non-typedef variants as canonical, otherwise we'll end - up taking typedef ids for structure tags during comparison. */ - if (TYPE_MAIN_VARIANT (t) != t) - mv_leader = gimple_register_type (TYPE_MAIN_VARIANT (t)); - - if (gimple_types == NULL) - gimple_types = htab_create_ggc (16381, gimple_type_hash, gimple_type_eq, 0); - - slot = htab_find_slot (gimple_types, t, INSERT); - if (*slot - && *(tree *)slot != t) - { - tree new_type = (tree) *((tree *) slot); - - /* Do not merge types with different addressability. */ - gcc_assert (TREE_ADDRESSABLE (t) == TREE_ADDRESSABLE (new_type)); - - /* If t is not its main variant then make t unreachable from its - main variant list. Otherwise we'd queue up a lot of duplicates - there. */ - if (t != TYPE_MAIN_VARIANT (t)) - { - tree tem = TYPE_MAIN_VARIANT (t); - while (tem && TYPE_NEXT_VARIANT (tem) != t) - tem = TYPE_NEXT_VARIANT (tem); - if (tem) - TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t); - TYPE_NEXT_VARIANT (t) = NULL_TREE; - } - - /* If we are a pointer then remove us from the pointer-to or - reference-to chain. Otherwise we'd queue up a lot of duplicates - there. */ - if (TREE_CODE (t) == POINTER_TYPE) - { - if (TYPE_POINTER_TO (TREE_TYPE (t)) == t) - TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t); - else - { - tree tem = TYPE_POINTER_TO (TREE_TYPE (t)); - while (tem && TYPE_NEXT_PTR_TO (tem) != t) - tem = TYPE_NEXT_PTR_TO (tem); - if (tem) - TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t); - } - TYPE_NEXT_PTR_TO (t) = NULL_TREE; - } - else if (TREE_CODE (t) == REFERENCE_TYPE) - { - if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t) - TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t); - else - { - tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t)); - while (tem && TYPE_NEXT_REF_TO (tem) != t) - tem = TYPE_NEXT_REF_TO (tem); - if (tem) - TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t); - } - TYPE_NEXT_REF_TO (t) = NULL_TREE; - } - - leader->type = t; - leader->leader = new_type; - t = new_type; - } - else - { - leader->type = t; - leader->leader = t; - /* We're the type leader. Make our TYPE_MAIN_VARIANT valid. */ - if (TYPE_MAIN_VARIANT (t) != t - && TYPE_MAIN_VARIANT (t) != mv_leader) - { - /* Remove us from our main variant list as we are not the variant - leader and the variant leader will change. */ - tree tem = TYPE_MAIN_VARIANT (t); - while (tem && TYPE_NEXT_VARIANT (tem) != t) - tem = TYPE_NEXT_VARIANT (tem); - if (tem) - TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t); - TYPE_NEXT_VARIANT (t) = NULL_TREE; - /* Adjust our main variant. Linking us into its variant list - will happen at fixup time. */ - TYPE_MAIN_VARIANT (t) = mv_leader; - } - *slot = (void *) t; - } - - return t; -} - - -/* Returns nonzero if P1 and P2 are equal. */ - -static int -gimple_canonical_type_eq (const void *p1, const void *p2) -{ - const_tree t1 = (const_tree) p1; - const_tree t2 = (const_tree) p2; - return gimple_types_compatible_p (CONST_CAST_TREE (t1), - CONST_CAST_TREE (t2), GTC_DIAG); -} - -/* Register type T in the global type table gimple_types. - If another type T', compatible with T, already existed in - gimple_types then return T', otherwise return T. This is used by - LTO to merge identical types read from different TUs. */ - -tree -gimple_register_canonical_type (tree t) -{ - void **slot; - tree orig_t = t; - - gcc_assert (TYPE_P (t)); - - if (TYPE_CANONICAL (t)) - return TYPE_CANONICAL (t); - - /* Always register the type itself first so that if it turns out - to be the canonical type it will be the one we merge to as well. */ - t = gimple_register_type (t); - - /* Always register the main variant first. This is important so we - pick up the non-typedef variants as canonical, otherwise we'll end - up taking typedef ids for structure tags during comparison. */ - if (TYPE_MAIN_VARIANT (t) != t) - gimple_register_canonical_type (TYPE_MAIN_VARIANT (t)); - - if (gimple_canonical_types == NULL) - gimple_canonical_types = htab_create_ggc (16381, gimple_canonical_type_hash, - gimple_canonical_type_eq, 0); - - slot = htab_find_slot (gimple_canonical_types, t, INSERT); - if (*slot - && *(tree *)slot != t) - { - tree new_type = (tree) *((tree *) slot); - - TYPE_CANONICAL (t) = new_type; - t = new_type; - } - else - { - TYPE_CANONICAL (t) = t; - *slot = (void *) t; - } - - /* Also cache the canonical type in the non-leaders. */ - TYPE_CANONICAL (orig_t) = t; - - return t; -} - - -/* Show statistics on references to the global type table gimple_types. */ - -void -print_gimple_types_stats (void) -{ - if (gimple_types) - fprintf (stderr, "GIMPLE type table: size %ld, %ld elements, " - "%ld searches, %ld collisions (ratio: %f)\n", - (long) htab_size (gimple_types), - (long) htab_elements (gimple_types), - (long) gimple_types->searches, - (long) gimple_types->collisions, - htab_collisions (gimple_types)); - else - fprintf (stderr, "GIMPLE type table is empty\n"); - if (type_hash_cache) - fprintf (stderr, "GIMPLE type hash table: size %ld, %ld elements, " - "%ld searches, %ld collisions (ratio: %f)\n", - (long) htab_size (type_hash_cache), - (long) htab_elements (type_hash_cache), - (long) type_hash_cache->searches, - (long) type_hash_cache->collisions, - htab_collisions (type_hash_cache)); - else - fprintf (stderr, "GIMPLE type hash table is empty\n"); - if (gimple_canonical_types) - fprintf (stderr, "GIMPLE canonical type table: size %ld, %ld elements, " - "%ld searches, %ld collisions (ratio: %f)\n", - (long) htab_size (gimple_canonical_types), - (long) htab_elements (gimple_canonical_types), - (long) gimple_canonical_types->searches, - (long) gimple_canonical_types->collisions, - htab_collisions (gimple_canonical_types)); - else - fprintf (stderr, "GIMPLE canonical type table is empty\n"); - if (canonical_type_hash_cache) - fprintf (stderr, "GIMPLE canonical type hash table: size %ld, %ld elements, " - "%ld searches, %ld collisions (ratio: %f)\n", - (long) htab_size (canonical_type_hash_cache), - (long) htab_elements (canonical_type_hash_cache), - (long) canonical_type_hash_cache->searches, - (long) canonical_type_hash_cache->collisions, - htab_collisions (canonical_type_hash_cache)); - else - fprintf (stderr, "GIMPLE canonical type hash table is empty\n"); - if (gtc_visited) - fprintf (stderr, "GIMPLE type comparison table: size %ld, %ld " - "elements, %ld searches, %ld collisions (ratio: %f)\n", - (long) htab_size (gtc_visited), - (long) htab_elements (gtc_visited), - (long) gtc_visited->searches, - (long) gtc_visited->collisions, - htab_collisions (gtc_visited)); - else - fprintf (stderr, "GIMPLE type comparison table is empty\n"); -} - -/* Free the gimple type hashtables used for LTO type merging. */ - -void -free_gimple_type_tables (void) -{ - /* Last chance to print stats for the tables. */ - if (flag_lto_report) - print_gimple_types_stats (); - - if (gimple_types) - { - htab_delete (gimple_types); - gimple_types = NULL; - } - if (gimple_canonical_types) - { - htab_delete (gimple_canonical_types); - gimple_canonical_types = NULL; - } - if (type_hash_cache) - { - htab_delete (type_hash_cache); - type_hash_cache = NULL; - } - if (canonical_type_hash_cache) - { - htab_delete (canonical_type_hash_cache); - canonical_type_hash_cache = NULL; - } - if (gtc_visited) - { - htab_delete (gtc_visited); - obstack_free (>c_ob, NULL); - gtc_visited = NULL; - } - gimple_type_leader = NULL; -} - /* Return a type the same as TYPE except unsigned or signed according to UNSIGNEDP. */ @@ -4560,6 +2252,7 @@ gimple_signed_or_unsigned_type (bool unsignedp, tree type) { tree type1; + int i; type1 = TYPE_MAIN_VARIANT (type); if (type1 == signed_char_type_node @@ -4577,10 +2270,15 @@ return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; - if (int128_integer_type_node && (type1 == int128_integer_type_node || type1 == int128_unsigned_type_node)) - return unsignedp - ? int128_unsigned_type_node - : int128_integer_type_node; + + for (i = 0; i < NUM_INT_N_ENTS; i ++) + if (int_n_enabled_p[i] + && (type1 == int_n_trees[i].unsigned_type + || type1 == int_n_trees[i].signed_type)) + return unsignedp + ? int_n_trees[i].unsigned_type + : int_n_trees[i].signed_type; + #if HOST_BITS_PER_WIDE_INT >= 64 if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node) return unsignedp ? unsigned_intTI_type_node : intTI_type_node; @@ -4693,10 +2391,14 @@ return (unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node); - if (int128_integer_type_node && TYPE_OK (int128_integer_type_node)) - return (unsignedp - ? int128_unsigned_type_node - : int128_integer_type_node); + + for (i = 0; i < NUM_INT_N_ENTS; i ++) + if (int_n_enabled_p[i] + && TYPE_MODE (type) == int_n_data[i].m + && TYPE_PRECISION (type) == int_n_data[i].bitsize) + return unsignedp + ? int_n_trees[i].unsigned_type + : int_n_trees[i].signed_type; #if HOST_BITS_PER_WIDE_INT >= 64 if (TYPE_OK (intTI_type_node)) @@ -4745,21 +2447,6 @@ alias_set_type gimple_get_alias_set (tree t) { - tree u; - - /* Permit type-punning when accessing a union, provided the access - is directly through the union. For example, this code does not - permit taking the address of a union member and then storing - through it. Even the type-punning allowed here is a GCC - extension, albeit a common and useful one; the C standard says - that such accesses have implementation-defined behavior. */ - for (u = t; - TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; - u = TREE_OPERAND (u, 0)) - if (TREE_CODE (u) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) - return 0; - /* That's all the expressions we handle specially. */ if (!TYPE_P (t)) return -1; @@ -4787,310 +2474,10 @@ } -/* Data structure used to count the number of dereferences to PTR - inside an expression. */ -struct count_ptr_d -{ - tree ptr; - unsigned num_stores; - unsigned num_loads; -}; - -/* Helper for count_uses_and_derefs. Called by walk_tree to look for - (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA. */ - -static tree -count_ptr_derefs (tree *tp, int *walk_subtrees, void *data) -{ - struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data; - struct count_ptr_d *count_p = (struct count_ptr_d *) wi_p->info; - - /* Do not walk inside ADDR_EXPR nodes. In the expression &ptr->fld, - pointer 'ptr' is *not* dereferenced, it is simply used to compute - the address of 'fld' as 'ptr + offsetof(fld)'. */ - if (TREE_CODE (*tp) == ADDR_EXPR) - { - *walk_subtrees = 0; - return NULL_TREE; - } - - if (TREE_CODE (*tp) == MEM_REF && TREE_OPERAND (*tp, 0) == count_p->ptr) - { - if (wi_p->is_lhs) - count_p->num_stores++; - else - count_p->num_loads++; - } - - return NULL_TREE; -} - -/* Count the number of direct and indirect uses for pointer PTR in - statement STMT. The number of direct uses is stored in - *NUM_USES_P. Indirect references are counted separately depending - on whether they are store or load operations. The counts are - stored in *NUM_STORES_P and *NUM_LOADS_P. */ - -void -count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p, - unsigned *num_loads_p, unsigned *num_stores_p) -{ - ssa_op_iter i; - tree use; - - *num_uses_p = 0; - *num_loads_p = 0; - *num_stores_p = 0; - - /* Find out the total number of uses of PTR in STMT. */ - FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE) - if (use == ptr) - (*num_uses_p)++; - - /* Now count the number of indirect references to PTR. This is - truly awful, but we don't have much choice. There are no parent - pointers inside INDIRECT_REFs, so an expression like - '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to - find all the indirect and direct uses of x_1 inside. The only - shortcut we can take is the fact that GIMPLE only allows - INDIRECT_REFs inside the expressions below. */ - if (is_gimple_assign (stmt) - || gimple_code (stmt) == GIMPLE_RETURN - || gimple_code (stmt) == GIMPLE_ASM - || is_gimple_call (stmt)) - { - struct walk_stmt_info wi; - struct count_ptr_d count; - - count.ptr = ptr; - count.num_stores = 0; - count.num_loads = 0; - - memset (&wi, 0, sizeof (wi)); - wi.info = &count; - walk_gimple_op (stmt, count_ptr_derefs, &wi); - - *num_stores_p = count.num_stores; - *num_loads_p = count.num_loads; - } - - gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p); -} - -/* From a tree operand OP return the base of a load or store operation - or NULL_TREE if OP is not a load or a store. */ - -static tree -get_base_loadstore (tree op) -{ - while (handled_component_p (op)) - op = TREE_OPERAND (op, 0); - if (DECL_P (op) - || INDIRECT_REF_P (op) - || TREE_CODE (op) == MEM_REF - || TREE_CODE (op) == TARGET_MEM_REF) - return op; - return NULL_TREE; -} - -/* For the statement STMT call the callbacks VISIT_LOAD, VISIT_STORE and - VISIT_ADDR if non-NULL on loads, store and address-taken operands - passing the STMT, the base of the operand and DATA to it. The base - will be either a decl, an indirect reference (including TARGET_MEM_REF) - or the argument of an address expression. - Returns the results of these callbacks or'ed. */ - -bool -walk_stmt_load_store_addr_ops (gimple stmt, void *data, - bool (*visit_load)(gimple, tree, void *), - bool (*visit_store)(gimple, tree, void *), - bool (*visit_addr)(gimple, tree, void *)) -{ - bool ret = false; - unsigned i; - if (gimple_assign_single_p (stmt)) - { - tree lhs, rhs; - if (visit_store) - { - lhs = get_base_loadstore (gimple_assign_lhs (stmt)); - if (lhs) - ret |= visit_store (stmt, lhs, data); - } - rhs = gimple_assign_rhs1 (stmt); - while (handled_component_p (rhs)) - rhs = TREE_OPERAND (rhs, 0); - if (visit_addr) - { - if (TREE_CODE (rhs) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (rhs, 0), data); - else if (TREE_CODE (rhs) == TARGET_MEM_REF - && TREE_CODE (TMR_BASE (rhs)) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (rhs), 0), data); - else if (TREE_CODE (rhs) == OBJ_TYPE_REF - && TREE_CODE (OBJ_TYPE_REF_OBJECT (rhs)) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (OBJ_TYPE_REF_OBJECT (rhs), - 0), data); - lhs = gimple_assign_lhs (stmt); - if (TREE_CODE (lhs) == TARGET_MEM_REF - && TREE_CODE (TMR_BASE (lhs)) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (lhs), 0), data); - } - if (visit_load) - { - rhs = get_base_loadstore (rhs); - if (rhs) - ret |= visit_load (stmt, rhs, data); - } - } - else if (visit_addr - && (is_gimple_assign (stmt) - || gimple_code (stmt) == GIMPLE_COND)) - { - for (i = 0; i < gimple_num_ops (stmt); ++i) - if (gimple_op (stmt, i) - && TREE_CODE (gimple_op (stmt, i)) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (gimple_op (stmt, i), 0), data); - } - else if (is_gimple_call (stmt)) - { - if (visit_store) - { - tree lhs = gimple_call_lhs (stmt); - if (lhs) - { - lhs = get_base_loadstore (lhs); - if (lhs) - ret |= visit_store (stmt, lhs, data); - } - } - if (visit_load || visit_addr) - for (i = 0; i < gimple_call_num_args (stmt); ++i) - { - tree rhs = gimple_call_arg (stmt, i); - if (visit_addr - && TREE_CODE (rhs) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (rhs, 0), data); - else if (visit_load) - { - rhs = get_base_loadstore (rhs); - if (rhs) - ret |= visit_load (stmt, rhs, data); - } - } - if (visit_addr - && gimple_call_chain (stmt) - && TREE_CODE (gimple_call_chain (stmt)) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (gimple_call_chain (stmt), 0), - data); - if (visit_addr - && gimple_call_return_slot_opt_p (stmt) - && gimple_call_lhs (stmt) != NULL_TREE - && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt)))) - ret |= visit_addr (stmt, gimple_call_lhs (stmt), data); - } - else if (gimple_code (stmt) == GIMPLE_ASM) - { - unsigned noutputs; - const char *constraint; - const char **oconstraints; - bool allows_mem, allows_reg, is_inout; - noutputs = gimple_asm_noutputs (stmt); - oconstraints = XALLOCAVEC (const char *, noutputs); - if (visit_store || visit_addr) - for (i = 0; i < gimple_asm_noutputs (stmt); ++i) - { - tree link = gimple_asm_output_op (stmt, i); - tree op = get_base_loadstore (TREE_VALUE (link)); - if (op && visit_store) - ret |= visit_store (stmt, op, data); - if (visit_addr) - { - constraint = TREE_STRING_POINTER - (TREE_VALUE (TREE_PURPOSE (link))); - oconstraints[i] = constraint; - parse_output_constraint (&constraint, i, 0, 0, &allows_mem, - &allows_reg, &is_inout); - if (op && !allows_reg && allows_mem) - ret |= visit_addr (stmt, op, data); - } - } - if (visit_load || visit_addr) - for (i = 0; i < gimple_asm_ninputs (stmt); ++i) - { - tree link = gimple_asm_input_op (stmt, i); - tree op = TREE_VALUE (link); - if (visit_addr - && TREE_CODE (op) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data); - else if (visit_load || visit_addr) - { - op = get_base_loadstore (op); - if (op) - { - if (visit_load) - ret |= visit_load (stmt, op, data); - if (visit_addr) - { - constraint = TREE_STRING_POINTER - (TREE_VALUE (TREE_PURPOSE (link))); - parse_input_constraint (&constraint, 0, 0, noutputs, - 0, oconstraints, - &allows_mem, &allows_reg); - if (!allows_reg && allows_mem) - ret |= visit_addr (stmt, op, data); - } - } - } - } - } - else if (gimple_code (stmt) == GIMPLE_RETURN) - { - tree op = gimple_return_retval (stmt); - if (op) - { - if (visit_addr - && TREE_CODE (op) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data); - else if (visit_load) - { - op = get_base_loadstore (op); - if (op) - ret |= visit_load (stmt, op, data); - } - } - } - else if (visit_addr - && gimple_code (stmt) == GIMPLE_PHI) - { - for (i = 0; i < gimple_phi_num_args (stmt); ++i) - { - tree op = PHI_ARG_DEF (stmt, i); - if (TREE_CODE (op) == ADDR_EXPR) - ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data); - } - } - - return ret; -} - -/* Like walk_stmt_load_store_addr_ops but with NULL visit_addr. IPA-CP - should make a faster clone for this case. */ - -bool -walk_stmt_load_store_ops (gimple stmt, void *data, - bool (*visit_load)(gimple, tree, void *), - bool (*visit_store)(gimple, tree, void *)) -{ - return walk_stmt_load_store_addr_ops (stmt, data, - visit_load, visit_store, NULL); -} - /* Helper for gimple_ior_addresses_taken_1. */ static bool -gimple_ior_addresses_taken_1 (gimple stmt ATTRIBUTE_UNUSED, - tree addr, void *data) +gimple_ior_addresses_taken_1 (gimple *, tree addr, tree, void *data) { bitmap addresses_taken = (bitmap)data; addr = get_base_address (addr); @@ -5108,54 +2495,728 @@ were any in this stmt. */ bool -gimple_ior_addresses_taken (bitmap addresses_taken, gimple stmt) +gimple_ior_addresses_taken (bitmap addresses_taken, gimple *stmt) { return walk_stmt_load_store_addr_ops (stmt, addresses_taken, NULL, NULL, gimple_ior_addresses_taken_1); } -/* Return a printable name for symbol DECL. */ - -const char * -gimple_decl_printable_name (tree decl, int verbosity) +/* Return true when STMTs arguments and return value match those of FNDECL, + a decl of a builtin function. */ + +bool +gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl) { - if (!DECL_NAME (decl)) - return NULL; - - if (DECL_ASSEMBLER_NAME_SET_P (decl)) + gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN); + + tree ret = gimple_call_lhs (stmt); + if (ret + && !useless_type_conversion_p (TREE_TYPE (ret), + TREE_TYPE (TREE_TYPE (fndecl)))) + return false; + + tree targs = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + unsigned nargs = gimple_call_num_args (stmt); + for (unsigned i = 0; i < nargs; ++i) { - 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; + /* Variadic args follow. */ + if (!targs) + return true; + tree arg = gimple_call_arg (stmt, i); + tree type = TREE_VALUE (targs); + if (!useless_type_conversion_p (type, TREE_TYPE (arg)) + /* char/short integral arguments are promoted to int + by several frontends if targetm.calls.promote_prototypes + is true. Allow such promotion too. */ + && !(INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node) + && targetm.calls.promote_prototypes (TREE_TYPE (fndecl)) + && useless_type_conversion_p (integer_type_node, + TREE_TYPE (arg)))) + return false; + targs = TREE_CHAIN (targs); } - - return IDENTIFIER_POINTER (DECL_NAME (decl)); + if (targs && !VOID_TYPE_P (TREE_VALUE (targs))) + return false; + return true; +} + +/* Return true when STMT is builtins call. */ + +bool +gimple_call_builtin_p (const gimple *stmt) +{ + tree fndecl; + if (is_gimple_call (stmt) + && (fndecl = gimple_call_fndecl (stmt)) != NULL_TREE + && DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN) + return gimple_builtin_call_types_compatible_p (stmt, fndecl); + return false; +} + +/* Return true when STMT is builtins call to CLASS. */ + +bool +gimple_call_builtin_p (const gimple *stmt, enum built_in_class klass) +{ + tree fndecl; + if (is_gimple_call (stmt) + && (fndecl = gimple_call_fndecl (stmt)) != NULL_TREE + && DECL_BUILT_IN_CLASS (fndecl) == klass) + return gimple_builtin_call_types_compatible_p (stmt, fndecl); + return false; } -/* Return true when STMT is builtins call to CODE. */ +/* Return true when STMT is builtins call to CODE of CLASS. */ + +bool +gimple_call_builtin_p (const gimple *stmt, enum built_in_function code) +{ + tree fndecl; + if (is_gimple_call (stmt) + && (fndecl = gimple_call_fndecl (stmt)) != NULL_TREE + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (fndecl) == code) + return gimple_builtin_call_types_compatible_p (stmt, fndecl); + return false; +} + +/* If CALL is a call to a combined_fn (i.e. an internal function or + a normal built-in function), return its code, otherwise return + CFN_LAST. */ + +combined_fn +gimple_call_combined_fn (const gimple *stmt) +{ + if (const gcall *call = dyn_cast <const gcall *> (stmt)) + { + if (gimple_call_internal_p (call)) + return as_combined_fn (gimple_call_internal_fn (call)); + + tree fndecl = gimple_call_fndecl (stmt); + if (fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && gimple_builtin_call_types_compatible_p (stmt, fndecl)) + return as_combined_fn (DECL_FUNCTION_CODE (fndecl)); + } + return CFN_LAST; +} + +/* Return true if STMT clobbers memory. STMT is required to be a + GIMPLE_ASM. */ bool -gimple_call_builtin_p (gimple stmt, enum built_in_function code) +gimple_asm_clobbers_memory_p (const gasm *stmt) +{ + unsigned i; + + for (i = 0; i < gimple_asm_nclobbers (stmt); i++) + { + tree op = gimple_asm_clobber_op (stmt, i); + if (strcmp (TREE_STRING_POINTER (TREE_VALUE (op)), "memory") == 0) + return true; + } + + /* Non-empty basic ASM implicitly clobbers memory. */ + if (gimple_asm_input_p (stmt) && strlen (gimple_asm_string (stmt)) != 0) + return true; + + return false; +} + +/* Dump bitmap SET (assumed to contain VAR_DECLs) to FILE. */ + +void +dump_decl_set (FILE *file, bitmap set) +{ + if (set) + { + bitmap_iterator bi; + unsigned i; + + fprintf (file, "{ "); + + EXECUTE_IF_SET_IN_BITMAP (set, 0, i, bi) + { + fprintf (file, "D.%u", i); + fprintf (file, " "); + } + + fprintf (file, "}"); + } + else + fprintf (file, "NIL"); +} + +/* Return true when CALL is a call stmt that definitely doesn't + free any memory or makes it unavailable otherwise. */ +bool +nonfreeing_call_p (gimple *call) +{ + if (gimple_call_builtin_p (call, BUILT_IN_NORMAL) + && gimple_call_flags (call) & ECF_LEAF) + switch (DECL_FUNCTION_CODE (gimple_call_fndecl (call))) + { + /* Just in case these become ECF_LEAF in the future. */ + case BUILT_IN_FREE: + case BUILT_IN_TM_FREE: + case BUILT_IN_REALLOC: + case BUILT_IN_STACK_RESTORE: + return false; + default: + return true; + } + else if (gimple_call_internal_p (call)) + switch (gimple_call_internal_fn (call)) + { + case IFN_ABNORMAL_DISPATCHER: + return true; + case IFN_ASAN_MARK: + return tree_to_uhwi (gimple_call_arg (call, 0)) == ASAN_MARK_UNPOISON; + default: + if (gimple_call_flags (call) & ECF_LEAF) + return true; + return false; + } + + tree fndecl = gimple_call_fndecl (call); + if (!fndecl) + return false; + struct cgraph_node *n = cgraph_node::get (fndecl); + if (!n) + return false; + enum availability availability; + n = n->function_symbol (&availability); + if (!n || availability <= AVAIL_INTERPOSABLE) + return false; + return n->nonfreeing_fn; +} + +/* Return true when CALL is a call stmt that definitely need not + be considered to be a memory barrier. */ +bool +nonbarrier_call_p (gimple *call) +{ + if (gimple_call_flags (call) & (ECF_PURE | ECF_CONST)) + return true; + /* Should extend this to have a nonbarrier_fn flag, just as above in + the nonfreeing case. */ + return false; +} + +/* Callback for walk_stmt_load_store_ops. + + Return TRUE if OP will dereference the tree stored in DATA, FALSE + otherwise. + + This routine only makes a superficial check for a dereference. Thus + it must only be used if it is safe to return a false negative. */ +static bool +check_loadstore (gimple *, tree op, tree, void *data) +{ + if (TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF) + { + /* Some address spaces may legitimately dereference zero. */ + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (op)); + if (targetm.addr_space.zero_address_valid (as)) + return false; + + return operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0); + } + return false; +} + + +/* Return true if OP can be inferred to be non-NULL after STMT executes, + either by using a pointer dereference or attributes. */ +bool +infer_nonnull_range (gimple *stmt, tree op) +{ + return infer_nonnull_range_by_dereference (stmt, op) + || infer_nonnull_range_by_attribute (stmt, op); +} + +/* Return true if OP can be inferred to be non-NULL after STMT + executes by using a pointer dereference. */ +bool +infer_nonnull_range_by_dereference (gimple *stmt, tree op) +{ + /* We can only assume that a pointer dereference will yield + non-NULL if -fdelete-null-pointer-checks is enabled. */ + if (!flag_delete_null_pointer_checks + || !POINTER_TYPE_P (TREE_TYPE (op)) + || gimple_code (stmt) == GIMPLE_ASM) + return false; + + if (walk_stmt_load_store_ops (stmt, (void *)op, + check_loadstore, check_loadstore)) + return true; + + return false; +} + +/* Return true if OP can be inferred to be a non-NULL after STMT + executes by using attributes. */ +bool +infer_nonnull_range_by_attribute (gimple *stmt, tree op) +{ + /* We can only assume that a pointer dereference will yield + non-NULL if -fdelete-null-pointer-checks is enabled. */ + if (!flag_delete_null_pointer_checks + || !POINTER_TYPE_P (TREE_TYPE (op)) + || gimple_code (stmt) == GIMPLE_ASM) + return false; + + if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt)) + { + tree fntype = gimple_call_fntype (stmt); + tree attrs = TYPE_ATTRIBUTES (fntype); + for (; attrs; attrs = TREE_CHAIN (attrs)) + { + attrs = lookup_attribute ("nonnull", attrs); + + /* If "nonnull" wasn't specified, we know nothing about + the argument. */ + if (attrs == NULL_TREE) + return false; + + /* If "nonnull" applies to all the arguments, then ARG + is non-null if it's in the argument list. */ + if (TREE_VALUE (attrs) == NULL_TREE) + { + for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++) + { + if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (stmt, i))) + && operand_equal_p (op, gimple_call_arg (stmt, i), 0)) + return true; + } + return false; + } + + /* Now see if op appears in the nonnull list. */ + for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t)) + { + unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (t)) - 1; + if (idx < gimple_call_num_args (stmt)) + { + tree arg = gimple_call_arg (stmt, idx); + if (operand_equal_p (op, arg, 0)) + return true; + } + } + } + } + + /* If this function is marked as returning non-null, then we can + infer OP is non-null if it is used in the return statement. */ + if (greturn *return_stmt = dyn_cast <greturn *> (stmt)) + if (gimple_return_retval (return_stmt) + && operand_equal_p (gimple_return_retval (return_stmt), op, 0) + && lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) + return true; + + return false; +} + +/* Compare two case labels. Because the front end should already have + made sure that case ranges do not overlap, it is enough to only compare + the CASE_LOW values of each case label. */ + +static int +compare_case_labels (const void *p1, const void *p2) +{ + const_tree const case1 = *(const_tree const*)p1; + const_tree const case2 = *(const_tree const*)p2; + + /* The 'default' case label always goes first. */ + if (!CASE_LOW (case1)) + return -1; + else if (!CASE_LOW (case2)) + return 1; + else + return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2)); +} + +/* Sort the case labels in LABEL_VEC in place in ascending order. */ + +void +sort_case_labels (vec<tree> label_vec) +{ + label_vec.qsort (compare_case_labels); +} + +/* Prepare a vector of case labels to be used in a GIMPLE_SWITCH statement. + + LABELS is a vector that contains all case labels to look at. + + INDEX_TYPE is the type of the switch index expression. Case labels + in LABELS are discarded if their values are not in the value range + covered by INDEX_TYPE. The remaining case label values are folded + to INDEX_TYPE. + + If a default case exists in LABELS, it is removed from LABELS and + returned in DEFAULT_CASEP. If no default case exists, but the + case labels already cover the whole range of INDEX_TYPE, a default + case is returned pointing to one of the existing case labels. + Otherwise DEFAULT_CASEP is set to NULL_TREE. + + DEFAULT_CASEP may be NULL, in which case the above comment doesn't + apply and no action is taken regardless of whether a default case is + found or not. */ + +void +preprocess_case_label_vec_for_gimple (vec<tree> labels, + tree index_type, + tree *default_casep) { - tree fndecl; - return (is_gimple_call (stmt) - && (fndecl = gimple_call_fndecl (stmt)) != NULL - && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL - && DECL_FUNCTION_CODE (fndecl) == code); + tree min_value, max_value; + tree default_case = NULL_TREE; + size_t i, len; + + i = 0; + min_value = TYPE_MIN_VALUE (index_type); + max_value = TYPE_MAX_VALUE (index_type); + while (i < labels.length ()) + { + tree elt = labels[i]; + tree low = CASE_LOW (elt); + tree high = CASE_HIGH (elt); + bool remove_element = FALSE; + + if (low) + { + gcc_checking_assert (TREE_CODE (low) == INTEGER_CST); + gcc_checking_assert (!high || TREE_CODE (high) == INTEGER_CST); + + /* This is a non-default case label, i.e. it has a value. + + See if the case label is reachable within the range of + the index type. Remove out-of-range case values. Turn + case ranges into a canonical form (high > low strictly) + and convert the case label values to the index type. + + NB: The type of gimple_switch_index() may be the promoted + type, but the case labels retain the original type. */ + + if (high) + { + /* This is a case range. Discard empty ranges. + If the bounds or the range are equal, turn this + into a simple (one-value) case. */ + int cmp = tree_int_cst_compare (high, low); + if (cmp < 0) + remove_element = TRUE; + else if (cmp == 0) + high = NULL_TREE; + } + + if (! high) + { + /* If the simple case value is unreachable, ignore it. */ + if ((TREE_CODE (min_value) == INTEGER_CST + && tree_int_cst_compare (low, min_value) < 0) + || (TREE_CODE (max_value) == INTEGER_CST + && tree_int_cst_compare (low, max_value) > 0)) + remove_element = TRUE; + else + low = fold_convert (index_type, low); + } + else + { + /* If the entire case range is unreachable, ignore it. */ + if ((TREE_CODE (min_value) == INTEGER_CST + && tree_int_cst_compare (high, min_value) < 0) + || (TREE_CODE (max_value) == INTEGER_CST + && tree_int_cst_compare (low, max_value) > 0)) + remove_element = TRUE; + else + { + /* If the lower bound is less than the index type's + minimum value, truncate the range bounds. */ + if (TREE_CODE (min_value) == INTEGER_CST + && tree_int_cst_compare (low, min_value) < 0) + low = min_value; + low = fold_convert (index_type, low); + + /* If the upper bound is greater than the index type's + maximum value, truncate the range bounds. */ + if (TREE_CODE (max_value) == INTEGER_CST + && tree_int_cst_compare (high, max_value) > 0) + high = max_value; + high = fold_convert (index_type, high); + + /* We may have folded a case range to a one-value case. */ + if (tree_int_cst_equal (low, high)) + high = NULL_TREE; + } + } + + CASE_LOW (elt) = low; + CASE_HIGH (elt) = high; + } + else + { + gcc_assert (!default_case); + default_case = elt; + /* The default case must be passed separately to the + gimple_build_switch routine. But if DEFAULT_CASEP + is NULL, we do not remove the default case (it would + be completely lost). */ + if (default_casep) + remove_element = TRUE; + } + + if (remove_element) + labels.ordered_remove (i); + else + i++; + } + len = i; + + if (!labels.is_empty ()) + sort_case_labels (labels); + + if (default_casep && !default_case) + { + /* If the switch has no default label, add one, so that we jump + around the switch body. If the labels already cover the whole + range of the switch index_type, add the default label pointing + to one of the existing labels. */ + if (len + && TYPE_MIN_VALUE (index_type) + && TYPE_MAX_VALUE (index_type) + && tree_int_cst_equal (CASE_LOW (labels[0]), + TYPE_MIN_VALUE (index_type))) + { + tree low, high = CASE_HIGH (labels[len - 1]); + if (!high) + high = CASE_LOW (labels[len - 1]); + if (tree_int_cst_equal (high, TYPE_MAX_VALUE (index_type))) + { + tree widest_label = labels[0]; + for (i = 1; i < len; i++) + { + high = CASE_LOW (labels[i]); + low = CASE_HIGH (labels[i - 1]); + if (!low) + low = CASE_LOW (labels[i - 1]); + + if (CASE_HIGH (labels[i]) != NULL_TREE + && (CASE_HIGH (widest_label) == NULL_TREE + || (wi::gtu_p + (wi::to_wide (CASE_HIGH (labels[i])) + - wi::to_wide (CASE_LOW (labels[i])), + wi::to_wide (CASE_HIGH (widest_label)) + - wi::to_wide (CASE_LOW (widest_label)))))) + widest_label = labels[i]; + + if (wi::to_wide (low) + 1 != wi::to_wide (high)) + break; + } + if (i == len) + { + /* Designate the label with the widest range to be the + default label. */ + tree label = CASE_LABEL (widest_label); + default_case = build_case_label (NULL_TREE, NULL_TREE, + label); + } + } + } + } + + if (default_casep) + *default_casep = default_case; +} + +/* Set the location of all statements in SEQ to LOC. */ + +void +gimple_seq_set_location (gimple_seq seq, location_t loc) +{ + for (gimple_stmt_iterator i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) + gimple_set_location (gsi_stmt (i), loc); } -#include "gt-gimple.h" +/* Release SSA_NAMEs in SEQ as well as the GIMPLE statements. */ + +void +gimple_seq_discard (gimple_seq seq) +{ + gimple_stmt_iterator gsi; + + for (gsi = gsi_start (seq); !gsi_end_p (gsi); ) + { + gimple *stmt = gsi_stmt (gsi); + gsi_remove (&gsi, true); + release_defs (stmt); + ggc_free (stmt); + } +} + +/* See if STMT now calls function that takes no parameters and if so, drop + call arguments. This is used when devirtualization machinery redirects + to __builtin_unreachable or __cxa_pure_virtual. */ + +void +maybe_remove_unused_call_args (struct function *fn, gimple *stmt) +{ + tree decl = gimple_call_fndecl (stmt); + if (TYPE_ARG_TYPES (TREE_TYPE (decl)) + && TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))) == void_type_node + && gimple_call_num_args (stmt)) + { + gimple_set_num_ops (stmt, 3); + update_stmt_fn (fn, stmt); + } +} + +/* Return false if STMT will likely expand to real function call. */ + +bool +gimple_inexpensive_call_p (gcall *stmt) +{ + if (gimple_call_internal_p (stmt)) + return true; + tree decl = gimple_call_fndecl (stmt); + if (decl && is_inexpensive_builtin (decl)) + return true; + return false; +} + +#if CHECKING_P + +namespace selftest { + +/* Selftests for core gimple structures. */ + +/* Verify that STMT is pretty-printed as EXPECTED. + Helper function for selftests. */ + +static void +verify_gimple_pp (const char *expected, gimple *stmt) +{ + pretty_printer pp; + pp_gimple_stmt_1 (&pp, stmt, 0 /* spc */, 0 /* flags */); + ASSERT_STREQ (expected, pp_formatted_text (&pp)); +} + +/* Build a GIMPLE_ASSIGN equivalent to + tmp = 5; + and verify various properties of it. */ + +static void +test_assign_single () +{ + tree type = integer_type_node; + tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("tmp"), + type); + tree rhs = build_int_cst (type, 5); + gassign *stmt = gimple_build_assign (lhs, rhs); + verify_gimple_pp ("tmp = 5;", stmt); + + ASSERT_TRUE (is_gimple_assign (stmt)); + ASSERT_EQ (lhs, gimple_assign_lhs (stmt)); + ASSERT_EQ (lhs, gimple_get_lhs (stmt)); + ASSERT_EQ (rhs, gimple_assign_rhs1 (stmt)); + ASSERT_EQ (NULL, gimple_assign_rhs2 (stmt)); + ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt)); + ASSERT_TRUE (gimple_assign_single_p (stmt)); + ASSERT_EQ (INTEGER_CST, gimple_assign_rhs_code (stmt)); +} + +/* Build a GIMPLE_ASSIGN equivalent to + tmp = a * b; + and verify various properties of it. */ + +static void +test_assign_binop () +{ + tree type = integer_type_node; + tree lhs = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("tmp"), + type); + tree a = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("a"), + type); + tree b = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("b"), + type); + gassign *stmt = gimple_build_assign (lhs, MULT_EXPR, a, b); + verify_gimple_pp ("tmp = a * b;", stmt); + + ASSERT_TRUE (is_gimple_assign (stmt)); + ASSERT_EQ (lhs, gimple_assign_lhs (stmt)); + ASSERT_EQ (lhs, gimple_get_lhs (stmt)); + ASSERT_EQ (a, gimple_assign_rhs1 (stmt)); + ASSERT_EQ (b, gimple_assign_rhs2 (stmt)); + ASSERT_EQ (NULL, gimple_assign_rhs3 (stmt)); + ASSERT_FALSE (gimple_assign_single_p (stmt)); + ASSERT_EQ (MULT_EXPR, gimple_assign_rhs_code (stmt)); +} + +/* Build a GIMPLE_NOP and verify various properties of it. */ + +static void +test_nop_stmt () +{ + gimple *stmt = gimple_build_nop (); + verify_gimple_pp ("GIMPLE_NOP", stmt); + ASSERT_EQ (GIMPLE_NOP, gimple_code (stmt)); + ASSERT_EQ (NULL, gimple_get_lhs (stmt)); + ASSERT_FALSE (gimple_assign_single_p (stmt)); +} + +/* Build a GIMPLE_RETURN equivalent to + return 7; + and verify various properties of it. */ + +static void +test_return_stmt () +{ + tree type = integer_type_node; + tree val = build_int_cst (type, 7); + greturn *stmt = gimple_build_return (val); + verify_gimple_pp ("return 7;", stmt); + + ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt)); + ASSERT_EQ (NULL, gimple_get_lhs (stmt)); + ASSERT_EQ (val, gimple_return_retval (stmt)); + ASSERT_FALSE (gimple_assign_single_p (stmt)); +} + +/* Build a GIMPLE_RETURN equivalent to + return; + and verify various properties of it. */ + +static void +test_return_without_value () +{ + greturn *stmt = gimple_build_return (NULL); + verify_gimple_pp ("return;", stmt); + + ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt)); + ASSERT_EQ (NULL, gimple_get_lhs (stmt)); + ASSERT_EQ (NULL, gimple_return_retval (stmt)); + ASSERT_FALSE (gimple_assign_single_p (stmt)); +} + +/* Run all of the selftests within this file. */ + +void +gimple_c_tests () +{ + test_assign_single (); + test_assign_binop (); + test_nop_stmt (); + test_return_stmt (); + test_return_without_value (); +} + +} // namespace selftest + + +#endif /* CHECKING_P */