[llvm-dev] New LLVM backend for Renesas RL78 MCU

Sebastian Perta via llvm-dev llvm-dev at lists.llvm.org
Wed Apr 1 10:26:05 PDT 2020


Hello all,

For the past couple of months I've been writing a new llvm backend for Renesas RL78 MCU:
https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/rl78.html
The software manual which contains all there is to know about RL78 is available here:
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rl78/r01us0015ej0220_rl78.pdf

The motivation behind this is the following:
For the past 7 years I've been working on the Renesas RL78 and RX MCU ports in GCC (originally developed and maintained by Red Hat).
In case of RX I have no real issues with GCC as performance is similar to the RX commercial/proprietary compilers,
however in case of RL78 the performance(both code size and speed) of GCC is very poor it ranges from 20% to 300% worse compared to the RL78 commercial compilers (from Renesas and IAR Systems).

I'm still a few months away from upstreaming the port but the port is currently quite stable and performance is very similar to the commercial/proprietary compilers (the machine outliner is very effective as RL78 has a very limited instruction set), and there's still a lot of room for improvement.
Also I'm able to keep ABI compatibility with the commercial compilers and implement features (available in the commercial compilers) which I wasn't able to do in GCC although I tried really hard for years.
So I would like take this opportunity to say thank you to you all for making LLVM so great and ease to use and extend.

Although I'm looking at other targets and follow the guidelines if there are pointers/suggestions which people would like to share I'm happy to listen.

I would like to show just one short example which was my starting point and motivation to switch to LLVM:
char foo(char a, char b, char c, char d, char e, char f) {
return a + b + c + d + e + f;
}

This is what GCC produces (30 bytes and 18 clock cycles excluding the ret instruction)
_foo:
mova, [sp+14]
movc, a
mova, [sp+12]
adda, c
movc, a
mova, [sp+10]
adda, c
movc, a
mova, [sp+8]
adda, c
movc, a
mova, [sp+6]
adda, c
movc, a
mova, [sp+4]
adda, c
movr8, a
ret
While with I can produce the following output code (11 bytes and 5 clock cycles excluding the ret)
Notice also the ABI difference (with LLVM I was able to use the same ABI as the commercial compilers)
_foo:
add a, x
add a, c
add a, b
add a, e
add a, d
ret

Please note the following comments are more directed at clang and I apologize if I shouldn't post here at all, I will repost the second part on cfe-dev list as well, but the first part of the email is about the announcement of the port and I think it belongs here.

Because I aim to replace GCC with LLVM, I already implemented the GCC RL78 attributes (__attribute__) and builtin functions (__builtin_rl78_*) however I recently received a request which brings me to the reason why I'm writing today:
I was asked if I can implement the C Language extension from the Renesas CCRL (Renesas RL78 commercial compiler) in clang in order to close the gap between the two compilers.

In GCC I implemented one of them (#pragma address) but when I pushed it upstream it wasn't met with too much enthusiasm and it didn't get accepted. I ended up maintaining it locally among many other things which I didn't upstream which made updating to new versions of GCC difficult.
This is one very important thing which I would like to avoid in LLVM, I don't want to do something that would not be accepted upstream and end up in the same situation as I was with GCC.

My question here will be: are the following CCRL extensions acceptable to be implemented in clang? or will I find myself in the same situation as I am with GCC as they won't be accepted upstream? Especially since for most of them we already/can have alternative implementations using __attribute__ and other approaches more in line with clang extensions.


First things I would like to explain are the pragmas.
Most CCRL pragmas have a trait which is quite unusual: the first parameter is function or a variable name, for example in order to declare a interrupt functions while in GCC I do:
void inter ( void ) __attribute__((interrupt));
In CCRL this is declared the following way:
#pragma interrupt inter
void inter ( void ) {
}

I haven't checked the clang source code but I imagine it is not straight forward to tie a pragma to a particular function declaration as there are no other such pragmas as far as I'm aware.

The complete list of pragmas in question is:
#pragma interrupt [(]interrupt-handler-name[(interrupt-specification [,...])][)]
The equivalent of __attribute__((interrupt)) as discussed above.
#pragma interrupt_brk [(]interrupt-handler-name[(interrupt-specification[,...])][)]
The equvivalent of __attribute__((brk_interrupt)).
#pragma section [ section-type][ new-section-name] section-type:{text|const|data|bss}
#pragma inline [(]function-name [,...][)]
#pragma noinline [(]function-name [,...][)]
As the name says inline, noinline. We have inline, __inline and __inline__ keywords and __attribute__ ((always_inline)).
#pragma inline_asm [(]function-name [,...][)]
This pragma specifies the body of the function is assembly code.
I image substantial changes will be required in clang for this.
#pragma address [(]variable-name=absolute-address[,...][)]
This can be implemented with __attribute((section("section-name")) and then handling that section in the linker script accordingly.
And a few more pragmas for we could have equivalent __attribute__.
#pragma saddr [(]variable-name[,...][)]
#pragma near [(] function-name [,...][)]
#pragma far [(] function-name [,...][)]
#pragma callt [(]function-name[,...][)]
#pragma stack_protector [(]function-name[(num=number)][,function-name[(num=number)]][,...][)]
#pragma no_stack_protector [(]function-name[,...][)]

Finally there are 2 operators:
__sectop("section-name")
__secend("section-name")
This can be easily done by adding symbols at start and end of output sections in the linker script and referencing them from C as global pointers.


The CCRL manual explaining those extension in detail is available here:
https://www.renesas.com/us/en/doc/products/tool/doc/015/r20ut3123ej0109-ccrl.pdf

Best Regards,
Sebastian




Renesas Electronics Europe GmbH, Geschaeftsfuehrer/President: Carsten Jauch, Sitz der Gesellschaft/Registered office: Duesseldorf, Arcadiastrasse 10, 40472 Duesseldorf, Germany, Handelsregister/Commercial Register: Duesseldorf, HRB 3708 USt-IDNr./Tax identification no.: DE 119353406 WEEE-Reg.-Nr./WEEE reg. no.: DE 14978647


More information about the llvm-dev mailing list