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.

Compiler/BEAGLEBN: Clarification for TI PRU calling convention ABI

Part Number: BEAGLEBN

Tool/software: TI C/C++ Compiler

Hi,

According to document SPRUHV7A, section 6.4.1.1 "Layout of Arguments Passed in Registers", structures with sizes 64-bits or less are passed in registers.

But using clpru version v2.1.5 for this C snippet:

struct S7 { char a[7]; };
char test_struct_pass(struct S7 s)
{
        return s.a[2];
}

I get the following assembly:

||test_struct_pass||:
;* --------------------------------------------------------------------------*
        SUB       r2, r2, 0x02          ; [ALU_PRU]
        SBBO      &r13.b2, r2, 0, 2     ; [ALU_PRU]
        LBBO      &r13.b2, r2, 2, 7     ; [ALU_PRU] |10| s,s
        LBBO      &r13.b2, r2, 0, 2     ; [ALU_PRU]
        ADD       r2, r2, 0x02          ; [ALU_PRU]
        JMP       r3.w2                 ; [ALU_PRU]

The way I read the documentation, I would expect the following code to be generated:

||test_struct_pass||:
;* --------------------------------------------------------------------------*
        MOV       R14.b0, R14.b2
        JMP       r3.w2                 ; [ALU_PRU]

If the above discrepancy is confirmed, what will TI update - the documentation or the toolchain?

Thanks,
Dimitar

  • Thank you for notifying us of this issue.  The code generated is correct.  The struct is passed in a register.  But, inside the function, part of it is copied off to a temporary spot on the local frame.  This is not optimal.  So, I filed CODEGEN-4131 in the SDOWP system.  You are welcome to follow it with the SDOWP link below in my signature.  It does not report a bug in the compiler, but requests that the generated assembly code be improved.

    Thanks and regards,

    -George

  • Which instructions copy R14.b2 in R14.b0? See my notes below.

    ||test_struct_pass||:
    ;* --------------------------------------------------------------------------*
            SUB       r2, r2, 0x02          ; Allocate stack space
            SBBO      &r13.b2, r2, 0, 2     ; Save R13.b2 and R13.b3
            LBBO      &r13.b2, r2, 2, 7     ; Load R14.b0 with s.a[2] from the argument passed on stack
            LBBO      &r13.b2, r2, 0, 2     ; Restore R13.b2 and R13.b3
            ADD       r2, r2, 0x02          ; Free stack space
            JMP       r3.w2                 ; 

    Regards,
    Dimitar

  • Dimitar,

    George was incorrect about the calling convention. The calling convention will only pass structs in registers of size 8, 16, 32, or 64 bits. Since your struct is 56 bits it doesn't qualify. In your case, the struct is passed on the stack. The instruction LBBO &r13.b2, r2, 2, 7 is what loads s.a[2] into r14.b0. 

  • Thank you for the clarification.
  • One more question - what about 24bits? I see that it is passed in registers:

    struct S3 { char a[3]; };
    char test_struct_pass3(struct S3 s)
    {
            return s.a[2];
    }

    ||test_struct_pass3||:
    ;* --------------------------------------------------------------------------*
            MOV       r14.b0, r14.b2        ; [ALU_PRU] |5| 
            JMP       r3.w2                 ; [ALU_PRU] 

  • You are correct.  This 3-byte struct is passed in registers.  This is inconsistent with the compiler manual.  CODEGEN-4178 is filed in the SDOWP system so this gets addressed.  You are welcome to follow it with the SDOWP link below in my signature,.

    Thanks and regards,

    -George