Hi,
for the attached Ada package declaring a simple variable-sized record type,
the compiler builds a "size function" in GENERIC which is at -Og:
sizetype _GLOBAL.SZ5_p (p__enum p0)
{
return (UNSIGNED_8) p0 + 252 <= 3 ? 32 : 0;
}
The UNSIGNED_8-based trick eliminates one branch but relies on the wrap-around
arithmetics of UNSIGNED_8. This size function is then translated into a DWARF
procedure, but the wrap-around arithmetics is dropped, leading to a wrong size
calculation when the DWARF procedure is executed.
The fix also contains an optimization of unsigned comparisons in DWARF for the
case where the type is smaller than the "generic type", as is the case here.
Tested on x86-64/Linux, OK for the mainline?
2024-06-03 Eric Botcazou <ebotca...@adacore.com>
* dwarf2out.cc (loc_list_from_tree_1) <CEIL_DIV_EXPR>; Add const.
<do_comp_binop>: Use a signed comparison for small unsigned types.
Implement wrap-around arithmetics for small integer types.
--
Eric Botcazou
package P is
type Enum is (Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine);
type Rec (Kind : Enum := Zero) is record
case Kind is
when Four .. Seven =>
S : String (1 .. 32);
when others =>
null;
end case;
end record;
end P;
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 5b064ffd78a..89efa5474d3 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -19383,7 +19383,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
case ROUND_DIV_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (loc)))
{
- enum machine_mode mode = TYPE_MODE (TREE_TYPE (loc));
+ const enum machine_mode mode = TYPE_MODE (TREE_TYPE (loc));
scalar_int_mode int_mode;
if ((dwarf_strict && dwarf_version < 5)
@@ -19518,6 +19518,15 @@ loc_list_from_tree_1 (tree loc, int want_address,
do_comp_binop:
if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
{
+ const enum machine_mode mode
+ = TYPE_MODE (TREE_TYPE (TREE_OPERAND (loc, 0)));
+ scalar_int_mode int_mode;
+
+ /* We can use a signed comparison if the sign bit is not set. */
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_SIZE (int_mode) < DWARF2_ADDR_SIZE)
+ goto do_binop;
+
list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
list_ret = loc_list_from_uint_comparison (list_ret, list_ret1,
@@ -19544,6 +19553,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
add_loc_list (&list_ret, list_ret1);
if (list_ret == 0)
return 0;
+
add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
break;
@@ -19668,6 +19678,28 @@ loc_list_from_tree_1 (tree loc, int want_address,
if (!ret && !list_ret)
return 0;
+ /* Implement wrap-around arithmetics for small integer types. */
+ if ((TREE_CODE (loc) == PLUS_EXPR
+ || TREE_CODE (loc) == MINUS_EXPR
+ || TREE_CODE (loc) == MULT_EXPR
+ || TREE_CODE (loc) == NEGATE_EXPR
+ || TREE_CODE (loc) == LSHIFT_EXPR)
+ && INTEGRAL_TYPE_P (TREE_TYPE (loc))
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (loc)))
+ {
+ const enum machine_mode mode = TYPE_MODE (TREE_TYPE (loc));
+ scalar_int_mode int_mode;
+
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_SIZE (int_mode) < DWARF2_ADDR_SIZE)
+ {
+ const unsigned HOST_WIDE_INT mask
+ = (HOST_WIDE_INT_1U << GET_MODE_BITSIZE (int_mode)) - 1;
+ add_loc_descr_to_each (list_ret, uint_loc_descriptor (mask));
+ add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_and, 0, 0));
+ }
+ }
+
if (want_address == 2 && !have_address
&& (dwarf_version >= 4 || !dwarf_strict))
{