Hi!

While working on the last dwarf2out.c patch, I've noticed we can generate
more compact DWARF location descriptions in several cases, e.g.
DW_OP_constu 0xf80000000
is 7 byts long, while
DW_OP_lit31 DW_OP_lit31 DW_OP_shl
pushes the same value to the stack and is just 3 bytes long.
The patch adjusts {,size_of_}int_loc_descriptor to generate those and
similar sequences when shorter (for case of the same length prefers
single op over several smaller ops though).
In addition to that, it attempts to optimize DW_OP_GNU_const_type
into int_loc_descriptor + DW_OP_GNU_convert when possible, and
optimizes DW_OP_plus_uconst <const> into int_loc_descriptor (const) DW_OP_plus
if the latter is shorter.

On the attached testcase .debug_info on x86_64 -m64 shrunk from
1092 bytes to 986 bytes (i.e. almost 10% reduction, though on artificial
testcase), and for -m32 it shrunk from 1440 to 1295 bytes.

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

2011-07-11  Jakub Jelinek  <ja...@redhat.com>

        PR debug/49676
        * dwarf2out.c (int_shift_loc_descriptor): New function.
        (int_loc_descriptor): If shorter, emit i as
        (i >> shift), shift, DW_OP_shl for suitable shift value.
        Similarly, try to optimize large negative values using
        DW_OP_neg of a positive value if shorter.
        (size_of_int_shift_loc_descriptor): New function.
        (size_of_int_loc_descriptor): Adjust to match int_loc_descriptor
        changes.
        (mem_loc_descriptor) <case CONST_INT>: Emit zero-extended constants
        that fit into DWARF2_ADDR_SIZE bytes as int_loc_descriptor +
        DW_OP_GNU_convert instead of DW_OP_GNU_const_type if the former
        is shorter.
        (resolve_addr_in_expr): Optimize DW_OP_plus_uconst with a large
        addend as added DW_OP_plus if it is shorter.

--- gcc/dwarf2out.c.jj  2011-07-11 10:39:50.000000000 +0200
+++ gcc/dwarf2out.c     2011-07-11 14:38:07.000000000 +0200
@@ -10135,6 +10135,21 @@ multiple_reg_loc_descriptor (rtx rtl, rt
   return loc_result;
 }
 
+static unsigned long size_of_int_loc_descriptor (HOST_WIDE_INT);
+
+/* Return a location descriptor that designates a constant i,
+   as a compound operation from constant (i >> shift), constant shift
+   and DW_OP_shl.  */
+
+static dw_loc_descr_ref
+int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
+{
+  dw_loc_descr_ref ret = int_loc_descriptor (i >> shift);
+  add_loc_descr (&ret, int_loc_descriptor (shift));
+  add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
+  return ret;
+}
+
 /* Return a location descriptor that designates a constant.  */
 
 static dw_loc_descr_ref
@@ -10146,15 +10161,45 @@ int_loc_descriptor (HOST_WIDE_INT i)
      defaulting to the LEB encoding.  */
   if (i >= 0)
     {
+      int clz = clz_hwi (i);
+      int ctz = ctz_hwi (i);
       if (i <= 31)
        op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
       else if (i <= 0xff)
        op = DW_OP_const1u;
       else if (i <= 0xffff)
        op = DW_OP_const2u;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i <= 0xffffffff)
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5
+              && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_litX DW_OP_litY DW_OP_shl takes just 3 bytes and
+          DW_OP_litX DW_OP_const1u Y DW_OP_shl takes just 4 bytes,
+          while DW_OP_const4u is 5 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 5);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+              && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_const1u X DW_OP_litY DW_OP_shl takes just 4 bytes,
+          while DW_OP_const4u is 5 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8);
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff)
        op = DW_OP_const4u;
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+              && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_const1u X DW_OP_const1u Y DW_OP_shl takes just 5 bytes,
+          while DW_OP_constu of constant >= 0x100000000 takes at least
+          6 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16
+              && clz + 16 + (size_of_uleb128 (i) > 5 ? 255 : 31)
+                 >= HOST_BITS_PER_WIDE_INT)
+       /* DW_OP_const2u X DW_OP_litY DW_OP_shl takes just 5 bytes,
+          DW_OP_const2u X DW_OP_const1u Y DW_OP_shl takes 6 bytes,
+          while DW_OP_constu takes in this case at least 6 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 16);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32
+              && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT
+              && size_of_uleb128 (i) > 6)
+       /* DW_OP_const4u X DW_OP_litY DW_OP_shl takes just 7 bytes.  */
+       return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 32);
       else
        op = DW_OP_constu;
     }
@@ -10164,35 +10209,88 @@ int_loc_descriptor (HOST_WIDE_INT i)
        op = DW_OP_const1s;
       else if (i >= -0x8000)
        op = DW_OP_const2s;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i >= -0x80000000)
-       op = DW_OP_const4s;
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000)
+       {
+         if (size_of_int_loc_descriptor (i) < 5)
+           {
+             dw_loc_descr_ref ret = int_loc_descriptor (-i);
+             add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+             return ret;
+           }
+         op = DW_OP_const4s;
+       }
       else
-       op = DW_OP_consts;
+       {
+         if (size_of_int_loc_descriptor (i)
+             < (unsigned long) 1 + size_of_sleb128 (i))
+           {
+             dw_loc_descr_ref ret = int_loc_descriptor (-i);
+             add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
+             return ret;
+           }
+         op = DW_OP_consts;
+       }
     }
 
   return new_loc_descr (op, i, 0);
 }
 
+/* Return size_of_locs (int_shift_loc_descriptor (i, shift))
+   without actually allocating it.  */
+
+static unsigned long
+size_of_int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
+{
+  return size_of_int_loc_descriptor (i >> shift)
+        + size_of_int_loc_descriptor (shift)
+        + 1;
+}
+
 /* Return size_of_locs (int_loc_descriptor (i)) without
    actually allocating it.  */
 
 static unsigned long
 size_of_int_loc_descriptor (HOST_WIDE_INT i)
 {
+  unsigned long s;
+
   if (i >= 0)
     {
+      int clz, ctz;
       if (i <= 31)
        return 1;
       else if (i <= 0xff)
        return 2;
       else if (i <= 0xffff)
        return 3;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i <= 0xffffffff)
+      clz = clz_hwi (i);
+      ctz = ctz_hwi (i);
+      if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5
+         && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 5);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+              && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 8);
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff)
        return 5;
+      s = size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+      if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
+         && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 8);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16
+              && clz + 16 + (s > 5 ? 255 : 31) >= HOST_BITS_PER_WIDE_INT)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 16);
+      else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32
+              && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT
+              && s > 6)
+       return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
+                                                   - clz - 32);
       else
-       return 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+       return 1 + s;
     }
   else
     {
@@ -10200,11 +10298,27 @@ size_of_int_loc_descriptor (HOST_WIDE_IN
        return 2;
       else if (i >= -0x8000)
        return 3;
-      else if (HOST_BITS_PER_WIDE_INT == 32
-              || i >= -0x80000000)
-       return 5;
+      else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000)
+       {
+         if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i)
+           {
+             s = size_of_int_loc_descriptor (-i) + 1;
+             if (s < 5)
+               return s;
+           }
+         return 5;
+       }
       else
-       return 1 + size_of_sleb128 (i);
+       {
+         unsigned long r = 1 + size_of_sleb128 (i);
+         if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i)
+           {
+             s = size_of_int_loc_descriptor (-i) + 1;
+             if (s < r)
+               return s;
+           }
+         return r;
+       }
     }
 }
 
@@ -11818,8 +11932,27 @@ mem_loc_descriptor (rtx rtl, enum machin
              || GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT))
        {
          dw_die_ref type_die = base_type_for_mode (mode, 1);
+         enum machine_mode amode;
          if (type_die == NULL)
            return NULL;
+         amode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
+                                MODE_INT, 0);
+         if (INTVAL (rtl) >= 0
+             && amode != BLKmode
+             && trunc_int_for_mode (INTVAL (rtl), amode) == INTVAL (rtl)
+             /* const DW_OP_GNU_convert <XXX> vs.
+                DW_OP_GNU_const_type <XXX, 1, const>.  */
+             && size_of_int_loc_descriptor (INTVAL (rtl)) + 1 + 1
+                < (unsigned long) 1 + 1 + 1 + GET_MODE_SIZE (mode))
+           {
+             mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+             op0 = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+             op0->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             op0->dw_loc_oprnd1.v.val_die_ref.die = type_die;
+             op0->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             add_loc_descr (&mem_loc_result, op0);
+             return mem_loc_result;
+           }
          mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0,
                                          INTVAL (rtl));
          mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
@@ -20962,6 +21095,19 @@ resolve_addr_in_expr (dw_loc_descr_ref l
            && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
          return false;
        break;
+      case DW_OP_plus_uconst:
+       if (size_of_loc_descr (loc)
+           > size_of_int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned)
+             + 1
+           && loc->dw_loc_oprnd1.v.val_unsigned > 0)
+         {
+           dw_loc_descr_ref repl
+             = int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned);
+           add_loc_descr (&repl, new_loc_descr (DW_OP_plus, 0, 0));
+           add_loc_descr (&repl, loc->dw_loc_next);
+           *loc = *repl;
+         }
+       break;
       case DW_OP_implicit_value:
        if (loc->dw_loc_oprnd2.val_class == dw_val_class_addr
            && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL))
--- gcc/testsuite/gcc.dg/guality/csttest.c.jj   2011-07-11 13:55:12.000000000 
+0200
+++ gcc/testsuite/gcc.dg/guality/csttest.c      2011-07-11 14:20:00.000000000 
+0200
@@ -0,0 +1,63 @@
+/* PR debug/49676 */
+/* { dg-do run { target lp64 } } */
+/* { dg-options "-g" } */
+
+volatile int v;
+
+__attribute__((noinline, noclone))
+unsigned long long
+foo (unsigned long long x)
+{
+  unsigned long long a = x * (0x17ULL << 31);  /* { dg-final { gdb-test 29 "a" 
"(0x17ULL << 31)" } } */
+  unsigned long long b = x * (0x7ULL << 33);   /* { dg-final { gdb-test 29 "b" 
"(0x7ULL << 33)" } } */
+  unsigned long long c = x * (0x1ULL << 35);   /* { dg-final { gdb-test 29 "c" 
"(0x1ULL << 35)" } } */
+  unsigned long long d = x * (0x17ULL << 15);  /* { dg-final { gdb-test 29 "d" 
"(0x17ULL << 15)" } } */
+  unsigned long long e = x * (0x17ULL << 50);  /* { dg-final { gdb-test 29 "e" 
"(0x17ULL << 50)" } } */
+  unsigned long long f = x * (0x37ULL << 31);  /* { dg-final { gdb-test 29 "f" 
"(0x37ULL << 31)" } } */
+  unsigned long long g = x * (0x37ULL << 50);  /* { dg-final { gdb-test 29 "g" 
"(0x37ULL << 50)" } } */
+  unsigned long long h = x * (0x1efULL << 33); /* { dg-final { gdb-test 29 "h" 
"(0x1efULL << 33)" } } */
+  unsigned long long i = x * (0x1efULL << 50); /* { dg-final { gdb-test 29 "i" 
"(0x1efULL << 50)" } } */
+  unsigned long long j = x * -(0x17ULL << 31); /* { dg-final { gdb-test 29 "j" 
"-(0x17ULL << 31)" } } */
+  unsigned long long k = x * -(0x7ULL << 33);  /* { dg-final { gdb-test 29 "k" 
"-(0x7ULL << 33)" } } */
+  unsigned long long l = x * -(0x1ULL << 35);  /* { dg-final { gdb-test 29 "l" 
"-(0x1ULL << 35)" } } */
+  unsigned long long m = x * -(0x17ULL << 15); /* { dg-final { gdb-test 29 "m" 
"-(0x17ULL << 15)" } } */
+  unsigned long long n = x * -(0x17ULL << 50); /* { dg-final { gdb-test 29 "n" 
"-(0x17ULL << 50)" } } */
+  unsigned long long o = x * -(0x37ULL << 31); /* { dg-final { gdb-test 29 "o" 
"-(0x37ULL << 31)" } } */
+  unsigned long long p = x * -(0x37ULL << 50); /* { dg-final { gdb-test 29 "p" 
"-(0x37ULL << 50)" } } */
+  unsigned long long q = x * -(0x1efULL << 33);        /* { dg-final { 
gdb-test 29 "q" "-(0x1efULL << 33)" } } */
+  unsigned long long r = x * -(0x1efULL << 50);        /* { dg-final { 
gdb-test 29 "r" "-(0x1efULL << 50)" } } */
+  v++;
+  return x;
+}
+
+__attribute__((noinline, noclone))
+unsigned long long
+bar (unsigned long long x)
+{
+  unsigned long long a = (x & 255) + (0x17ULL << 31);  /* { dg-final { 
gdb-test 55 "a" "(0x17ULL << 31)" } } */
+  unsigned long long b = (x & 255) + (0x7ULL << 33);   /* { dg-final { 
gdb-test 55 "b" "(0x7ULL << 33)" } } */
+  unsigned long long c = (x & 255) + (0x1ULL << 35);   /* { dg-final { 
gdb-test 55 "c" "(0x1ULL << 35)" } } */
+  unsigned long long d = (x & 255) + (0x17ULL << 15);  /* { dg-final { 
gdb-test 55 "d" "(0x17ULL << 15)" } } */
+  unsigned long long e = (x & 255) + (0x17ULL << 50);  /* { dg-final { 
gdb-test 55 "e" "(0x17ULL << 50)" } } */
+  unsigned long long f = (x & 255) + (0x37ULL << 31);  /* { dg-final { 
gdb-test 55 "f" "(0x37ULL << 31)" } } */
+  unsigned long long g = (x & 255) + (0x37ULL << 50);  /* { dg-final { 
gdb-test 55 "g" "(0x37ULL << 50)" } } */
+  unsigned long long h = (x & 255) + (0x1efULL << 33); /* { dg-final { 
gdb-test 55 "h" "(0x1efULL << 33)" } } */
+  unsigned long long i = (x & 255) + (0x1efULL << 50); /* { dg-final { 
gdb-test 55 "i" "(0x1efULL << 50)" } } */
+  unsigned long long j = (x & 255) + -(0x17ULL << 31); /* { dg-final { 
gdb-test 55 "j" "-(0x17ULL << 31)" } } */
+  unsigned long long k = (x & 255) + -(0x7ULL << 33);  /* { dg-final { 
gdb-test 55 "k" "-(0x7ULL << 33)" } } */
+  unsigned long long l = (x & 255) + -(0x1ULL << 35);  /* { dg-final { 
gdb-test 55 "l" "-(0x1ULL << 35)" } } */
+  unsigned long long m = (x & 255) + -(0x17ULL << 15); /* { dg-final { 
gdb-test 55 "m" "-(0x17ULL << 15)" } } */
+  unsigned long long n = (x & 255) + -(0x17ULL << 50); /* { dg-final { 
gdb-test 55 "n" "-(0x17ULL << 50)" } } */
+  unsigned long long o = (x & 255) + -(0x37ULL << 31); /* { dg-final { 
gdb-test 55 "o" "-(0x37ULL << 31)" } } */
+  unsigned long long p = (x & 255) + -(0x37ULL << 50); /* { dg-final { 
gdb-test 55 "p" "-(0x37ULL << 50)" } } */
+  unsigned long long q = (x & 255) + -(0x1efULL << 33);        /* { dg-final { 
gdb-test 55 "q" "-(0x1efULL << 33)" } } */
+  unsigned long long r = (x & 255) + -(0x1efULL << 50);        /* { dg-final { 
gdb-test 55 "r" "-(0x1efULL << 50)" } } */
+  v++;
+  return x;
+}
+
+int
+main ()
+{
+  return foo (1) + bar (256) - 257;
+}

        Jakub

Reply via email to