On 09/09/2022 15:31, Jakub Jelinek wrote: >> --- a/gcc/tree-if-conv.cc >> +++ b/gcc/tree-if-conv.cc >> @@ -1074,13 +1076,19 @@ if_convertible_stmt_p (gimple *stmt, vec refs) >> tree fndecl = gimple_call_fndecl (stmt); >> if (fndecl) >> { >> + /* We can vectorize some builtins and functions with SIMD >> + clones. */ >> int flags = gimple_call_flags (stmt); >> + struct cgraph_node *node = cgraph_node::get (fndecl); >> if ((flags & ECF_CONST) >> && !(flags & ECF_LOOPING_CONST_OR_PURE) >> - /* We can only vectorize some builtins at the moment, >> - so restrict if-conversion to those. */ >> && fndecl_built_in_p (fndecl)) >> return true; >> + else if (node && node->simd_clones != NULL) >> + { >> + need_to_predicate = true; > > I think it would be worth it to check that at least one of the > node->simd_clones clones has ->inbranch set, because if all calls > are declare simd notinbranch, then predicating the loop will be just a > wasted effort. > >> + return true; >> + } >> } >> return false; >> } >> @@ -2614,6 +2622,31 @@ predicate_statements (loop_p loop) >> gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi)); >> update_stmt (stmt); >> } >> + >> + /* Add a predicate parameter to functions that have a SIMD clone. >> + This will cause the vectorizer to match the "in branch" clone >> + variants because they also have the extra parameter, and serves >> + to build the mask vector in a natural way. */ >> + gcall *call = dyn_cast (gsi_stmt (gsi)); >> + if (call && !gimple_call_internal_p (call)) >> + { >> + tree orig_fndecl = gimple_call_fndecl (call); >> + int orig_nargs = gimple_call_num_args (call); >> + auto_vec args; >> + for (int i=0; i < orig_nargs; i++) >> + args.safe_push (gimple_call_arg (call, i)); >> + args.safe_push (cond); >> + >> + /* Replace the call with a new one that has the extra >> + parameter. The FUNCTION_DECL remains unchanged so that >> + the vectorizer can find the SIMD clones. This call will >> + either be deleted or replaced at that time, so the >> + mismatch is short-lived and we can live with it. */ >> + gcall *new_call = gimple_build_call_vec (orig_fndecl, args); >> + gimple_call_set_lhs (new_call, gimple_call_lhs (call)); >> + gsi_replace (&gsi, new_call, true); > > I think this is way too dangerous to represent conditional calls that way, > there is nothing to distinguish those from non-conditional calls. > I think I'd prefer (but please see what Richi thinks too) to represent > the conditional calls as a call to a new internal function, say > IFN_COND_CALL or IFN_MASK_CALL, which would have the arguments the original > call had, plus 2 extra ones first (or 3?), one that would be saved copy of > original gimple_call_fn (i.e. usually &fndecl), another one that would be the > condition (and dunno about whether we need also something to represent > gimple_call_fntype, or whether we simply should punt during ifcvt > on conditional calls where gimple_call_fntype is incompatible with > the function type of fndecl. Another question is about > gimple_call_chain. Punt or copy it over to the ifn and back. The attached should resolve these issues. OK for mainline? Andrew