Search code examples
armcortex-m

What would be a reason to use ADDS instruction instead of the ADD instruction in ARM assembly?


My course notes always use ADDS and SUBS in their ARM code snippets, instead of the ADD and SUB as I would expect. Here's one such snippet for example:

__asm void my_capitalize(char *str)
{
cap_loop
  LDRB r1, [r0]   // Load byte into r1 from memory pointed to by r0 (str pointer)
  CMP r1, #'a'-1  // compare it with the character before 'a'
  BLS cap_skip    // If byte is lower or same, then skip this byte
  CMP r1, #'z'    // Compare it with the 'z' character
  BHI cap_skip    // If it is higher, then skip this byte
  SUBS r1,#32     // Else subtract out difference to capitalize it
  STRB r1, [r0]   // Store the capitalized byte back in memory

cap_skip
  ADDS r0, r0, #1 // Increment str pointer
  CMP r1, #0      // Was the byte 0?
  BNE cap_loop    // If not, repeat the loop
  BX lr           // Else return from subroutine
}

This simple code for example converts all lowercase English in a string to uppercase. What I do not understand in this code is why they are not using ADD and SUB commands instead of ADDS and SUBS currently being used. The ADDS and SUBS command, afaik, update the APSR flags NZCV, for later use. However, as you can see in the above snippet, the updated values are not being utilized. Is there any other utility of this command then?


Solution

  • Arithmetic instructions (ADD, SUB, etc) don't modify the status flag, unlike comparison instructions (CMP,TEQ) which update the condition flags by default. However, adding the S to the arithmetic instructions(ADDS, SUBS, etc) will update the condition flags according to the result of the operation. That is the only point of using the S for the arithmetic instructions, so if the cf are not going to be checked, there is no reason to use ADDS instead of ADD.


    There are more codes to append to the instruction (link), in order to achieve different purposes, such as CC (the conditional flag C=0), hence:

    ADDCC: do the operation if the carry status bit is set to 0.

    ADDCCS: do the operation if the carry status bit is set to 0 and afterwards, update the status flags (if C=1, the status flags are not overwritten).


    From the cycles point of view, there is no difference between updating the conditional flags or not. Considering an ARMv6-M as example, ADDS and ADD will take 1 cycle.


    Discard the use of ADD might look like a lazy choice, since ADD is quite useful for some cases. Going further, consider these examples:

      SUBS r0, r0, #1
      ADDS r0, r0, #2
      BNE go_wherever
    

    and

      SUBS r0, r0, #1
      ADD r0, r0, #2
      BNE go_wherever
    

    may yield different behaviours.


    As old_timer has pointed out, the UAL becomes quite relevant on this topic. Talking about the unified language, the preferred syntax is ADDS, instead of ADD (link). So the OP's code is absolutely fine (even recommended) if the purpose is to be assembled for Thumb and/or ARM (using UAL).