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.

ARM-CGT-CLANG-1_1.3.0-beta.1 saving registers in interrupt functions which call other functions

Other Parts Discussed in Thread: RM48L952, HALCOGEN

The attached project is a HALCoGen based project for a RM48L952, which uses an RTI interrupt. The source code was created by HALCoGen specifying "TI tools" and there are two build configurations:

a. Debug_TI_ARM_CGT using TI ARM v20.2.5

b. Debug_TI_CLANG using TI ARM Clang v1.3.0

After adding the Debug_TI_CLANG build configuration made a few adjustments to the source code and linker command file to allow to compile and run for both compilers, keeping the modifications within the HALCoGen /* USER CODE */ blocks so the modifications are preserved if HALCoGen is used to re-generate the driver code.

The source/rti.c source file contains the following HALCoGen created rtiCompare0Interrupt() interrupt handler which calls a user supplied handler:

/* USER CODE BEGIN (73) */
/* Work-around for TI ARM CLANG not understanding CODE_STATE and INTERRUPT pragmas */
void rtiCompare0Interrupt(void) __attribute__((target("arm"))) __attribute__((interrupt("IRQ")));
/* USER CODE END */

/** @fn void rtiCompare0Interrupt(void)
*   @brief RTI1 Compare 0 Interrupt Handler
*
*   RTI1 Compare 0 interrupt handler 
*
*/
#pragma CODE_STATE(rtiCompare0Interrupt, 32)
#pragma INTERRUPT(rtiCompare0Interrupt, IRQ)

/* SourceId : RTI_SourceId_022 */
/* DesignId : RTI_DesignId_022 */
/* Requirements : HL_SR95 */
void rtiCompare0Interrupt(void)
{
/* USER CODE BEGIN (74) */
/* USER CODE END */

    rtiREG1->INTFLAG = 1U;
    rtiNotification(rtiNOTIFICATION_COMPARE0);

/* USER CODE BEGIN (75) */
/* USER CODE END */
}

The TI ARM v20.2.5 compiler generates the following for rtiCompare0Interrupt() which preserves the floating point registers, presumably since the TI ARM v20.2.5 doesn't know if the called function may use floating point registers:

865       {
          rtiCompare0Interrupt():
08001660:   E92D500F            push       {r0, r1, r2, r3, r12, r14}
08001664:   EEF8CA10            vmrs       r12, fpexc
08001668:   E92D1000            stmdb      r13!, {r12}
0800166c:   EEF1CA10            vmrs       r12, fpscr
08001670:   E92D1000            stmdb      r13!, {r12}
08001674:   ED2D0B10            vpush      {d0, d1, d2, d3, d4, d5, d6, d7}
869           rtiREG1->INTFLAG = 1U;
08001678:   E30FCC88            movw       r12, #0xfc88
0800167c:   E34FCFFF            movt       r12, #0xffff
08001680:   E3A00001            mov        r0, #1
08001684:   E58C0000            str        r0, [r12]
870           rtiNotification(rtiNOTIFICATION_COMPARE0);
08001688:   EBFFFF9C            bl         rtiNotification
0800168c:   ECBD0B10            vpop       {d0, d1, d2, d3, d4, d5, d6, d7}
08001690:   E8BD1000            ldm        r13!, {r12}
08001694:   EEE1CA10            vmsr       fpscr, r12
08001698:   E8BD1000            ldm        r13!, {r12}
0800169c:   EEE8CA10            vmsr       fpexc, r12
080016a0:   E8BD500F            pop        {r0, r1, r2, r3, r12, r14}
080016a4:   E25EF004            subs       pc, r14, #4

Whereas the TI ARM Clang v1.3.0 compiler generates the following for rtiCompare0Interrupt() which doesn't preserve the floating point registers:

865       {
          rtiCompare0Interrupt():
08001630:   E92D5C0F            push       {r0, r1, r2, r3, r10, r11, r12, r14}
08001634:   E28DB014            add        r11, r13, #0x14
08001638:   E7C2D01F            bfc        r13, #0, #3
0800163c:   E30FEC88            movw       r14, #0xfc88
08001640:   E3A00001            mov        r0, #1
08001644:   E34FEFFF            movt       r14, #0xffff
869           rtiREG1->INTFLAG = 1U;
08001648:   E58E0000            str        r0, [r14]
870           rtiNotification(rtiNOTIFICATION_COMPARE0);
0800164c:   E3A00001            mov        r0, #1
08001650:   EBFFFFAA            bl         rtiNotification
874       }
08001654:   E24BD014            sub        r13, r11, #0x14
08001658:   E8BD5C0F            pop        {r0, r1, r2, r3, r10, r11, r12, r14}
0800165c:   E25EF004            subs       pc, r14, #4

The TI ARM Clang v1.3.0 compiler does produce a "call to function without interrupt attribute could clobber interruptee's VFP registers" warning for the call to rtiNotification() from rtiCompare0Interrupt():

Building file: "../source/rti.c"
Invoking: Arm Compiler
"C:/ti/ccs1030/ccs/tools/compiler/ti-cgt-armllvm_1.3.0-beta.1/bin/tiarmclang.exe" -c -march=armv7r -mcpu=cortex-r4 -mfloat-abi=hard -mfpu=vfpv3-d16 -mlittle-endian -marm -O2 -I"C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky" -I"C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include" -I"C:/ti/ccs1030/ccs/tools/compiler/ti-cgt-armllvm_1.3.0-beta.1/include" -D_INLINE -gdwarf-3 -Werror=ti-intrinsics -fno-short-wchar -fcommon -ffunction-sections -MMD -MP -MF"source/rti.d_raw" -MT"source/rti.o" -std=gnu90  -o"source/rti.o" "../source/rti.c"
In file included from ../source/rti.c:54:
In file included from C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include\rti.h:53:
In file included from C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include/reg_rti.h:52:
C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include/sys_common.h:95:9: warning: __little_endian__ is a legacy TI macro that is not defined in clang compilers and will evaluate to 0, use '!defined(__ARM_BIG_ENDIAN)' instead [-Wti-macros]
#ifndef __little_endian__
        ^
../source/rti.c:858:9: warning: pragma CODE_STATE is a legacy TI pragma and not supported in clang compilers. use '__attribute__((target("code_state")))' instead [-Wti-pragmas]
#pragma CODE_STATE(rtiCompare0Interrupt, 32)
        ^
../source/rti.c:859:9: warning: pragma INTERRUPT is a legacy TI pragma and not supported in clang compilers. use '__attribute__((interrupt("int_kind")))' instead [-Wti-pragmas]
#pragma INTERRUPT(rtiCompare0Interrupt, IRQ)
        ^
../source/rti.c:870:5: warning: call to function without interrupt attribute could clobber interruptee's VFP registers [-Wextra]
    rtiNotification(rtiNOTIFICATION_COMPARE0);
    ^
4 warnings generated.
Finished building: "../source/rti.c"

The warning suggests for safety the called rtiNotification() should be marked as an interrupt function. However, when attempted that with the following in include/rti.h the program no longer runs correctly:

/* USER CODE BEGIN (6) */
void rtiNotification(uint32 notification) __attribute((interrupt));
/* USER CODE END */

The reason is specifying the interrupt attribute for a function:

When compiling for an Arm Cortex-R processor, the compiler will generate code to preserve general purpose reguiters and a sequence of instructions to effect an appropriate exception return for the processor

When happened was that rtiCompare0Interrupt() and rtiNotification() were both marked as interrupt functions:

a. rtiCompare0Interrupt()  was called from a IRQ.

b. rtiCompare0Interrupt() called rtiNotification().

c. When rtiNotification() attempted to return, since had been been marked as interrupt the compiler generated epilogue which attempted to perform an exception return the function was re-entered and the processor then spent all its time in the rtiNotification() function.

With the TI ARM Clang v1.3.0 compiler what is the correct way for an interrupt handler which calls other functions to preserve VFP registers when functions with unknown side-effects are called?

I found Warn when calling a non interrupt function from an interrupt on ARM which appears to be when the "call to function without interrupt attribute could clobber interruptee's VFP registers" warning was added to LLVM, but what is the correct way to get the same behavior as the TI ARM v20.2.5 and preserve the VFP registers (for safety) if an interrupt function calls other functions?

Also, the text of the "call to function without interrupt attribute could clobber interruptee's VFP registers" is a bit misleading since as adding an interrupt attribute to the called function can break the code.

6470.RM48L952_rtiblinky.zip