This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ARM7TDMI: SUBS vs SUB + CMP

Note: This was originally posted on 2nd April 2009 at http://forums.arm.com

Hi,

I have a question regarding the SUBS instruction and how it compares to SUB and CMP (due to unexpected behavior in a C-program).

The original C-code goes like this (all variables are 32 bit signed integers):

    t = a*b - c*c;
    if (t > 0) d = t;

In a particular case (a = 0x80, b = 0x106DCD9, c = 0x4E352501) I get an overflow in a*b as well as in the subtraction. What is puzzling to me is that there's a difference between the the following two assembler versions in a certain simulated environment - and I'm trying to figure out if this is expected or a bug in the simulator:

MUL temp1, c, c
MUL temp2, a, b
SUBS t, temp2, temp1
MOVGT d, t

and

MUL temp1, c, c
MUL temp2, a, b
SUB t, temp2, temp1
CMP t, #0
MOVGT d, t

(These are genereated depending on different compiler settings.)

Any help is greatly appreciated!

Greger
Parents
  • Note: This was originally posted on 2nd April 2009 at http://forums.arm.com

    That looks like a bug in your simulator - although not because the behavior is different.

    The reason...

    GT is defined as executing if "Z == 0 and N == V" in the CPSR flag bits.

    In your example:
    temp1 = F3C3 4A01 (overflowed)
    temp2 = 836E6C80
    t = temp2 - temp1 (underflowed)

    In the SUBS case the SUBS instruction will perform (836E6C80 - F3C3 4A01 = 8FAB227F) which will set Nzcv in the CPSR (Negative, non-zero, no carry, no overflow)  - this means the final MOVGT won't execute. No carry for a subtract indicates underflow.

    In the CMP case the CMP instruction will perform (8FAB227F - 0) which will set NzCv in the CPSR (Negative, non-zero, Carry, no overflow) - which should also mean that the final MOVGT won't execute. Carry for a subtract indicates no underflow occured.

    It is worth noting that the CPSR flags are different for these two cases, so some condition codes for the final MOV may validly generate different behavior for the two cases. Compilers are not designed to cope with under/overflow - so this is allowed by the C spec =)
Reply
  • Note: This was originally posted on 2nd April 2009 at http://forums.arm.com

    That looks like a bug in your simulator - although not because the behavior is different.

    The reason...

    GT is defined as executing if "Z == 0 and N == V" in the CPSR flag bits.

    In your example:
    temp1 = F3C3 4A01 (overflowed)
    temp2 = 836E6C80
    t = temp2 - temp1 (underflowed)

    In the SUBS case the SUBS instruction will perform (836E6C80 - F3C3 4A01 = 8FAB227F) which will set Nzcv in the CPSR (Negative, non-zero, no carry, no overflow)  - this means the final MOVGT won't execute. No carry for a subtract indicates underflow.

    In the CMP case the CMP instruction will perform (8FAB227F - 0) which will set NzCv in the CPSR (Negative, non-zero, Carry, no overflow) - which should also mean that the final MOVGT won't execute. Carry for a subtract indicates no underflow occured.

    It is worth noting that the CPSR flags are different for these two cases, so some condition codes for the final MOV may validly generate different behavior for the two cases. Compilers are not designed to cope with under/overflow - so this is allowed by the C spec =)
Children
No data