On Sun, Apr 22, 2012 at 8:50 AM, Ramana Radhakrishnan <ramana.radhakrish...@linaro.org> wrote: > Hi, > > A colleague noticed that we were not vectorizing loops that had end of > loop computations that were MIN type operations that weren't expressed > in the form of a typical min operation. A transform from (i < x ) && > ( i < y) to ( i < min (x, y)) is only something that we should do in > these situations rather than as a general transformation where we > might be able to end up generating slightly better code because the > condition would end up being dependent on an invariant outside the > loop. However in the general case such a transformation would is not > advisable - it's up to the reader to work that out.
I don't exactly understand why the general transform is not advisable. We already synthesize min/max operations. Can you elaborate on why you think that better code might be generated when not doing this transform? > #define min(x,y) ((x) <= (y) ? (x) : (y)) > > void foo (int x, int y, int * a, int * b, int *c) > { > int i; > > for (i = 0; > i < x && i < y; > /* i < min (x, y); */ > i++) > a[i] = b[i] * c[i]; > > } > > The patch below deals with this case and I'm guessing that it could > also handle more of the comparison cases and come up with more > intelligent choices and should be made quite a lot more robust than > what it is right now. Yes. At least if you have i < 5 && i < y we canonicalize it to i <= 4 && i < y, so your pattern matching would fail. Btw, the canonical case this happens in is probably for (i = 0; i < n; ++i) for (j = 0; j < m && j < i; ++j) a[i][j] = ... thus iterating over the lower/upper triangular part of a non-square matrix (including or not including the diagonal, thus also j < m && j <= i) Richard. > regards, > Ramana > > > > diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c > index ce5eb20..a529536 100644 > --- a/gcc/tree-ssa-loop-im.c > +++ b/gcc/tree-ssa-loop-im.c > @@ -563,6 +563,7 @@ stmt_cost (gimple stmt) > > switch (gimple_assign_rhs_code (stmt)) > { > + case MIN_EXPR: > case MULT_EXPR: > case WIDEN_MULT_EXPR: > case WIDEN_MULT_PLUS_EXPR: > @@ -971,6 +972,124 @@ rewrite_reciprocal (gimple_stmt_iterator *bsi) > return stmt1; > } > > +/* We look for a sequence that is : > + def_stmt1 : x = a < b > + def_stmt2 : y = a < c > + stmt: z = x & y > + use_stmt_cond: if ( z != 0) > + > + where b, c are loop invariant . > + > + In which case we might as well replace this by : > + > + t = min (b, c) > + if ( a < t ) > +*/ > + > +static gimple > +rewrite_min_test (gimple_stmt_iterator *bsi) > +{ > + gimple stmt, def_stmt_x, def_stmt_y, use_stmt_cond, stmt1; > + tree x, y, z, a, b, c, var, t, name; > + use_operand_p use; > + bool is_lhs_of_comparison = false; > + > + stmt = gsi_stmt (*bsi); > + z = gimple_assign_lhs (stmt); > + > + /* We start by looking at whether x is used in the > + right set of conditions. */ > + if (TREE_CODE (z) != SSA_NAME > + || !single_imm_use (z, &use, &use_stmt_cond) > + || gimple_code (use_stmt_cond) != GIMPLE_COND) > + return stmt; > + > + x = gimple_assign_rhs1 (stmt); > + y = gimple_assign_rhs2 (stmt); > + > + if (TREE_CODE (x) != SSA_NAME > + || TREE_CODE (y) != SSA_NAME) > + return stmt; > + > + def_stmt_x = SSA_NAME_DEF_STMT (x); > + def_stmt_y = SSA_NAME_DEF_STMT (y); > + > + /* def_stmt_x and def_stmt_y should be of the > + form > + > + x = a cmp b > + y = a cmp c > + > + or > + > + x = b cmp a > + y = c cmp a > + */ > + if (!is_gimple_assign (def_stmt_x) > + || !is_gimple_assign (def_stmt_y) > + || (gimple_assign_rhs_code (def_stmt_x) > + != gimple_assign_rhs_code (def_stmt_y))) > + return stmt; > + > + if (gimple_assign_rhs1 (def_stmt_x) == gimple_assign_rhs1 (def_stmt_y) > + && (gimple_assign_rhs_code (def_stmt_x) == LT_EXPR > + || gimple_assign_rhs_code (def_stmt_x) == LE_EXPR)) > + { > + a = gimple_assign_rhs1 (def_stmt_x); > + b = gimple_assign_rhs2 (def_stmt_x); > + c = gimple_assign_rhs2 (def_stmt_y); > + is_lhs_of_comparison = true; > + } > + else > + { > + if (gimple_assign_rhs2 (def_stmt_x) == gimple_assign_rhs2 (def_stmt_y) > + && (gimple_assign_rhs_code (def_stmt_x) == GT_EXPR > + || gimple_assign_rhs_code (def_stmt_x) == GE_EXPR)) > + { > + a = gimple_assign_rhs2 (def_stmt_x); > + b = gimple_assign_rhs1 (def_stmt_x); > + c = gimple_assign_rhs1 (def_stmt_y); > + } > + else > + return stmt; > + } > + > + if (outermost_invariant_loop (b, loop_containing_stmt (def_stmt_x)) != NULL > + && outermost_invariant_loop (c, loop_containing_stmt > (def_stmt_y)) != NULL) > + > + { > + if (dump_file) > + fprintf (dump_file, "Found a potential transformation to min\n"); > + > + /* mintmp = min (b , c). */ > + > + var = create_tmp_var (TREE_TYPE (b), "mintmp"); > + add_referenced_var (var); > + t = fold_build2 (MIN_EXPR, TREE_TYPE (b), b, c); > + stmt1 = gimple_build_assign (var, t); > + name = make_ssa_name (var, stmt1); > + gimple_assign_set_lhs (stmt1, name); > + gimple_cond_set_code (use_stmt_cond, gimple_assign_rhs_code > (def_stmt_x)); > + > + > + if (is_lhs_of_comparison) > + { > + gimple_cond_set_lhs (use_stmt_cond, a); > + gimple_cond_set_rhs (use_stmt_cond, name); > + } > + else > + { > + gimple_cond_set_lhs (use_stmt_cond, name); > + gimple_cond_set_rhs (use_stmt_cond, a); > + } > + update_stmt (use_stmt_cond); > + gsi_insert_before (bsi, stmt1, GSI_NEW_STMT); > + return stmt1; > + } > + > + return stmt; > +} > + > /* Check if the pattern at *BSI is a bittest of the form > (A >> B) & 1 != 0 and in this case rewrite it to A & (1 << B) != 0. */ > > @@ -1171,6 +1290,11 @@ determine_invariantness_stmt (struct > dom_walk_data *dw_data ATTRIBUTE_UNUSED, > && TREE_CODE (op0) == SSA_NAME > && has_single_use (op0)) > stmt = rewrite_bittest (&bsi); > + else > + if (pos == MOVE_POSSIBLE > + && gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) > + stmt = rewrite_min_test (&bsi); > + > } > > lim_data = init_lim_data (stmt);