diff mbox

Decrease size of mem_loc_descriptor

Message ID 20110601142910.GX17079@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek June 1, 2011, 2:29 p.m. UTC
On Tue, May 31, 2011 at 09:26:23AM -0700, Richard Henderson wrote:
> On 05/31/2011 02:19 AM, Jakub Jelinek wrote:
> > Hi!
> > 
> > - http://gcc.gnu.org/ml/gcc-patches/2011-05/msg01182.html                                                                                          
> >   various debug info improvements (typed DWARF stack etc.)                                                                                         
> 
> Ok.  Although it might be good to break up mem_loc_descriptor.
> You've got some rather big implementations of operations now.

Here is a patch that does that for a bunch of larger hunks,
mem_loc_descriptor linecount decreased by 40% or so.

Bootstrapped/regtested on x86_64-linux and i686-linux,
the patch should make no difference on generated debug info,
which I've verified on cc1plus debuginfo as well as debuginfo
of gcc.dg/guality/*.c at -g -O2 {-m32,-m64}.
Ok for trunk?

2011-06-01  Jakub Jelinek  <jakub@redhat.com>

	* dwarf2out.c (compare_loc_descriptor, scompare_loc_descriptor,
	ucompare_loc_descriptor, minmax_loc_descriptor, clz_loc_descriptor,
	popcount_loc_descriptor, bswap_loc_descriptor, rotate_loc_descriptor):
	New functions.
	(mem_loc_descriptor): Use them.



	Jakub

Comments

Richard Henderson June 1, 2011, 3:56 p.m. UTC | #1
On 06/01/2011 07:29 AM, Jakub Jelinek wrote:
> 2011-06-01  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* dwarf2out.c (compare_loc_descriptor, scompare_loc_descriptor,
> 	ucompare_loc_descriptor, minmax_loc_descriptor, clz_loc_descriptor,
> 	popcount_loc_descriptor, bswap_loc_descriptor, rotate_loc_descriptor):
> 	New functions.
> 	(mem_loc_descriptor): Use them.

Ok.


r~
diff mbox

Patch

--- gcc/dwarf2out.c.jj	2011-06-01 10:20:03.000000000 +0200
+++ gcc/dwarf2out.c	2011-06-01 12:23:32.000000000 +0200
@@ -13855,6 +13855,627 @@  convert_descriptor_to_signed (enum machi
   return op;
 }
 
+/* Return location descriptor for comparison OP with operands OP0 and OP1.  */
+
+static dw_loc_descr_ref
+compare_loc_descriptor (enum dwarf_location_atom op, dw_loc_descr_ref op0,
+			dw_loc_descr_ref op1)
+{
+  dw_loc_descr_ref ret = op0;
+  add_loc_descr (&ret, op1);
+  add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+  if (STORE_FLAG_VALUE != 1)
+    {
+      add_loc_descr (&ret, int_loc_descriptor (STORE_FLAG_VALUE));
+      add_loc_descr (&ret, new_loc_descr (DW_OP_mul, 0, 0));
+    }
+  return ret;
+}
+
+/* Return location descriptor for signed comparison OP RTL.  */
+
+static dw_loc_descr_ref
+scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
+			 enum machine_mode mem_mode)
+{
+  enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+  dw_loc_descr_ref op0, op1;
+  int shift;
+
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (XEXP (rtl, 1));
+  if (op_mode == VOIDmode)
+    return NULL;
+
+  if (dwarf_strict
+      && (GET_MODE_CLASS (op_mode) != MODE_INT
+	  || GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE))
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
+
+  if (GET_MODE_CLASS (op_mode) != MODE_INT
+      || GET_MODE_SIZE (op_mode) >= DWARF2_ADDR_SIZE)
+    return compare_loc_descriptor (op, op0, op1);
+
+  shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode)) * BITS_PER_UNIT;
+  /* For eq/ne, if the operands are known to be zero-extended,
+     there is no need to do the fancy shifting up.  */
+  if (op == DW_OP_eq || op == DW_OP_ne)
+    {
+      dw_loc_descr_ref last0, last1;
+      for (last0 = op0; last0->dw_loc_next != NULL; last0 = last0->dw_loc_next)
+	;
+      for (last1 = op1; last1->dw_loc_next != NULL; last1 = last1->dw_loc_next)
+	;
+      /* deref_size zero extends, and for constants we can check
+	 whether they are zero extended or not.  */
+      if (((last0->dw_loc_opc == DW_OP_deref_size
+	    && last0->dw_loc_oprnd1.v.val_int <= GET_MODE_SIZE (op_mode))
+	   || (CONST_INT_P (XEXP (rtl, 0))
+	       && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0))
+		  == (INTVAL (XEXP (rtl, 0)) & GET_MODE_MASK (op_mode))))
+	  && ((last1->dw_loc_opc == DW_OP_deref_size
+	       && last1->dw_loc_oprnd1.v.val_int <= GET_MODE_SIZE (op_mode))
+	      || (CONST_INT_P (XEXP (rtl, 1))
+		  && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 1))
+		     == (INTVAL (XEXP (rtl, 1)) & GET_MODE_MASK (op_mode)))))
+	return compare_loc_descriptor (op, op0, op1);
+    }
+  add_loc_descr (&op0, int_loc_descriptor (shift));
+  add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+  if (CONST_INT_P (XEXP (rtl, 1)))
+    op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
+  else
+    {
+      add_loc_descr (&op1, int_loc_descriptor (shift));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+    }
+  return compare_loc_descriptor (op, op0, op1);
+}
+
+/* Return location descriptor for unsigned comparison OP RTL.  */
+
+static dw_loc_descr_ref
+ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
+			 enum machine_mode mem_mode)
+{
+  enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+  dw_loc_descr_ref op0, op1;
+
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (XEXP (rtl, 1));
+  if (op_mode == VOIDmode)
+    return NULL;
+  if (GET_MODE_CLASS (op_mode) != MODE_INT)
+    return NULL;
+
+  if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
+    return NULL;
+
+  if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
+
+  if (GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
+    {
+      HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
+      dw_loc_descr_ref last0, last1;
+      for (last0 = op0; last0->dw_loc_next != NULL; last0 = last0->dw_loc_next)
+	;
+      for (last1 = op1; last1->dw_loc_next != NULL; last1 = last1->dw_loc_next)
+	;
+      if (CONST_INT_P (XEXP (rtl, 0)))
+	op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
+      /* deref_size zero extends, so no need to mask it again.  */
+      else if (last0->dw_loc_opc != DW_OP_deref_size
+	       || last0->dw_loc_oprnd1.v.val_int > GET_MODE_SIZE (op_mode))
+	{
+	  add_loc_descr (&op0, int_loc_descriptor (mask));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+	}
+      if (CONST_INT_P (XEXP (rtl, 1)))
+	op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
+      /* deref_size zero extends, so no need to mask it again.  */
+      else if (last1->dw_loc_opc != DW_OP_deref_size
+	       || last1->dw_loc_oprnd1.v.val_int > GET_MODE_SIZE (op_mode))
+	{
+	  add_loc_descr (&op1, int_loc_descriptor (mask));
+	  add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+	}
+    }
+  else if (GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE)
+    {
+      HOST_WIDE_INT bias = 1;
+      bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+      add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+      if (CONST_INT_P (XEXP (rtl, 1)))
+	op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
+				  + INTVAL (XEXP (rtl, 1)));
+      else
+	add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst,
+					    bias, 0));
+    }
+  else
+    {
+      dw_die_ref type_die = base_type_for_mode (op_mode, 1);
+      dw_loc_descr_ref cvt;
+
+      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 (&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);
+    }
+  return compare_loc_descriptor (op, op0, op1);
+}
+
+/* Return location descriptor for {U,S}{MIN,MAX}.  */
+
+static dw_loc_descr_ref
+minmax_loc_descriptor (rtx rtl, enum machine_mode mode,
+		       enum machine_mode mem_mode)
+{
+  enum dwarf_location_atom op;
+  dw_loc_descr_ref op0, op1, ret;
+  dw_loc_descr_ref bra_node, drop_node;
+
+  if (dwarf_strict
+      && (GET_MODE_CLASS (mode) != MODE_INT
+	  || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE))
+    return NULL;
+
+  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 == NULL || op1 == NULL)
+    return NULL;
+
+  add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+  add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
+  if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+    {
+      if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+	{
+	  HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+	  add_loc_descr (&op0, int_loc_descriptor (mask));
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+	  add_loc_descr (&op1, int_loc_descriptor (mask));
+	  add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+	}
+      else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
+	{
+	  HOST_WIDE_INT bias = 1;
+	  bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+	  add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+	  add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+	}
+      else
+	{
+	  dw_die_ref type_die = base_type_for_mode (mode, 1);
+	  dw_loc_descr_ref cvt;
+	  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 (&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);
+	}
+    }
+  else if (GET_MODE_CLASS (mode) == MODE_INT
+	   && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+    {
+      int shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (mode)) * BITS_PER_UNIT;
+      add_loc_descr (&op0, int_loc_descriptor (shift));
+      add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+      add_loc_descr (&op1, int_loc_descriptor (shift));
+      add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+    }
+
+  if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
+    op = DW_OP_lt;
+  else
+    op = DW_OP_gt;
+  ret = op0;
+  add_loc_descr (&ret, op1);
+  add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+  bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, bra_node);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, drop_node);
+  bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+  bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+  return ret;
+}
+
+/* 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  */
+
+static dw_loc_descr_ref
+clz_loc_descriptor (rtx rtl, enum machine_mode mode,
+		    enum machine_mode mem_mode)
+{
+  dw_loc_descr_ref op0, ret, tmp;
+  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;
+
+  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))
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL)
+    return NULL;
+  ret = op0;
+  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 (&ret, new_loc_descr (DW_OP_dup, 0, 0));
+  l1jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l1jump);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_drop, 0, 0));
+  tmp = mem_loc_descriptor (GEN_INT (valv), mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  l4jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l4jump);
+  l1label = mem_loc_descriptor (GET_CODE (rtl) == FFS
+				? const1_rtx : const0_rtx,
+				mode, mem_mode,
+				VAR_INIT_STATUS_INITIALIZED);
+  if (l1label == NULL)
+    return NULL;
+  add_loc_descr (&ret, l1label);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l2label = new_loc_descr (DW_OP_dup, 0, 0);
+  add_loc_descr (&ret, 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)
+    tmp = 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
+    tmp = mem_loc_descriptor (msb, mode, mem_mode,
+			      VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
+  l3jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l3jump);
+  tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (GET_CODE (rtl) == CLZ
+				      ? DW_OP_shl : DW_OP_shr, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, 1, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l2jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l2jump);
+  l3label = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, l3label);
+  l4label = new_loc_descr (DW_OP_nop, 0, 0);
+  add_loc_descr (&ret, 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;
+  return ret;
+}
+
+/* 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  */
+
+static dw_loc_descr_ref
+popcount_loc_descriptor (rtx rtl, enum machine_mode mode,
+			 enum machine_mode mem_mode)
+{
+  dw_loc_descr_ref op0, ret, tmp;
+  dw_loc_descr_ref l1jump, l1label;
+  dw_loc_descr_ref l2jump, l2label;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || GET_MODE (XEXP (rtl, 0)) != mode)
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL)
+    return NULL;
+  ret = op0;
+  tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l1label = new_loc_descr (DW_OP_dup, 0, 0);
+  add_loc_descr (&ret, l1label);
+  l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l2jump);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_rot, 0, 0));
+  tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (GET_CODE (rtl) == POPCOUNT
+				      ? DW_OP_plus : DW_OP_xor, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+  l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l1jump);
+  l2label = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, 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;
+  return ret;
+}
+
+/* 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  */
+
+static dw_loc_descr_ref
+bswap_loc_descriptor (rtx rtl, enum machine_mode mode,
+		      enum machine_mode mem_mode)
+{
+  dw_loc_descr_ref op0, ret, tmp;
+  dw_loc_descr_ref l1jump, l1label;
+  dw_loc_descr_ref l2jump, l2label;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT
+      || BITS_PER_UNIT != 8
+      || (GET_MODE_BITSIZE (mode) != 32
+	  &&  GET_MODE_BITSIZE (mode) != 64))
+    return NULL;
+
+  op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (op0 == NULL)
+    return NULL;
+
+  ret = op0;
+  tmp = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+			    mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  l1label = new_loc_descr (DW_OP_pick, 2, 0);
+  add_loc_descr (&ret, l1label);
+  tmp = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+			    mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_pick, 3, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_minus, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+  tmp = mem_loc_descriptor (GEN_INT (255), mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  if (tmp == NULL)
+    return NULL;
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_pick, 2, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_or, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
+  tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_eq, 0, 0));
+  l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+  add_loc_descr (&ret, l2jump);
+  tmp = mem_loc_descriptor (GEN_INT (8), mode, mem_mode,
+			    VAR_INIT_STATUS_INITIALIZED);
+  add_loc_descr (&ret, tmp);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_minus, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+  add_loc_descr (&ret, l1jump);
+  l2label = new_loc_descr (DW_OP_drop, 0, 0);
+  add_loc_descr (&ret, l2label);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+  add_loc_descr (&ret, 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;
+  return ret;
+}
+
+/* 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  */
+
+static dw_loc_descr_ref
+rotate_loc_descriptor (rtx rtl, enum machine_mode mode,
+		       enum machine_mode mem_mode)
+{
+  rtx rtlop1 = XEXP (rtl, 1);
+  dw_loc_descr_ref op0, op1, ret, mask[2] = { NULL, NULL };
+  int i;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return NULL;
+
+  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)
+    return NULL;
+  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));
+      }
+  ret = op0;
+  add_loc_descr (&ret, op1);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_over, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_over, 0, 0));
+  if (GET_CODE (rtl) == ROTATERT)
+    {
+      add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+      add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst,
+					  GET_MODE_BITSIZE (mode), 0));
+    }
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
+  if (mask[0] != NULL)
+    add_loc_descr (&ret, mask[0]);
+  add_loc_descr (&ret, new_loc_descr (DW_OP_rot, 0, 0));
+  if (mask[1] != NULL)
+    {
+      add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+      add_loc_descr (&ret, mask[1]);
+      add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
+    }
+  if (GET_CODE (rtl) == ROTATE)
+    {
+      add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+      add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst,
+					  GET_MODE_BITSIZE (mode), 0));
+    }
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_or, 0, 0));
+  return ret;
+}
+
 /* 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
@@ -14491,218 +15112,44 @@  mem_loc_descriptor (rtx rtl, enum machin
       break;
 
     case EQ:
-      op = DW_OP_eq;
-      goto do_scompare;
+      mem_loc_result = scompare_loc_descriptor (DW_OP_eq, rtl, mem_mode);
+      break;
 
     case GE:
-      op = DW_OP_ge;
-      goto do_scompare;
+      mem_loc_result = scompare_loc_descriptor (DW_OP_ge, rtl, mem_mode);
+      break;
 
     case GT:
-      op = DW_OP_gt;
-      goto do_scompare;
+      mem_loc_result = scompare_loc_descriptor (DW_OP_gt, rtl, mem_mode);
+      break;
 
     case LE:
-      op = DW_OP_le;
-      goto do_scompare;
+      mem_loc_result = scompare_loc_descriptor (DW_OP_le, rtl, mem_mode);
+      break;
 
     case LT:
-      op = DW_OP_lt;
-      goto do_scompare;
+      mem_loc_result = scompare_loc_descriptor (DW_OP_lt, rtl, mem_mode);
+      break;
 
     case NE:
-      op = DW_OP_ne;
-      goto do_scompare;
-
-    do_scompare:
-      {
-	enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
-
-	if (op_mode == VOIDmode)
-	  op_mode = GET_MODE (XEXP (rtl, 1));
-	if (op_mode == VOIDmode)
-	  break;
-
-	if (dwarf_strict
-	    && (GET_MODE_CLASS (op_mode) != MODE_INT
-		|| GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE))
-	  break;
-
-	op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
-				  VAR_INIT_STATUS_INITIALIZED);
-	op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
-				  VAR_INIT_STATUS_INITIALIZED);
-
-	if (op0 == 0 || op1 == 0)
-	  break;
-
-	if (GET_MODE_CLASS (op_mode) == MODE_INT
-	    && GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
-	  {
-	    int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode);
-	    shift *= BITS_PER_UNIT;
-	    /* For eq/ne, if the operands are known to be zero-extended,
-	       there is no need to do the fancy shifting up.  */
-	    if (op == DW_OP_eq || op == DW_OP_ne)
-	      {
-		dw_loc_descr_ref last0, last1;
-		for (last0 = op0;
-		     last0->dw_loc_next != NULL;
-		     last0 = last0->dw_loc_next)
-		  ;
-		for (last1 = op1;
-		     last1->dw_loc_next != NULL;
-		     last1 = last1->dw_loc_next)
-		  ;
-		/* deref_size zero extends, and for constants we can check
-		   whether they are zero extended or not.  */
-		if (((last0->dw_loc_opc == DW_OP_deref_size
-		      && last0->dw_loc_oprnd1.v.val_int
-			 <= GET_MODE_SIZE (op_mode))
-		     || (CONST_INT_P (XEXP (rtl, 0))
-			 && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0))
-			     == (INTVAL (XEXP (rtl, 0))
-				 & GET_MODE_MASK (op_mode))))
-		    && ((last1->dw_loc_opc == DW_OP_deref_size
-			 && last1->dw_loc_oprnd1.v.val_int
-			    <= GET_MODE_SIZE (op_mode))
-			|| (CONST_INT_P (XEXP (rtl, 1))
-			    && (unsigned HOST_WIDE_INT)
-			       INTVAL (XEXP (rtl, 1))
-			       == (INTVAL (XEXP (rtl, 1))
-				   & GET_MODE_MASK (op_mode)))))
-		  goto do_compare;
-	      }
-	    add_loc_descr (&op0, int_loc_descriptor (shift));
-	    add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
-	    if (CONST_INT_P (XEXP (rtl, 1)))
-	      op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
-	    else
-	      {
-		add_loc_descr (&op1, int_loc_descriptor (shift));
-		add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
-	      }
-	  }
-      }
-
-    do_compare:
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, op1);
-      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-      if (STORE_FLAG_VALUE != 1)
-	{
-	  add_loc_descr (&mem_loc_result,
-			 int_loc_descriptor (STORE_FLAG_VALUE));
-	  add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
-	}
+      mem_loc_result = scompare_loc_descriptor (DW_OP_ne, rtl, mem_mode);
       break;
 
     case GEU:
-      op = DW_OP_ge;
-      goto do_ucompare;
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_ge, rtl, mem_mode);
+      break;
 
     case GTU:
-      op = DW_OP_gt;
-      goto do_ucompare;
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_gt, rtl, mem_mode);
+      break;
 
     case LEU:
-      op = DW_OP_le;
-      goto do_ucompare;
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_le, rtl, mem_mode);
+      break;
 
     case LTU:
-      op = DW_OP_lt;
-      goto do_ucompare;
-
-    do_ucompare:
-      {
-	enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
-
-	if (op_mode == VOIDmode)
-	  op_mode = GET_MODE (XEXP (rtl, 1));
-	if (op_mode == VOIDmode)
-	  break;
-	if (GET_MODE_CLASS (op_mode) != MODE_INT)
-	  break;
-
-	if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
-	  break;
-
-	if (op_mode != VOIDmode && GET_MODE_CLASS (op_mode) != MODE_INT)
-	    break;
-
-	op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
-				  VAR_INIT_STATUS_INITIALIZED);
-	op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
-				  VAR_INIT_STATUS_INITIALIZED);
-
-	if (op0 == 0 || op1 == 0)
-	  break;
-
-	if (GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
-	  {
-	    HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
-	    dw_loc_descr_ref last0, last1;
-	    for (last0 = op0;
-		 last0->dw_loc_next != NULL;
-		 last0 = last0->dw_loc_next)
-	      ;
-	    for (last1 = op1;
-		 last1->dw_loc_next != NULL;
-		 last1 = last1->dw_loc_next)
-	      ;
-	    if (CONST_INT_P (XEXP (rtl, 0)))
-	      op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
-	    /* deref_size zero extends, so no need to mask it again.  */
-	    else if (last0->dw_loc_opc != DW_OP_deref_size
-		     || last0->dw_loc_oprnd1.v.val_int
-			> GET_MODE_SIZE (op_mode))
-	      {
-		add_loc_descr (&op0, int_loc_descriptor (mask));
-		add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
-	      }
-	    if (CONST_INT_P (XEXP (rtl, 1)))
-	      op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
-	    /* deref_size zero extends, so no need to mask it again.  */
-	    else if (last1->dw_loc_opc != DW_OP_deref_size
-		     || last1->dw_loc_oprnd1.v.val_int
-			> GET_MODE_SIZE (op_mode))
-	      {
-		add_loc_descr (&op1, int_loc_descriptor (mask));
-		add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
-	      }
-	  }
-	else if (GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE)
-	  {
-	    HOST_WIDE_INT bias = 1;
-	    bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
-	    add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-	    if (CONST_INT_P (XEXP (rtl, 1)))
-	      op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
-					+ INTVAL (XEXP (rtl, 1)));
-	    else
-	      add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst,
-						  bias, 0));
-	  }
-	else
-	  {
-	    dw_die_ref type_die = base_type_for_mode (op_mode, 1);
-	    dw_loc_descr_ref cvt;
-
-	    if (type_die == 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);
-	    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);
-	  }
-      }
-      goto do_compare;
+      mem_loc_result = ucompare_loc_descriptor (DW_OP_lt, rtl, mem_mode);
+      break;
 
     case UMIN:
     case UMAX:
@@ -14711,87 +15158,7 @@  mem_loc_descriptor (rtx rtl, enum machin
       /* FALLTHRU */
     case SMIN:
     case SMAX:
-      if (dwarf_strict
-	  && (GET_MODE_CLASS (mode) != MODE_INT
-	      || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE))
-	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;
-
-      add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
-      add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
-      add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
-      if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
-	{
-	  if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
-	    {
-	      HOST_WIDE_INT mask = GET_MODE_MASK (mode);
-	      add_loc_descr (&op0, int_loc_descriptor (mask));
-	      add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
-	      add_loc_descr (&op1, int_loc_descriptor (mask));
-	      add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
-	    }
-	  else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
-	    {
-	      HOST_WIDE_INT bias = 1;
-	      bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
-	      add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-	      add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
-	    }
-	  else
-	    {
-	      dw_die_ref type_die = base_type_for_mode (mode, 1);
-	      dw_loc_descr_ref cvt;
-
-	      if (type_die == 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);
-	      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);
-	    }
-	}
-      else if (GET_MODE_CLASS (mode) == MODE_INT
-	       && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
-	{
-	  int shift = DWARF2_ADDR_SIZE - GET_MODE_SIZE (mode);
-	  shift *= BITS_PER_UNIT;
-	  add_loc_descr (&op0, int_loc_descriptor (shift));
-	  add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
-	  add_loc_descr (&op1, int_loc_descriptor (shift));
-	  add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
-	}
-
-      if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
-	op = DW_OP_lt;
-      else
-	op = DW_OP_gt;
-      mem_loc_result = op0;
-      add_loc_descr (&mem_loc_result, op1);
-      add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
-      {
-	dw_loc_descr_ref bra_node, drop_node;
-
-	bra_node = new_loc_descr (DW_OP_bra, 0, 0);
-	add_loc_descr (&mem_loc_result, bra_node);
-	add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
-	drop_node = new_loc_descr (DW_OP_drop, 0, 0);
-	add_loc_descr (&mem_loc_result, drop_node);
-	bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
-	bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
-      }
+      mem_loc_result = minmax_loc_descriptor (rtl, mode, mem_mode);
       break;
 
     case ZERO_EXTRACT:
@@ -14916,345 +15283,21 @@  mem_loc_descriptor (rtx rtl, enum machin
     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;
-	}
+      mem_loc_result = clz_loc_descriptor (rtl, mode, mem_mode);
       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;
-	}
+      mem_loc_result = popcount_loc_descriptor (rtl, mode, mem_mode);
       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;
-	}
+      mem_loc_result = bswap_loc_descriptor (rtl, mode, mem_mode);
       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;
-	}
+      mem_loc_result = rotate_loc_descriptor (rtl, mode, mem_mode);
       break;
 
     case COMPARE: