Skip to content

[ARM32][compiler-rt] movle Condition Fails After __aeabi_cdcmple Due to Inconsistent CPSR Flags Across libgcc/libunwind #134663

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dongjianqiang2 opened this issue Apr 7, 2025 · 6 comments
Labels
compiler-rt question A question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!

Comments

@dongjianqiang2
Copy link
Contributor

dongjianqiang2 commented Apr 7, 2025

Hi, I compiled the Luajit with clang, and found the __aeabi_cdcmple fails to set CPSR Flags correctly for movle insn.

https://github.com/LuaJIT/LuaJIT/blob/v2.1/src/vm_arm.dasc#L1705

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

extern void __aeabi_cdcmple(double a, double b);

void test_with_movle() {
    uint32_t cpsr;
    uint32_t r0_val, r1_val;

    __asm__ __volatile__(
        // Set initial register values
        "mov r0, #0x0\n\t"        // a_low = 0x0
        "ldr r1, =0xBFF00000\n\t" // a_high = 0xBFF00000 → a = -1.0
        "mov r2, #0x0\n\t"        // b_low = 0x0
        "ldr r3, =0x40000000\n\t" // b_high = 0x40000000 → b = 2.0

        // Call comparison function (modifies CPSR)
        "bl __aeabi_cdcmple\n\t"

        // Conditional move: if a <= b (LE condition true), r0 = r2, r1 = r3
        "movle r0, r2\n\t" // If LE, move b_low to r0
        "movle r1, r3\n\t" // If LE, move b_high to r1

        // Save registers to variables
        "mov %0, r0\n\t"   // Save r0 to r0_val
        "mov %1, r1\n\t"   // Save r1 to r1_val
        "mrs %2, cpsr\n\t" // Save CPSR
        : "=r" (r0_val), "=r" (r1_val), "=r" (cpsr)
        :
        : "r0", "r1", "r2", "r3", "lr", "cc", "memory"
    );

    // Extract CPSR flags
    int N = (cpsr >> 31) & 1;  // Bit 31: N (Negative)
    int Z = (cpsr >> 30) & 1;  // Bit 30: Z (Zero)
    int C = (cpsr >> 29) & 1;  // Bit 29: C (Carry)
    int V = (cpsr >> 28) & 1;  // Bit 28: V (Overflow)

    // Print results
    printf("After movle:\n");
    printf("r0 = 0x%08X, r1 = 0x%08X\n", r0_val, r1_val);
    printf("Flags: N=%d, Z=%d, C=%d, V=%d\n", N, Z, C, V);
}

int main() {
    test_with_movle();
    return 0;
}

gcc with libgcc:
After movle:
r0 = 0x00000000, r1 = 0x40000000
Flags: N=1, Z=0, C=0, V=0

clang with compiler-rt:
After movle:
r0 = 0x00000000, r1 = 0xBFF00000
Flags: N=0, Z=0, C=0, V=0

Is this a compatibility issue between Clang and GCC?

@dongjianqiang2
Copy link
Contributor Author

@nikic @jmgao @weimingzha0

@efriedma-quic
Copy link
Collaborator

The "Z" and "C" values are consistent between clang and gcc. The ABI rules say the the other values you're printing are arbitrary, including the other flags and r0-r3. (https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#the-floating-point-helper-functions). Not sure what you're expecting.

@dongjianqiang2
Copy link
Contributor Author

The "Z" and "C" values are consistent between clang and gcc. The ABI rules say the the other values you're printing are arbitrary, including the other flags and r0-r3. (https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#the-floating-point-helper-functions). Not sure what you're expecting.

Thank you for your reply. From the assembly code of LuaJIT, it uses the __aeabi_cdcmple call to determine whether the movle instruction’s condition is satisfied. The condition code for movle is ‌Z=1 || (N≠V)‌.

While both libgcc and libunwind implementations return the same Z flag value, they differ in the N (Negative) and V (Overflow) flags.

‌N≠V‌ implies either:
The comparison result is negative without overflow, or
The result is positive but with overflow (in signed comparison scenarios).
The CPSR state returned by libgcc appears to align more logically with the expected behavior for condition code evaluation. This suggests potential inconsistencies in how libunwind handles flag updates during __aeabi_cdcmple, which may lead to incorrect movle behavior.

Here is the dasc file link: https://github.com/LuaJIT/LuaJIT/blob/v2.1/src/vm_arm.dasc#L1705 and its disassembly‌ code:

        bl      __aeabi_cdcmple
        add     sl, sl, #8
        movle   r0, r2
        movle   r1, r3

@efriedma-quic
Copy link
Collaborator

The ABI is specified in a way that they expect you to use unsigned comparisons (e.g. movls). So the LuaJIT code is depending on behavior that isn't specified. Code using routines specified in the ABI should respect the rules in the ABI document.

Currently compiler-rt always sets the N and V bits to 0. It might be possible to change the compiler-rt code so that signed comparisons "work", I guess, since it's not specified in the first place. Not sure.

(Ignore the bit about r0-r3; there's a specific carveout for the 3-way compares I missed my first time scanning through the spec.)

@dongjianqiang2
Copy link
Contributor Author

The ABI is specified in a way that they expect you to use unsigned comparisons (e.g. movls). So the LuaJIT code is depending on behavior that isn't specified. Code using routines specified in the ABI should respect the rules in the ABI document.

Currently compiler-rt always sets the N and V bits to 0. It might be possible to change the compiler-rt code so that signed comparisons "work", I guess, since it's not specified in the first place. Not sure.

(Ignore the bit about r0-r3; there's a specific carveout for the 3-way compares I missed my first time scanning through the spec.)

Yes
so for min function,Luajit expect to use movhi,instead of movpl.

    bl      __aeabi_cdcmple
    add     sl, sl, #8   // ignore
    movhi   r0, r2
    movhi   r1, r3

because movpl is depanding on N == V, behavior also isn't specified. movhi condition code is C=1 && Z=0, it meets expectations ; )

@dongjianqiang2
Copy link
Contributor Author

Luajit fixed at LuaJIT/LuaJIT@51d4c26
Thanks!

@EugeneZelenko EugeneZelenko added the question A question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead! label Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler-rt question A question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!
Projects
None yet
Development

No branches or pull requests

4 participants