This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

64 bits operations in Cortex R4

Hi,

I am comparing 64 bits variable with (-1) using following code


int CompareTest3(unsigned long long a)
{
    int res;
 
    res = ((unsigned int)a == ((unsigned int)-1))
       && ((a >> 32) == ((unsigned int)-1));
 
    return res;
}
What I expect to see is two 32 bits comparisons with 0xFFFFFFFF. The assembly looks like this

01b6fc: MOV             R2, R0
01b6fe: MOV             R3, R1
01b700: CMP.W           R2, #4294967295
01b704: MOV.W           R0, #0
01b708: BNE             0x0001B71A
01b70a: MOVS            R2, #0x0      <-- ?
01b70c: CMP             R2, #0x0
01b70e: MOV             R1, R3
01b710: BNE             0x0001B716
01b712: CMP.W           R1, #4294967295
01b716: BNE             0x0001B71A
01b718: MOVS            R0, #0x1
01b71a: BX              R14

What are lines 6-9 intended for ?

My toolchain is TMS470 4 7 1.202. Compilation command

TMS470_4_7_1_202\bin\cl470.exe --elf --abi=eabi -mv7R4 --code_state=16  --diag_warning=225  --small_enum --gcc --endian=little -g -O2   --preproc_with_compile -g  main.c

Thanks.

  • While not answering your question, wouldn't

      return a == (unsigned long long)-1;

    be simpler?

  • You probably meant to write this ...

        res = ((unsigned int)a == ((unsigned int)-1))
           && ((unsigned int) (a >> 32) == ((unsigned int)-1));
           //  ^^^^^^^^^^^^^^  new code here
    
    

    Without that additional cast, the type of the expression (a >> 32) remains unsigned long long.  Thus, the expression ((unsigned int) -1) is first converted to unsigned long long by zero extending it to 64-bits.  Then those two unsigned long long expressions are compared.  The first part of that is comparing the upper word of (a >> 32) against zero.  

    To echo what pf said, why not write this directly.  I think you mean to see if the value contains all 1's.  I would write that ...

       return a == ~0LL;
    

    Thanks and regards,

    -George

  • Thank you, George

    You are right. Following implementation

    int CompareTest3(unsigned long long a)
    {
        int res;

        res = ((unsigned int)a == ((unsigned int)-1))
           && ((unsigned int)(a >> 32) == ((unsigned int)-1));
        return res;
    }
     
    gives this
     
    01b6f4: MOV             R2, R0
    01b6f6: MOV             R3, R1
    01b6f8: CMP.W           R2, #4294967295
    01b6fc: MOV.W           R0, #0
    01b700: BNE             0x0001B70C
    01b702: ADDS            R1, R3, #0x0
    01b704: CMP.W           R1, #4294967295
    01b708: BNE             0x0001B70C
    01b70a: MOVS            R0, #0x1
    01b70c: BX              R14
    01b70e: MOV             R8, R8
     
     
    I do not quite understand why the optimizer can not figure out that after shift right by 32 bits there is not going to be anything but zeros in the high significan 32 bits and comparison with another 32 bits work is trivial.  

     

    Also it is not clear how lines
     
    01b70a: MOVS            R2, #0x0
    01b70c: CMP             R2, #0x0
    01b70e: MOV             R1, R3
    01b710: BNE             0x0001B716
     
    do the trick of testing high significant 32 bits word of the function argument for zero.
     
    I have tried following code (let's call it naive implementation) 

    int CompareTest(unsigned long long a)
    {
        int res;
        res = (a == ((unsigned long long)-1));
        return res;
    }

    The assembly is worse
     
    01b6fc: PUSH            {R3, R4, R5, LR}
    01b6fe: MOV             R3, R1
    01b700: MOV             R2, R0
    01b702: ADD             R1, PC, #0xB0 $C$LL1 [0x1b7b4] <-- FFFFFFFFFF
    01b704: MOVS            R0, #0x0
    01b706: LDMIA.W         R1, {R4, R5}
    01b70a: CMP             R3, R5
    01b70c: BNE             0x0001B710
    01b70e: CMP             R2, R4
    01b710: BNE             0x0001B714
    01b712: MOVS            R0, #0x1
    01b714: POP             {R3, R4, R5, PC}
     
    By comparing 32 bits variables I save access to the stack.
  • Arkady Miasnikov said:

    Also it is not clear how lines

    01b70a: MOVS            R2, #0x0
    01b70c: CMP             R2, #0x0
    01b70e: MOV             R1, R3
    01b710: BNE             0x0001B716

    do the trick of testing high significant 32 bits word of the function argument for zero.

     

    I will use the notation HI,LO to represent a 64-bit value composed of the 32 low-order bits LO and the 32 high-order bits HI.

    The original value of the argument "a" arrives in R1,R0.  It is immediately moved to R3,R2.

    Suppose the result of "a>>32" is to end up in a temporary Thi,Tlo.  But we know Tlo is just what used to be in the high-order part of a, so Tlo is simply R3.  We know that Thi wil be zero so we load that into R2.  The 64-bit result of the shift is R2,R3.

    We now want to do a 64-bit comparison of "a>>32" and "0,-1".  That is, we want to compare R2,R3 to 0,-1 which is done by first comparing R2 to 0 followed by a comparison of R3 to -1.  OK, the embarassing part is not realizing we could/should know that R2 is already equal to 0.