public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/testme)] unify split logic, reorder neighbors if needed
@ 2020-09-24 19:16 Alexandre Oliva
  0 siblings, 0 replies; only message in thread
From: Alexandre Oliva @ 2020-09-24 19:16 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:6e7427d55b312da45624b7163dbc4c0403e342ca

commit 6e7427d55b312da45624b7163dbc4c0403e342ca
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Thu Sep 24 14:47:17 2020 -0300

    unify split logic, reorder neighbors if needed

Diff:
---
 gcc/fold-const.c | 451 +++++++++++++++++++++++++------------------------------
 1 file changed, 205 insertions(+), 246 deletions(-)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 87448f9b911..bfbf88c9f15 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -6681,6 +6681,72 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
 	return 0;
     }
 
+  /* This will be bumped to 2 if any of the field pairs crosses an
+     alignment boundary, so the merged compare has to be done in two
+     parts.  */
+  int parts = 1;
+  /* Set to true if the second combined compare should come first,
+     e.g., because the second original compare accesses a word that
+     the first one doesn't, and the combined compares access those in
+     cmp[0].  */
+  bool first1 = false;
+  /* Set to true if the first original compare is not the one being
+     split.  */
+  bool maybe_separate = false;
+
+  /* The following 2-dimensional arrays use the first index to
+     identify left(0)- vs right(1)-hand compare operands, and the
+     second one to identify merged compare parts.  */
+  /* The memory loads or constants to be compared.  */
+  tree ld_arg[2][2];
+  /* The first bit of the corresponding inner object that the
+     corresponding LD_ARG covers.  */
+  HOST_WIDE_INT bitpos[2][2];
+  /* The bit count starting at BITPOS that the corresponding LD_ARG
+     covers.  */
+  HOST_WIDE_INT bitsiz[2][2];
+  /* The number of bits by which LD_ARG has already been shifted
+     right, WRT mask.  */
+  HOST_WIDE_INT shifted[2][2];
+  /* The number of bits by which both LD_ARG and MASK need shifting to
+     bring its least-significant bit to bit zero.  */
+  HOST_WIDE_INT toshift[2][2];
+  /* An additional mask to be applied to LD_ARG, to remove any bits
+     that may have been loaded for use in another compare, but that
+     don't belong in the corresponding compare.  */
+  tree xmask[2][2] = {};
+
+  /* The combined compare or compares.  */
+  tree cmp[2];
+
+  /* Consider we're comparing two non-contiguous fields of packed
+     structs, both aligned at 32-bit boundaries:
+
+     ll_arg: an 8-bit field at offset 0
+     lr_arg: a 16-bit field at offset 2
+
+     rl_arg: an 8-bit field at offset 1
+     rr_arg: a 16-bit field at offset 3
+
+     We'll have r_split_load, because rr_arg straddles across an
+     alignment boundary.
+
+     We'll want to have:
+
+     bitpos  = { {  0,  0 }, {  0, 32 } }
+     bitsiz  = { { 32, 32 }, { 32,  8 } }
+
+     And, for little-endian:
+
+     shifted = { {  0,  0 }, {  0, 32 } }
+     toshift = { {  0, 24 }, {  0,  0 } }
+
+     Or, for big-endian:
+
+     shifted = { {  0,  0 }, {  8,  0 } }
+     toshift = { {  8,  0 }, {  0,  0 } }
+  */
+
   /* See if we can find a mode that contains both fields being compared on
      the left.  If we can't, fail.  Otherwise, update all constants and masks
      to be relative to a field of that size.  */
@@ -6705,6 +6771,11 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
 	return 0;
 
       l_split_load = true;
+      parts = 2;
+      if (ll_bitpos >= boundary)
+	maybe_separate = first1 = true;
+      else if (ll_bitpos + ll_bitsize <= boundary)
+	maybe_separate = true;
     }
   else
     l_split_load = false;
@@ -6804,6 +6875,11 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
 	    return 0;
 
 	  r_split_load = true;
+	  parts = 2;
+	  if (lr_bitpos >= boundary)
+	    maybe_separate = first1 = true;
+	  else if (lr_bitpos + lr_bitsize <= boundary)
+	    maybe_separate = true;
 	}
       else
 	r_split_load = false;
@@ -6833,58 +6909,8 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
 							    rntype, rr_mask),
 			     size_int (xrr_bitpos));
 
-      ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
       lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask);
 
-      int parts = 1;
-      tree ld_arg[2][2];
-      HOST_WIDE_INT bitpos[2][2];
-      HOST_WIDE_INT bitsiz[2][2];
-      HOST_WIDE_INT shifted[2][2];
-      HOST_WIDE_INT toshift[2][2];
-      tree xmask[2][2] = {};
-
-      /* Consider we're comparing two non-contiguous fields of packed
-	 structs, both aligned at 32-bit boundaries:
-
-	 ll_arg: an 8-bit field at offset 0
-	 lr_arg: a 16-bit field at offset 2
-
-	 rl_arg: an 8-bit field at offset 1
-	 rr_arg: a 16-bit field at offset 3
-
-	 We'll have r_split_load, because rr_arg straddles across an
-	 alignment boundary.
-
-	 We'll want to have:
-
-	 bitpos  = { {  0,  0 }, {  0, 32 } }
-	 bitsiz  = { { 32, 32 }, { 32,  8 } }
-
-	 And, for little-endian:
-
-	 shifted = { {  0,  0 }, {  0, 32 } }
-	 toshift = { {  0, 24 }, {  0,  0 } }
-
-	 Or, for big-endian:
-
-	 shifted = { {  0,  0 }, {  8,  0 } }
-	 toshift = { {  8,  0 }, {  0,  0 } }
-      */
-
-      toshift[0][0] = MIN (xll_bitpos, xrl_bitpos);
-      shifted[0][0] = 0;
-
-      if (!l_split_load)
-	{
-	  bitpos[0][0] = lnbitpos;
-	  bitsiz[0][0] = lnbitsize;
-	  ld_arg[0][0] = make_bit_field_ref (loc, ll_inner, ll_arg,
-					     lntype, lnbitsize, lnbitpos,
-					     ll_unsignedp || rl_unsignedp,
-					     ll_reversep);
-	}
-
       toshift[1][0] = MIN (xlr_bitpos, xrr_bitpos);
       shifted[1][0] = 0;
 
@@ -6898,20 +6924,8 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
 					     lr_reversep);
 	}
 
-      if (l_split_load || r_split_load)
+      if (parts > 1)
 	{
-	  parts = 2;
-
-	  if (l_split_load)
-	    build_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
-			      shifted[0], loc, ll_inner, ll_arg,
-			      lnmode, lnmode2, lnbitpos, ll_reversep);
-	  else
-	    reuse_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
-			      shifted[0], xmask[0],
-			      rnbitpos + GET_MODE_BITSIZE (rnmode)
-			      - lr_bitpos + ll_bitpos, ll_reversep);
-
 	  if (r_split_load)
 	    build_split_load (ld_arg[1], bitpos[1], bitsiz[1], toshift[1],
 			      shifted[1], loc, lr_inner, lr_arg,
@@ -6922,215 +6936,160 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
 			      lnbitpos + GET_MODE_BITSIZE (lnmode)
 			      - ll_bitpos + lr_bitpos, lr_reversep);
 	}
-
-      tree cmp[2];
-
-      for (int i = 0; i < parts; i++)
-	{
-	  tree op[2] = { ld_arg[0][i], ld_arg[1][i] };
-	  tree mask[2] = { ll_mask, lr_mask };
-
-	  for (int j = 0; j < 2; j++)
+    }
+  else
+    {
+      /* Handle the case of comparisons with constants.  If there is
+	 something in common between the masks, those bits of the
+	 constants must be the same.  If not, the condition is always
+	 false.  Test for this to avoid generating incorrect code
+	 below.  */
+      result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask);
+      if (! integer_zerop (result)
+	  && simple_cst_equal (const_binop (BIT_AND_EXPR,
+					    result, l_const),
+			       const_binop (BIT_AND_EXPR,
+					    result, r_const)) != 1)
+	{
+	  if (wanted_code == NE_EXPR)
 	    {
-	      /* Mask out the bits belonging to the other part.  */
-	      if (xmask[j][i])
-		mask[j] = const_binop (BIT_AND_EXPR, mask[j], xmask[j][i]);
-
-	      if (shifted[j][i])
-		{
-		  tree shiftsz = bitsize_int (shifted[j][i]);
-		  mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
-		}
-	      mask[j] = fold_convert_loc (loc, TREE_TYPE (op[j]), mask[j]);
+	      warning (0,
+		       "%<or%> of unmatched not-equal tests"
+		       " is always 1");
+	      return constant_boolean_node (true, truth_type);
 	    }
-
-	  HOST_WIDE_INT shift = (toshift[0][i] - toshift[1][i]);
-
-	  if (shift)
+	  else
 	    {
-	      int j;
-	      if (shift > 0)
-		j = 0;
-	      else
-		{
-		  j = 1;
-		  shift = -shift;
-		}
-
-	      tree shiftsz = bitsize_int (shift);
-	      op[j] = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (op[j]),
-				       op[j], shiftsz);
-	      mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
+	      warning (0,
+		       "%<and%> of mutually exclusive equal-tests"
+		       " is always 0");
+	      return constant_boolean_node (false, truth_type);
 	    }
+	}
 
-	  /* Convert to the smaller type before masking out unwanted
-	     bits.  */
-	  tree type = TREE_TYPE (op[0]);
-	  if (type != TREE_TYPE (op[1]))
-	    {
-	      int j = (TYPE_PRECISION (type)
-		       < TYPE_PRECISION (TREE_TYPE (op[1])));
-	      if (!j)
-		type = TREE_TYPE (op[1]);
-	      op[j] = fold_convert_loc (loc, type, op[j]);
-	      mask[j] = fold_convert_loc (loc, type, mask[j]);
-	    }
+      if (lnbitpos < 0)
+	return 0;
 
-	  for (int j = 0; j < 2; j++)
-	    if (! integer_all_onesp (mask[j]))
-	      op[j] = build2_loc (loc, BIT_AND_EXPR, type,
-				  op[j], mask[j]);
+      /* The constants are combined so as to line up with the loaded
+	 field, so use the same parameters.  */
+      ld_arg[1][0] = const_binop (BIT_IOR_EXPR, l_const, r_const);
+      toshift[1][0] = MIN (xll_bitpos, xrl_bitpos);
+      shifted[1][0] = 0;
+      bitpos[1][0] = lnbitpos;
+      bitsiz[1][0] = lnbitsize;
 
-	  cmp[i] = build2_loc (loc, wanted_code, truth_type, op[0], op[1]);
-	}
+      if (parts > 1)
+	reuse_split_load (ld_arg[1], bitpos[1], bitsiz[1], toshift[1],
+			  shifted[1], xmask[1],
+			  lnbitpos + GET_MODE_BITSIZE (lnmode),
+			  lr_reversep);
 
-      if (parts == 1)
-	result = cmp[0];
-      else if (!separatep
-	       || ((!l_split_load
-		    || (ll_bitpos < bitpos[0][1]
-			&& ll_bitpos + ll_bitsize > bitpos[0][1]))
-		   && (!r_split_load
-		       || (lr_bitpos < bitpos[1][1]
-			   && lr_bitpos + lr_bitsize > bitpos[1][1]))))
-	result = build2_loc (loc, orig_code, truth_type, cmp[0], cmp[1]);
-      else if ((l_split_load && ll_bitpos >= bitpos[0][1])
-	       || (r_split_load && lr_bitpos >= bitpos[1][1]))
-	{
-	  result = cmp[1];
-	  *separatep = cmp[0];
-	}
-      else
-	{
-	  result = cmp[0];
-	  *separatep = cmp[1];
-	}
+      lr_mask = build_int_cst_type (TREE_TYPE (ld_arg[1][0]), -1);
 
-      return result;
+      /* If the compiler thinks this is used uninitialized below, it's
+	 because it can't realize that parts can only be 2 when
+	 comparing wiht constants if l_split_load is also true.  This
+	 just silences the warning.  */
+      rnbitpos = 0;
     }
 
-  /* Handle the case of comparisons with constants.  If there is something in
-     common between the masks, those bits of the constants must be the same.
-     If not, the condition is always false.  Test for this to avoid generating
-     incorrect code below.  */
-  result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask);
-  if (! integer_zerop (result)
-      && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const),
-			   const_binop (BIT_AND_EXPR, result, r_const)) != 1)
+  ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
+  toshift[0][0] = MIN (xll_bitpos, xrl_bitpos);
+  shifted[0][0] = 0;
+
+  if (!l_split_load)
     {
-      if (wanted_code == NE_EXPR)
-	{
-	  warning (0, "%<or%> of unmatched not-equal tests is always 1");
-	  return constant_boolean_node (true, truth_type);
-	}
-      else
-	{
-	  warning (0, "%<and%> of mutually exclusive equal-tests is always 0");
-	  return constant_boolean_node (false, truth_type);
-	}
+      bitpos[0][0] = lnbitpos;
+      bitsiz[0][0] = lnbitsize;
+      ld_arg[0][0] = make_bit_field_ref (loc, ll_inner, ll_arg,
+					 lntype, lnbitsize, lnbitpos,
+					 ll_unsignedp || rl_unsignedp,
+					 ll_reversep);
     }
 
-  if (lnbitpos < 0)
-    return 0;
+  if (parts > 1)
+    {
+      if (l_split_load)
+	build_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
+			  shifted[0], loc, ll_inner, ll_arg,
+			  lnmode, lnmode2, lnbitpos, ll_reversep);
+      else
+	reuse_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
+			  shifted[0], xmask[0],
+			  rnbitpos + GET_MODE_BITSIZE (rnmode)
+			  - lr_bitpos + ll_bitpos, ll_reversep);
+    }
 
-  if (l_split_load)
+  for (int i = 0; i < parts; i++)
     {
-      HOST_WIDE_INT align = TYPE_ALIGN (TREE_TYPE (ll_inner));
-      HOST_WIDE_INT lnlbitsize = GET_MODE_BITSIZE (lnmode);
-      HOST_WIDE_INT lnrbitsize = GET_MODE_BITSIZE (lnmode2);
-      HOST_WIDE_INT midpoint = lnlbitsize;
-      HOST_WIDE_INT lnrbitpos = lnbitpos + midpoint;
-      HOST_WIDE_INT lnlbitpos = lnrbitpos - lnlbitsize;
-      gcc_checking_assert ((lnrbitpos & (align - 1)) == 0);
-      tree lnltype = lang_hooks.types.type_for_size (lnlbitsize, 1);
-      tree lnrtype = lang_hooks.types.type_for_size (lnrbitsize, 1);
-      tree lll_arg = make_bit_field_ref (loc, ll_inner, ll_arg,
-					 lnltype, lnlbitsize, lnlbitpos,
-					 ll_unsignedp || rl_unsignedp,
-					 ll_reversep);
-      tree llr_arg = make_bit_field_ref (loc, ll_inner, ll_arg,
-					 lnrtype, lnrbitsize, lnrbitpos,
-					 ll_unsignedp || rl_unsignedp,
-					 ll_reversep);
+      tree op[2] = { ld_arg[0][i], ld_arg[1][i] };
+      tree mask[2] = { ll_mask, lr_mask };
 
-      HOST_WIDE_INT lnlcbitpos;
-      HOST_WIDE_INT lnrcbitpos;
-      /* The bit field ref constant folding below already takes care
-	 of default target endianness.  */
-      if (!ll_reversep)
+      for (int j = 0; j < 2; j++)
 	{
-	  lnlcbitpos = 0;
-	  lnrcbitpos = lnlbitsize;
+	  /* Mask out the bits belonging to the other part.  */
+	  if (xmask[j][i])
+	    mask[j] = const_binop (BIT_AND_EXPR, mask[j], xmask[j][i]);
+
+	  if (shifted[j][i])
+	    {
+	      tree shiftsz = bitsize_int (shifted[j][i]);
+	      mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
+	    }
+	  mask[j] = fold_convert_loc (loc, TREE_TYPE (op[j]), mask[j]);
 	}
-      else
+
+      HOST_WIDE_INT shift = (toshift[0][i] - toshift[1][i]);
+
+      if (shift)
 	{
-	  lnlcbitpos = lnrbitsize;
-	  lnrcbitpos = 0;
-	}
-
-      tree mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
-      tree lll_mask = fold_build3 (BIT_FIELD_REF, lnltype, mask,
-				   bitsize_int (lnlbitsize),
-				   bitsize_int (lnlcbitpos));
-      if (! integer_all_onesp (lll_mask))
-	lll_arg = fold_build2_loc (loc, BIT_AND_EXPR, lnltype,
-				   lll_arg, lll_mask);
-      tree llr_mask = fold_build3 (BIT_FIELD_REF, lnrtype, mask,
-				   bitsize_int (lnrbitsize),
-				   bitsize_int (lnrcbitpos));
-      if (! integer_all_onesp (llr_mask))
-	llr_arg = fold_build2_loc (loc, BIT_AND_EXPR, lnrtype,
-				   llr_arg, llr_mask);
-      tree lnr_const = const_binop (BIT_IOR_EXPR, l_const, r_const);
-      tree lll_const = fold_build3 (BIT_FIELD_REF, lnltype, lnr_const,
-				    bitsize_int (lnlbitsize),
-				    bitsize_int (lnlcbitpos));
-      tree lll_result = fold_build2_loc (loc, wanted_code, truth_type,
-					 lll_arg, lll_const);
-      tree llr_const = fold_build3 (BIT_FIELD_REF, lnrtype, lnr_const,
-				    bitsize_int (lnrbitsize),
-				    bitsize_int (lnrcbitpos));
-      tree llr_result = fold_build2_loc (loc, wanted_code, truth_type,
-					 llr_arg, llr_const);
-
-      /* If the accesses were adjacent in the compare chain, or if LHS
-	 already accessed both "words", then we can have both words
-	 accessed in the RESULT, leaving no remains of *RHS for
-	 *SEPARATEP.  Otherwise, figure out which part of the object
-	 was already accessed by LHS, and put it in the RESULT,
-	 returning the bits newly-accessed by RHS in *SEPARATEP.  */
-      if (!separatep
-	  || (ll_bitpos < lnrbitpos && ll_bitpos + ll_bitsize > lnrbitpos))
-	result = build2_loc (loc, orig_code, truth_type,
-			     lll_result, llr_result);
-      else if (ll_bitpos >= lnrbitpos)
-	{
-	  result = llr_result;
-	  *separatep = lll_result;
+	  int j;
+	  if (shift > 0)
+	    j = 0;
+	  else
+	    {
+	      j = 1;
+	      shift = -shift;
+	    }
+
+	  tree shiftsz = bitsize_int (shift);
+	  op[j] = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (op[j]),
+				   op[j], shiftsz);
+	  mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
 	}
-      else
+
+      /* Convert to the smaller type before masking out unwanted
+	 bits.  */
+      tree type = TREE_TYPE (op[0]);
+      if (type != TREE_TYPE (op[1]))
 	{
-	  result = lll_result;
-	  *separatep = llr_result;
+	  int j = (TYPE_PRECISION (type)
+		   < TYPE_PRECISION (TREE_TYPE (op[1])));
+	  if (!j)
+	    type = TREE_TYPE (op[1]);
+	  op[j] = fold_convert_loc (loc, type, op[j]);
+	  mask[j] = fold_convert_loc (loc, type, mask[j]);
 	}
-    }
-  else
-    {
 
-      /* Construct the expression we will return.  First get the component
-	 reference we will make.  Unless the mask is all ones the width of
-	 that field, perform the mask operation.  Then compare with the
-	 merged constant.  */
-      result = make_bit_field_ref (loc, ll_inner, ll_arg,
-				   lntype, lnbitsize, lnbitpos,
-				   ll_unsignedp || rl_unsignedp, ll_reversep);
+      for (int j = 0; j < 2; j++)
+	if (! integer_all_onesp (mask[j]))
+	  op[j] = build2_loc (loc, BIT_AND_EXPR, type,
+			      op[j], mask[j]);
+
+      cmp[i] = build2_loc (loc, wanted_code, truth_type, op[0], op[1]);
+    }
 
-      ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
-      if (! integer_all_onesp (ll_mask))
-	result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask);
+  if (first1)
+    std::swap (cmp[0], cmp[1]);
 
-      result = build2_loc (loc, wanted_code, truth_type, result,
-			   const_binop (BIT_IOR_EXPR, l_const, r_const));
+  if (parts == 1)
+    result = cmp[0];
+  else if (!separatep || !maybe_separate)
+    result = build2_loc (loc, orig_code, truth_type, cmp[0], cmp[1]);
+  else
+    {
+      result = cmp[0];
+      *separatep = cmp[1];
     }
 
   return result;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-09-24 19:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-24 19:16 [gcc(refs/users/aoliva/heads/testme)] unify split logic, reorder neighbors if needed Alexandre Oliva

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).