diff mbox

RFA: Small PATCH to add pow2p_hwi to hwint.h

Message ID CADzB+2kt6bN4hb38n=QaO3mnbmLUWrb5bVfPEtdEBX3PTDf-bw@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Sept. 8, 2016, 8:59 p.m. UTC
On Thu, Sep 8, 2016 at 11:55 AM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Thu, 8 Sep 2016, Jason Merrill wrote:
>
>> Various places in GCC use negate, bit-and and compare to test whether
>> an integer is a power of 2, but I think it would be clearer for this
>> test to be wrapped in a function.
>
> (x & -x) == x is also true for 0.  Whatever the correct function semantics
> for 0, the comment needs to reflect them.

Yep, I was just realizing that, too.  This much larger patch introduces:

 least_bit_hwi: (x & -x)
 pow2_or_zerop: (x & -x) == x
 pow2p_hwi: x && x == (x & -x)
 ctz_or_zero: floor_log2 (x & -x)

and replaces these patterns accordingly.  I'm not at all attached to the names.

Tested x86_64-pc-linux-gnu.
commit 4b76501b72f3953ac57cb077b4e25a90afb6d9a9
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Sep 8 13:10:12 2016 -0400

            Add inline functions for various bitwise operations.
    
            * hwint.h (least_bit_hwi, pow2_or_zerop, pow2p_hwi, ctz_or_zero):
            New.
            * hwint.c (exact_log2): Use pow2p_hwi.
            (ctz_hwi, ffs_hwi): Use least_bit_hwi.
            * alias.c (memrefs_conflict_p): Use pow2_or_zerop.
            * builtins.c (get_object_alignment_2, get_object_alignment)
            (get_pointer_alignment, fold_builtin_atomic_always_lock_free): Use
            least_bit_hwi.
            * calls.c (compute_argument_addresses, store_one_arg): Use
            least_bit_hwi.
            * cfgexpand.c (expand_one_stack_var_at): Use least_bit_hwi.
            * combine.c (force_to_mode): Use least_bit_hwi.
            * emit-rtl.c (set_mem_attributes_minus_bitpos, adjust_address_1):
            Use least_bit_hwi.
            * expmed.c (synth_mult, expand_divmod): Use ctz_or_zero, ctz_hwi.
            (init_expmed_one_conv): Use pow2p_hwi.
            * fold-const.c (round_up_loc, round_down_loc): Use pow2_or_zerop.
            (fold_binary_loc): Use pow2p_hwi.
            * function.c (assign_parm_find_stack_rtl): Use least_bit_hwi.
            * gimple-fold.c (gimple_fold_builtin_memory_op): Use pow2p_hwi.
            * gimple-ssa-strength-reduction.c (replace_ref): Use least_bit_hwi.
            * hsa-gen.c (gen_hsa_addr_with_align, hsa_bitmemref_alignment):
            Use least_bit_hwi.
            * ipa-cp.c (ipcp_alignment_lattice::meet_with_1): Use least_bit_hwi.
            * ipa-prop.c (ipa_modify_call_arguments): Use least_bit_hwi.
            * omp-low.c (oacc_loop_fixed_partitions)
            (oacc_loop_auto_partitions): Use least_bit_hwi.
            * rtlanal.c (nonzero_bits1): Use ctz_or_zero.
            * stor-layout.c (place_field): Use least_bit_hwi.
            * tree-pretty-print.c (dump_generic_node): Use pow2p_hwi.
            * tree-sra.c (build_ref_for_offset): Use least_bit_hwi.
            * tree-ssa-ccp.c (ccp_finalize): Use least_bit_hwi.
            * tree-ssa-math-opts.c (bswap_replace): Use least_bit_hwi.
            * tree-ssa-strlen.c (handle_builtin_memcmp): Use pow2p_hwi.
            * tree-vect-data-refs.c (vect_analyze_group_access_1)
            (vect_grouped_store_supported, vect_grouped_load_supported)
            (vect_permute_load_chain, vect_shift_permute_load_chain)
            (vect_transform_grouped_load): Use pow2p_hwi.
            * tree-vect-generic.c (expand_vector_divmod): Use ctz_or_zero.
            * tree-vect-patterns.c (vect_recog_divmod_pattern): Use ctz_or_zero.
            * tree-vect-stmts.c (vectorizable_mask_load_store): Use
            least_bit_hwi.
            * tsan.c (instrument_expr): Use least_bit_hwi.
            * var-tracking.c (negative_power_of_two_p): Use pow2_or_zerop.

Comments

Jeff Law Sept. 16, 2016, 4:40 p.m. UTC | #1
On 09/08/2016 02:59 PM, Jason Merrill wrote:
> On Thu, Sep 8, 2016 at 11:55 AM, Joseph Myers <joseph@codesourcery.com> wrote:
>> > On Thu, 8 Sep 2016, Jason Merrill wrote:
>> >
>>> >> Various places in GCC use negate, bit-and and compare to test whether
>>> >> an integer is a power of 2, but I think it would be clearer for this
>>> >> test to be wrapped in a function.
>> >
>> > (x & -x) == x is also true for 0.  Whatever the correct function semantics
>> > for 0, the comment needs to reflect them.
> Yep, I was just realizing that, too.  This much larger patch introduces:
>
>  least_bit_hwi: (x & -x)
>  pow2_or_zerop: (x & -x) == x
>  pow2p_hwi: x && x == (x & -x)
>  ctz_or_zero: floor_log2 (x & -x)
>
> and replaces these patterns accordingly.  I'm not at all attached to the names.
>
> Tested x86_64-pc-linux-gnu.
>
>
> hwint.diff
>
>
> commit 4b76501b72f3953ac57cb077b4e25a90afb6d9a9
> Author: Jason Merrill <jason@redhat.com>
> Date:   Thu Sep 8 13:10:12 2016 -0400
>
>             Add inline functions for various bitwise operations.
>
>             * hwint.h (least_bit_hwi, pow2_or_zerop, pow2p_hwi, ctz_or_zero):
>             New.
>             * hwint.c (exact_log2): Use pow2p_hwi.
>             (ctz_hwi, ffs_hwi): Use least_bit_hwi.
>             * alias.c (memrefs_conflict_p): Use pow2_or_zerop.
>             * builtins.c (get_object_alignment_2, get_object_alignment)
>             (get_pointer_alignment, fold_builtin_atomic_always_lock_free): Use
>             least_bit_hwi.
>             * calls.c (compute_argument_addresses, store_one_arg): Use
>             least_bit_hwi.
>             * cfgexpand.c (expand_one_stack_var_at): Use least_bit_hwi.
>             * combine.c (force_to_mode): Use least_bit_hwi.
>             * emit-rtl.c (set_mem_attributes_minus_bitpos, adjust_address_1):
>             Use least_bit_hwi.
>             * expmed.c (synth_mult, expand_divmod): Use ctz_or_zero, ctz_hwi.
>             (init_expmed_one_conv): Use pow2p_hwi.
>             * fold-const.c (round_up_loc, round_down_loc): Use pow2_or_zerop.
>             (fold_binary_loc): Use pow2p_hwi.
>             * function.c (assign_parm_find_stack_rtl): Use least_bit_hwi.
>             * gimple-fold.c (gimple_fold_builtin_memory_op): Use pow2p_hwi.
>             * gimple-ssa-strength-reduction.c (replace_ref): Use least_bit_hwi.
>             * hsa-gen.c (gen_hsa_addr_with_align, hsa_bitmemref_alignment):
>             Use least_bit_hwi.
>             * ipa-cp.c (ipcp_alignment_lattice::meet_with_1): Use least_bit_hwi.
>             * ipa-prop.c (ipa_modify_call_arguments): Use least_bit_hwi.
>             * omp-low.c (oacc_loop_fixed_partitions)
>             (oacc_loop_auto_partitions): Use least_bit_hwi.
>             * rtlanal.c (nonzero_bits1): Use ctz_or_zero.
>             * stor-layout.c (place_field): Use least_bit_hwi.
>             * tree-pretty-print.c (dump_generic_node): Use pow2p_hwi.
>             * tree-sra.c (build_ref_for_offset): Use least_bit_hwi.
>             * tree-ssa-ccp.c (ccp_finalize): Use least_bit_hwi.
>             * tree-ssa-math-opts.c (bswap_replace): Use least_bit_hwi.
>             * tree-ssa-strlen.c (handle_builtin_memcmp): Use pow2p_hwi.
>             * tree-vect-data-refs.c (vect_analyze_group_access_1)
>             (vect_grouped_store_supported, vect_grouped_load_supported)
>             (vect_permute_load_chain, vect_shift_permute_load_chain)
>             (vect_transform_grouped_load): Use pow2p_hwi.
>             * tree-vect-generic.c (expand_vector_divmod): Use ctz_or_zero.
>             * tree-vect-patterns.c (vect_recog_divmod_pattern): Use ctz_or_zero.
>             * tree-vect-stmts.c (vectorizable_mask_load_store): Use
>             least_bit_hwi.
>             * tsan.c (instrument_expr): Use least_bit_hwi.
>             * var-tracking.c (negative_power_of_two_p): Use pow2_or_zerop.
I was briefly worried about some of the expmed changes, but managed to 
convince myself they were correct.

Ok for the trunk.

Thanks,
jeff
diff mbox

Patch

diff --git a/gcc/alias.c b/gcc/alias.c
index f4b5a92..277125e 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -2534,7 +2534,7 @@  memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
     {
       HOST_WIDE_INT sc = INTVAL (XEXP (x, 1));
       unsigned HOST_WIDE_INT uc = sc;
-      if (sc < 0 && -uc == (uc & -uc))
+      if (sc < 0 && pow2_or_zerop (-uc))
 	{
 	  if (xsize > 0)
 	    xsize = -xsize;
@@ -2549,7 +2549,7 @@  memrefs_conflict_p (int xsize, rtx x, int ysize, rtx y, HOST_WIDE_INT c)
     {
       HOST_WIDE_INT sc = INTVAL (XEXP (y, 1));
       unsigned HOST_WIDE_INT uc = sc;
-      if (sc < 0 && -uc == (uc & -uc))
+      if (sc < 0 && pow2_or_zerop (-uc))
 	{
 	  if (ysize > 0)
 	    ysize = -ysize;
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 1073e35..0ccba15 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -305,7 +305,7 @@  get_object_alignment_2 (tree exp, unsigned int *alignp,
 	{
 	  ptr_bitmask = TREE_INT_CST_LOW (TREE_OPERAND (addr, 1));
 	  ptr_bitmask *= BITS_PER_UNIT;
-	  align = ptr_bitmask & -ptr_bitmask;
+	  align = least_bit_hwi (ptr_bitmask);
 	  addr = TREE_OPERAND (addr, 0);
 	}
 
@@ -325,7 +325,7 @@  get_object_alignment_2 (tree exp, unsigned int *alignp,
 	      unsigned HOST_WIDE_INT step = 1;
 	      if (TMR_STEP (exp))
 		step = TREE_INT_CST_LOW (TMR_STEP (exp));
-	      align = MIN (align, (step & -step) * BITS_PER_UNIT);
+	      align = MIN (align, least_bit_hwi (step) * BITS_PER_UNIT);
 	    }
 	  if (TMR_INDEX2 (exp))
 	    align = BITS_PER_UNIT;
@@ -404,7 +404,7 @@  get_object_alignment (tree exp)
      ptr & (align - 1) == bitpos.  */
 
   if (bitpos != 0)
-    align = (bitpos & -bitpos);
+    align = least_bit_hwi (bitpos);
   return align;
 }
 
@@ -502,7 +502,7 @@  get_pointer_alignment (tree exp)
      ptr & (align - 1) == bitpos.  */
 
   if (bitpos != 0)
-    align = (bitpos & -bitpos);
+    align = least_bit_hwi (bitpos);
 
   return align;
 }
@@ -5565,7 +5565,7 @@  fold_builtin_atomic_always_lock_free (tree arg0, tree arg1)
 
       /* Either this argument is null, or it's a fake pointer encoding
          the alignment of the object.  */
-      val = val & -val;
+      val = least_bit_hwi (val);
       val *= BITS_PER_UNIT;
 
       if (val == 0 || mode_align < val)
diff --git a/gcc/calls.c b/gcc/calls.c
index 4ad3e34..86369e9 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1805,7 +1805,7 @@  compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
 	  else if (CONST_INT_P (offset))
 	    {
 	      align = INTVAL (offset) * BITS_PER_UNIT | boundary;
-	      align = align & -align;
+	      align = least_bit_hwi (align);
 	    }
 	  set_mem_align (args[i].stack, align);
 
@@ -5026,7 +5026,7 @@  store_one_arg (struct arg_data *arg, rtx argblock, int flags,
 	  int pad = used - size;
 	  if (pad)
 	    {
-	      unsigned int pad_align = (pad & -pad) * BITS_PER_UNIT;
+	      unsigned int pad_align = least_bit_hwi (pad) * BITS_PER_UNIT;
 	      parm_align = MIN (parm_align, pad_align);
 	    }
 	}
@@ -5086,7 +5086,7 @@  store_one_arg (struct arg_data *arg, rtx argblock, int flags,
 	    parm_align = BITS_PER_UNIT;
 	  else if (excess)
 	    {
-	      unsigned int excess_align = (excess & -excess) * BITS_PER_UNIT;
+	      unsigned int excess_align = least_bit_hwi (excess) * BITS_PER_UNIT;
 	      parm_align = MIN (parm_align, excess_align);
 	    }
 	}
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 130a16b..7df645e 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1009,7 +1009,7 @@  expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
 	 important, we'll simply use the alignment that is already set.  */
       if (base == virtual_stack_vars_rtx)
 	offset -= frame_phase;
-      align = offset & -offset;
+      align = least_bit_hwi (offset);
       align *= BITS_PER_UNIT;
       if (align == 0 || align > base_align)
 	align = base_align;
diff --git a/gcc/combine.c b/gcc/combine.c
index 1b262f9..226f81a 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -8557,7 +8557,7 @@  force_to_mode (rtx x, machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* If X is (minus C Y) where C's least set bit is larger than any bit
 	 in the mask, then we may replace with (neg Y).  */
       if (CONST_INT_P (XEXP (x, 0))
-	  && ((UINTVAL (XEXP (x, 0)) & -UINTVAL (XEXP (x, 0))) > mask))
+	  && least_bit_hwi (UINTVAL (XEXP (x, 0))) > mask)
 	{
 	  x = simplify_gen_unary (NEG, GET_MODE (x), XEXP (x, 1),
 				  GET_MODE (x));
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a4f3c6b..1fbd266 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1843,7 +1843,7 @@  check_bases (tree t,
      doesn't define its own, then the current class inherits one.  */
   if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t)))
     {
-      tree tm_attr = tm_mask_to_attr (seen_tm_mask & -seen_tm_mask);
+      tree tm_attr = tm_mask_to_attr (least_bit_hwi (seen_tm_mask));
       TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t));
     }
 }
@@ -5074,7 +5074,7 @@  set_one_vmethod_tm_attributes (tree type, tree fndecl)
      restrictive one.  */
   else if (tm_attr == NULL)
     {
-      apply_tm_attr (fndecl, tm_mask_to_attr (found & -found));
+      apply_tm_attr (fndecl, tm_mask_to_attr (least_bit_hwi (found)));
     }
   /* Otherwise validate that we're not weaker than a function
      that is being overridden.  */
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index a724608..9e0bda2 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1964,7 +1964,7 @@  set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
       get_object_alignment_1 (t, &obj_align, &obj_bitpos);
       obj_bitpos = (obj_bitpos - bitpos) & (obj_align - 1);
       if (obj_bitpos != 0)
-	obj_align = (obj_bitpos & -obj_bitpos);
+	obj_align = least_bit_hwi (obj_bitpos);
       attrs.align = MAX (attrs.align, obj_align);
     }
 
@@ -2298,7 +2298,7 @@  adjust_address_1 (rtx memref, machine_mode mode, HOST_WIDE_INT offset,
      if zero.  */
   if (offset != 0)
     {
-      max_align = (offset & -offset) * BITS_PER_UNIT;
+      max_align = least_bit_hwi (offset) * BITS_PER_UNIT;
       attrs.align = MIN (attrs.align, max_align);
     }
 
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 1cedf02..8c25e3f 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -127,10 +127,10 @@  init_expmed_one_conv (struct init_expmed_rtl *all, machine_mode to_mode,
      comparison purposes here, reduce the bit size by one in that
      case.  */
   if (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT
-      && exact_log2 (to_size) != -1)
+      && pow2p_hwi (to_size))
     to_size --;
   if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT
-      && exact_log2 (from_size) != -1)
+      && pow2p_hwi (from_size))
     from_size --;
   
   /* Assume cost of zero-extend and sign-extend is the same.  */
@@ -2636,7 +2636,7 @@  synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
   if ((t & 1) == 0)
     {
     do_alg_shift:
-      m = floor_log2 (t & -t);	/* m = number of low zero bits */
+      m = ctz_or_zero (t); /* m = number of low zero bits */
       if (m < maxm)
 	{
 	  q = t >> m;
@@ -2873,9 +2873,8 @@  synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
     {
     do_alg_add_t2_m:
       q = t - 1;
-      q = q & -q;
-      m = exact_log2 (q);
-      if (m >= 0 && m < maxm)
+      m = ctz_hwi (q);
+      if (q && m < maxm)
 	{
 	  op_cost = shiftadd_cost (speed, mode, m);
 	  new_limit.cost = best_cost.cost - op_cost;
@@ -2897,9 +2896,8 @@  synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
 
     do_alg_sub_t2_m:
       q = t + 1;
-      q = q & -q;
-      m = exact_log2 (q);
-      if (m >= 0 && m < maxm)
+      m = ctz_hwi (q);
+      if (q && m < maxm)
 	{
 	  op_cost = shiftsub0_cost (speed, mode, m);
 	  new_limit.cost = best_cost.cost - op_cost;
@@ -4215,7 +4213,7 @@  expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
 			   initial right shift.  */
 			if (mh != 0 && (d & 1) == 0)
 			  {
-			    pre_shift = floor_log2 (d & -d);
+			    pre_shift = ctz_or_zero (d);
 			    mh = choose_multiplier (d >> pre_shift, size,
 						    size - pre_shift,
 						    &ml, &post_shift, &dummy);
@@ -4873,7 +4871,7 @@  expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
 	    int pre_shift;
 	    rtx t1;
 
-	    pre_shift = floor_log2 (d & -d);
+	    pre_shift = ctz_or_zero (d);
 	    ml = invert_mod2n (d >> pre_shift, size);
 	    t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
 			       pre_shift, NULL_RTX, unsignedp);
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index bf177b6..ef1e26a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -10005,7 +10005,7 @@  fold_binary_loc (location_t loc,
 	         mode which allows further optimizations.  */
 	      int pop = wi::popcount (warg1);
 	      if (!(pop >= BITS_PER_UNIT
-		    && exact_log2 (pop) != -1
+		    && pow2p_hwi (pop)
 		    && wi::mask (pop, false, warg1.get_precision ()) == warg1))
 		return fold_build2_loc (loc, code, type, op0,
 					wide_int_to_tree (type, masked));
@@ -14251,7 +14251,7 @@  round_up_loc (location_t loc, tree value, unsigned int divisor)
     }
 
   /* If divisor is a power of two, simplify this to bit manipulation.  */
-  if (divisor == (divisor & -divisor))
+  if (pow2_or_zerop (divisor))
     {
       if (TREE_CODE (value) == INTEGER_CST)
 	{
@@ -14314,7 +14314,7 @@  round_down_loc (location_t loc, tree value, int divisor)
     }
 
   /* If divisor is a power of two, simplify this to bit manipulation.  */
-  if (divisor == (divisor & -divisor))
+  if (pow2_or_zerop (divisor))
     {
       tree t;
 
diff --git a/gcc/function.c b/gcc/function.c
index 53bad87..94ed786 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -2716,7 +2716,7 @@  assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
   else if (CONST_INT_P (offset_rtx))
     {
       align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
-      align = align & -align;
+      align = least_bit_hwi (align);
     }
   set_mem_align (stack_parm, align);
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fbbe520..2e0bd80 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -699,7 +699,7 @@  gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
 	  && !c_strlen (src, 2))
 	{
 	  unsigned ilen = tree_to_uhwi (len);
-	  if (exact_log2 (ilen) != -1)
+	  if (pow2p_hwi (ilen))
 	    {
 	      tree type = lang_hooks.types.type_for_size (ilen * 8, 1);
 	      if (type
diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c
index 9e0b3d1..68115ee 100644
--- a/gcc/gimple-ssa-strength-reduction.c
+++ b/gcc/gimple-ssa-strength-reduction.c
@@ -1874,7 +1874,7 @@  replace_ref (tree *expr, slsr_cand_t c)
      requirement for the data type.  See PR58041.  */
   get_object_alignment_1 (*expr, &align, &misalign);
   if (misalign != 0)
-    align = (misalign & -misalign);
+    align = least_bit_hwi (misalign);
   if (align < TYPE_ALIGN (acc_type))
     acc_type = build_aligned_type (acc_type, align);
 
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 314bb5b..4d1b276 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -2207,7 +2207,7 @@  gen_hsa_addr_with_align (tree ref, hsa_bb *hbb, BrigAlignment8_t *output_align)
       unsigned align = hsa_byte_alignment (addr->m_symbol->m_align);
       unsigned misalign = addr->m_imm_offset & (align - 1);
       if (misalign)
-        align = (misalign & -misalign);
+        align = least_bit_hwi (misalign);
       *output_align = hsa_alignment_encoding (BITS_PER_UNIT * align);
     }
   return addr;
@@ -2434,7 +2434,7 @@  hsa_bitmemref_alignment (tree ref)
   BrigAlignment8_t base = hsa_object_alignment (ref);
   if (byte_bits == 0)
     return base;
-  return MIN (base, hsa_alignment_encoding (byte_bits & -byte_bits));
+  return MIN (base, hsa_alignment_encoding (least_bit_hwi (byte_bits)));
 }
 
 /* Generate HSAIL instructions loading something into register DEST.  RHS is
diff --git a/gcc/hwint.c b/gcc/hwint.c
index b936c52..5373028 100644
--- a/gcc/hwint.c
+++ b/gcc/hwint.c
@@ -74,7 +74,7 @@  ceil_log2 (unsigned HOST_WIDE_INT x)
 int
 exact_log2 (unsigned HOST_WIDE_INT x)
 {
-  if (x != (x & -x))
+  if (!pow2p_hwi (x))
     return -1;
   return floor_log2 (x);
 }
@@ -85,7 +85,7 @@  exact_log2 (unsigned HOST_WIDE_INT x)
 int
 ctz_hwi (unsigned HOST_WIDE_INT x)
 {
-  return x ? floor_log2 (x & -x) : HOST_BITS_PER_WIDE_INT;
+  return x ? floor_log2 (least_bit_hwi (x)) : HOST_BITS_PER_WIDE_INT;
 }
 
 /* Similarly for most significant bits.  */
@@ -102,7 +102,7 @@  clz_hwi (unsigned HOST_WIDE_INT x)
 int
 ffs_hwi (unsigned HOST_WIDE_INT x)
 {
-  return 1 + floor_log2 (x & -x);
+  return 1 + floor_log2 (least_bit_hwi (x));
 }
 
 /* Return the number of set bits in X.  */
diff --git a/gcc/hwint.h b/gcc/hwint.h
index 6b4d537..e3a8ff0 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -219,10 +219,42 @@  ceil_log2 (unsigned HOST_WIDE_INT x)
   return floor_log2 (x - 1) + 1;
 }
 
+/* Return X with all but the lowest bit masked off.  */
+
+inline unsigned HOST_WIDE_INT
+least_bit_hwi (unsigned HOST_WIDE_INT x)
+{
+  return (x & -x);
+}
+
+/* True if X is zero or a power of two.  */
+
+inline bool
+pow2_or_zerop (unsigned HOST_WIDE_INT x)
+{
+  return least_bit_hwi (x) == x;
+}
+
+/* True if X is a power of two.  */
+
+inline bool
+pow2p_hwi (unsigned HOST_WIDE_INT x)
+{
+  return x && pow2_or_zerop (x);
+}
+
+/* Like ctz_hwi, except 0 when x == 0.  */
+
+inline int
+ctz_or_zero (unsigned HOST_WIDE_INT x)
+{
+  return ffs_hwi (x) - 1;
+}
+
 static inline int
 exact_log2 (unsigned HOST_WIDE_INT x)
 {
-  return x == (x & -x) && x ? ctz_hwi (x) : -1;
+  return pow2p_hwi (x) ? ctz_hwi (x) : -1;
 }
 
 #endif /* GCC_VERSION >= 3004 */
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 5ff7bed..60fcd02 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -929,7 +929,7 @@  ipcp_alignment_lattice::meet_with_1 (unsigned new_align, unsigned new_misalign)
   if (misalign != (new_misalign % align))
     {
       int diff = abs ((int) misalign - (int) (new_misalign % align));
-      align = (unsigned) diff & -diff;
+      align = least_bit_hwi (diff);
       if (align)
 	misalign = misalign % align;
       else
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 1629781..b86a4a0 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -4170,7 +4170,7 @@  ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
 			   * BITS_PER_UNIT);
 	      misalign = misalign & (align - 1);
 	      if (misalign != 0)
-		align = (misalign & -misalign);
+		align = least_bit_hwi (misalign);
 	      if (align < TYPE_ALIGN (type))
 		type = build_aligned_type (type, align);
 	      base = force_gimple_operand_gsi (&gsi, base,
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index c890e83..bf52d84 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -19452,7 +19452,7 @@  oacc_loop_fixed_partitions (oacc_loop *loop, unsigned outer_mask)
     }
   else
     {
-      unsigned outermost = this_mask & -this_mask;
+      unsigned outermost = least_bit_hwi (this_mask);
 
       if (outermost && outermost <= outer_mask)
 	{
@@ -19533,7 +19533,7 @@  oacc_loop_auto_partitions (oacc_loop *loop, unsigned outer_mask)
       
       /* Determine the outermost partitioning used within this loop. */
       this_mask = loop->inner | GOMP_DIM_MASK (GOMP_DIM_MAX);
-      this_mask = (this_mask & -this_mask);
+      this_mask = least_bit_hwi (this_mask);
 
       /* Pick the partitioning just inside that one.  */
       this_mask >>= 1;
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 6470c43..9b4654c 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -4511,8 +4511,8 @@  nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
 	int sign_index = GET_MODE_PRECISION (GET_MODE (x)) - 1;
 	int width0 = floor_log2 (nz0) + 1;
 	int width1 = floor_log2 (nz1) + 1;
-	int low0 = floor_log2 (nz0 & -nz0);
-	int low1 = floor_log2 (nz1 & -nz1);
+	int low0 = ctz_or_zero (nz0);
+	int low1 = ctz_or_zero (nz1);
 	unsigned HOST_WIDE_INT op0_maybe_minusp
 	  = nz0 & (HOST_WIDE_INT_1U << sign_index);
 	unsigned HOST_WIDE_INT op1_maybe_minusp
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index cf71714..07eac87 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1169,14 +1169,12 @@  place_field (record_layout_info rli, tree field)
   /* Work out the known alignment so far.  Note that A & (-A) is the
      value of the least-significant bit in A that is one.  */
   if (! integer_zerop (rli->bitpos))
-    known_align = (tree_to_uhwi (rli->bitpos)
-		   & - tree_to_uhwi (rli->bitpos));
+    known_align = least_bit_hwi (tree_to_uhwi (rli->bitpos));
   else if (integer_zerop (rli->offset))
     known_align = 0;
   else if (tree_fits_uhwi_p (rli->offset))
     known_align = (BITS_PER_UNIT
-		   * (tree_to_uhwi (rli->offset)
-		      & - tree_to_uhwi (rli->offset)));
+		   * least_bit_hwi (tree_to_uhwi (rli->offset)));
   else
     known_align = rli->offset_align;
 
@@ -1479,14 +1477,12 @@  place_field (record_layout_info rli, tree field)
      approximate this by seeing if its position changed), lay out the field
      again; perhaps we can use an integral mode for it now.  */
   if (! integer_zerop (DECL_FIELD_BIT_OFFSET (field)))
-    actual_align = (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field))
-		    & - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)));
+    actual_align = least_bit_hwi (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)));
   else if (integer_zerop (DECL_FIELD_OFFSET (field)))
     actual_align = MAX (BIGGEST_ALIGNMENT, rli->record_align);
   else if (tree_fits_uhwi_p (DECL_FIELD_OFFSET (field)))
     actual_align = (BITS_PER_UNIT
-		   * (tree_to_uhwi (DECL_FIELD_OFFSET (field))
-		      & - tree_to_uhwi (DECL_FIELD_OFFSET (field))));
+		    * least_bit_hwi (tree_to_uhwi (DECL_FIELD_OFFSET (field))));
   else
     actual_align = DECL_OFFSET_ALIGN (field);
   /* ACTUAL_ALIGN is still the actual alignment *within the record* .
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 734ecda..0915fd4 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -1353,7 +1353,7 @@  dump_generic_node (pretty_printer *pp, tree node, int spc, int flags,
 				      ? "unsigned long long"
 				      : "signed long long"));
 		else if (TYPE_PRECISION (node) >= CHAR_TYPE_SIZE
-			 && exact_log2 (TYPE_PRECISION (node)) != -1)
+			 && pow2p_hwi (TYPE_PRECISION (node)))
 		  {
 		    pp_string (pp, (TYPE_UNSIGNED (node) ? "uint" : "int"));
 		    pp_decimal_int (pp, TYPE_PRECISION (node));
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 3c7e4c0..4a2ff0d 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -1680,7 +1680,7 @@  build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
 
   misalign = (misalign + offset) & (align - 1);
   if (misalign != 0)
-    align = (misalign & -misalign);
+    align = least_bit_hwi (misalign);
   if (align != TYPE_ALIGN (exp_type))
     exp_type = build_aligned_type (exp_type, align);
 
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 9871304..291b949 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -929,7 +929,7 @@  ccp_finalize (bool nonzero_p)
 	  /* Trailing mask bits specify the alignment, trailing value
 	     bits the misalignment.  */
 	  tem = val->mask.to_uhwi ();
-	  align = (tem & -tem);
+	  align = least_bit_hwi (tem);
 	  if (align > 1)
 	    set_ptr_info_alignment (get_ptr_info (name), align,
 				    (TREE_INT_CST_LOW (val->value)
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index b93bcf3..0cea1a8 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -2647,7 +2647,7 @@  bswap_replace (gimple *cur_stmt, gimple *src_stmt, tree fndecl,
 	      unsigned HOST_WIDE_INT l
 		= (load_offset * BITS_PER_UNIT) & (align - 1);
 	      if (l)
-		align = l & -l;
+		align = least_bit_hwi (l);
 	    }
 	}
 
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 9d7b4df..339812e 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -1983,7 +1983,7 @@  handle_builtin_memcmp (gimple_stmt_iterator *gsi)
 
   if (tree_fits_uhwi_p (len)
       && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
-      && exact_log2 (leni) != -1)
+      && pow2p_hwi (leni))
     {
       leni *= CHAR_TYPE_SIZE;
       unsigned align1 = get_pointer_alignment (arg1);
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index e908c86..03c4a66 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -2241,7 +2241,7 @@  vect_analyze_group_access_1 (struct data_reference *dr)
       if (DR_IS_READ (dr)
 	  && (dr_step % type_size) == 0
 	  && groupsize > 0
-	  && exact_log2 (groupsize) != -1)
+	  && pow2p_hwi (groupsize))
 	{
 	  GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) = stmt;
 	  GROUP_SIZE (vinfo_for_stmt (stmt)) = groupsize;
@@ -4736,7 +4736,7 @@  vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INT count)
       else
 	{
 	  /* If length is not equal to 3 then only power of 2 is supported.  */
-	  gcc_assert (exact_log2 (count) != -1);
+	  gcc_assert (pow2p_hwi (count));
 
 	  for (i = 0; i < nelt / 2; i++)
 	    {
@@ -4914,7 +4914,7 @@  vect_permute_store_chain (vec<tree> dr_chain,
   else
     {
       /* If length is not equal to 3 then only power of 2 is supported.  */
-      gcc_assert (exact_log2 (length) != -1);
+      gcc_assert (pow2p_hwi (length));
 
       for (i = 0, n = nelt / 2; i < n; i++)
 	{
@@ -5309,7 +5309,7 @@  vect_grouped_load_supported (tree vectype, bool single_element_p,
       else
 	{
 	  /* If length is not equal to 3 then only power of 2 is supported.  */
-	  gcc_assert (exact_log2 (count) != -1);
+	  gcc_assert (pow2p_hwi (count));
 	  for (i = 0; i < nelt; i++)
 	    sel[i] = i * 2;
 	  if (can_vec_perm_p (mode, false, sel))
@@ -5483,7 +5483,7 @@  vect_permute_load_chain (vec<tree> dr_chain,
   else
     {
       /* If length is not equal to 3 then only power of 2 is supported.  */
-      gcc_assert (exact_log2 (length) != -1);
+      gcc_assert (pow2p_hwi (length));
 
       for (i = 0; i < nelt; ++i)
 	sel[i] = i * 2;
@@ -5632,7 +5632,7 @@  vect_shift_permute_load_chain (vec<tree> dr_chain,
   memcpy (result_chain->address (), dr_chain.address (),
 	  length * sizeof (tree));
 
-  if (exact_log2 (length) != -1 && LOOP_VINFO_VECT_FACTOR (loop_vinfo) > 4)
+  if (pow2p_hwi (length) && LOOP_VINFO_VECT_FACTOR (loop_vinfo) > 4)
     {
       unsigned int j, log_length = exact_log2 (length);
       for (i = 0; i < nelt / 2; ++i)
@@ -5880,7 +5880,7 @@  vect_transform_grouped_load (gimple *stmt, vec<tree> dr_chain, int size,
      get chain for loads group using vect_shift_permute_load_chain.  */
   mode = TYPE_MODE (STMT_VINFO_VECTYPE (vinfo_for_stmt (stmt)));
   if (targetm.sched.reassociation_width (VEC_PERM_EXPR, mode) > 1
-      || exact_log2 (size) != -1
+      || pow2p_hwi (size)
       || !vect_shift_permute_load_chain (dr_chain, size, stmt,
 					 gsi, &result_chain))
     vect_permute_load_chain (dr_chain, size, stmt, gsi, &result_chain);
diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c
index 9f0ec65..5d4273f 100644
--- a/gcc/tree-vect-generic.c
+++ b/gcc/tree-vect-generic.c
@@ -494,7 +494,7 @@  expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0,
 	      || (!has_vector_shift && pre_shift != -1))
 	    {
 	      if (has_vector_shift)
-		pre_shift = floor_log2 (d & -d);
+		pre_shift = ctz_or_zero (d);
 	      else if (pre_shift == -1)
 		{
 		  unsigned int j;
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 7e6e45d..3dfbc7b 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -2736,7 +2736,7 @@  vect_recog_divmod_pattern (vec<gimple *> *stmts,
 	 for even divisors, using an initial right shift.  */
       if (mh != 0 && (d & 1) == 0)
 	{
-	  pre_shift = floor_log2 (d & -d);
+	  pre_shift = ctz_or_zero (d);
 	  mh = choose_multiplier (d >> pre_shift, prec, prec - pre_shift,
 				  &ml, &post_shift, &dummy_int);
 	  gcc_assert (!mh);
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index ce5536c..8aa0f01 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -2340,7 +2340,7 @@  vectorizable_mask_load_store (gimple *stmt, gimple_stmt_iterator *gsi,
 	  set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
 				  misalign);
 	  tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),
-				    misalign ? misalign & -misalign : align);
+				    misalign ? least_bit_hwi (misalign) : align);
 	  new_stmt
 	    = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
 					  ptr, vec_mask, vec_rhs);
@@ -2390,7 +2390,7 @@  vectorizable_mask_load_store (gimple *stmt, gimple_stmt_iterator *gsi,
 	  set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
 				  misalign);
 	  tree ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)),
-				    misalign ? misalign & -misalign : align);
+				    misalign ? least_bit_hwi (misalign) : align);
 	  new_stmt
 	    = gimple_build_call_internal (IFN_MASK_LOAD, 3, dataref_ptr,
 					  ptr, vec_mask);
diff --git a/gcc/tsan.c b/gcc/tsan.c
index aa95f4e..91b11ec 100644
--- a/gcc/tsan.c
+++ b/gcc/tsan.c
@@ -174,7 +174,7 @@  instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write)
       if ((align - 1) & bitpos)
 	{
 	  align = (align - 1) & bitpos;
-	  align = align & -align;
+	  align = least_bit_hwi (align);
 	}
       expr = build_fold_addr_expr (unshare_expr (base));
       expr = build2 (MEM_REF, char_type_node, expr,
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index fdad874..07b3e07 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -1983,7 +1983,7 @@  static bool
 negative_power_of_two_p (HOST_WIDE_INT i)
 {
   unsigned HOST_WIDE_INT x = -(unsigned HOST_WIDE_INT)i;
-  return x == (x & -x);
+  return pow2_or_zerop (x);
 }
 
 /* Strip constant offsets and alignments off of LOC.  Return the base
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 00a9b30..ba866ce 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -2632,7 +2632,7 @@  assemble_trampoline_template (void)
 static inline unsigned
 min_align (unsigned int a, unsigned int b)
 {
-  return (a | b) & -(a | b);
+  return least_bit_hwi (a | b);
 }
 
 /* Return the assembler directive for creating a given kind of integer