[Bug ada/98228] [11 Regression] ICE: Assert_Failure atree.adb:931: Error detected at s-gearop.adb:382:34 [a-ngrear.adb:313:7 [a-nllrar.ads:18:1]] on s390x-linux-gnu
mhillen at linux dot ibm.com
gcc-bugzilla@gcc.gnu.org
Fri Jan 22 21:20:21 GMT 2021
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98228
--- Comment #15 from Marius Hillenbrand <mhillen at linux dot ibm.com> ---
tl;dr: I found the root cause and a way to repro on x86. When the
gnat/gcc interface converts gnat entities into tree decls,
maybe_pad_type() pads some record types. maybe_pad_type() calls
make_packable_type() to potentially pad a record into an integral type.
On s390x, we hit that case for sem_type__interp, which is padded from 12
bytes in BLKmode to a TImode. That results in the wrapped record to be
flagged as nonaddressable, which causes mayhem in tbaa (one way this
blows up below).
On x86-64 in contrast, maybe_pad_type() rejects the padding to TI in
that specific case, because TI requires 128-bit or larger alignment on
x86-64, while a 64-bit alignment is enough to get TI chosen on s390x).
When removing that condition, the issue reproduces on x86-64. When I
force that rejection on s390x, bootstrapping is successful (tested
with bootstrap-lto-lean, which extensively reproduces; not yet with a
full profiledbootstrap).
tree packable_type = make_packable_type (type, true, align);
if (TYPE_MODE (packable_type) != BLKmode)
&& align >= TYPE_ALIGN (packable_type)) // <- false on x86
type = packable_type;
(I also have tweaked the calling convention for
sem_type__get_next_interp to mimic that on s390x, with a pointer for
the output parameter It)
procedure Get_Next_Interp (I : in out Interp_Index; It : out Interp);
pragma Export (C, Get_Next_Interp);
pragma Export_Procedure (Get_Next_Interp,
External => "sem_type__get_next_interp",
Mechanism => (I => Value, It => Reference));
pragma No_Inline (Get_Next_Interp); -- causes repro in more places
# High-level flow of the resulting crashes:
- the procedure sem_type__get_next_interp has an output parameter of
record type sem_type__interp and overwrites that completely.
- in locations that call sem_type__get_next_interp, local variables of
type sem_type__interp get wrapped by maybe_pad_type in an outer
padding record for proper alignment. the padding record has a single
field "F" for the inner record.
- on s390x, that field gets falsely flagged as nonaddressable (see
zoom-in below).
- as a consequence of that flag, type based alias analysis does not
relate the padded record to the alias set of the inner record.
- modref_may_conflict disambiguates references to the local variables
(padded record) from sem_type__get_next_interp actually overwriting
the (inner) record -- "correct" decision based on the data, but
clearly the wrong result.
- as a result, loops that iterate via sem_type__get_next_interp are
"optimized" into endless loops, because their abort condition is
never checked against the updated data.
- these loops overrun All_Interp.Table and trigger assertions or
segfault (i've seen both).
# How does the field get marked nonaddressable?
maybe_pad_type calls make_packable_type, which attempts to find an
integral type that fits the record to be padded; in our case it
chooses TI.
<record_type # sem_type__interp packed TI
on x86-64, maybe_pad_type rejects that choice: the newly crafted type
requests 128-bit alignment which is above the requested/granted(?)
alignment of 64 bits. in contrast, on s390x TImode is ok with 64-bit
alignment and we proceed with the new type, TImode and 128 bits / 16 B
size.
however, maybe_pad_type creates the outer record first, before
deciding on inflating to TImode. so, the outer record gets size 96 /
12 B.
when creating the field "F", create_field_decl decides to mark it as a
bit-field, because the field's size (12) is different from the size of
its type (TI: 16).
then, maybe_pad_type calls finish_record_type to attach the field F to
the padding record. that finds that it cannot resolve the bit-field
property of the field and consequently has to mark it as
nonaddressable.
# Potential fix? Not enough:
simply passing adressable=-1 to create_field_decl (as in make_alignment_type)
is not enough. on a first glance, the padded records are not marked
nonaddressable any more, but there are still missing relations between alias
sets and resulting incorrect optimizations.
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 494f60e0879..aad343d3028 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -1577,12 +1577,17 @@ maybe_pad_type (tree type, tree size, unsigned int
align,
/* Now create the field with the original size. */
field = create_field_decl (get_identifier ("F"), type, record, orig_size,
- bitsize_zero_node, 0, 1);
+ bitsize_zero_node, 0, -1);
DECL_INTERNAL_P (field) = 1;
/* We will output additional debug info manually below. */
finish_record_type (record, field, 1, false);
+ /* Check that we did not accidentally create a bit-field or the field turned
+ nonaddressable. (PR98228) */
+ gcc_assert (!DECL_BIT_FIELD(TYPE_FIELDS(record)));
+ gcc_assert (!DECL_NONADDRESSABLE_P(TYPE_FIELDS(record)));
+
/* Set the RM size if requested. */
if (set_rm_size)
{
More information about the Gcc-bugs
mailing list