I've encountered an issue with powerpc-eabivle-gcc.exe, revision 4.9.4. The call of the libary function iprintf (not tried if it is the same for printf, etc.) is preceeded by a machine instruction e_crxor 6,6,6, which clears a floating point related fault bit. If the call of iprintf is the very last statement of a function then the stack frame cleanup is combined with the jump to the library function and the emitted machine instructions are accordingly changed. Unfortunately this involves a change of the instruction e_crxor into a Book E instruction crxor 6,6,6. The SW runs into a trap #6, Program interrupt.
The same code runs fine if either compiled with Book E instruction set or with VLE but without optimzation.
Here is the C code. (Note, the commented statement "asm volatile ("se_nop\n");" is a work around. The printf is no longer last statement and the correct e_crxor 6,6,6 is emitted):
/**
* A non cyclic task, which is activated by software trigger every time the button on the
* evaluation board is pressed.
*/
static void taskOnButtonDown(void)
{
checkAndIncrementTaskCnts(idTaskOnButtonDown);
++ mai_cntTaskOnButtonDown;
iprintf("You pressed the button the %lu. time\r\n", mai_cntTaskOnButtonDown);
/* Change the value of artificial CPU load on every click by 10%. */
if(_cpuLoadInPercent < 100)
_cpuLoadInPercent += 10;
else
_cpuLoadInPercent = 0;
iprintf("The additional, artificial CPU load has been set to %u%%\r\n", _cpuLoadInPercent);
// asm volatile ("se_nop\n");
} /* End of taskOnButtonDown */
Here is the assembly listing:
e_lis %r3,.LC8@ha # tmp166,
.loc 2 626 0
.loc 2 622 0
e_la %r3,.LC8@l(%r3) #,, tmp166
e_lwz %r4,_cpuLoadInPercent@sda21(%r0) # _cpuLoadInPercent,
.loc 2 626 0
se_mtlr %r0 #,
.cfi_restore 65
se_addi %r1,8 #,
.LCFI4:
.cfi_def_cfa_offset 0
.loc 2 622 0
crxor 6,6,6
e_b iprintf #
.LVL30:
.cfi_endproc
Console output with command line:
Compiling TRK-USB-MPC5643L-RTOS-VLE for production
Compiling C file code/mai_main.c
C:/ProgramFiles/MinGW-powerpc-eabivle-4.9.4/bin/powerpc-eabivle-gcc.exe -c -mcpu=e200z4 -mbig-endian -mvle -mspe -misel=yes -meabi -msdata=default -G8 -mregnames -mhard-float -fshort-double -mno-string -fno-common -fno-exceptions -ffunction-sections -fdata-sections -fshort-enums -fdiagnostics-show-option -finline-functions -fzero-initialized-in-bss -fno-tree-loop-optimize -Wall -Wno-main -Wno-old-style-declaration -Winline -Wextra -Wstrict-overflow=4 -Wmissing-declarations -Wno-parentheses -Wdiv-by-zero -Wcast-align -Wformat -Wformat-security -Wignored-qualifiers -Wsign-conversion -Wsign-compare -Werror=missing-declarations -Werror=implicit-function-declaration -Wno-nested-externs -Werror=int-to-pointer-cast -Werror=pointer-sign -Werror=pointer-to-int-cast -Werror=return-local-addr -MMD -Wa,-a=bin/ppc/PRODUCTION/obj/mai_main.lst -std=gnu11 -Icode/ -Icode/RTOS/ -Icode/serial/ -Icode/startup/ -DPRODUCTION -DNDEBUG -save-temps=obj -fverbose-asm -g1 -gdwarf-2 -Os -o bin/ppc/PRODUCTION/obj/mai_main.o code/mai_main.c
Full code context can be found at https://github.com/PeterVranken/TRK-USB-MPC5643L
I wonder if this issue has been accepted meanwhile by NXP as compiler bug report?
yes, ticket ID is cmpe200gcc-184
Fixed in Update 2 S32 Design Studio for Power Architecture 2017.R1 - Update 2 available
The crxor 6,6,6 is part of the PowerPC ABI.
When passing arguments to a variable argument function, the compiler must set the bit if any argument is passed in float point registers, otherwise it must reset the bit if none of the arguments is float point.
But it happens that VLE does not have float point registers (All float point data is passed on GPRs). So neither instruction is present in the output. That is the case for any VLE compiler (in vle mode or booke mode).
But I managed to reproduce the problem when -mspe is passed.
edmar:~/labhome/work_misc_tests> less vle_tail_vargs.s
extern int foo (const char *, ...);
extern double d;
extern int i;
int
main (int argc, char **argv)
{
foo ("foo %f\n", d);
foo ("foo %d\n", i);
}
~/dt-labhome/releases/installed/g4255b52/gcc-4.9.4-Ee200-eabivle/i686-linux/bin/powerpc-eabivle-gcc -O3 -S vle_tail_vargs.c -mspe
Generates this output:
main:
e_stwu 1,-8(1)
se_mflr 0
se_stw 0,12(1)
e_bl __eabi
e_lis 3,.LC0@ha
e_lis 7,d@ha
e_la 3,.LC0@l(3)
e_la 7,d@l(7)
se_lwz 5,0(7)
se_lwz 6,4(7)
e_crxor 6,6,6
e_bl foo
se_lwz 0,12(1)
e_lis 3,.LC1@ha
e_lis 7,i@ha
e_la 3,.LC1@l(3)
e_lwz 4,i@l(7)
se_mtlr 0
se_addi 1,8
crxor 6,6,6
e_b foo
The funny thing is that, because FP registers are always passed on GPR on SPE, the compiler clears the cr6 bit for both calls to "foo". The instruction is not necessary, but it is there for backward compatibility (SPE x Classic PowerPC).
So the tail call optimization pass must be made aware of the vle mode, and emit the correct instruction.
I cant reproduce it on my side. Could you please post here output "powerpc-eabivle-gcc.exe --version"
And could you add "-dp" switch into command line for gcc also. So we could see what pattern been selected.
Hi Alexander,
using the switch –dp on the compiler command line changes the produced assembly listing to:
569 .loc 3 749 0
570 004a 1C630000 e_la %r3,.LC8@l(%r3) # 31 elf_low_vle/1
571 004e 50800000 e_lwz %r4,_cpuLoadInPercent@sda21(%r0) # 32 *movsi_vle/10
761:code/mai_main.c ****
572 .loc 3 761 0
573 0052 0090 se_mtlr %r0 # 46 *movsi_vle/5
574 .cfi_restore 65
575 0054 2071 se_addi %r1,8 # 48 *addsi3_vle1/1
576 .LCFI6:
577 .cfi_def_cfa_offset 0
749:code/mai_main.c **** #ifdef __VLE__
578 .loc 3 749 0
579 0056 4CC63182 crxor 6,6,6 # 33 *sibcall_value_nonlocal_sysvsi/2
580 005a 78000000 e_b iprintf
581 .LVL51:
582 .cfi_endproc
Regards
Peter
Dear Alexander,
I get:
powerpc-eabivle-gcc.exe (GCC) 4.9.4 20160726 (Sat May 27 11:09:55 CDT 2017 build.sh rev=gd8b6c20 s=F494 ELe200 -V release_gd8b6c20_build_Fed_ELe200_ML0)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Regards,
Peter