On Thu, 11 Jul 2024, Filip Kastl wrote:

> > > > > +/* Check that the "exponential index transform" can be applied to 
> > > > > this switch.
> > > > > +
> > > > > +   See comment of the exp_index_transform function for details about 
> > > > > this
> > > > > +   transformation.
> > > > > +
> > > > > +   We want:
> > > > > +   - This form of the switch is more efficient
> > > > > +   - Cases are powers of 2
> > > > > +
> > > > > +   Expects that SWTCH has at least one case.  */
> > > > > +
> > > > > +bool
> > > > > +switch_conversion::is_exp_index_transform_viable (gswitch *swtch)
> > > > > +{
> > > > > +  tree index = gimple_switch_index (swtch);
> > > > > +  tree index_type = TREE_TYPE (index);
> > > > > +  basic_block swtch_bb = gimple_bb (swtch);
> > > > > +  unsigned num_labels = gimple_switch_num_labels (swtch);
> > > > > +
> > > > > +  /* Check that we can efficiently compute logarithm of 2^k (using 
> > > > > FFS) and
> > > > > +     test that a given number is 2^k for some k (using POPCOUNT).  */
> > > > > +  optimization_type opt_type = bb_optimization_type (swtch_bb);
> > > > > +  if (!direct_internal_fn_supported_p (IFN_FFS, index_type, opt_type)
> > > > > +    || !direct_internal_fn_supported_p (IFN_POPCOUNT, index_type, 
> > > > > opt_type))
> > > > > +    return false;
> > > > > +
> > > > 
> > > > See above, I think this can be improved.  Would be nice to split out
> > > > a can_pow2p (type) and can_log2 (type) and a corresponding
> > > > gen_pow2p (op) and gen_log2 (op) function so this could be re-used
> > > > and alternate variants added when required.
> > > > 
> > > 
> > > Just to check that I understand this correctly:  You'd like me to create
> > > functions can_pow2p, can_log2.  Those functions will check that there are
> > > optabs for the target machine which allow us to efficiently test
> > > power-of-2-ness of a number and which allow us to efficiently compute the
> > > base-2 log of a power-of-2 number.  You'd also like me to create functions
> > > gen_pow2p and gen_log2 which generate this code.  For now these functions 
> > > will
> > > just use POPCOUNT and FFS but they can be later extended to also consider
> > > different instructions.  Is that right?
> > 
> > Right.
> > 
> > > Into which file should I put these functions?
> > 
> > Just in this file for now.
> >  
> > > Is can_pow2p and gen_pow2p necessary?  As you noted one can always use
> > > (x & -x) == x so testing pow2p can always be done efficiently.
> > 
> > If you add this fallback then can_pow2p / gen_pow2p wouldn't be
> > necessary indeed.
> 
> Hi Richard,
> 
> I put some work into splitting out the can_ and gen_ functions as you
> suggested.  I'm still a bit unsure what your vision of these is so before I
> submit all the changes I made to the patch as version 2 I would like to share
> how I implemented the functions (see bellow).  Is this how you imagined the
> functions?  Would you change something or do the they look ok?
> 
> I wasn't sure how generic to make the functions.  The more generic the more
> convoluted the implementation becomes.  For example: I could make them more
> generic by also including a gsi_iterator_update parameter or I could make them
> less generic but more straightforward by removing the BEFORE parameter.

I think they are fine as-is.  Other APIs like this chose to emit stmts
to a gimple_seq which the caller can then insert in the way of his
choosing.

Ideally we'd abstract this better in the infrastructure, like having
a insert-iterator that embeds both 'before' and update with the
insertion point.  I guess the standard library would have a
insert_before_forward_iterator and insert_after_forward_iterator
and insert_before_backward_iterator, etc. ...  Note that as you
emit a sequence of stmts their order is of course fixed, it's only
the sequence insertion that the caller should influence.

I think that GSI_CONTINUE_LINKING is what works for both before
and after insertion, I'm not sure your GSI_SAME_STMT use for before
is correct?

Richard.

> Cheers,
> Filip Kastl
> 
> 
> /* Does the target have optabs needed to efficiently compute exact base two
>    logarithm of a value with type TYPE?
> 
>    See gen_log2.  */
> 
> static bool
> can_log2 (tree type, optimization_type opt_type)
> {
>   /* Check if target supports FFS.  */
>   return direct_internal_fn_supported_p (IFN_FFS, type, opt_type);
> }
> 
> /* Assume that OP is a power of two.  Build a sequence of gimple statements
>    efficiently computing the base two logarithm of OP using special optabs.
>    Insert statements before GSI if BEFORE is true or after GSI otherwise.
>    Return the result value as an ssa name tree.
> 
>    Leave GSI at the same statement (GSI_SAME_STMT behavior).
> 
>    Should only be used if target supports the needed optabs.  See can_log2.  
> */
> 
> static tree
> gen_log2 (gimple_stmt_iterator *gsi, bool before, location_t loc, tree op)
> {
>   /* Use .FFS (op) - 1.  */
>   gimple *s = gsi->ptr;
>   tree type = TREE_TYPE (op);
>   gsi_iterator_update update = before ? GSI_SAME_STMT : GSI_NEW_STMT;
>   tree tmp1 = gimple_build (gsi, before, update, loc, IFN_FFS, type, op);
>   tree tmp2 = gimple_build (gsi, before, update, loc, MINUS_EXPR, type, tmp1,
>                             build_one_cst (type));
>   gsi->ptr = s;
>   return tmp2;
> }
> 
> /* Build a sequence of gimple statements checking that OP is a power of 2.  
> Use
>    special optabs if targets supports them.  Insert statements before GSI if
>    BEFORE is true or after GSI otherwise.  Return the result value as a
>    boolean_type_node ssa name tree.
> 
>    Leave GSI at the same statement (GSI_SAME_STMT behavior).  */
> 
> static tree
> gen_pow2p (gimple_stmt_iterator *gsi, bool before, location_t loc, tree op)
> {
>   tree result;
> 
>   /* Use either .POPCOUNT (op) == 1 or op & -op == op.  */
>   tree type = TREE_TYPE (op);
>   gimple *s = gsi->ptr;
>   gsi_iterator_update update = before ? GSI_SAME_STMT : GSI_NEW_STMT;
>   optimization_type opt_type = bb_optimization_type (gsi->bb);
>   if (direct_internal_fn_supported_p (IFN_POPCOUNT, type, opt_type))
>     {
>       tree tmp = gimple_build (gsi, before, update, loc, IFN_POPCOUNT, type,
>                                op);
>       result = gimple_build (gsi, before, update, loc, EQ_EXPR,
>                              boolean_type_node, tmp, build_one_cst (type));
>     }
>   else
>     {
>       tree tmp1 = gimple_build (gsi, before, update, loc, NEGATE_EXPR, type,
>                                 op);
>       tree tmp2 = gimple_build (gsi, before, update, loc, BIT_AND_EXPR, type,
>                                 op, tmp1);
>       result = gimple_build (gsi, before, update, loc, EQ_EXPR,
>                              boolean_type_node, tmp2, op);
>     }
>   gsi->ptr = s;
> 
>   return result;
> }
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to