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

assigning function parameters to registers

I have code (borrowed from another platform )that attempts to optimize by using assembly code.
The function is an addition of arrays and is a C function such as
uint32_t AddNumbers ( uint32_t *p_addResult , uint32_t *p_left , uint32_t *p_right , const uint ARRAY_SIZE)

Can I get pointed to a syntax where the passed variables can be assigned to registers and assembly variables.



uint32_t AddNumbers ( uint32_t *p_addResult , uint32_t *p_left , uint32_t *p_right , const uint ARRAY_SIZE)
{

uint32_t l_counter = ARRAY_SIZE;
uint32_t l_carry = 0;
    uint32_t l_left;
    uint32_t l_right;
 __asm(
       ..
        "ldmia %[lptr]!, {%[left]} \n\t"
        "ldmia %[rptr]!, {%[right]} \n\t"
        "lsrs %[carry], #1 \n\t"
        "adcs %[left], %[right] \n\t"

         ...
        : [dptr] "+l" (p_addResult), [lptr] "+l" (p_left), [rptr] "+l" (p_right), [ctr] "+l" (l_counter), [carry] "+l" (l_carry), [left] "=l" (l_left), [right] "=l" (l_right)
}

I am getting syntax errors for the part above that assigns the C variables to registers and assembly variables.

Thanks

Parents
  • The easy solution?

    Don't implement any assembler functions in C/C++ source files - do it in a real assembler file.

    Note also that the optimizer doesn't care if a processor instruction comes from inlined assembler or as result of compiling C code. It will still try to remap registers, change order of instructions etc. The only way to "own" the instruction sequence is by having it in an assembler file.

Reply
  • The easy solution?

    Don't implement any assembler functions in C/C++ source files - do it in a real assembler file.

    Note also that the optimizer doesn't care if a processor instruction comes from inlined assembler or as result of compiling C code. It will still try to remap registers, change order of instructions etc. The only way to "own" the instruction sequence is by having it in an assembler file.

Children
  • I am willing to explore this. Any good documentation on how I could go about doing this?

    My use case is

    A.c refers to a function in B.c. Some functions in B need assembly optimization. How do I specify these functions ( like my addition example) and associate them in B.c

    Apologize for being such a noob !

  • adder.s

                    PRESERVE8
                    THUMB
    
                    AREA    |.text|, CODE, READONLY
    
    ; M0 version
    
    AddNumbers PROC
        EXPORT AddNumbers
    
    ; R0 = p_addResult
    ; R1 = p_left
    ; R2 = p_right
    ; R3 = size
    
        push {r4, r5}
        movs r5, #0 ; clear carry
    _AddLoop
        ldm r1!, { r4 }
        lsrs r5, #1 ; get carry from low order R5
        ldm r2!, { r5 }
        adcs r4, r5
        stm r0!, { r4 }
        adcs r5, r5 ; get carry into R5
        subs r3, #1
        bne _AddLoop
        movs r0, #1
        ands r0, r5 ; return carry in R0
        pop {r4, r5}
        bx lr
    
        ENDP ; AddNumbers
    
                     END
    

  • Thanks for this snippet. Had a few questions

    1. Where is the association done between the function params and the registers ?

    Specifically where is the binding done ?
    ; R0 = p_addResult
    ; R1 = p_left
    ; R2 = p_right
    ; R3 = size

    2. Penned my understanding of the logic. Learning to fish here!

    push {r4, r5} // Push to the stack whatever is in r4 and r5 . movs r5, #0 ; clear carry // clear the carry bit in register r5 but why?
    _AddLoop ldm r1!, { r4 } // copy value from r1 to r4 lsrs r5, #1 ; get carry from low order R5 // Shift right by 1 ? What is this achieving? ldm r2!, { r5 } // copy value from r2 to r5 adcs r4, r5 // add with carry r4 and r5 stm r0!, { r4 } // store result in r0 the result in r4 adcs r5, r5 ; get carry into R5 // ? subs r3, #1 decrement size ? however we are we affecting the pointers to point to the next array value . where are we going from p_left[8] to using p_left[7] while iterating? bne _AddLoop // loop back movs r0, #1 // moving 1 into r0 . ands r0, r5 ; return carry in R0 // And'ing with r5 but why did we do this ?
    pop {r4, r5} bx lr

  • Some questions(?) inlined within code

     PRESERVE8
                    THUMB
    
                    AREA    |.text|, CODE, READONLY
    
    ; M0 version
    
    AddNumbers PROC
        EXPORT AddNumbers
    
    ; R0 = p_addResult
    ; R1 = p_left
    ; R2 = p_right
    ; R3 = size
    
        push {r4, r5} // push whatever is in r4 and r5 into stack
        movs r5, #0 ; clear carry
    _AddLoop
        ldm r1!, { r4 } // load p_left onto r4
        lsrs r5, #1 ; get carry from low order R5 // left shift right r5 by 1? Perhaps I am missing the crux for addition with carry . adcs below adds r4 and r5 . so the carry is part of r5 and we're trying to extract it here ?
        ldm r2!, { r5 } // load p_right onto r5
        adcs r4, r5     // ok
        stm r0!, { r4 } // result of addition into r0
        adcs r5, r5 ; get carry into R5  // ? what does this achieve?
        subs r3, #1  // decrement size.
        bne _AddLoop // loop again, ? however where do we affect going from index to index -1 for the C arrays ?
        movs r0, #1  //? why
        ands r0, r5 ; return carry in R0 ? ANDING r0 and R5 to extract carry flag but why do we do this ?
        pop {r4, r5} // restore context
        bx lr        // branch with link but what's lr?
    
        ENDP ; AddNumbers
    
                     END