> Yes, but even bitsizetype is undistinguishable from other (usually 2 *
> pointer size) precision integral types.

OK, I can propose the attached patch.  The typed_binop_from_tree computation 
works on my Ada testcase in 32-bit mode from within GDB, but not in 64-bit 
mode because GDB chokes with:

That operation is not available on integers of more than 8 bytes.

This is worked around by the div->shift transformation, but then the previous 
change is not exercised any more...  Btw, is the rationale for using unsigned 
types for wide integer modes documented anywhere?  That's not very obvious.


        * dwarf2out.c (mem_loc_descriptor) <UDIV>: Fix typo.
        (typed_binop_from_tree): New function.
        (loc_list_from_tree_1) <EXACT_DIV_EXPR>: For an unsigned type,
        turn a divide by a power of 2 into a shift.
        <CEIL_DIV_EXPR>: For an unsigned type, use a signed divide if the
        size of the mode is lower than DWARF2_ADDR_SIZE; otherwise, do a
        typed divide by calling typed_binop_from_tree.

-- 
Eric Botcazou
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 73543190c2d..21ae7fb5ef3 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -16317,11 +16317,13 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
       if ((!dwarf_strict || dwarf_version >= 5)
 	  && is_a <scalar_int_mode> (mode, &int_mode))
 	{
-	  if (GET_MODE_SIZE (int_mode) > DWARF2_ADDR_SIZE)
+	  /* We can use a signed divide if the sign bit is not set.  */
+	  if (GET_MODE_SIZE (int_mode) < DWARF2_ADDR_SIZE)
 	    {
 	      op = DW_OP_div;
 	      goto do_binop;
 	    }
+
 	  mem_loc_result = typed_binop (DW_OP_div, rtl,
 					base_type_for_mode (int_mode, 1),
 					int_mode, mem_mode);
@@ -18413,6 +18415,48 @@ function_to_dwarf_procedure (tree fndecl)
   return dwarf_proc_die;
 }
 
+/* Helper function for loc_list_from_tree.  Perform OP binary op,
+   but after converting arguments to type_die, afterwards convert
+   back to unsigned.  */
+
+static dw_loc_list_ref
+typed_binop_from_tree (enum dwarf_location_atom op, tree loc,
+		       dw_die_ref type_die, scalar_int_mode mode,
+		       struct loc_descr_context *context)
+{
+  dw_loc_list_ref op0, op1;
+  dw_loc_descr_ref cvt, binop;
+
+  if (type_die == NULL)
+    return NULL;
+
+  op0 = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
+  op1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
+  if (op0 == NULL || op1 == NULL)
+    return NULL;
+
+  cvt = new_loc_descr (dwarf_OP (DW_OP_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_to_each (op0, cvt);
+
+  cvt = new_loc_descr (dwarf_OP (DW_OP_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_to_each (op1, cvt);
+
+  add_loc_list (&op0, op1);
+  if (op0 == NULL)
+    return NULL;
+
+  binop = new_loc_descr (op, 0, 0);
+  convert_descriptor_to_mode (mode, binop);
+  add_loc_descr_to_each (op0, binop);
+
+  return op0;
+}
 
 /* Generate Dwarf location list representing LOC.
    If WANT_ADDRESS is false, expression computing LOC will be computed
@@ -18994,13 +19038,53 @@ loc_list_from_tree_1 (tree loc, int want_address,
       op = DW_OP_or;
       goto do_binop;
 
+    case EXACT_DIV_EXPR:
     case FLOOR_DIV_EXPR:
+    case TRUNC_DIV_EXPR:
+      /* Turn a divide by a power of 2 into a shift when possible.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (loc))
+	  && tree_fits_uhwi_p (TREE_OPERAND (loc, 1)))
+	{
+	  const int log2 = exact_log2 (tree_to_uhwi (TREE_OPERAND (loc, 1)));
+	  if (log2 > 0)
+	    {
+	      list_ret
+		= loc_list_from_tree_1 (TREE_OPERAND (loc, 0), 0, context);
+	      if (list_ret == 0)
+		return 0;
+
+	      add_loc_descr_to_each (list_ret, uint_loc_descriptor (log2));
+	      add_loc_descr_to_each (list_ret,
+				     new_loc_descr (DW_OP_shr, 0, 0));
+	      break;
+	    }
+	}
+
+      /* fall through */
+
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
-    case TRUNC_DIV_EXPR:
-    case EXACT_DIV_EXPR:
       if (TYPE_UNSIGNED (TREE_TYPE (loc)))
-	return 0;
+	{
+	  enum machine_mode mode = TYPE_MODE (TREE_TYPE (loc));
+	  scalar_int_mode int_mode;
+
+	  if ((dwarf_strict && dwarf_version < 5)
+	      || !is_a <scalar_int_mode> (mode, &int_mode))
+	    return 0;
+
+	  /* We can use a signed divide if the sign bit is not set.  */
+	  if (GET_MODE_SIZE (int_mode) < DWARF2_ADDR_SIZE)
+	    {
+	      op = DW_OP_div;
+	      goto do_binop;
+	    }
+
+	  list_ret = typed_binop_from_tree (DW_OP_div, loc,
+					    base_type_for_mode (int_mode, 1),
+					    int_mode, context);
+	  break;
+	}
       op = DW_OP_div;
       goto do_binop;
 

Reply via email to