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

Reply via email to