This is an archive of the discontinued LLVM Phabricator instance.

[compiler-rt] [Arm] Make the tests for the runtime functions __aeabi_c{d,f} work on Big-Endian.
ClosedPublic

Authored by simpal01 on Jul 13 2023, 8:21 AM.

Details

Summary

We are trying to build the compiler-rt as big-endian. And found that the tests compiler-rt/test/builtins/Unit/arm/aeabi_cdcmpeq_test.c and compiler-rt/test/builtins/Unit/arm/aeabi_cfcmpeq_test.c do not work on big endian at the moment. This patch makes these tests work on big endian as well.

Diff Detail

Event Timeline

simpal01 created this revision.Jul 13 2023, 8:21 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2023, 8:21 AM
Herald added subscribers: Enna1, dberris. · View Herald Transcript
simpal01 requested review of this revision.Jul 13 2023, 8:21 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2023, 8:21 AM
Herald added a subscriber: Restricted Project. · View Herald Transcript
simpal01 retitled this revision from [compiler-rt] Make the functions __aeabi_c{d,f} work on Big-Endian. to [compiler-rt] [Arm] Make the functions __aeabi_c{d,f} work on Big-Endian..Jul 13 2023, 8:52 AM
simpal01 edited the summary of this revision. (Show Details)
simpal01 edited the summary of this revision. (Show Details)Jul 13 2023, 8:53 AM
simpal01 retitled this revision from [compiler-rt] [Arm] Make the functions __aeabi_c{d,f} work on Big-Endian. to [compiler-rt] [Arm] Make the tests for the runtime functions __aeabi_c{d,f} work on Big-Endian..Jul 13 2023, 8:59 AM

The code change looks sensible to me. Rationale: aeabi_cdcmp.S doesn't actually operate on the double precision numbers passed in r0/r1 and r2/r3. It only passes them to subroutines written in C, such as __aeabi_cdcmpeq_check_nan or __aeabi_dcmplt. So the assembly can be the same for both endiannesses: it doesn't have to worry about the fact that the MSWs of the doubles are in r0 and r2 when building big-endian, instead of in r1 and r3 when little-endian. The compiler takes care of that when it compiles the subroutines.

(And aeabi_cfcmp.S has the same structure, but it wouldn't matter even if it didn't, because for single precision, the register allocation would be the same in both endiannesses anyway.)

But I'm not sure there needs to be a 70-line C program given in full in the commit message :-)

simpal01 edited the summary of this revision. (Show Details)Jul 14 2023, 3:12 AM

i have tested this locally using opensource clang with GCC Linaro toolchain and by running it on qemu arm big endian system.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

union cpsr {
    struct {
        uint32_t n: 1;
        uint32_t z: 1;
        uint32_t c: 1;
        uint32_t v: 1;
        uint32_t filler: 28;
    } flags;
    uint32_t value;
};

__attribute__((noinline, pcs("aapcs"))) static uint32_t call_apsr_d(double a, double b,
                                                                    __attribute__((pcs("aapcs"))) void (*fn)(double, double)) {
  uint32_t result;
  fn(a, b);
  asm volatile("mrs %0, apsr"
               : "=r"(result));
  return result;
}


extern __attribute__((pcs("aapcs"))) void __aeabi_cdcmpeq(double a, double b);

int test__aeabi_cdcmpeq(double a, double b, int expected)
{
    uint32_t cpsr_value = call_apsr_d(a, b, __aeabi_cdcmpeq);
    union cpsr cpsr = { .value = cpsr_value };
    if (expected != cpsr.flags.z) {
        printf("error in __aeabi_cdcmpeq(%f, %f) => Z = %d, expected %d\n",
               a, b, cpsr.flags.z, expected);
        return 1;
    }
    else
       printf("__aeabi_cdcmpeq(%f, %f) => PASS\n",a,b);
    return 0;
}

int main()
{
    if (test__aeabi_cdcmpeq(1.0, 1.0, 1)) 
        return 1; 
    if (test__aeabi_cdcmpeq(1234.567, 765.4321, 0))
        return 1;
    if (test__aeabi_cdcmpeq(-123.0, -678.0, 0))
        return 1;
    if (test__aeabi_cdcmpeq(0.0, -0.0, 1)) 
        return 1;
    if (test__aeabi_cdcmpeq(1.0, NAN, 0))
        return 1;
    if (test__aeabi_cdcmpeq(NAN, 1.0, 0))
        return 1;
    if (test__aeabi_cdcmpeq(NAN, NAN, 0))
        return 1;
    if (test__aeabi_cdcmpeq(INFINITY, 1.0, 0))
        return 1;
    if (test__aeabi_cdcmpeq(0.0, INFINITY, 0))
        return 1;
    if (test__aeabi_cdcmpeq(-INFINITY, 0.0, 0))
        return 1;
    if (test__aeabi_cdcmpeq(0.0, -INFINITY, 0))
        return 1;
    if (test__aeabi_cdcmpeq(INFINITY, INFINITY, 1)) 
        return 1;
    if (test__aeabi_cdcmpeq(-INFINITY, -INFINITY, 1)) 
        return 1; 
    return 0;
}

clang --target=armeb-linux-gnueabihf -mbig-endian --static -mcpu=cortex-a8 test.c -o test.axf -fuse-ld=/work/gcc-linaro-4.8-2015.06-x86_64_armeb-linux-gnueabihf/bin/armeb-linux-gnueabihf-ld.bfd --gcc-toolchain=/work/gcc-linaro-4.8-2015.06-x86_64_armeb-linux-gnueabihf --sysroot=/work/gcc-linaro-4.8-2015.06-x86_64_armeb-linux-gnueabihf/armeb-linux-gnueabihf/libc

$ qemu-armeb-static -L /work/gcc-linaro-4.8-2015.06-x86_64_armeb-linux-gnueabihf/armeb-linux-gnueabihf/libc test.axf
__aeabi_cdcmpeq(0.000000, 1.000000) => PASS
__aeabi_cdcmpeq(-0.000000, 765.432100) => PASS
__aeabi_cdcmpeq(0.000000, -678.000000) => PASS
__aeabi_cdcmpeq(0.000000, -0.000000) => PASS
__aeabi_cdcmpeq(0.000000, nan) => PASS
__aeabi_cdcmpeq(0.000000, 1.000000) => PASS
__aeabi_cdcmpeq(0.000000, nan) => PASS
__aeabi_cdcmpeq(0.000000, 1.000000) => PASS
__aeabi_cdcmpeq(0.000000, inf) => PASS
__aeabi_cdcmpeq(0.000000, 0.000000) => PASS
__aeabi_cdcmpeq(0.000000, -inf) => PASS
__aeabi_cdcmpeq(0.000000, inf) => PASS
__aeabi_cdcmpeq(0.000000, -inf) => PASS

But I'm not sure there needs to be a 70-line C program given in full in the commit message :-)

Yeah true :) i have taken that off from the commit message and added as a separate comment.

simon_tatham accepted this revision.Jul 14 2023, 5:23 AM

Thanks :-) LGTM, but as usual, please give other people a chance to comment before pushing it.

This revision is now accepted and ready to land.Jul 14 2023, 5:23 AM
peter.smith accepted this revision.Jul 14 2023, 6:32 AM

LGTM too.