diff --git a/gcc/tree-loop-distribution.cc b/gcc/tree-loop-distribution.cc index db6e9096a86..b74e8569b94 100644 --- a/gcc/tree-loop-distribution.cc +++ b/gcc/tree-loop-distribution.cc @@ -659,6 +659,9 @@ class loop_distribution replace them accordingly. */ bool transform_reduction_loop (loop_p loop); + /* Transform some loops which calculate a CRC. */ + bool transform_reduction_loop (loop_p loop, tree niters); + /* Compute topological order for basic blocks. Topological order is needed because data dependence is computed for data references in lexicographical order. */ @@ -3432,6 +3435,26 @@ generate_strlen_builtin_using_rawmemchr (loop_p loop, tree reduction_var, start_len); } +static void +generate_crc_builtin (loop_p loop, tree reduction_var, + tree crc_in, tree data_in, tree xor_val, + location_t loc) +{ + gimple_seq seq = NULL; + tree reduction_var_new = make_ssa_name (TREE_TYPE (reduction_var)); + + crc_in = force_gimple_operand (crc_in, &seq, true, NULL_TREE); + data_in = force_gimple_operand (data_in, &seq, true, NULL_TREE); + tree fn = build_fold_addr_expr (builtin_decl_implicit (BUILT_IN_CRC8S)); + gimple *fn_call = gimple_build_call (fn, 3, crc_in, data_in, xor_val); + gimple_call_set_lhs (fn_call, reduction_var_new); + gimple_set_location (fn_call, loc); + gimple_seq_add_stmt (&seq, fn_call); + + generate_reduction_builtin_1 (loop, seq, reduction_var, reduction_var_new, + "generated crc%s", E_QImode); +} + /* Return true if we can count at least as many characters by taking pointer difference as we can count via reduction_var without an overflow. Thus compute 2^n < (2^(m-1) / s) where n = TYPE_PRECISION (reduction_var_type), @@ -3713,6 +3736,128 @@ loop_distribution::transform_reduction_loop (loop_p loop) return false; } +/* Match loops like: + + [local count: 954449105]: + # data_16 = PHI + # crc_22 = PHI + # i_3 = PHI + # ivtmp_7 = PHI + _8 = (unsigned char) crc_22; + _1 = _8 ^ data_16; + x16_12 = _1 & 1; + data_13 = data_16 >> 1; + _19 = crc_22 >> 1; + if (x16_12 != 0) + goto ; [50.00%] + else + goto ; [50.00%] + + [local count: 477224553]: + goto ; [100.00%] + + [local count: 477224552]: + crc_17 = _19 ^ 40961; + + [local count: 954449105]: + # crc_4 = PHI + i_18 = i_3 + 1; + ivtmp_6 = ivtmp_7 - 1; + if (ivtmp_6 != 0) + goto ; [88.89%] + else + goto ; [11.11%] + + [local count: 848409806]: + goto ; [100.00%] */ + +bool +loop_distribution::transform_reduction_loop (loop_p loop, tree niters) +{ + gimple *reduction_stmt; + + if (!wi::eq_p (wi::to_widest (niters), 7)) + return false; + + if (loop->num_nodes != 5) + return false; + + reduction_stmt = determine_reduction_stmt (loop); + if (reduction_stmt == NULL) + return false; + + /* Reduction variables are guaranteed to be SSA names. */ + tree reduction_var; + switch (gimple_code (reduction_stmt)) + { + case GIMPLE_ASSIGN: + case GIMPLE_PHI: + reduction_var = gimple_get_lhs (reduction_stmt); + break; + default: + /* Bail out e.g. for GIMPLE_CALL. */ + return false; + } + + if (EDGE_COUNT (loop->header->preds) != 2) + return false; + + edge e, entry_edge = NULL, backedge = NULL; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, loop->header->preds) + if (e->src->loop_father != loop) + entry_edge = e; + else + backedge = e; + + if (!entry_edge || !backedge) + return false; + + tree crc_in = NULL_TREE, data_in = NULL_TREE; + + for (gphi_iterator gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); + gsi_next (&gsi)) + { + gphi *phi = gsi.phi (); + tree val = PHI_ARG_DEF_FROM_EDGE (phi, entry_edge); + if (PHI_ARG_DEF_FROM_EDGE (phi, backedge) == reduction_var) + crc_in = val; + else if (!data_in) + data_in = val; + } + if (!crc_in || !data_in) + return false; + + basic_block xor_bb = NULL; + gcond *cond = safe_dyn_cast (last_stmt (loop->header)); + if (!cond) + return false; + + FOR_EACH_EDGE (e, ei, loop->header->succs) + if ((e->flags & EDGE_TRUE_VALUE && gimple_cond_code (cond) == NE_EXPR) + || (e->flags & EDGE_FALSE_VALUE && gimple_cond_code (cond) == EQ_EXPR)) + xor_bb = e->dest; + + if (!xor_bb) + return false; + + gimple_stmt_iterator gsi = gsi_start_nondebug_bb (xor_bb); + if (gsi_end_p (gsi)) + return false; + gimple *xor_stmt = gsi_stmt (gsi); + if (!is_gimple_assign (xor_stmt) || gimple_assign_rhs_code(xor_stmt) != BIT_XOR_EXPR) + return false; + tree xor_val = gimple_assign_rhs2 (xor_stmt); + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) + return false; + + generate_crc_builtin (loop, reduction_var, crc_in, data_in, xor_val, + gimple_location (xor_stmt)); + return true; +} + /* Given innermost LOOP, return the outermost enclosing loop that forms a perfect loop nest. */ @@ -3798,6 +3943,11 @@ loop_distribution::execute (function *fun) free_data_refs (datarefs_vec); continue; } + else if (TREE_CODE (niters) == INTEGER_CST && flag_tree_loop_distribute_patterns) + { + if (transform_reduction_loop (loop, niters)) + continue; + } /* Get the perfect loop nest for distribution. */ loop = prepare_perfect_loop_nest (loop);