I am still waiting for a review on this (I'll make the libgcc change
before committing if the rest is deemed ok).
Just FYI I have figured out what is making the last two test cases fail,
was waiting to commit this and open a bugzilla as recommend by Jakub,
but I'll write it up here before I forget...
The root cause:
When a _BitInt(N) where N > 64 and thus we use limb_mode = SImode and
abi_limb_mode = DImode so for instance _BitInt(65) and that variable is
created (or modified such that the sign-bit is changed) and then it's
address is taken, the compiler fails to realize that it needs to
'define' the top-32 padding (extended) bits.
A small reproducer using the BitInt's BEXTC testing primitive:
#include "bitintext.h"
int main ()
{
_BitInt(65) g = -147090211948845388976606115811401318743wb;
BEXTC (g);
return 0;
}
The BEXTC will copy _BitInt(65) into the next largest "full" BitInt, so
_BitInt(128) and use that to check the 'top' bits are properly extended,
which they won't be because 'padding' bits 96...127 are left undefined.
See the code before the docopy for a compilation with -mcpu=cortex-m3 -O2
movs r2, #16 <--- size argument 16-bytes
aka 128 bits
mov r3, #-1 <--- if we treat g as an
array of 32-bit limbs then this is prepping the value that goes into g[2]
push {fp, lr}
adr ip, .L15
ldrd fp, [ip] <---- loads the
constants for g[0] and g[1]
sub sp, sp, #32
add r0, sp, r2
mov r1, sp
str r3, [sp, #8] <--- stores the -1 for
g[2] onto the stack
strd fp, [sp] <--- stores the
constants for g[0], g[1] onto the stack which the address for g[0] is
passed in r1
bl do_copy
you see here we never populate the last 32-bits of the stack that is
meant to represent g[3]
I checked and this is not an issue when a _BitInt(65) is passed to a
function, as the compiler knows it needs to represent the padded bits,
but because of the BEXTC check the compiler fails to recognize the need
to extend the padding bits because the address of the smaller _BitInt is
taken.
To confirm that this does work when passing BitInt use the following
test program:
extern void callee (_BitInt(66));
void caller (void)
{
_BitInt(66) a = -5;
callee (a);
}
Again a compilation for cortex-m3 with -O2 shows the extended bits are
correctly defined:
caller:
ldr r3, .L3
ldm r3, {r0, r1, r2, r3}
b callee
.L3:
.word -5
.word -1
.word -1
.word -1
I'm not sure if we can consider taking the address of a BitInt and
passing that as an 'ABI' boundary, I suspect the answer is yes... the
receiver of the pointer has to be able to expect that those bits are
set, but I have no idea how to fix this. I'm strongly contemplating
redefining the Arm ABI to use 32-bit limbs ... not sure I see the value
in 64-bit limbs but maybe there is... I don't think LLVM has implemented
bitints larger than 64 anyway...
Hope this helps.
On 21/10/2025 10:28, Jakub Jelinek wrote:
On Tue, Oct 21, 2025 at 10:12:20AM +0100, Andre Vieira wrote:
--- a/libgcc/config/arm/libgcc-bpabi.ver
+++ b/libgcc/config/arm/libgcc-bpabi.ver
@@ -106,3 +106,14 @@ GCC_3.5 {
GCC_4.3.0 {
_Unwind_Backtrace
}
+
+%inherit GCC_14.0.0 GCC_4.3.0
+GGC_14.0.0 {
No, this needs to be GCC_16.0.0. Because while they were added
on x86 and aarch64 (little endian) in GCC 14, they are only being
added in GCC 16 for arm 32/s390x/loongarch and maybe aarch64 big endian.
So, it can't be exported in a symbol version associated with an already
released compiler.
+ __fixsfbitint
+ __fixdfbitint
+ __floatbitinthf
+ __floatbitintsf
+ __floatbitintdf
+ __mulbitint3
+ __divmodbitint4
+}
s390x also does
%ifdef __s390x__
%inherit GCC_16.0.0 GCC_4.1.0
GCC_16.0.0 {
__mulbitint3
__divmodbitint4
__fixsfbitint
__fixdfbitint
__fixtfbitint
__floatbitintsf
__floatbitintdf
__floatbitinttf
}
%endif
and loongarch
GCC_16.0.0 {
__mulbitint3
__divmodbitint4
__fixsfbitint
__fixdfbitint
__fixtfbitint
__floatbitintsf
__floatbitintdf
__floatbitinttf
}
Jakub