On Sat, 29 Apr 2017, Jakub Jelinek wrote: > On Wed, Feb 15, 2017 at 12:51:30PM +0100, Jakub Jelinek wrote: > > On Wed, Feb 15, 2017 at 12:46:44PM +0100, Richard Biener wrote: > > > >> Possibly, but for GCC 8. > > > > > > > > To both this switchconv patch and the potential improvement for loading > > > > from const arrays (can create an enhancement PR for that), or just the > > > > latter? > > > > > > Both I think - the patch is pretty big. > > > > Ok, I'll queue the patch for GCC8 then. > > If the tree-vrp.c change makes it in, is this patch ok for trunk too now > that we are in stage1? Bootstrapped/regtested on x86_64-linux and > i686-linux on top of the tree-vrp.c change (without the tree-vrp.c change > vrp40.c regresses).
Ok. Thanks, Richard. > 2017-04-29 Jakub Jelinek <ja...@redhat.com> > > PR tree-optimization/79472 > * tree-switch-conversion.c (struct switch_conv_info): Add > contiguous_range and default_case_nonstandard fields. > (collect_switch_conv_info): Compute contiguous_range and > default_case_nonstandard fields, don't clear final_bb if > contiguous_range and only the default case doesn't have the required > structure. > (check_all_empty_except_final): Set default_case_nonstandard instead > of failing if contiguous_range and the default case doesn't have empty > block. > (check_final_bb): Add SWTCH argument, don't fail if contiguous_range > and only the default case doesn't have the required constants. Skip > virtual phis. > (gather_default_values): Skip virtual phis. Allow non-NULL CASE_LOW > if default_case_nonstandard. > (build_constructors): Build constant 1 just once. Assert that default > values aren't inserted in between cases if contiguous_range. Skip > virtual phis. > (build_arrays): Skip virtual phis. > (prune_bbs): Add DEFAULT_BB argument, don't remove that bb. > (fix_phi_nodes): Don't add e2f phi arg if default_case_nonstandard. > Handle virtual phis. > (gen_inbound_check): Handle default_case_nonstandard case. > (process_switch): Adjust check_final_bb caller. Call > gather_default_values with the first non-default case instead of > default case if default_case_nonstandard. > > * gcc.dg/tree-ssa/cswtch-3.c: New test. > * gcc.dg/tree-ssa/cswtch-4.c: New test. > * gcc.dg/tree-ssa/cswtch-5.c: New test. > > --- gcc/tree-switch-conversion.c.jj 2017-02-14 14:54:08.020975500 +0100 > +++ gcc/tree-switch-conversion.c 2017-02-14 17:09:01.162826954 +0100 > @@ -592,6 +592,14 @@ struct switch_conv_info > dump file, if there is one. */ > const char *reason; > > + /* True if default case is not used for any value between range_min and > + range_max inclusive. */ > + bool contiguous_range; > + > + /* True if default case does not have the required shape for other case > + labels. */ > + bool default_case_nonstandard; > + > /* Parameters for expand_switch_using_bit_tests. Should be computed > the same way as in expand_case. */ > unsigned int uniq; > @@ -606,8 +614,9 @@ collect_switch_conv_info (gswitch *swtch > unsigned int branch_num = gimple_switch_num_labels (swtch); > tree min_case, max_case; > unsigned int count, i; > - edge e, e_default; > + edge e, e_default, e_first; > edge_iterator ei; > + basic_block first; > > memset (info, 0, sizeof (*info)); > > @@ -616,8 +625,8 @@ collect_switch_conv_info (gswitch *swtch > Collect the bits we can deduce from the CFG. */ > info->index_expr = gimple_switch_index (swtch); > info->switch_bb = gimple_bb (swtch); > - info->default_bb = > - label_to_block (CASE_LABEL (gimple_switch_default_label (swtch))); > + info->default_bb > + = label_to_block (CASE_LABEL (gimple_switch_default_label (swtch))); > e_default = find_edge (info->switch_bb, info->default_bb); > info->default_prob = e_default->probability; > info->default_count = e_default->count; > @@ -625,17 +634,54 @@ collect_switch_conv_info (gswitch *swtch > if (e != e_default) > info->other_count += e->count; > > + /* Get upper and lower bounds of case values, and the covered range. */ > + min_case = gimple_switch_label (swtch, 1); > + max_case = gimple_switch_label (swtch, branch_num - 1); > + > + info->range_min = CASE_LOW (min_case); > + if (CASE_HIGH (max_case) != NULL_TREE) > + info->range_max = CASE_HIGH (max_case); > + else > + info->range_max = CASE_LOW (max_case); > + > + info->contiguous_range = true; > + tree last = CASE_HIGH (min_case) ? CASE_HIGH (min_case) : info->range_min; > + for (i = 2; i < branch_num; i++) > + { > + tree elt = gimple_switch_label (swtch, i); > + wide_int w = last; > + if (w + 1 != CASE_LOW (elt)) > + { > + info->contiguous_range = false; > + break; > + } > + last = CASE_HIGH (elt) ? CASE_HIGH (elt) : CASE_LOW (elt); > + } > + > + if (info->contiguous_range) > + { > + first = label_to_block (CASE_LABEL (gimple_switch_label (swtch, 1))); > + e_first = find_edge (info->switch_bb, first); > + } > + else > + { > + first = info->default_bb; > + e_first = e_default; > + } > + > /* See if there is one common successor block for all branch > targets. If it exists, record it in FINAL_BB. > - Start with the destination of the default case as guess > - or its destination in case it is a forwarder block. */ > - if (! single_pred_p (e_default->dest)) > - info->final_bb = e_default->dest; > - else if (single_succ_p (e_default->dest) > - && ! single_pred_p (single_succ (e_default->dest))) > - info->final_bb = single_succ (e_default->dest); > + Start with the destination of the first non-default case > + if the range is contiguous and default case otherwise as > + guess or its destination in case it is a forwarder block. */ > + if (! single_pred_p (e_first->dest)) > + info->final_bb = e_first->dest; > + else if (single_succ_p (e_first->dest) > + && ! single_pred_p (single_succ (e_first->dest))) > + info->final_bb = single_succ (e_first->dest); > /* Require that all switch destinations are either that common > - FINAL_BB or a forwarder to it. */ > + FINAL_BB or a forwarder to it, except for the default > + case if contiguous range. */ > if (info->final_bb) > FOR_EACH_EDGE (e, ei, info->switch_bb->succs) > { > @@ -647,22 +693,18 @@ collect_switch_conv_info (gswitch *swtch > && single_succ (e->dest) == info->final_bb) > continue; > > + if (e == e_default && info->contiguous_range) > + { > + info->default_case_nonstandard = true; > + continue; > + } > + > info->final_bb = NULL; > break; > } > > - /* Get upper and lower bounds of case values, and the covered range. */ > - min_case = gimple_switch_label (swtch, 1); > - max_case = gimple_switch_label (swtch, branch_num - 1); > - > - info->range_min = CASE_LOW (min_case); > - if (CASE_HIGH (max_case) != NULL_TREE) > - info->range_max = CASE_HIGH (max_case); > - else > - info->range_max = CASE_LOW (max_case); > - > - info->range_size = > - int_const_binop (MINUS_EXPR, info->range_max, info->range_min); > + info->range_size > + = int_const_binop (MINUS_EXPR, info->range_max, info->range_min); > > /* Get a count of the number of case labels. Single-valued case labels > simply count as one, but a case range counts double, since it may > @@ -713,7 +755,7 @@ check_range (struct switch_conv_info *in > static bool > check_all_empty_except_final (struct switch_conv_info *info) > { > - edge e; > + edge e, e_default = find_edge (info->switch_bb, info->default_bb); > edge_iterator ei; > > FOR_EACH_EDGE (e, ei, info->switch_bb->succs) > @@ -723,6 +765,12 @@ check_all_empty_except_final (struct swi > > if (!empty_block_p (e->dest)) > { > + if (info->contiguous_range && e == e_default) > + { > + info->default_case_nonstandard = true; > + continue; > + } > + > info->reason = "bad case - a non-final BB not empty"; > return false; > } > @@ -737,7 +785,7 @@ check_all_empty_except_final (struct swi > phi nodes are OK, otherwise false. */ > > static bool > -check_final_bb (struct switch_conv_info *info) > +check_final_bb (gswitch *swtch, struct switch_conv_info *info) > { > gphi_iterator gsi; > > @@ -747,6 +795,9 @@ check_final_bb (struct switch_conv_info > gphi *phi = gsi.phi (); > unsigned int i; > > + if (virtual_operand_p (gimple_phi_result (phi))) > + continue; > + > info->phi_count++; > > for (i = 0; i < gimple_phi_num_args (phi); i++) > @@ -754,27 +805,55 @@ check_final_bb (struct switch_conv_info > basic_block bb = gimple_phi_arg_edge (phi, i)->src; > > if (bb == info->switch_bb > - || (single_pred_p (bb) && single_pred (bb) == info->switch_bb)) > + || (single_pred_p (bb) > + && single_pred (bb) == info->switch_bb > + && (!info->default_case_nonstandard > + || empty_block_p (bb)))) > { > tree reloc, val; > + const char *reason = NULL; > > val = gimple_phi_arg_def (phi, i); > if (!is_gimple_ip_invariant (val)) > + reason = "non-invariant value from a case"; > + else > { > - info->reason = "non-invariant value from a case"; > - return false; /* Non-invariant argument. */ > + reloc = initializer_constant_valid_p (val, TREE_TYPE (val)); > + if ((flag_pic && reloc != null_pointer_node) > + || (!flag_pic && reloc == NULL_TREE)) > + { > + if (reloc) > + reason > + = "value from a case would need runtime relocations"; > + else > + reason > + = "value from a case is not a valid initializer"; > + } > } > - reloc = initializer_constant_valid_p (val, TREE_TYPE (val)); > - if ((flag_pic && reloc != null_pointer_node) > - || (!flag_pic && reloc == NULL_TREE)) > + if (reason) > { > - if (reloc) > - info->reason > - = "value from a case would need runtime relocations"; > - else > - info->reason > - = "value from a case is not a valid initializer"; > - return false; > + /* For contiguous range, we can allow non-constant > + or one that needs relocation, as long as it is > + only reachable from the default case. */ > + if (bb == info->switch_bb) > + bb = info->final_bb; > + if (!info->contiguous_range || bb != info->default_bb) > + { > + info->reason = reason; > + return false; > + } > + > + unsigned int branch_num = gimple_switch_num_labels (swtch); > + for (unsigned int i = 1; i < branch_num; i++) > + { > + tree lab = CASE_LABEL (gimple_switch_label (swtch, i)); > + if (label_to_block (lab) == bb) > + { > + info->reason = reason; > + return false; > + } > + } > + info->default_case_nonstandard = true; > } > } > } > @@ -815,7 +894,9 @@ free_temp_arrays (struct switch_conv_inf > } > > /* Populate the array of default values in the order of phi nodes. > - DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch. */ > + DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch > + if the range is non-contiguous or the default case has standard > + structure, otherwise it is the first non-default case instead. */ > > static void > gather_default_values (tree default_case, struct switch_conv_info *info) > @@ -825,7 +906,8 @@ gather_default_values (tree default_case > edge e; > int i = 0; > > - gcc_assert (CASE_LOW (default_case) == NULL_TREE); > + gcc_assert (CASE_LOW (default_case) == NULL_TREE > + || info->default_case_nonstandard); > > if (bb == info->final_bb) > e = find_edge (info->switch_bb, bb); > @@ -835,6 +917,8 @@ gather_default_values (tree default_case > for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next > (&gsi)) > { > gphi *phi = gsi.phi (); > + if (virtual_operand_p (gimple_phi_result (phi))) > + continue; > tree val = PHI_ARG_DEF_FROM_EDGE (phi, e); > gcc_assert (val); > info->default_values[i++] = val; > @@ -850,6 +934,7 @@ build_constructors (gswitch *swtch, stru > { > unsigned i, branch_num = gimple_switch_num_labels (swtch); > tree pos = info->range_min; > + tree pos_one = build_int_cst (TREE_TYPE (pos), 1); > > for (i = 1; i < branch_num; i++) > { > @@ -869,6 +954,7 @@ build_constructors (gswitch *swtch, stru > while (tree_int_cst_lt (pos, CASE_LOW (cs))) > { > int k; > + gcc_assert (!info->contiguous_range); > for (k = 0; k < info->phi_count; k++) > { > constructor_elt elt; > @@ -879,8 +965,7 @@ build_constructors (gswitch *swtch, stru > info->constructors[k]->quick_push (elt); > } > > - pos = int_const_binop (PLUS_EXPR, pos, > - build_int_cst (TREE_TYPE (pos), 1)); > + pos = int_const_binop (PLUS_EXPR, pos, pos_one); > } > gcc_assert (tree_int_cst_equal (pos, CASE_LOW (cs))); > > @@ -893,6 +978,8 @@ build_constructors (gswitch *swtch, stru > !gsi_end_p (gsi); gsi_next (&gsi)) > { > gphi *phi = gsi.phi (); > + if (virtual_operand_p (gimple_phi_result (phi))) > + continue; > tree val = PHI_ARG_DEF_FROM_EDGE (phi, e); > tree low = CASE_LOW (cs); > pos = CASE_LOW (cs); > @@ -905,8 +992,7 @@ build_constructors (gswitch *swtch, stru > elt.value = unshare_expr_without_location (val); > info->constructors[j]->quick_push (elt); > > - pos = int_const_binop (PLUS_EXPR, pos, > - build_int_cst (TREE_TYPE (pos), 1)); > + pos = int_const_binop (PLUS_EXPR, pos, pos_one); > } while (!tree_int_cst_lt (high, pos) > && tree_int_cst_lt (low, pos)); > j++; > @@ -1118,8 +1204,12 @@ build_arrays (gswitch *swtch, struct swi > info->arr_ref_first = stmt; > > for (gpi = gsi_start_phis (info->final_bb), i = 0; > - !gsi_end_p (gpi); gsi_next (&gpi), i++) > - build_one_array (swtch, i, arr_index_type, gpi.phi (), tidx, info); > + !gsi_end_p (gpi); gsi_next (&gpi)) > + { > + gphi *phi = gpi.phi (); > + if (!virtual_operand_p (gimple_phi_result (phi))) > + build_one_array (swtch, i++, arr_index_type, phi, tidx, info); > + } > } > > /* Generates and appropriately inserts loads of default values at the > position > @@ -1148,7 +1238,7 @@ gen_def_assigns (gimple_stmt_iterator *g > of succession). */ > > static void > -prune_bbs (basic_block bbd, basic_block final) > +prune_bbs (basic_block bbd, basic_block final, basic_block default_bb) > { > edge_iterator ei; > edge e; > @@ -1158,7 +1248,7 @@ prune_bbs (basic_block bbd, basic_block > basic_block bb; > bb = e->dest; > remove_edge (e); > - if (bb != final) > + if (bb != final && bb != default_bb) > delete_basic_block (bb); > } > delete_basic_block (bbd); > @@ -1177,11 +1267,20 @@ fix_phi_nodes (edge e1f, edge e2f, basic > int i; > > for (gsi = gsi_start_phis (bbf), i = 0; > - !gsi_end_p (gsi); gsi_next (&gsi), i++) > + !gsi_end_p (gsi); gsi_next (&gsi)) > { > gphi *phi = gsi.phi (); > - add_phi_arg (phi, info->target_inbound_names[i], e1f, > UNKNOWN_LOCATION); > - add_phi_arg (phi, info->target_outbound_names[i], e2f, > UNKNOWN_LOCATION); > + tree inbound, outbound; > + if (virtual_operand_p (gimple_phi_result (phi))) > + inbound = outbound = gimple_vop (cfun); > + else > + { > + inbound = info->target_inbound_names[i]; > + outbound = info->target_outbound_names[i++]; > + } > + add_phi_arg (phi, inbound, e1f, UNKNOWN_LOCATION); > + if (!info->default_case_nonstandard) > + add_phi_arg (phi, outbound, e2f, UNKNOWN_LOCATION); > } > } > > @@ -1218,10 +1317,10 @@ gen_inbound_check (gswitch *swtch, struc > > gcond *cond_stmt; > > - gassign *last_assign; > + gassign *last_assign = NULL; > gimple_stmt_iterator gsi; > basic_block bb0, bb1, bb2, bbf, bbd; > - edge e01, e02, e21, e1d, e1f, e2f; > + edge e01 = NULL, e02, e21, e1d, e1f, e2f; > location_t loc = gimple_location (swtch); > > gcc_assert (info->default_values); > @@ -1241,9 +1340,12 @@ gen_inbound_check (gswitch *swtch, struc > update_stmt (cond_stmt); > > /* block 2 */ > - label2 = gimple_build_label (label_decl2); > - gsi_insert_before (&gsi, label2, GSI_SAME_STMT); > - last_assign = gen_def_assigns (&gsi, info); > + if (!info->default_case_nonstandard) > + { > + label2 = gimple_build_label (label_decl2); > + gsi_insert_before (&gsi, label2, GSI_SAME_STMT); > + last_assign = gen_def_assigns (&gsi, info); > + } > > /* block 1 */ > label1 = gimple_build_label (label_decl1); > @@ -1258,16 +1360,40 @@ gen_inbound_check (gswitch *swtch, struc > e02 = split_block (bb0, cond_stmt); > bb2 = e02->dest; > > - e21 = split_block (bb2, last_assign); > - bb1 = e21->dest; > - remove_edge (e21); > + if (info->default_case_nonstandard) > + { > + bb1 = bb2; > + bb2 = info->default_bb; > + e01 = e02; > + e01->flags = EDGE_TRUE_VALUE; > + e02 = make_edge (bb0, bb2, EDGE_FALSE_VALUE); > + edge e_default = find_edge (bb1, bb2); > + for (gphi_iterator gsi = gsi_start_phis (bb2); > + !gsi_end_p (gsi); gsi_next (&gsi)) > + { > + gphi *phi = gsi.phi (); > + tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e_default); > + add_phi_arg (phi, arg, e02, > + gimple_phi_arg_location_from_edge (phi, e_default)); > + } > + /* Partially fix the dominator tree, if it is available. */ > + if (dom_info_available_p (CDI_DOMINATORS)) > + redirect_immediate_dominators (CDI_DOMINATORS, bb1, bb0); > + } > + else > + { > + e21 = split_block (bb2, last_assign); > + bb1 = e21->dest; > + remove_edge (e21); > + } > > e1d = split_block (bb1, info->arr_ref_last); > bbd = e1d->dest; > remove_edge (e1d); > > /* flags and profiles of the edge for in-range values */ > - e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE); > + if (!info->default_case_nonstandard) > + e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE); > e01->probability = REG_BR_PROB_BASE - info->default_prob; > e01->count = info->other_count; > > @@ -1283,17 +1409,24 @@ gen_inbound_check (gswitch *swtch, struc > e1f->probability = REG_BR_PROB_BASE; > e1f->count = info->other_count; > > - e2f = make_edge (bb2, bbf, EDGE_FALLTHRU); > - e2f->probability = REG_BR_PROB_BASE; > - e2f->count = info->default_count; > + if (info->default_case_nonstandard) > + e2f = NULL; > + else > + { > + e2f = make_edge (bb2, bbf, EDGE_FALLTHRU); > + e2f->probability = REG_BR_PROB_BASE; > + e2f->count = info->default_count; > + } > > /* frequencies of the new BBs */ > bb1->frequency = EDGE_FREQUENCY (e01); > bb2->frequency = EDGE_FREQUENCY (e02); > - bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f); > + if (!info->default_case_nonstandard) > + bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f); > > /* Tidy blocks that have become unreachable. */ > - prune_bbs (bbd, info->final_bb); > + prune_bbs (bbd, info->final_bb, > + info->default_case_nonstandard ? info->default_bb : NULL); > > /* Fixup the PHI nodes in bbF. */ > fix_phi_nodes (e1f, e2f, bbf, info); > @@ -1304,15 +1437,17 @@ gen_inbound_check (gswitch *swtch, struc > vec<basic_block> bbs_to_fix_dom; > > set_immediate_dominator (CDI_DOMINATORS, bb1, bb0); > - set_immediate_dominator (CDI_DOMINATORS, bb2, bb0); > + if (!info->default_case_nonstandard) > + set_immediate_dominator (CDI_DOMINATORS, bb2, bb0); > if (! get_immediate_dominator (CDI_DOMINATORS, bbf)) > /* If bbD was the immediate dominator ... */ > set_immediate_dominator (CDI_DOMINATORS, bbf, bb0); > > - bbs_to_fix_dom.create (4); > + bbs_to_fix_dom.create (3 + (bb2 != bbf)); > bbs_to_fix_dom.quick_push (bb0); > bbs_to_fix_dom.quick_push (bb1); > - bbs_to_fix_dom.quick_push (bb2); > + if (bb2 != bbf) > + bbs_to_fix_dom.quick_push (bb2); > bbs_to_fix_dom.quick_push (bbf); > > iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true); > @@ -1387,7 +1522,7 @@ process_switch (gswitch *swtch) > gcc_assert (info.reason); > return info.reason; > } > - if (!check_final_bb (&info)) > + if (!check_final_bb (swtch, &info)) > { > gcc_assert (info.reason); > return info.reason; > @@ -1397,7 +1532,9 @@ process_switch (gswitch *swtch) > transformation. */ > > create_temp_arrays (&info); > - gather_default_values (gimple_switch_default_label (swtch), &info); > + gather_default_values (info.default_case_nonstandard > + ? gimple_switch_label (swtch, 1) > + : gimple_switch_default_label (swtch), &info); > build_constructors (swtch, &info); > > build_arrays (swtch, &info); /* Build the static arrays and assignments. > */ > --- gcc/testsuite/gcc.dg/tree-ssa/cswtch-3.c.jj 2017-02-14 > 15:46:55.002417399 +0100 > +++ gcc/testsuite/gcc.dg/tree-ssa/cswtch-3.c 2017-02-14 15:46:55.002417399 > +0100 > @@ -0,0 +1,330 @@ > +/* PR tree-optimization/79472 */ > +/* { dg-options "-O2 -fdump-tree-switchconv" } */ > +/* { dg-do run } */ > + > +int *expected; > + > +void > +foo (int x, int y) > +{ > + if (x != expected[0] || y != expected[1]) > + __builtin_abort (); > + expected += 2; > +} > + > +__attribute__((noinline, noclone)) void > +f1 (int v, int w) > +{ > + int i, j; > + if (w) > + { > + i = 129; > + j = i - 1; > + goto lab; > + } > + switch (v) > + { > + case 170: > + j = 7; > + i = 27; > + break; > + case 171: > + i = 8; > + j = 122; > + break; > + case 172: > + i = 21; > + j = -19; > + break; > + case 173: > + i = 18; > + j = 17; > + break; > + case 174: > + i = 139; > + j = -5; > + break; > + case 175: > + i = 14; > + j = -26; > + break; > + case 176: > + j = 5; > + i = -14; > + break; > + case 177: > + j = 8; > + i = 12; > + break; > + default: > + __builtin_abort (); > + } > + > + lab: > + foo (i, j); > +} > + > +__attribute__((noinline, noclone)) void > +f2 (int v) > +{ > + int i, j; > + switch (v) > + { > + case 170: > + j = 7; > + i = 27; > + break; > + case 171: > + i = 8; > + j = 122; > + break; > + case 172: > + i = 21; > + j = -19; > + break; > + case 173: > + i = 18; > + j = 17; > + break; > + case 174: > + i = 139; > + j = -5; > + break; > + case 175: > + i = 14; > + j = -26; > + break; > + case 176: > + j = 5; > + i = -14; > + break; > + case 177: > + j = 8; > + i = 12; > + break; > + default: > + foo (5, 12); > + foo (17, 19); > + i = 8; > + j = 19; > + break; > + } > + > + foo (i, j); > +} > + > +__attribute__((noinline, noclone)) void > +f3 (int v) > +{ > + int i; > + switch (v) > + { > + default: > + i = v; > + goto lab; > + case 170: > + i = 27; > + break; > + case 171: > + i = 8; > + break; > + case 172: > + i = 21; > + break; > + case 173: > + i = 18; > + break; > + case 174: > + i = 139; > + break; > + case 175: > + i = 14; > + break; > + case 176: > + i = -14; > + break; > + case 177: > + i = 12; > + break; > + } > + > + lab: > + foo (i, -5); > +} > + > +__attribute__((noinline, noclone)) void > +f4 (int v, int w) > +{ > + int i, j, k = 5; > + if (w) > + { > + foo (0, 0); > + k = 26; > + goto do_default; > + } > + switch (v) > + { > + case 170: > + j = 7; > + i = 27; > + break; > + case 171: > + i = 8; > + j = 122; > + break; > + case 172: > + i = 21; > + j = -19; > + break; > + case 173: > + i = 18; > + j = 17; > + break; > + case 174: > + i = 139; > + j = -5; > + break; > + case 175: > + i = 14; > + j = -26; > + break; > + case 176: > + j = 5; > + i = -14; > + break; > + case 177: > + j = 8; > + i = 12; > + break; > + default: > + do_default: > + foo (5, 12); > + foo (17, 19); > + i = 8; > + j = 19; > + break; > + } > + > + foo (i, j + k); > +} > + > +void > +f5 (int v, int w) > +{ > + int i; > + if (w) > + { > + foo (23, 0); > + i = 129; > + } > + else > + switch (v) > + { > + case 170: > + i = 27; > + break; > + case 171: > + i = 8; > + break; > + case 172: > + i = 21; > + break; > + case 173: > + i = 18; > + break; > + case 174: > + i = 139; > + break; > + case 175: > + i = 14; > + break; > + case 176: > + i = -14; > + break; > + case 177: > + i = 12; > + break; > + default: > + i = 80; > + break; > + } > + > + lab: > + foo (i, 0); > +} > + > +int > +main () > +{ > + int *e; > +#define T(call, cnt, ...) \ > + expected = e = (int []) __VA_ARGS__; \ > + call; \ > + if (expected != e + cnt) \ > + __builtin_abort () > + T (f1 (171, 1), 2, { 129, 128 }); > + T (f1 (140, 1), 2, { 129, 128 }); > + T (f1 (170, 0), 2, { 27, 7 }); > + T (f1 (171, 0), 2, { 8, 122 }); > + T (f1 (172, 0), 2, { 21, -19 }); > + T (f1 (173, 0), 2, { 18, 17 }); > + T (f1 (174, 0), 2, { 139, -5 }); > + T (f1 (175, 0), 2, { 14, -26 }); > + T (f1 (176, 0), 2, { -14, 5 }); > + T (f1 (177, 0), 2, { 12, 8 }); > + T (f2 (-31), 6, { 5, 12, 17, 19, 8, 19 }); > + T (f2 (169), 6, { 5, 12, 17, 19, 8, 19 }); > + T (f2 (170), 2, { 27, 7 }); > + T (f2 (171), 2, { 8, 122 }); > + T (f2 (172), 2, { 21, -19 }); > + T (f2 (173), 2, { 18, 17 }); > + T (f2 (174), 2, { 139, -5 }); > + T (f2 (175), 2, { 14, -26 }); > + T (f2 (176), 2, { -14, 5 }); > + T (f2 (177), 2, { 12, 8 }); > + T (f2 (178), 6, { 5, 12, 17, 19, 8, 19 }); > + T (f2 (231), 6, { 5, 12, 17, 19, 8, 19 }); > + T (f3 (-31), 2, { -31, -5 }); > + T (f3 (169), 2, { 169, -5 }); > + T (f3 (170), 2, { 27, -5 }); > + T (f3 (171), 2, { 8, -5 }); > + T (f3 (172), 2, { 21, -5 }); > + T (f3 (173), 2, { 18, -5 }); > + T (f3 (174), 2, { 139, -5 }); > + T (f3 (175), 2, { 14, -5 }); > + T (f3 (176), 2, { -14, -5 }); > + T (f3 (177), 2, { 12, -5 }); > + T (f3 (178), 2, { 178, -5 }); > + T (f3 (231), 2, { 231, -5 }); > + T (f4 (171, 1), 8, { 0, 0, 5, 12, 17, 19, 8, 45 }); > + T (f4 (140, 1), 8, { 0, 0, 5, 12, 17, 19, 8, 45 }); > + T (f4 (-31, 0), 6, { 5, 12, 17, 19, 8, 24 }); > + T (f4 (169, 0), 6, { 5, 12, 17, 19, 8, 24 }); > + T (f4 (170, 0), 2, { 27, 12 }); > + T (f4 (171, 0), 2, { 8, 127 }); > + T (f4 (172, 0), 2, { 21, -14 }); > + T (f4 (173, 0), 2, { 18, 22 }); > + T (f4 (174, 0), 2, { 139, 0 }); > + T (f4 (175, 0), 2, { 14, -21 }); > + T (f4 (176, 0), 2, { -14, 10 }); > + T (f4 (177, 0), 2, { 12, 13 }); > + T (f4 (178, 0), 6, { 5, 12, 17, 19, 8, 24 }); > + T (f4 (231, 0), 6, { 5, 12, 17, 19, 8, 24 }); > + T (f5 (171, 1), 4, { 23, 0, 129, 0 }); > + T (f5 (140, 1), 4, { 23, 0, 129, 0 }); > + T (f5 (-31, 0), 2, { 80, 0 }); > + T (f5 (169, 0), 2, { 80, 0 }); > + T (f5 (170, 0), 2, { 27, 0 }); > + T (f5 (171, 0), 2, { 8, 0 }); > + T (f5 (172, 0), 2, { 21, 0 }); > + T (f5 (173, 0), 2, { 18, 0 }); > + T (f5 (174, 0), 2, { 139, 0 }); > + T (f5 (175, 0), 2, { 14, 0 }); > + T (f5 (176, 0), 2, { -14, 0 }); > + T (f5 (177, 0), 2, { 12, 0 }); > + T (f5 (178, 0), 2, { 80, 0 }); > + T (f5 (231, 0), 2, { 80, 0 }); > +} > + > +/* { dg-final { scan-tree-dump-times "Switch converted" 5 "switchconv" } } */ > +/* { dg-final { scan-tree-dump-times "= CSWTCH" 8 "switchconv" } } */ > --- gcc/testsuite/gcc.dg/tree-ssa/cswtch-4.c.jj 2017-02-14 > 15:46:55.003417386 +0100 > +++ gcc/testsuite/gcc.dg/tree-ssa/cswtch-4.c 2017-02-14 15:46:55.003417386 > +0100 > @@ -0,0 +1,57 @@ > +/* PR tree-optimization/79472 */ > +/* { dg-options "-O2 -fdump-tree-switchconv" } */ > +/* { dg-do compile } */ > + > +void > +frobulate (unsigned int v) > +{ > + const char *s; > + > + switch (v) > + { > + case 0: > + s = "foo"; > + break; > + case 1: > + s = "bar"; > + break; > + case 2: > + s = "spam"; > + break; > + default: > + __builtin_abort (); > + break; > + } > + > + __builtin_printf ("%s\n", s); > +} > + > +void > +frobulate_for_gcc (unsigned int v) > +{ > + const char *s; > + > + switch (v) > + { > + case 0: > + s = "foo"; > + break; > + case 1: > + s = "bar"; > + break; > + case 2: > + s = "spam"; > + break; > + default: > + s = (const char *) 0; > + break; > + } > + > + if (!s) > + __builtin_abort (); > + > + __builtin_printf ("%s\n", s); > +} > + > +/* { dg-final { scan-tree-dump-times "Switch converted" 2 "switchconv" } } */ > +/* { dg-final { scan-tree-dump-times "= CSWTCH" 2 "switchconv" } } */ > --- gcc/testsuite/gcc.dg/tree-ssa/cswtch-5.c.jj 2017-02-14 > 17:11:40.802710606 +0100 > +++ gcc/testsuite/gcc.dg/tree-ssa/cswtch-5.c 2017-02-14 17:13:59.424872889 > +0100 > @@ -0,0 +1,66 @@ > +/* PR tree-optimization/79472 */ > +/* { dg-options "-O2 -fdump-tree-switchconv" } */ > +/* { dg-do compile } */ > + > +void > +foo (unsigned int v) > +{ > + const char *s; > + > + switch (v) > + { > + case 0: > + s = "foo"; > + break; > + case 1: > + s = "bar"; > + break; > + case 2: > + s = "spam"; > + break; > + default: > + for (int i = 0; i < v; i++) > + __builtin_printf ("baz\n"); > + return; > + } > + > + __builtin_printf ("%s\n", s); > +} > + > +int > +bar (unsigned int v, int w) > +{ > + const char *s; > + > + switch (v) > + { > + case 0: > + s = "foo"; > + break; > + case 1: > + s = "bar"; > + break; > + case 2: > + s = "spam"; > + break; > + default: > + __builtin_printf ("baz\n"); > + if (v > 25) > + __builtin_printf ("bl1\n"); > + else > + __builtin_printf ("bl2\n"); > + goto lab; > + } > + > + __builtin_printf ("%s\n", s); > + if (w > 25) > + __builtin_printf ("cl1\n"); > + else > + __builtin_printf ("cl2\n"); > + lab: > + __builtin_printf ("dl\n"); > + return v + w; > +} > + > +/* { dg-final { scan-tree-dump-times "Switch converted" 2 "switchconv" } } */ > +/* { dg-final { scan-tree-dump-times "= CSWTCH" 2 "switchconv" } } */ > > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)