[PATCH] Misc debug info improvements

Jakub Jelinek jakub@redhat.com
Mon May 16 13:20:00 GMT 2011


Hi!

This patch contains a bunch of smaller debug info improvements:
1) on the typeddwarf.c testcase on x86_64 there were completely needlessly
   many DW_OP_GNU_entry_value ops emitted, while the corresponding argument
   registers were still live.  Fixed by the cselib_subst_to_values hunk.
2) var-tracking wasn't doing a good job with hard registers changing their
   mode, which happens very often e.g. on x86_64-linux.  E.g. a DImode
   setter sets some register, but the following user can use just SImode
   from that register.  cselib created a completely new VALUE for the SImode
   access, and cselib for a short time and var-tracking afterwards only
   knew that the VALUE was live in the corresponding hard register.
   Fixed by adding an additional location to the new VALUE, that it is the
   same thing as lowpart SUBREG of the older reg VALUE, from which we can
   find how it was set and where else the value might be live.
3) we can optimize ZERO_EXTEND, instead of using 6 bytes in location
   description for DW_OP_const1u <shift> DW_OP_shl DW_OP_const1u <shift> DW_OP_shr
   we can emit DW_OP_const{1,2,4}u <mask> DW_OP_and.  For 4u it is
   already the same size, but at least fewer ops, for 8u it would be
   larger.
4) for signed modulo, if the operands are typed, we know the types are
   signed and thus can just use DW_OP_mod (which is unsigned modulo
   only for untyped operands, for typed ones the sign of operands matters)
5) this patch adds code to handle 9 new RTL codes

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2011-05-16  Jakub Jelinek  <jakub@redhat.com>

	* cselib.c (promote_debug_loc): Allow l->next non-NULL for
	cselib_preserve_constants.
	(cselib_lookup_1): If cselib_preserve_constants,
	a new VALUE is being created for REG and there is a VALUE for the
	same register in wider mode, add another loc with lowpart SUBREG of
	the wider VALUE.
	(cselib_subst_to_values): Handle ENTRY_VALUE.
	* var-tracking.c (vt_expand_loc, vt_expand_loc_dummy): Increase
	max_depth from 8 to 10.
	* dwarf2out.c (convert_descriptor_to_signed): New function.
	(mem_loc_descriptor) <case ZERO_EXTEND>: Optimize using DW_OP_and
	instead of two shifts.
	(mem_loc_descriptor) <do_shift>: ZERO_EXTEND second argument to
	the right mode if needed.
	(mem_loc_descriptor) <case MOD>: For typed ops just use DW_OP_mod.
	(mem_loc_descriptor) <case UNSIGNED_FIX>: Use
	convert_descriptor_to_signed.
	(mem_loc_descriptor) <case UDIV, CLZ, CTZ, FFS, POPCOUNT, PARITY,
	BSWAP, ROTATE, ROTATERT>: Handle these rtls.

	* gcc.dg/guality/bswaptest.c: New test.
	* gcc.dg/guality/clztest.c: New test.
	* gcc.dg/guality/ctztest.c: New test.
	* gcc.dg/guality/rotatetest.c: New test.

--- gcc/cselib.c.jj	2011-05-02 18:39:28.000000000 +0200
+++ gcc/cselib.c	2011-05-13 17:55:24.000000000 +0200
@@ -257,7 +257,7 @@ promote_debug_loc (struct elt_loc_list *
     {
       n_debug_values--;
       l->setting_insn = cselib_current_insn;
-      gcc_assert (!l->next);
+      gcc_assert (!l->next || cselib_preserve_constants);
     }
 }
 
@@ -1719,6 +1719,12 @@ cselib_subst_to_values (rtx x, enum mach
 	}
       return e->val_rtx;
 
+    case ENTRY_VALUE:
+      e = cselib_lookup (x, GET_MODE (x), 0, memmode);
+      if (! e)
+	break;
+      return e->val_rtx;
+
     case CONST_DOUBLE:
     case CONST_VECTOR:
     case CONST_INT:
@@ -1843,6 +1849,43 @@ cselib_lookup_1 (rtx x, enum machine_mod
 	  used_regs[n_used_regs++] = i;
 	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
 	}
+      else if (cselib_preserve_constants
+	       && GET_MODE_CLASS (mode) == MODE_INT)
+	{
+	  /* During var-tracking, try harder to find equivalences
+	     for SUBREGs.  If a setter sets say a DImode register
+	     and user uses that register only in SImode, add a lowpart
+	     subreg location.  */
+	  struct elt_list *lwider = NULL;
+	  l = REG_VALUES (i);
+	  if (l && l->elt == NULL)
+	    l = l->next;
+	  for (; l; l = l->next)
+	    if (GET_MODE_CLASS (GET_MODE (l->elt->val_rtx)) == MODE_INT
+		&& GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+		   > GET_MODE_SIZE (mode)
+		&& (lwider == NULL
+		    || GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+		       < GET_MODE_SIZE (GET_MODE (lwider->elt->val_rtx))))
+	      {
+		struct elt_loc_list *el;
+		if (i < FIRST_PSEUDO_REGISTER
+		    && hard_regno_nregs[i][GET_MODE (l->elt->val_rtx)] != 1)
+		  continue;
+		for (el = l->elt->locs; el; el = el->next)
+		  if (!REG_P (el->loc))
+		    break;
+		if (el)
+		  lwider = l;
+	      }
+	  if (lwider)
+	    {
+	      rtx sub = lowpart_subreg (mode, lwider->elt->val_rtx,
+					GET_MODE (lwider->elt->val_rtx));
+	      if (sub)
+		e->locs->next = new_elt_loc_list (e->locs->next, sub);
+	    }
+	}
       REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
       slot = cselib_find_slot (x, e->hash, INSERT, memmode);
       *slot = e;
--- gcc/var-tracking.c.jj	2011-05-11 19:51:48.000000000 +0200
+++ gcc/var-tracking.c	2011-05-13 10:52:25.000000000 +0200
@@ -7415,7 +7415,7 @@ vt_expand_loc (rtx loc, htab_t vars, boo
   data.dummy = false;
   data.cur_loc_changed = false;
   data.ignore_cur_loc = ignore_cur_loc;
-  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
+  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 10,
 				    vt_expand_loc_callback, &data);
 
   if (loc && MEM_P (loc))
@@ -7437,7 +7437,7 @@ vt_expand_loc_dummy (rtx loc, htab_t var
   data.dummy = true;
   data.cur_loc_changed = false;
   data.ignore_cur_loc = false;
-  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
+  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 10,
 					  vt_expand_loc_callback, &data);
   *pcur_loc_changed = data.cur_loc_changed;
   return ret;
--- gcc/dwarf2out.c.jj	2011-05-11 19:39:04.000000000 +0200
+++ gcc/dwarf2out.c	2011-05-16 10:52:47.000000000 +0200
@@ -13824,6 +13824,37 @@ base_type_for_mode (enum machine_mode mo
   return type_die;
 }
 
+/* For OP descriptor assumed to be in unsigned MODE, convert it to a signed
+   type matching MODE, or, if MODE is narrower than DWARF2_ADDR_SIZE, signed
+   type matching DWARF2_ADDR_SIZE.  Return NULL if the conversion is not
+   possible.  */
+
+static dw_loc_descr_ref
+convert_descriptor_to_signed (enum machine_mode mode, dw_loc_descr_ref op)
+{
+  enum machine_mode outer_mode = mode;
+  dw_die_ref type_die;
+  dw_loc_descr_ref cvt;
+
+  if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+    {
+      outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
+				  MODE_INT, 0);
+      if (outer_mode == BLKmode
+	  || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE)
+	return NULL;
+    }
+  type_die = base_type_for_mode (outer_mode, 0);
+  if (type_die == NULL)
+    return NULL;
+  cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+  cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+  cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+  cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+  add_loc_descr (&op, cvt);
+  return op;
+}
+
 /* The following routine converts the RTL for a variable or parameter
    (resident in memory) into an equivalent Dwarf representation of a
    mechanism for getting the address of that same variable onto the top of a
@@ -13986,6 +14017,21 @@ mem_loc_descriptor (rtx rtl, enum machin
 				mem_mode, VAR_INIT_STATUS_INITIALIZED);
       if (op0 == 0)
 	break;
+      else if (GET_CODE (rtl) == ZERO_EXTEND
+	       && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+	       && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+		  < HOST_BITS_PER_WIDE_INT
+	       /* If DW_OP_const{1,2,4}u won't be used, it is shorter
+		  to expand zero extend as two shifts instead of
+		  masking.  */
+	       && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= 4)
+	{
+	  enum machine_mode imode = GET_MODE (XEXP (rtl, 0));
+	  mem_loc_result = op0;
+	  add_loc_descr (&mem_loc_result,
+			 int_loc_descriptor (GET_MODE_MASK (imode)));
+	  add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_and, 0, 0));
+	}
       else if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
 	{
 	  int shift = DWARF2_ADDR_SIZE
@@ -14239,10 +14285,15 @@ mem_loc_descriptor (rtx rtl, enum machin
     do_shift:
       op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
 				VAR_INIT_STATUS_INITIALIZED);
-      op1 = mem_loc_descriptor (XEXP (rtl, 1),
-				GET_MODE (XEXP (rtl, 1)) == VOIDmode
-				? mode : GET_MODE (XEXP (rtl, 1)), mem_mode,
-				VAR_INIT_STATUS_INITIALIZED);
+      {
+	rtx rtlop1 = XEXP (rtl, 1);
+	if (GET_MODE (rtlop1) != VOIDmode
+	    && GET_MODE_BITSIZE (GET_MODE (rtlop1))
+	       < GET_MODE_BITSIZE (mode))
+	  rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
+	op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
+				  VAR_INIT_STATUS_INITIALIZED);
+      }
 
       if (op0 == 0 || op1 == 0)
 	break;
@@ -14279,6 +14330,16 @@ mem_loc_descriptor (rtx rtl, enum machin
       break;
 
     case MOD:
+      if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE && !dwarf_strict)
+	{
+	  /* If MODE is wider than DWARF2_ADDR_SIZE, mem_loc_descriptor
+	     should return signed typed values and therefore DW_OP_mod
+	     won't be unsigned as it defaults for untyped stack values,
+	     but signed.  */
+	  op = DW_OP_mod;
+	  goto do_binop;
+	}
+
       op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
 				VAR_INIT_STATUS_INITIALIZED);
       op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
@@ -14296,6 +14357,38 @@ mem_loc_descriptor (rtx rtl, enum machin
       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
       break;
 
+    case UDIV:
+      if (!dwarf_strict && GET_MODE_CLASS (mode) == MODE_INT)
+	{
+	  dw_die_ref type_die;
+	  dw_loc_descr_ref cvt;
+
+	  type_die = base_type_for_mode (mode, 1);
+	  if (type_die == NULL)
+	    break;
+	  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op0 == 0 || op1 == 0)
+	    break;
+	  cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+	  cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+	  cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+	  cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+	  add_loc_descr (&op0, cvt);
+	  cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+	  cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+	  cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+	  cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
+	  add_loc_descr (&op1, cvt);
+	  mem_loc_result = op0;
+	  add_loc_descr (&mem_loc_result, op1);
+	  add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
+	  mem_loc_result = convert_descriptor_to_signed (mode, mem_loc_result);
+	}
+      break;
+
     case NOT:
       op = DW_OP_not;
       goto do_unop;
@@ -14812,31 +14905,359 @@ mem_loc_descriptor (rtx rtl, enum machin
 	      && (GET_CODE (rtl) == UNSIGNED_FIX
 		  || GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE))
 	    {
-	      enum machine_mode outer_mode = mode;
-	      if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
-		{
-		  outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
-					      MODE_INT, 0);
-		  if (outer_mode == BLKmode
-		      || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE)
-		    break;
-		}
-	      type_die = base_type_for_mode (outer_mode, 0);
-	      if (type_die == NULL)
+	      op0 = convert_descriptor_to_signed (mode, op0);
+	      if (op0 == NULL)
 		break;
-	      cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
-	      cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
-	      cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
-	      cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
-	      add_loc_descr (&op0, cvt);
 	    }
 	  mem_loc_result = op0;
 	}
       break;
 
-    case COMPARE:
+    case CLZ:
+    case CTZ:
+    case FFS:
+      /* CLZ (where constV is CLZ_DEFINED_VALUE_AT_ZERO computed value,
+	      const0 is DW_OP_lit0 or corresponding typed constant,
+	      const1 is DW_OP_lit1 or corresponding typed constant
+	      and constMSB is constant with just the MSB bit set
+	      for the mode):
+	   DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
+	 L1: const0 DW_OP_swap
+	 L2: DW_OP_dup constMSB DW_OP_and DW_OP_bra <L3> const1 DW_OP_shl
+	     DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+	 L3: DW_OP_drop
+	 L4: DW_OP_nop
+
+	 CTZ is similar:
+	   DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
+	 L1: const0 DW_OP_swap
+	 L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
+	     DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+	 L3: DW_OP_drop
+	 L4: DW_OP_nop
+
+	 FFS is similar:
+	   DW_OP_dup DW_OP_bra <L1> DW_OP_drop const0 DW_OP_skip <L4>
+	 L1: const1 DW_OP_swap
+	 L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
+	     DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+	 L3: DW_OP_drop
+	 L4: DW_OP_nop  */
+      if (GET_MODE_CLASS (mode) == MODE_INT
+	  && GET_MODE (XEXP (rtl, 0)) == mode
+	  && (GET_CODE (rtl) != CLZ
+	      || GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT))
+	{
+	  HOST_WIDE_INT valv;
+	  dw_loc_descr_ref l1jump, l1label;
+	  dw_loc_descr_ref l2jump, l2label;
+	  dw_loc_descr_ref l3jump, l3label;
+	  dw_loc_descr_ref l4jump, l4label;
+	  rtx msb;
+
+	  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op0 == NULL)
+	    break;
+	  if (GET_CODE (rtl) == CLZ)
+	    {
+	      if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, valv))
+		valv = GET_MODE_BITSIZE (mode);
+	    }
+	  else if (GET_CODE (rtl) == FFS)
+	    valv = 0;
+	  else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, valv))
+	    valv = GET_MODE_BITSIZE (mode);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+	  l1jump = new_loc_descr (DW_OP_bra, 0, 0);
+	  add_loc_descr (&op0, l1jump);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_drop, 0, 0));
+	  op1 = mem_loc_descriptor (GEN_INT (valv), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  l4jump = new_loc_descr (DW_OP_skip, 0, 0);
+	  add_loc_descr (&op0, l4jump);
+	  l1label = mem_loc_descriptor (GET_CODE (rtl) == FFS
+					? const1_rtx : const0_rtx,
+					mode, mem_mode,
+					VAR_INIT_STATUS_INITIALIZED);
+	  if (l1label == NULL)
+	    break;
+	  add_loc_descr (&op0, l1label);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  l2label = new_loc_descr (DW_OP_dup, 0, 0);
+	  add_loc_descr (&op0, l2label);
+	  if (GET_CODE (rtl) != CLZ)
+	    msb = const1_rtx;
+	  else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+	    msb = GEN_INT ((unsigned HOST_WIDE_INT) 1
+			   << (GET_MODE_BITSIZE (mode) - 1));
+	  else
+	    msb = immed_double_const (0, (unsigned HOST_WIDE_INT) 1
+					 << (GET_MODE_BITSIZE (mode)
+					     - HOST_BITS_PER_WIDE_INT - 1),
+				      mode);
+	  if (GET_CODE (msb) == CONST_INT && INTVAL (msb) < 0)
+	    op1 = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
+				 ? DW_OP_const4u
+				 : HOST_BITS_PER_WIDE_INT == 64
+				 ? DW_OP_const8u : DW_OP_constu,
+				 INTVAL (msb), 0);
+	  else
+	    op1 = mem_loc_descriptor (msb, mode, mem_mode,
+				      VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+	  l3jump = new_loc_descr (DW_OP_bra, 0, 0);
+	  add_loc_descr (&op0, l3jump);
+	  op1 = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (GET_CODE (rtl) == CLZ
+					      ? DW_OP_shl : DW_OP_shr, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, 1, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  l2jump = new_loc_descr (DW_OP_skip, 0, 0);
+	  add_loc_descr (&op0, l2jump);
+	  l3label = new_loc_descr (DW_OP_drop, 0, 0);
+	  add_loc_descr (&op0, l3label);
+	  l4label = new_loc_descr (DW_OP_nop, 0, 0);
+	  add_loc_descr (&op0, l4label);
+	  l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+	  l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+	  l3jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l3jump->dw_loc_oprnd1.v.val_loc = l3label;
+	  l4jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l4jump->dw_loc_oprnd1.v.val_loc = l4label;
+	  mem_loc_result = op0;
+	}
+      break;
+
+    case POPCOUNT:
+    case PARITY:
+      /* POPCOUNT (const0 is DW_OP_lit0 or corresponding typed constant,
+		   const1 is DW_OP_lit1 or corresponding typed constant):
+	     const0 DW_OP_swap
+	 L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
+	     DW_OP_plus DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
+	 L2: DW_OP_drop
+
+	 PARITY is similar:
+	 L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
+	     DW_OP_xor DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
+	 L2: DW_OP_drop  */
+      if (GET_MODE_CLASS (mode) == MODE_INT
+	  && GET_MODE (XEXP (rtl, 0)) == mode)
+	{
+	  dw_loc_descr_ref l1jump, l1label;
+	  dw_loc_descr_ref l2jump, l2label;
+
+	  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op0 == NULL)
+	    break;
+	  op1 = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  l1label = new_loc_descr (DW_OP_dup, 0, 0);
+	  add_loc_descr (&op0, l1label);
+	  l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+	  add_loc_descr (&op0, l2jump);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_rot, 0, 0));
+	  op1 = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (GET_CODE (rtl) == POPCOUNT
+					      ? DW_OP_plus : DW_OP_xor, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  op1 = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_shr, 0, 0));
+	  l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+	  add_loc_descr (&op0, l1jump);
+	  l2label = new_loc_descr (DW_OP_drop, 0, 0);
+	  add_loc_descr (&op0, l2label);
+	  l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+	  l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+	  mem_loc_result = op0;
+	}
+      break;
+
+    case BSWAP:
+      /* BSWAP (constS is initial shift count, either 56 or 24):
+	     constS const0
+	 L1: DW_OP_pick <2> constS DW_OP_pick <3> DW_OP_minus DW_OP_shr
+	     const255 DW_OP_and DW_OP_pick <2> DW_OP_shl DW_OP_or
+	     DW_OP_swap DW_OP_dup const0 DW_OP_eq DW_OP_bra <L2> const8
+	     DW_OP_minus DW_OP_swap DW_OP_skip <L1>
+	 L2: DW_OP_drop DW_OP_swap DW_OP_drop  */
+      if (GET_MODE_CLASS (mode) == MODE_INT
+	  && BITS_PER_UNIT == 8
+	  && (GET_MODE_BITSIZE (mode) == 32
+	      || GET_MODE_BITSIZE (mode) == 64))
+	{
+	  dw_loc_descr_ref l1jump, l1label;
+	  dw_loc_descr_ref l2jump, l2label;
+
+	  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op0 == NULL)
+	    break;
+
+	  op1 = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+				    mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  op1 = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  l1label = new_loc_descr (DW_OP_pick, 2, 0);
+	  add_loc_descr (&op0, l1label);
+	  op1 = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+				    mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_pick, 3, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_minus, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_shr, 0, 0));
+	  op1 = mem_loc_descriptor (GEN_INT (255), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op1 == NULL)
+	    break;
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_pick, 2, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_or, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+	  op1 = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_eq, 0, 0));
+	  l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+	  add_loc_descr (&op0, l2jump);
+	  op1 = mem_loc_descriptor (GEN_INT (8), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_minus, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+	  add_loc_descr (&op0, l1jump);
+	  l2label = new_loc_descr (DW_OP_drop, 0, 0);
+	  add_loc_descr (&op0, l2label);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_drop, 0, 0));
+	  l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+	  l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+	  l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+	  mem_loc_result = op0;
+	}
+      break;
+
     case ROTATE:
     case ROTATERT:
+      /* ROTATE (constMASK is mode mask, BITSIZE is bitsize of mode):
+	     DW_OP_over DW_OP_over DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
+	     [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_neg
+	     DW_OP_plus_uconst <BITSIZE> DW_OP_shr DW_OP_or
+
+	 ROTATERT is similar:
+	     DW_OP_over DW_OP_over DW_OP_neg DW_OP_plus_uconst <BITSIZE>
+	     DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
+	     [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_shr DW_OP_or
+	 */
+      if (GET_MODE_CLASS (mode) == MODE_INT)
+	{
+	  rtx rtlop1 = XEXP (rtl, 1);
+	  dw_loc_descr_ref mask[2] = { NULL, NULL };
+	  int i;
+
+	  if (GET_MODE (rtlop1) != VOIDmode
+	      && GET_MODE_BITSIZE (GET_MODE (rtlop1))
+		 < GET_MODE_BITSIZE (mode))
+	    rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
+	  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
+				    VAR_INIT_STATUS_INITIALIZED);
+	  if (op0 == NULL || op1 == NULL)
+	    break;
+	  if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+	    for (i = 0; i < 2; i++)
+	      {
+		if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
+		  mask[i] = mem_loc_descriptor (GEN_INT (GET_MODE_MASK (mode)),
+						mode, mem_mode,
+						VAR_INIT_STATUS_INITIALIZED);
+		else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
+		  mask[i] = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
+					   ? DW_OP_const4u
+					   : HOST_BITS_PER_WIDE_INT == 64
+					   ? DW_OP_const8u : DW_OP_constu,
+					   GET_MODE_MASK (mode), 0);
+		else
+		  mask[i] = NULL;
+		if (mask[i] == NULL)
+		  return NULL;
+		add_loc_descr (&mask[i], new_loc_descr (DW_OP_and, 0, 0));
+	      }
+	  add_loc_descr (&op0, op1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_over, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_over, 0, 0));
+	  if (GET_CODE (rtl) == ROTATERT)
+	    {
+	      add_loc_descr (&op0, new_loc_descr (DW_OP_neg, 0, 0));
+	      add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst,
+						  GET_MODE_BITSIZE (mode), 0));
+	    }
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+	  if (mask[0] != NULL)
+	    add_loc_descr (&op0, mask[0]);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_rot, 0, 0));
+	  if (mask[1] != NULL)
+	    {
+	      add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	      add_loc_descr (&op0, mask[1]);
+	      add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+	    }
+	  if (GET_CODE (rtl) == ROTATE)
+	    {
+	      add_loc_descr (&op0, new_loc_descr (DW_OP_neg, 0, 0));
+	      add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst,
+						  GET_MODE_BITSIZE (mode), 0));
+	    }
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_shr, 0, 0));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_or, 0, 0));
+	  mem_loc_result = op0;
+	}
+      break;
+
+    case COMPARE:
     case TRUNCATE:
       /* In theory, we could implement the above.  */
       /* DWARF cannot represent the unsigned compare operations
@@ -14856,7 +15277,6 @@ mem_loc_descriptor (rtx rtl, enum machin
     case US_ASHIFT:
     case SS_TRUNCATE:
     case US_TRUNCATE:
-    case UDIV:
     case UNORDERED:
     case ORDERED:
     case UNEQ:
@@ -14870,12 +15290,6 @@ mem_loc_descriptor (rtx rtl, enum machin
     case SAT_FRACT:
     case UNSIGNED_SAT_FRACT:
     case SQRT:
-    case BSWAP:
-    case FFS:
-    case CLZ:
-    case CTZ:
-    case POPCOUNT:
-    case PARITY:
     case ASM_OPERANDS:
     case VEC_MERGE:
     case VEC_SELECT:
--- gcc/testsuite/gcc.dg/guality/bswaptest.c.jj	2011-05-13 22:20:24.000000000 +0200
+++ gcc/testsuite/gcc.dg/guality/bswaptest.c	2011-05-13 22:20:40.000000000 +0200
@@ -0,0 +1,32 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noclone, noinline)) long
+foo (long x)
+{
+  long f = __builtin_bswap64 (x);
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 12 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noclone, noinline)) int
+bar (int x)
+{
+  int f = __builtin_bswap32 (x);
+  int g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 22 "g" "f" } } */
+  return f;
+}
+
+int
+main ()
+{
+  foo (0x123456789abcde0fUL);
+  bar (0x12345678);
+  return 0;
+}
--- gcc/testsuite/gcc.dg/guality/clztest.c.jj	2011-05-13 14:09:41.000000000 +0200
+++ gcc/testsuite/gcc.dg/guality/clztest.c	2011-05-13 14:07:02.000000000 +0200
@@ -0,0 +1,33 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noinline, noclone)) long
+foo (long x)
+{
+  long f = __builtin_clzl (x);
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 12 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noinline, noclone)) long
+bar (long x)
+{
+  long f = __builtin_clzl (x);
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 22 "g" "f" } } */
+  return f;
+}
+
+int
+main ()
+{
+  long x = vv;
+  foo (x + 0x123456UL);
+  bar (x + 0x7fffffffUL);
+  return 0;
+}
--- gcc/testsuite/gcc.dg/guality/ctztest.c.jj	2011-05-13 14:29:43.000000000 +0200
+++ gcc/testsuite/gcc.dg/guality/ctztest.c	2011-05-13 14:28:25.000000000 +0200
@@ -0,0 +1,33 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noinline, noclone)) long
+foo (long x)
+{
+  long f = __builtin_ctzl (x);
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 12 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noinline, noclone)) long
+bar (long x)
+{
+  long f = __builtin_ctzl (x);
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 22 "g" "f" } } */
+  return f;
+}
+
+int
+main ()
+{
+  long x = vv;
+  foo (x + 0x1234560UL);
+  bar (x + 0x7fff8000UL);
+  return 0;
+}
--- gcc/testsuite/gcc.dg/guality/rotatetest.c.jj	2011-05-16 10:58:45.000000000 +0200
+++ gcc/testsuite/gcc.dg/guality/rotatetest.c	2011-05-16 10:57:43.000000000 +0200
@@ -0,0 +1,76 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noclone, noinline)) long
+f1 (unsigned long x)
+{
+  long f = (x << 12) | (x >> (64 - 12));
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 12 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noclone, noinline)) long
+f2 (unsigned long x, int y)
+{
+  long f = (x << y) | (x >> (64 - y));
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 22 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noclone, noinline)) long
+f3 (unsigned long x, int y)
+{
+  long f = (x >> y) | (x << (64 - y));
+  long g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 32 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noclone, noinline)) unsigned int
+f4 (unsigned int x)
+{
+  unsigned int f = (x << 12) | (x >> (32 - 12));
+  unsigned int g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 42 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noclone, noinline)) unsigned int
+f5 (unsigned int x, int y)
+{
+  unsigned int f = (x << y) | (x >> (64 - y));
+  unsigned int g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 52 "g" "f" } } */
+  return f;
+}
+
+__attribute__((noclone, noinline)) unsigned int
+f6 (unsigned int x, int y)
+{
+  unsigned int f = (x >> y) | (x << (64 - y));
+  unsigned int g = f;
+  asm volatile ("" : "+r" (f));
+  vv++;		/* { dg-final { gdb-test 62 "g" "f" } } */
+  return f;
+}
+
+int
+main ()
+{
+  f1 (0x123456789abcde0fUL);
+  f2 (0x123456789abcde0fUL, 18);
+  f3 (0x123456789abcde0fUL, 17);
+  f4 (0x12345678);
+  f5 (0x12345678, 18);
+  f6 (0x12345678, 17);
+  return 0;
+}

	Jakub



More information about the Gcc-patches mailing list