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.

TMS570LC4357: Description of CRET Pseudo Instruction?

Part Number: TMS570LC4357

Team,

Do we have any details about the CRET instruction that the compiler is gernating? It seems to be a pseudo instruction which results in a branch (b) instruction. But I couldn't find any description about CRET. A customer of mine is doing a safety certification and they need to document/certify all generated code. For this it's important to know if CRET is really always resulting in a branch. 

As example, for following C code, the compiler generates assembly code which is using CRET to call some_func_...:

void f(void)
{
   if(glob_var_1_boolean)
   {
      some_func_1();
   }
   else
   {
      some_func_2();
   }
}

Customer is using TI ARM C/C++ Compiler v20.2.1.LTS with these options:

--abi=eabi --arm_vmrs_si_workaround=off --code_state=16 --diag_wrap=off --embedded_constants=on --endian=big --float_support=VFPv3D16 --hll_source=on --object_format=elf --silicon_version=7R5 --symdebug:dwarf --symdebug:dwarf_version=3 --unaligned_access=on

Thanks,
  Robert

  • Hi Robert,

    We started working on your issue and will provide an update soon.

  • Do we have any details about the CRET instruction that the compiler is gernating? It seems to be a pseudo instruction which results in a branch (b) instruction.

    That's correct.  Details ...

    When I build that example code with the options shown, I do not see CRET instructions.  I see the following ...

    f:
    ;* --------------------------------------------------------------------------*
            PUSH      {A4, LR}              ; [DPU_V7R4_PIPE0]
            LDR       A1, $C$CON1           ; [DPU_V7R4_PIPE0] |6|
            LDR       A1, [A1, #0]          ; [DPU_V7R4_PIPE0] |6|
            CBZ       A1, ||$C$L1||         ; []
            ; BRANCHCC OCCURS {||$C$L1||}    ; [] |6|
    ;* --------------------------------------------------------------------------*
            BL        some_func_1           ; [DPU_V7R4_PIPE1] |8|
            ; CALL OCCURS {some_func_1 }     ; [] |8|
            B         ||$C$L2||             ; [DPU_V7R4_PIPE1]
            ; BRANCH OCCURS {||$C$L2||}      ; []
    ;* --------------------------------------------------------------------------*
    ||$C$L1||:
            BL        some_func_2           ; [DPU_V7R4_PIPE1] |12|
            ; CALL OCCURS {some_func_2 }     ; [] |12|
    ;* --------------------------------------------------------------------------*
    ||$C$L2||:
            POP       {A4, PC}

    By default, the compiler deletes the automatically generated assembly file.  But I use the option --keep_asm to disable that behavior.  I filtered the output, so that debug directives and blank lines are removed.  

    Note how the PUSH instruction pushes the registers A4 and LRLR contains the return address.  The function calls are implemented with the BL instruction, which loads return address in LR.  The POP instruction does not pop back into LR, but into the PC instead.  This is how the return to the caller occurs.

    Now, do everything the same way, but add the option --opt_level=3 to optimize at level 3.  Now the assembly code is ...

    f:
    ;* --------------------------------------------------------------------------*
            LDR       A1, $C$CON1           ; [DPU_V7R4_PIPE0] |6|
            LDR       A1, [A1, #0]          ; [DPU_V7R4_PIPE0] |6|
            CBNZ      A1, ||$C$L1||         ; []
            ; BRANCHCC OCCURS {||$C$L1||}    ; [] |6|
    ;* --------------------------------------------------------------------------*
            CRET      some_func_2           ; [DPU_V7R4_PIPE1] |12|
            ; CALL OCCURS {some_func_2 }     ; [] |12|
    ;* --------------------------------------------------------------------------*
    ||$C$L1||:
            CRET      some_func_1           ; [DPU_V7R4_PIPE1] |8|
            ; CALL OCCURS {some_func_1 }     ; [] |8|

    Note no PUSH or POP instructions.  The call is implemented with a CRET instruction, which is just another way to spell the B (branch) instruction.  Because LR is never changed, the function called (some_func_1 or some_func_2) returns not to f, but to the caller of f.  To make it easy to see that this particular optimization is happening, the instruction CRET (call return) is emitted, even though a B (branch) is the very same instruction.

    Thanks and regards,

    -George