Comment 0 for bug 2043060

Revision history for this message
Dan Lewis (danielwlewis) wrote :

ARM GCC 13.2.0 compiles 64-bit integer compares such as the following:

    int32_t Compare64(int64_t x64, int64_t y64)
        {
        return (x64 <= y64) ;
        }

into a sequence of ARM Thumb instructions similar to:

    Compare64:
        CMP R0,R2
        SBCS R1,R1,R3
        ITE LE
        MOVLE R0,#1
        MOVGT R0,#0
        BX LR

However, this produces an incorrect result for x64 = 6 and y64 = 5. The problem is that although the CMP, SBCS sequence leaves the correct values in the N, V, and C flags, the Z flag only depends on bits 63..32 of the result and ignores bits 31..00. Any 64-bit compare must correct the value of the Z flag before making a decision; the following is a functionally correct solution using straight-line code:

    Compare64:
        SUBS R12,R0,R2 // R12 used as a scratch register
        MRS R0,APSR // preserves Z flag from bits 32..00
        SBCS R12,R1,R3 // R12 used as a scratch register

     // N, V and C are correct at this point, but Z is not.
     // The following code corrects the Z flag:

        MRS R1,APSR // get flags from bits 63..32
        ORN R0,R0,1 << 30 // isolate Z flag from bits 31..00
        AND R0,R0,R1 // combine with Z from bits 63..32
        MSR APSR_nzcvq,R0 // Z is now 1 iff bits 63..00 are all zeroes

     // Now all flags are correct and any condition code can be used

        ITE LE
        MOVLE R0,#1
        MOVGT R0,#0
        BX LR