gcc/ * gimple.h (gimple_switch): New subclass of gimple_stmt_with_ops, adding the invariant that stmt->code == GIMPLE_SWITCH. (is_a_helper <gimple_switch *>::test): New. (is_a_helper <const gimple_switch *>::test): New. (gimple_try): Likewise.
* coretypes.h (gimple_switch): Add forward declaration here. * gdbhooks.py (build_pretty_printer): Add gimple_switch, using the gimple printer. * gimple.c (gimple_build_switch_nlabels): Return a gimple_switch rather than just a gimple. (gimple_build_switch): Likewise. * gimple.h (gimple_build_switch_nlabels): Likewise. (gimple_build_switch): Likewise. * gimple.h (gimple_switch_num_labels): Update type-signature to require a gimple_switch rather than just a gimple. (gimple_switch_set_num_labels): Likewise. (gimple_switch_set_index): Likewise. (gimple_switch_label): Likewise. (gimple_switch_set_label): Likewise. (gimple_switch_default_label): Likewise. (gimple_switch_set_default_label): Likewise. * expr.h (expand_case): Likewise. * gimple-pretty-print.c (dump_gimple_call): Likewise. * stmt.c (compute_cases_per_edge): Likewise. (expand_case): Likewise. * tree-cfg.h (group_case_labels_stmt): Likewise. * tree-cfg.c (make_gimple_switch_edges): Likewise. (find_taken_edge_switch_expr) Likewise. (find_case_label_for_value) Likewise. (get_cases_for_edge): Likewise. (group_case_labels_stmt): Likewise. (verify_gimple_switch): Likewise. * tree-eh.c (verify_norecord_switch_expr): Likewise. * tree-eh.c (lower_eh_constructs_2): Likewise. * tree-loop-distribution.c (generate_loops_for_partition): Likewise. * tree-ssa-dom.c (record_edge_info): Likewise. * tree-ssa-forwprop.c (simplify_gimple_switch_label_vec): Likewise. (simplify_gimple_switch): Likewise. * tree-switch-conversion.c (emit_case_bit_tests): Likewise. (collect_switch_conv_info): Likewise. (build_constructors): Likewise. (array_value_type): Likewise. (build_one_array): Likewise. (build_arrays): Likewise. (gen_inbound_check): Likewise. * tree-vrp.c (find_switch_asserts): Likewise. (find_case_label_range): Likewise. (find_case_label_ranges): Likewise. (vrp_visit_switch_stmt): Likewise. (simplify_switch_using_ranges): Likewise. * tree-vrp.c (switch_update): Strengthen field "stmt" from being merely a gimple_stmt * to being a gimple_switch *. * cfgexpand.c (expand_gimple_stmt_1): Add checked cast to gimple_switch in regions where the stmt code has been tested as GIMPLE_SWITCH. * gimple-pretty-print.c (pp_gimple_stmt_1): Likewise. * tree-cfg.c (make_edges): Likewise. (end_recording_case_labels): Likewise. (cleanup_dead_labels): Likewise. (cleanup_dead_labels): Likewise. (group_case_labels): Likewise. (find_taken_edge): Likewise. (find_case_label_for_value): Likewise. (verify_gimple_stmt): Likewise. (gimple_verify_flow_info): Likewise. (gimple_redirect_edge_and_branch): Likewise. * tree-inline.c (estimate_num_insns): Likewise. * tree-ssa-forwprop.c (ssa_forward_propagate_and_combine): Likewise. * tree-ssa-uncprop.c (associate_equivalences_with_edges): Likewise. * tree-switch-conversion.c (do_switchconv): Likewise. * tree-vrp.c (find_assert_locations_1): Likewise. (vrp_visit_stmt): Likewise. (simplify_stmt_using_ranges): Likewise. * ipa-inline-analysis.c (set_switch_stmt_execution_predicate): Introduce local "lastg" as a generic gimple, so that local "last" can be of type gimple_switch once lastg's code has been verified. * omp-low.c (diagnose_sb_2): Introduce switch_stmt local to handle the GIMPLE_SWITCH case. * tree-cfg.c (find_taken_edge_switch_expr): Add gimple_switch argument, since the caller (find_taken_edge) has checked that last_stmt is a switch. * doc/gimple.texi (Class hierarchy of GIMPLE statements): Add gimple_switch class. (GIMPLE_SWITCH): Update signatures of accessor functions to reflect above gimple_stmt to gimple_switch changes. --- gcc/cfgexpand.c | 2 +- gcc/coretypes.h | 5 ++++ gcc/doc/gimple.texi | 34 ++++++++++++++----------- gcc/expr.h | 2 +- gcc/gdbhooks.py | 4 ++- gcc/gimple-pretty-print.c | 4 +-- gcc/gimple.c | 11 +++++---- gcc/gimple.h | 44 ++++++++++++++++++++++++++------- gcc/ipa-inline-analysis.c | 7 +++--- gcc/omp-low.c | 5 ++-- gcc/stmt.c | 4 +-- gcc/tree-cfg.c | 59 ++++++++++++++++++++++---------------------- gcc/tree-cfg.h | 2 +- gcc/tree-eh.c | 5 ++-- gcc/tree-inline.c | 21 +++++++++------- gcc/tree-loop-distribution.c | 5 ++-- gcc/tree-ssa-dom.c | 8 +++--- gcc/tree-ssa-forwprop.c | 6 ++--- gcc/tree-ssa-uncprop.c | 8 +++--- gcc/tree-switch-conversion.c | 18 +++++++------- gcc/tree-vrp.c | 24 +++++++++--------- 21 files changed, 162 insertions(+), 116 deletions(-) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 00d0db2..992521c 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3161,7 +3161,7 @@ expand_gimple_stmt_1 (gimple_stmt *stmt) case GIMPLE_PREDICT: break; case GIMPLE_SWITCH: - expand_case (stmt); + expand_case (as_a <gimple_switch *> (stmt)); break; case GIMPLE_ASM: expand_asm_stmt (stmt); diff --git a/gcc/coretypes.h b/gcc/coretypes.h index c48f146..6aeb2b6 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -64,6 +64,11 @@ typedef const union tree_node *const_tree; class gimple_stmt; typedef gimple_stmt *gimple_seq; struct gimple_stmt_iterator; + +/* Forward declarations of gimple subclasses. + Keep this in the same order as the corresponding codes in gimple.def. */ +class gimple_switch; + union section; typedef union section section; struct gcc_options; diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi index 6fc4360..311c586 100644 --- a/gcc/doc/gimple.texi +++ b/gcc/doc/gimple.texi @@ -311,12 +311,14 @@ kinds, along with their relationships to @code{GSS_} values (layouts) and | | (no GSS layout) | | | + gimple_stmt_with_ops - | | layout: GSS_WITH_OPS - | | Used for 5 codes: GIMPLE_COND - | | GIMPLE_DEBUG - | | GIMPLE_GOTO - | | GIMPLE_LABEL - | | GIMPLE_SWITCH + | | | layout: GSS_WITH_OPS + | | | Used for 4 codes: GIMPLE_COND + | | | GIMPLE_DEBUG + | | | GIMPLE_GOTO + | | | GIMPLE_LABEL + | | | + | | + gimple_switch + | | code: GIMPLE_SWITCH | | | + gimple_stmt_with_memory_ops_base | | layout: GSS_WITH_MEM_OPS_BASE @@ -2252,7 +2254,7 @@ Set @code{RETVAL} to be the return value for @code{GIMPLE_RETURN} @code{G}. @subsection @code{GIMPLE_SWITCH} @cindex @code{GIMPLE_SWITCH} -@deftypefn {GIMPLE function} gimple_stmt *gimple_build_switch (tree index, @ +@deftypefn {GIMPLE function} gimple_switch *gimple_build_switch (tree index, @ tree default_label, @code{VEC}(tree,heap) *args) Build a @code{GIMPLE_SWITCH} statement. @code{INDEX} is the index variable to switch on, and @code{DEFAULT_LABEL} represents the default label. @@ -2260,44 +2262,46 @@ to switch on, and @code{DEFAULT_LABEL} represents the default label. non-default case labels. Each label is a tree of code @code{CASE_LABEL_EXPR}. @end deftypefn -@deftypefn {GIMPLE function} unsigned gimple_switch_num_labels (gimple_stmt *g) +@deftypefn {GIMPLE function} unsigned gimple_switch_num_labels (@ +const gimple_switch *g) Return the number of labels associated with the switch statement @code{G}. @end deftypefn @deftypefn {GIMPLE function} void gimple_switch_set_num_labels (@ -gimple_stmt *g, unsigned nlabels) +gimple_switch *g, unsigned nlabels) Set @code{NLABELS} to be the number of labels for the switch statement @code{G}. @end deftypefn -@deftypefn {GIMPLE function} tree gimple_switch_index (gimple_stmt *g) +@deftypefn {GIMPLE function} tree gimple_switch_index (const gimple_switch *g) Return the index variable used by the switch statement @code{G}. @end deftypefn -@deftypefn {GIMPLE function} void gimple_switch_set_index (gimple_stmt *g, @ +@deftypefn {GIMPLE function} void gimple_switch_set_index (gimple_switch *g, @ tree index) Set @code{INDEX} to be the index variable for switch statement @code{G}. @end deftypefn -@deftypefn {GIMPLE function} tree gimple_switch_label (gimple_stmt *g, @ +@deftypefn {GIMPLE function} tree gimple_switch_label (const gimple_switch *g, @ unsigned index) Return the label numbered @code{INDEX}. The default label is 0, followed by any labels in a switch statement. @end deftypefn -@deftypefn {GIMPLE function} void gimple_switch_set_label (gimple_stmt *g, @ +@deftypefn {GIMPLE function} void gimple_switch_set_label (gimple_switch *g, @ unsigned index, tree label) Set the label number @code{INDEX} to @code{LABEL}. 0 is always the default label. @end deftypefn -@deftypefn {GIMPLE function} tree gimple_switch_default_label (gimple_stmt *g) +@deftypefn {GIMPLE function} tree gimple_switch_default_label (@ +const gimple_switch *g) Return the default label for a switch statement. @end deftypefn @deftypefn {GIMPLE function} void gimple_switch_set_default_label (@ -gimple_stmt *g, tree label) +gimple_switch *g, tree label) Set the default label for a switch statement. @end deftypefn diff --git a/gcc/expr.h b/gcc/expr.h index 73a32f7..807dad5 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -777,7 +777,7 @@ rtx get_personality_function (tree); /* In stmt.c */ /* Expand a GIMPLE_SWITCH statement. */ -extern void expand_case (gimple_stmt *); +extern void expand_case (gimple_switch *); /* Like expand_case but special-case for SJLJ exception dispatching. */ extern void expand_sjlj_dispatch_table (rtx, vec<tree> ); diff --git a/gcc/gdbhooks.py b/gcc/gdbhooks.py index 2bc67f0..f5171f3 100644 --- a/gcc/gdbhooks.py +++ b/gcc/gdbhooks.py @@ -454,7 +454,9 @@ def build_pretty_printer(): 'tree', TreePrinter) pp.add_printer_for_types(['cgraph_node *'], 'cgraph_node', CGraphNodePrinter) - pp.add_printer_for_types(['gimple_stmt *'], + pp.add_printer_for_types(['gimple_stmt *', + # Keep this in the same order as gimple.def: + 'gimple_switch *'], 'gimple', GimplePrinter) pp.add_printer_for_types(['basic_block', 'basic_block_def *'], diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 268b43bb..03ad971 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -775,7 +775,7 @@ dump_gimple_call (pretty_printer *buffer, gimple_stmt *gs, int spc, int flags) pp_gimple_stmt_1. */ static void -dump_gimple_switch (pretty_printer *buffer, gimple_stmt *gs, int spc, int flags) +dump_gimple_switch (pretty_printer *buffer, gimple_switch *gs, int spc, int flags) { unsigned int i; @@ -2126,7 +2126,7 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple_stmt *gs, int spc, int flags) break; case GIMPLE_SWITCH: - dump_gimple_switch (buffer, gs, spc, flags); + dump_gimple_switch (buffer, as_a <gimple_switch *> (gs), spc, flags); break; case GIMPLE_TRY: diff --git a/gcc/gimple.c b/gcc/gimple.c index bc8d757..9701f49 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -714,13 +714,14 @@ gimple_build_resx (int region) NLABELS is the number of labels in the switch excluding the default. DEFAULT_LABEL is the default label for the switch statement. */ -gimple_stmt * +gimple_switch * gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label) { /* nlabels + 1 default label + 1 index. */ gcc_checking_assert (default_label); - gimple_stmt *p = gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK, - 1 + 1 + nlabels); + gimple_switch *p = + as_a <gimple_switch *> (gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK, + 1 + 1 + nlabels)); gimple_switch_set_index (p, index); gimple_switch_set_default_label (p, default_label); return p; @@ -732,12 +733,12 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label) DEFAULT_LABEL is the default label ARGS is a vector of labels excluding the default. */ -gimple_stmt * +gimple_switch * gimple_build_switch (tree index, tree default_label, vec<tree> args) { unsigned i, nlabels = args.length (); - gimple_stmt *p = gimple_build_switch_nlabels (nlabels, index, default_label); + gimple_switch *p = gimple_build_switch_nlabels (nlabels, index, default_label); /* Copy the labels from the vector to the switch statement. */ for (i = 0; i < nlabels; i++) diff --git a/gcc/gimple.h b/gcc/gimple.h index 4cc88f0..0bf8853 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -764,6 +764,16 @@ enum gimple_statement_structure_enum { }; #undef DEFGSSTRUCT +/* A statement with the invariant that + stmt->code == GIMPLE_SWITCH + i.e. a switch statement. */ + +struct GTY((tag("GSS_WITH_OPS"))) + gimple_switch : public gimple_stmt_with_ops +{ + /* no additional fields; this uses the layout for GSS_WITH_OPS. */ +}; + template <> template <> inline bool @@ -951,6 +961,14 @@ is_a_helper <gimple_phi *>::test (gimple_stmt *gs) template <> template <> inline bool +is_a_helper <gimple_switch *>::test (gimple_stmt *gs) +{ + return gs->code == GIMPLE_SWITCH; +} + +template <> +template <> +inline bool is_a_helper <gimple_transaction *>::test (gimple_stmt *gs) { return gs->code == GIMPLE_TRANSACTION; @@ -1143,6 +1161,14 @@ is_a_helper <const gimple_phi *>::test (const gimple_stmt *gs) template <> template <> inline bool +is_a_helper <const gimple_switch *>::test (const gimple_stmt *gs) +{ + return gs->code == GIMPLE_SWITCH; +} + +template <> +template <> +inline bool is_a_helper <const gimple_transaction *>::test (const gimple_stmt *gs) { return gs->code == GIMPLE_TRANSACTION; @@ -1193,8 +1219,8 @@ gimple_try *gimple_build_try (gimple_seq, gimple_seq, enum gimple_try_flags); gimple_stmt *gimple_build_wce (gimple_seq); gimple_stmt *gimple_build_resx (int); -gimple_stmt *gimple_build_switch_nlabels (unsigned, tree, tree); -gimple_stmt *gimple_build_switch (tree, tree, vec<tree> ); +gimple_switch *gimple_build_switch_nlabels (unsigned, tree, tree); +gimple_switch *gimple_build_switch (tree, tree, vec<tree> ); gimple_stmt *gimple_build_eh_dispatch (int); gimple_stmt *gimple_build_debug_bind_stat (tree, tree, gimple_stmt *MEM_STAT_DECL); #define gimple_build_debug_bind(var,val,stmt) \ @@ -3942,7 +3968,7 @@ gimple_eh_dispatch_set_region (gimple_stmt *gs, int region) /* Return the number of labels associated with the switch statement GS. */ static inline unsigned -gimple_switch_num_labels (const gimple_stmt *gs) +gimple_switch_num_labels (const gimple_switch *gs) { unsigned num_ops; GIMPLE_CHECK (gs, GIMPLE_SWITCH); @@ -3955,7 +3981,7 @@ gimple_switch_num_labels (const gimple_stmt *gs) /* Set NLABELS to be the number of labels for the switch statement GS. */ static inline void -gimple_switch_set_num_labels (gimple_stmt *g, unsigned nlabels) +gimple_switch_set_num_labels (gimple_switch *g, unsigned nlabels) { GIMPLE_CHECK (g, GIMPLE_SWITCH); gimple_set_num_ops (g, nlabels + 1); @@ -3985,7 +4011,7 @@ gimple_switch_index_ptr (const gimple_stmt *gs) /* Set INDEX to be the index variable for switch statement GS. */ static inline void -gimple_switch_set_index (gimple_stmt *gs, tree index) +gimple_switch_set_index (gimple_switch *gs, tree index) { GIMPLE_CHECK (gs, GIMPLE_SWITCH); gcc_gimple_checking_assert (SSA_VAR_P (index) || CONSTANT_CLASS_P (index)); @@ -3997,7 +4023,7 @@ gimple_switch_set_index (gimple_stmt *gs, tree index) labels in a switch statement. */ static inline tree -gimple_switch_label (const gimple_stmt *gs, unsigned index) +gimple_switch_label (const gimple_switch *gs, unsigned index) { GIMPLE_CHECK (gs, GIMPLE_SWITCH); gcc_gimple_checking_assert (gimple_num_ops (gs) > index + 1); @@ -4007,7 +4033,7 @@ gimple_switch_label (const gimple_stmt *gs, unsigned index) /* Set the label number INDEX to LABEL. 0 is always the default label. */ static inline void -gimple_switch_set_label (gimple_stmt *gs, unsigned index, tree label) +gimple_switch_set_label (gimple_switch *gs, unsigned index, tree label) { GIMPLE_CHECK (gs, GIMPLE_SWITCH); gcc_gimple_checking_assert (gimple_num_ops (gs) > index + 1 @@ -4019,7 +4045,7 @@ gimple_switch_set_label (gimple_stmt *gs, unsigned index, tree label) /* Return the default label for a switch statement. */ static inline tree -gimple_switch_default_label (const gimple_stmt *gs) +gimple_switch_default_label (const gimple_switch *gs) { tree label = gimple_switch_label (gs, 0); gcc_checking_assert (!CASE_LOW (label) && !CASE_HIGH (label)); @@ -4029,7 +4055,7 @@ gimple_switch_default_label (const gimple_stmt *gs) /* Set the default label for a switch statement. */ static inline void -gimple_switch_set_default_label (gimple_stmt *gs, tree label) +gimple_switch_set_default_label (gimple_switch *gs, tree label) { gcc_checking_assert (!CASE_LOW (label) && !CASE_HIGH (label)); gimple_switch_set_label (gs, 0, label); diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index d4ecc09..35517c8 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -1801,7 +1801,7 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info, struct inline_summary *summary, basic_block bb) { - gimple_stmt *last; + gimple_stmt *lastg; tree op; int index; struct agg_position_info aggpos; @@ -1810,9 +1810,10 @@ set_switch_stmt_execution_predicate (struct ipa_node_params *info, size_t n; size_t case_idx; - last = last_stmt (bb); - if (!last || gimple_code (last) != GIMPLE_SWITCH) + lastg = last_stmt (bb); + if (!lastg || gimple_code (lastg) != GIMPLE_SWITCH) return; + gimple_switch *last = as_a <gimple_switch *> (lastg); op = gimple_switch_index (last); if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos)) return; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index f402d50..b6c845b 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -10462,10 +10462,11 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_SWITCH: { + gimple_switch *switch_stmt = as_a <gimple_switch *> (stmt); unsigned int i; - for (i = 0; i < gimple_switch_num_labels (stmt); ++i) + for (i = 0; i < gimple_switch_num_labels (switch_stmt); ++i) { - tree lab = CASE_LABEL (gimple_switch_label (stmt, i)); + tree lab = CASE_LABEL (gimple_switch_label (switch_stmt, i)); n = splay_tree_lookup (all_labels, (splay_tree_key) lab); if (n && diagnose_sb_0 (gsi_p, context, (gimple_stmt *) n->value)) break; diff --git a/gcc/stmt.c b/gcc/stmt.c index 32dffaa..c1ae362 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -1130,7 +1130,7 @@ reset_out_edges_aux (basic_block bb) STMT. Record this information in the aux field of the edge. */ static inline void -compute_cases_per_edge (gimple_stmt *stmt) +compute_cases_per_edge (gimple_switch *stmt) { basic_block bb = gimple_bb (stmt); reset_out_edges_aux (bb); @@ -1152,7 +1152,7 @@ compute_cases_per_edge (gimple_stmt *stmt) Generate the code to test it and jump to the right place. */ void -expand_case (gimple_stmt *stmt) +expand_case (gimple_switch *stmt) { tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE; rtx default_label = NULL_RTX; diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 22621d2..e75c3b4 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -150,7 +150,7 @@ static void make_blocks (gimple_seq); static void make_edges (void); static void assign_discriminators (void); static void make_cond_expr_edges (basic_block); -static void make_gimple_switch_edges (basic_block); +static void make_gimple_switch_edges (gimple_switch *, basic_block); static bool make_goto_expr_edges (basic_block); static void make_gimple_asm_edges (basic_block); static edge gimple_redirect_edge_and_branch (edge, basic_block); @@ -169,8 +169,8 @@ static bool gimple_can_merge_blocks_p (basic_block, basic_block); static void remove_bb (basic_block); static edge find_taken_edge_computed_goto (basic_block, tree); static edge find_taken_edge_cond_expr (basic_block, tree); -static edge find_taken_edge_switch_expr (basic_block, tree); -static tree find_case_label_for_value (gimple_stmt *, tree); +static edge find_taken_edge_switch_expr (gimple_switch *, basic_block, tree); +static tree find_case_label_for_value (gimple_switch *, tree); void init_empty_tree_cfg_for_function (struct function *fn) @@ -769,7 +769,7 @@ make_edges (void) fallthru = false; break; case GIMPLE_SWITCH: - make_gimple_switch_edges (bb); + make_gimple_switch_edges (as_a <gimple_switch *> (last), bb); fallthru = false; break; case GIMPLE_RESX: @@ -1094,7 +1094,7 @@ end_recording_case_labels (void) { gimple_stmt *stmt = last_stmt (bb); if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) - group_case_labels_stmt (stmt); + group_case_labels_stmt (as_a <gimple_switch *> (stmt)); } } BITMAP_FREE (touched_switch_bbs); @@ -1106,7 +1106,7 @@ end_recording_case_labels (void) Otherwise return NULL. */ static tree -get_cases_for_edge (edge e, gimple_stmt *t) +get_cases_for_edge (edge e, gimple_switch *t) { void **slot; size_t i, n; @@ -1145,9 +1145,8 @@ get_cases_for_edge (edge e, gimple_stmt *t) /* Create the edges for a GIMPLE_SWITCH starting at block BB. */ static void -make_gimple_switch_edges (basic_block bb) +make_gimple_switch_edges (gimple_switch *entry, basic_block bb) { - gimple_stmt *entry = last_stmt (bb); size_t i, n; n = gimple_switch_num_labels (entry); @@ -1398,12 +1397,13 @@ cleanup_dead_labels (void) case GIMPLE_SWITCH: { - size_t i, n = gimple_switch_num_labels (stmt); + gimple_switch *switch_stmt = as_a <gimple_switch *> (stmt); + size_t i, n = gimple_switch_num_labels (switch_stmt); /* Replace all destination labels. */ for (i = 0; i < n; ++i) { - tree case_label = gimple_switch_label (stmt, i); + tree case_label = gimple_switch_label (switch_stmt, i); label = CASE_LABEL (case_label); new_label = main_block_label (label); if (new_label != label) @@ -1500,7 +1500,7 @@ cleanup_dead_labels (void) Eg. three separate entries 1: 2: 3: become one entry 1..3: */ void -group_case_labels_stmt (gimple_stmt *stmt) +group_case_labels_stmt (gimple_switch *stmt) { int old_size = gimple_switch_num_labels (stmt); int i, j, new_size = old_size; @@ -1588,7 +1588,7 @@ group_case_labels (void) { gimple_stmt *stmt = last_stmt (bb); if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) - group_case_labels_stmt (stmt); + group_case_labels_stmt (as_a <gimple_switch *> (stmt)); } } @@ -2053,8 +2053,8 @@ find_taken_edge (basic_block bb, tree val) if (gimple_code (stmt) == GIMPLE_COND) return find_taken_edge_cond_expr (bb, val); - if (gimple_code (stmt) == GIMPLE_SWITCH) - return find_taken_edge_switch_expr (bb, val); + if (gimple_switch *switch_stmt = dyn_cast <gimple_switch *> (stmt)) + return find_taken_edge_switch_expr (switch_stmt, bb, val); if (computed_goto_p (stmt)) { @@ -2113,14 +2113,13 @@ find_taken_edge_cond_expr (basic_block bb, tree val) NULL if any edge may be taken. */ static edge -find_taken_edge_switch_expr (basic_block bb, tree val) +find_taken_edge_switch_expr (gimple_switch *switch_stmt, basic_block bb, + tree val) { basic_block dest_bb; edge e; - gimple_stmt *switch_stmt; tree taken_case; - switch_stmt = last_stmt (bb); taken_case = find_case_label_for_value (switch_stmt, val); dest_bb = label_to_block (CASE_LABEL (taken_case)); @@ -2135,7 +2134,7 @@ find_taken_edge_switch_expr (basic_block bb, tree val) sorted: We can do a binary search for a case matching VAL. */ static tree -find_case_label_for_value (gimple_stmt *switch_stmt, tree val) +find_case_label_for_value (gimple_switch *switch_stmt, tree val) { size_t low, high, n = gimple_switch_num_labels (switch_stmt); tree default_case = gimple_switch_default_label (switch_stmt); @@ -4262,7 +4261,7 @@ verify_gimple_goto (gimple_stmt *stmt) is a problem, otherwise false. */ static bool -verify_gimple_switch (gimple_stmt *stmt) +verify_gimple_switch (gimple_switch *stmt) { unsigned int i, n; tree elt, prev_upper_bound = NULL_TREE; @@ -4444,7 +4443,7 @@ verify_gimple_stmt (gimple_stmt *stmt) return verify_gimple_goto (stmt); case GIMPLE_SWITCH: - return verify_gimple_switch (stmt); + return verify_gimple_switch (as_a <gimple_switch *> (stmt)); case GIMPLE_RETURN: return verify_gimple_return (stmt); @@ -5177,26 +5176,27 @@ gimple_verify_flow_info (void) case GIMPLE_SWITCH: { + gimple_switch *switch_stmt = as_a <gimple_switch *> (stmt); tree prev; edge e; size_t i, n; - n = gimple_switch_num_labels (stmt); + n = gimple_switch_num_labels (switch_stmt); /* Mark all the destination basic blocks. */ for (i = 0; i < n; ++i) { - tree lab = CASE_LABEL (gimple_switch_label (stmt, i)); + tree lab = CASE_LABEL (gimple_switch_label (switch_stmt, i)); basic_block label_bb = label_to_block (lab); gcc_assert (!label_bb->aux || label_bb->aux == (void *)1); label_bb->aux = (void *)1; } /* Verify that the case labels are sorted. */ - prev = gimple_switch_label (stmt, 0); + prev = gimple_switch_label (switch_stmt, 0); for (i = 1; i < n; ++i) { - tree c = gimple_switch_label (stmt, i); + tree c = gimple_switch_label (switch_stmt, i); if (!CASE_LOW (c)) { error ("found default case not at the start of " @@ -5242,7 +5242,7 @@ gimple_verify_flow_info (void) /* Check that we have all of them. */ for (i = 0; i < n; ++i) { - tree lab = CASE_LABEL (gimple_switch_label (stmt, i)); + tree lab = CASE_LABEL (gimple_switch_label (switch_stmt, i)); basic_block label_bb = label_to_block (lab); if (label_bb->aux != (void *)2) @@ -5430,8 +5430,9 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) case GIMPLE_SWITCH: { + gimple_switch *switch_stmt = as_a <gimple_switch *> (stmt); tree label = gimple_block_label (dest); - tree cases = get_cases_for_edge (e, stmt); + tree cases = get_cases_for_edge (e, switch_stmt); /* If we have a list of cases associated with E, then use it as it's a lot faster than walking the entire case vector. */ @@ -5452,7 +5453,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) to move all the cases associated with E to E2. */ if (e2) { - tree cases2 = get_cases_for_edge (e2, stmt); + tree cases2 = get_cases_for_edge (e2, switch_stmt); CASE_CHAIN (last) = CASE_CHAIN (cases2); CASE_CHAIN (cases2) = first; @@ -5461,11 +5462,11 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) } else { - size_t i, n = gimple_switch_num_labels (stmt); + size_t i, n = gimple_switch_num_labels (switch_stmt); for (i = 0; i < n; i++) { - tree elt = gimple_switch_label (stmt, i); + tree elt = gimple_switch_label (switch_stmt, i); if (label_to_block (CASE_LABEL (elt)) == e->dest) CASE_LABEL (elt) = label; } diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h index 347b55e..39fd302 100644 --- a/gcc/tree-cfg.h +++ b/gcc/tree-cfg.h @@ -32,7 +32,7 @@ extern void end_recording_case_labels (void); extern basic_block label_to_block_fn (struct function *, tree); #define label_to_block(t) (label_to_block_fn (cfun, t)) extern void cleanup_dead_labels (void); -extern void group_case_labels_stmt (gimple_stmt *); +extern void group_case_labels_stmt (gimple_switch *); extern void group_case_labels (void); extern void replace_uses_by (tree, tree); extern basic_block single_noncomplex_succ (basic_block bb); diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 08e23ef..44bfd0c3 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -713,7 +713,8 @@ maybe_record_in_goto_queue (struct leh_state *state, gimple_stmt *stmt) of the labels will leave outer GIMPLE_TRY_FINALLY nodes. Verify this. */ static void -verify_norecord_switch_expr (struct leh_state *state, gimple_stmt *switch_expr) +verify_norecord_switch_expr (struct leh_state *state, + gimple_switch *switch_expr) { struct leh_tf_state *tf = state->tf; size_t i, n; @@ -2057,7 +2058,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi) break; case GIMPLE_SWITCH: - verify_norecord_switch_expr (state, stmt); + verify_norecord_switch_expr (state, as_a <gimple_switch *> (stmt)); break; case GIMPLE_TRY: diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index ce4b0fb..32ae17a 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -3813,15 +3813,18 @@ estimate_num_insns (gimple_stmt *stmt, eni_weights *weights) break; case GIMPLE_SWITCH: - /* Take into account cost of the switch + guess 2 conditional jumps for - each case label. - - TODO: once the switch expansion logic is sufficiently separated, we can - do better job on estimating cost of the switch. */ - if (weights->time_based) - cost = floor_log2 (gimple_switch_num_labels (stmt)) * 2; - else - cost = gimple_switch_num_labels (stmt) * 2; + { + gimple_switch *switch_stmt = as_a <gimple_switch *> (stmt); + /* Take into account cost of the switch + guess 2 conditional jumps for + each case label. + + TODO: once the switch expansion logic is sufficiently separated, we can + do better job on estimating cost of the switch. */ + if (weights->time_based) + cost = floor_log2 (gimple_switch_num_labels (switch_stmt)) * 2; + else + cost = gimple_switch_num_labels (switch_stmt) * 2; + } break; case GIMPLE_CALL: diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 41a5559..7eca65a 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -685,10 +685,11 @@ generate_loops_for_partition (struct loop *loop, partition_t partition, gimple_cond_make_false (stmt); update_stmt (stmt); } - else if (gimple_code (stmt) == GIMPLE_SWITCH) + else if (gimple_switch *switch_stmt = + dyn_cast <gimple_switch *> (stmt)) { gimple_switch_set_index - (stmt, CASE_LOW (gimple_switch_label (stmt, 1))); + (switch_stmt, CASE_LOW (gimple_switch_label (switch_stmt, 1))); update_stmt (stmt); } else diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 7f5b4bb..244d79d 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -1784,21 +1784,21 @@ record_edge_info (basic_block bb) gimple_stmt *stmt = gsi_stmt (gsi); location_t loc = gimple_location (stmt); - if (gimple_code (stmt) == GIMPLE_SWITCH) + if (gimple_switch *switch_stmt = dyn_cast <gimple_switch *> (stmt)) { - tree index = gimple_switch_index (stmt); + tree index = gimple_switch_index (switch_stmt); if (TREE_CODE (index) == SSA_NAME) { int i; - int n_labels = gimple_switch_num_labels (stmt); + int n_labels = gimple_switch_num_labels (switch_stmt); tree *info = XCNEWVEC (tree, last_basic_block_for_fn (cfun)); edge e; edge_iterator ei; for (i = 0; i < n_labels; i++) { - tree label = gimple_switch_label (stmt, i); + tree label = gimple_switch_label (switch_stmt, i); basic_block target_bb = label_to_block (CASE_LABEL (label)); if (CASE_HIGH (label) || !CASE_LOW (label) diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 793f0fa..893a62c 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1284,7 +1284,7 @@ simplify_not_neg_expr (gimple_stmt_iterator *gsi_p) have values outside the range of the new type. */ static void -simplify_gimple_switch_label_vec (gimple_stmt *stmt, tree index_type) +simplify_gimple_switch_label_vec (gimple_switch *stmt, tree index_type) { unsigned int branch_num = gimple_switch_num_labels (stmt); auto_vec<tree> labels (branch_num); @@ -1354,7 +1354,7 @@ simplify_gimple_switch_label_vec (gimple_stmt *stmt, tree index_type) the condition which we may be able to optimize better. */ static bool -simplify_gimple_switch (gimple_stmt *stmt) +simplify_gimple_switch (gimple_switch *stmt) { /* The optimization that we really care about is removing unnecessary casts. That will let us do much better in propagating the inferred @@ -3809,7 +3809,7 @@ pass_forwprop::execute (function *fun) } case GIMPLE_SWITCH: - changed = simplify_gimple_switch (stmt); + changed = simplify_gimple_switch (as_a <gimple_switch *> (stmt)); break; case GIMPLE_COND: diff --git a/gcc/tree-ssa-uncprop.c b/gcc/tree-ssa-uncprop.c index 50ae88f..9b07967 100644 --- a/gcc/tree-ssa-uncprop.c +++ b/gcc/tree-ssa-uncprop.c @@ -171,14 +171,14 @@ associate_equivalences_with_edges (void) /* For a SWITCH_EXPR, a case label which represents a single value and which is the only case label which reaches the target block creates an equivalence. */ - else if (gimple_code (stmt) == GIMPLE_SWITCH) + else if (gimple_switch *switch_stmt = dyn_cast <gimple_switch *> (stmt)) { - tree cond = gimple_switch_index (stmt); + tree cond = gimple_switch_index (switch_stmt); if (TREE_CODE (cond) == SSA_NAME && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (cond)) { - int i, n_labels = gimple_switch_num_labels (stmt); + int i, n_labels = gimple_switch_num_labels (switch_stmt); tree *info = XCNEWVEC (tree, last_basic_block_for_fn (cfun)); /* Walk over the case label vector. Record blocks @@ -186,7 +186,7 @@ associate_equivalences_with_edges (void) a single value. */ for (i = 0; i < n_labels; i++) { - tree label = gimple_switch_label (stmt, i); + tree label = gimple_switch_label (switch_stmt, i); basic_block bb = label_to_block (CASE_LABEL (label)); if (CASE_HIGH (label) diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c index a831a64..909355c 100644 --- a/gcc/tree-switch-conversion.c +++ b/gcc/tree-switch-conversion.c @@ -299,7 +299,7 @@ case_bit_test_cmp (const void *p1, const void *p2) node targets. */ static void -emit_case_bit_tests (gimple_stmt *swtch, tree index_expr, +emit_case_bit_tests (gimple_switch *swtch, tree index_expr, tree minval, tree range) { struct case_bit_test test[MAX_CASE_BIT_TESTS]; @@ -609,7 +609,7 @@ struct switch_conv_info /* Collect information about GIMPLE_SWITCH statement SWTCH into INFO. */ static void -collect_switch_conv_info (gimple_stmt *swtch, struct switch_conv_info *info) +collect_switch_conv_info (gimple_switch *swtch, struct switch_conv_info *info) { unsigned int branch_num = gimple_switch_num_labels (swtch); tree min_case, max_case; @@ -853,7 +853,7 @@ gather_default_values (tree default_case, struct switch_conv_info *info) order of phi nodes. SWTCH is the switch statement being converted. */ static void -build_constructors (gimple_stmt *swtch, struct switch_conv_info *info) +build_constructors (gimple_switch *swtch, struct switch_conv_info *info) { unsigned i, branch_num = gimple_switch_num_labels (swtch); tree pos = info->range_min; @@ -945,7 +945,7 @@ constructor_contains_same_values_p (vec<constructor_elt, va_gc> *vec) all the constants. */ static tree -array_value_type (gimple_stmt *swtch, tree type, int num, +array_value_type (gimple_switch *swtch, tree type, int num, struct switch_conv_info *info) { unsigned int i, len = vec_safe_length (info->constructors[num]); @@ -1022,7 +1022,7 @@ array_value_type (gimple_stmt *swtch, tree type, int num, new array. */ static void -build_one_array (gimple_stmt *swtch, int num, tree arr_index_type, gimple_stmt *phi, +build_one_array (gimple_switch *swtch, int num, tree arr_index_type, gimple_stmt *phi, tree tidx, struct switch_conv_info *info) { tree name, cst; @@ -1088,7 +1088,7 @@ build_one_array (gimple_stmt *swtch, int num, tree arr_index_type, gimple_stmt * them. */ static void -build_arrays (gimple_stmt *swtch, struct switch_conv_info *info) +build_arrays (gimple_switch *swtch, struct switch_conv_info *info) { tree arr_index_type; tree tidx, sub, utype; @@ -1209,7 +1209,7 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf, */ static void -gen_inbound_check (gimple_stmt *swtch, struct switch_conv_info *info) +gen_inbound_check (gimple_switch *swtch, struct switch_conv_info *info) { tree label_decl1 = create_artificial_label (UNKNOWN_LOCATION); tree label_decl2 = create_artificial_label (UNKNOWN_LOCATION); @@ -1329,7 +1329,7 @@ gen_inbound_check (gimple_stmt *swtch, struct switch_conv_info *info) conversion failed. */ static const char * -process_switch (gimple_stmt *swtch) +process_switch (gimple_switch *swtch) { struct switch_conv_info info; @@ -1467,7 +1467,7 @@ pass_convert_switch::execute (function *fun) putc ('\n', dump_file); } - failure_reason = process_switch (stmt); + failure_reason = process_switch (as_a <gimple_switch *> (stmt)); if (! failure_reason) { if (dump_file) diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index b8db7a3..9252219 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -168,7 +168,7 @@ static bool values_propagated; static int *vr_phi_edge_counts; typedef struct { - gimple_stmt *stmt; + gimple_switch *stmt; tree vec; } switch_update; @@ -5616,7 +5616,7 @@ compare_case_labels (const void *p1, const void *p2) list of assertions for the corresponding operands. */ static bool -find_switch_asserts (basic_block bb, gimple_stmt *last) +find_switch_asserts (basic_block bb, gimple_switch *last) { bool need_assert; gimple_stmt_iterator bsi; @@ -5787,7 +5787,7 @@ find_assert_locations_1 (basic_block bb, sbitmap live) if (last && gimple_code (last) == GIMPLE_SWITCH && !ZERO_SSA_OPERANDS (last, SSA_OP_USE)) - need_assert |= find_switch_asserts (bb, last); + need_assert |= find_switch_asserts (bb, as_a <gimple_switch *> (last)); /* Traverse all the statements in BB marking used names and looking for statements that may infer assertions for their used operands. */ @@ -7269,7 +7269,7 @@ vrp_visit_cond_stmt (gimple_stmt *stmt, edge *taken_edge_p) returned. */ static bool -find_case_label_index (gimple_stmt *stmt, size_t start_idx, tree val, size_t *idx) +find_case_label_index (gimple_switch *stmt, size_t start_idx, tree val, size_t *idx) { size_t n = gimple_switch_num_labels (stmt); size_t low, high; @@ -7319,7 +7319,7 @@ find_case_label_index (gimple_stmt *stmt, size_t start_idx, tree val, size_t *id Returns true if the default label is not needed. */ static bool -find_case_label_range (gimple_stmt *stmt, tree min, tree max, size_t *min_idx, +find_case_label_range (gimple_switch *stmt, tree min, tree max, size_t *min_idx, size_t *max_idx) { size_t i, j; @@ -7375,7 +7375,7 @@ find_case_label_range (gimple_stmt *stmt, tree min, tree max, size_t *min_idx, Returns true if the default label is not needed. */ static bool -find_case_label_ranges (gimple_stmt *stmt, value_range_t *vr, size_t *min_idx1, +find_case_label_ranges (gimple_switch *stmt, value_range_t *vr, size_t *min_idx1, size_t *max_idx1, size_t *min_idx2, size_t *max_idx2) { @@ -7453,7 +7453,7 @@ find_case_label_ranges (gimple_stmt *stmt, value_range_t *vr, size_t *min_idx1, SSA_PROP_VARYING. */ static enum ssa_prop_result -vrp_visit_switch_stmt (gimple_stmt *stmt, edge *taken_edge_p) +vrp_visit_switch_stmt (gimple_switch *stmt, edge *taken_edge_p) { tree op, val; value_range_t *vr; @@ -7568,8 +7568,8 @@ vrp_visit_stmt (gimple_stmt *stmt, edge *taken_edge_p, tree *output_p) return vrp_visit_assignment_or_call (stmt, output_p); else if (gimple_code (stmt) == GIMPLE_COND) return vrp_visit_cond_stmt (stmt, taken_edge_p); - else if (gimple_code (stmt) == GIMPLE_SWITCH) - return vrp_visit_switch_stmt (stmt, taken_edge_p); + else if (gimple_switch *switch_stmt = dyn_cast <gimple_switch *> (stmt)) + return vrp_visit_switch_stmt (switch_stmt, taken_edge_p); /* All other statements produce nothing of interest for VRP, so mark their outputs varying and prevent further simulation. */ @@ -9020,7 +9020,7 @@ simplify_cond_using_ranges (gimple_stmt *stmt) argument. */ static bool -simplify_switch_using_ranges (gimple_stmt *stmt) +simplify_switch_using_ranges (gimple_switch *stmt) { tree op = gimple_switch_index (stmt); value_range_t *vr; @@ -9414,8 +9414,8 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) } else if (gimple_code (stmt) == GIMPLE_COND) return simplify_cond_using_ranges (stmt); - else if (gimple_code (stmt) == GIMPLE_SWITCH) - return simplify_switch_using_ranges (stmt); + else if (gimple_switch *switch_stmt = dyn_cast <gimple_switch *> (stmt)) + return simplify_switch_using_ranges (switch_stmt); else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt)) return simplify_internal_call_using_ranges (gsi, stmt); -- 1.8.5.3