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

Safe to use r13-r15 as general register?

Note: This was originally posted on 18th July 2011 at http://forums.arm.com

Hello, I am writting a function, which involves complicated algorithm, I want to have a lot of general purpose registers to keep the routine speed. I have read some article that r13-r15 are special registers, but can be used as general purpose registers.

Can I do it like this
   stmfd       sp!, {r4-r15,lr}
:
:
    ldmfd       sp!, {r4-r15,pc}

Thank you very much!
  • Note: This was originally posted on 19th July 2011 at http://forums.arm.com

    I read some ARM document, it says

    A called routine need not preserve the values of r0-r3, IP (r12) and LR (r14)

    so when subroutine returns, does it mean that it will automatically restore the value of r0-r3, and r12, in the caller function?

    Thank you.
  • Note: This was originally posted on 25th July 2011 at http://forums.arm.com

    If you don't need stack operation during a period of time, will this save one more register?

    str sp, [pc, #?]
    ...
    //use sp as gp reg
    ...
    ldr sp, [pc, #??] // you should know the offset from where you put sp value
  • Note: This was originally posted on 18th July 2011 at http://forums.arm.com


    Hello, I am writting a function, which involves complicated algorithm, I want to have a lot of general purpose registers to keep the routine speed. I have read some article that r13-r15 are special registers, but can be used as general purpose registers.

    Can I do it like this
       stmfd       sp!, {r4-r15,lr}
    :
    :
        ldmfd       sp!, {r4-r15,pc}

    Thank you very much!


    Unfortunately, r13-r15 are special registers and can not be used like that way. Actually, r15 is pc, r14 is lr, and r13 is sp.
  • Note: This was originally posted on 19th July 2011 at http://forums.arm.com

    You can use r13 and r14.
    I used to do that

    To save and restore register you can do this:



    my_fct:
    movw        r12, #:lower16:.save_zone
    movt        r12, #:upper16:.save_zone
    stmia   r12, {r4 - r11, sp, lr}

    ...

    movw        r12, #:lower16:.save_zone
    movt        r12, #:upper16:.save_zone
    ldmia   r12, {r4 - r11, sp, pc}

    .data
    .save_zone:
    .word   0, 0, 0, 0, 0, 0, 0
    .word   0, 0, 0, 0, 0, 0, 0


    r12 can be used because it is a scratch register, but if you want, you can push it before changing it and restore it after having restored sp (r13) !

    Etienne
  • Note: This was originally posted on 19th July 2011 at http://forums.arm.com


    I read some ARM document, it says

    A called routine need not preserve the values of r0-r3, IP (r12) and LR (r14)

    so when subroutine returns, does it mean that it will automatically restore the value of r0-r3, and r12, in the caller function?

    Thank you.


    Not at all!
    It means that the caller don't care about the values of r0, r1, r2 and r3.
    for r12, the caller must not use it. In fact it can use it, but the caller must know that after a sub function call r12 can have changed...
    for r14, the BL instruction will change r14 !


    In all case, the ARM never save any register for you !
    so the caller must know that those register may change after a subroutine call.

  • Note: This was originally posted on 25th July 2011 at http://forums.arm.com


    If you don't need stack operation during a period of time, will this save one more register?

    str sp, [pc, #?]
    ...
    //use sp as gp reg
    ...
    ldr sp, [pc, #??] // you should know the offset from where you put sp value


    if you don't need sp.
    Use the code I gave before (the first one).

    You will have 15 "general" register.

    Etienne
  • Note: This was originally posted on 23rd July 2011 at http://forums.arm.com


    On ARM, interrupts have a separate banked stack pointer. You don't have to worry about sharing the stack with them and are therefore free to use r13 for anything you want so long as you preserve it before returning.


    That's correct!

    But in this case .save_zone will be the same and then saved datas will be lost at the end of the recursive (or re-entrant call)

    If really you need to manage this case you can use this better (but slower) code


    my_fct:
    push   {r0 - r12, lr}
    movw        r12, #:lower16:.save_zone
    movt        r12, #:upper16:.save_zone
    ldr   r11, [r12], #4
    str   sp, [r12, r11, lsl #2]
    add   r11, #1
    str   r11, [r12, #-4]!

    ...

    movw        r12, #:lower16:.save_zone
    movt        r12, #:upper16:.save_zone
    ldr   r11, [r12], #4
    sub   r11, r11, #1
    ldr   sp, [r12, r11, lsl #2]
    str   r11, [r12, #-4]!
    pop   {r0 - r12, pc}

    .data
    .save_zone:
    .word   0
    .word   0, 0, 0, 0, 0, 0, 0


    Of course you have to test the value of r11 to control the deep of the recursion.

    Etienne
  • Note: This was originally posted on 22nd July 2011 at http://forums.arm.com


    But it's important to understand that that code is not re-entrant: that is, if my_fct is interrupted and the interrupt calls (possibly indirectly) my_fct again then the when the outer call to my_fct tries to return, bad things™ will happen.


    On ARM, interrupts have a separate banked stack pointer. You don't have to worry about sharing the stack with them and are therefore free to use r13 for anything you want so long as you preserve it before returning.
  • Note: This was originally posted on 18th July 2011 at http://forums.arm.com

    You can safely stack off LR (r14) and use it as a general purpose register as long as you don't need it (i.e. you are in a leaf function).

    Iso
  • Note: This was originally posted on 19th July 2011 at http://forums.arm.com

    The called function is allowed to corrupt r0-r3, and r12. The caller must store to stack before the call, and load from stack after the call. Nothing automatic about it - these are real instructions emitted by the compiler.

    In many cases these registers won't contain anything the caller cares about though, so it doesn't matter if they get corrupted by the called function.
  • Note: This was originally posted on 19th July 2011 at http://forums.arm.com

    But it's important to understand that that code is not re-entrant: that is, if my_fct is interrupted and the interrupt calls (possibly indirectly) my_fct again then the when the outer call to my_fct tries to return, bad things™ will happen.