Status of the AVR backend 2019/LLVM 7.0

Hello all,

It is a near year and a new LLVM release; 7.0. It has been a while since the last AVR update email, the backend has become much better at handling complex programs.

To that end, this is the first LLVM release than can successfully compile all of upstream Rust’s main compiler support library libcore without error. This was the main blocker in merging the avr-rust fork upstream.

There have a few been more backend contributors this year, mostly coming from the avr-rust project.

The vast majority of the changes this last year have been related to compilation bugfixes. We have been focusing on improving Rust support, which exposed a number of compilation bugs and C-only assumptions that have now been fixed. The amount of IR correctly accepted by the AVR backend has noticeably increased, including implementation of atomics and things not seen in C such as structs with zero size.

Frontends supporting AVR- clang

Changes

Support for functions in nonzero address spaces has landed upstream

Address space 0 is always RAM, address space 1 is always program/flash memory
In the past, functions could only be in address space 0, and thus the entire LLVM middlend acted on the unfound assumption that every functon pointer is in RAM… but it still mostly worked
Although a function pointer memory address would inherently load from address space 0 - RAM, but with a memory offset into flash memory!

Now functions can be tagged with address spaces even at the textual IR level

A bunch of uninteresting compilation assertion error fixes. Almost all of the changes fall into this category

A few test suite fixes - thanks to several driveby contributors, it’s appreciated!

i128 divisions are now supported via libgcc calls

Test suite stability

The AVR backend and it’s test suite status has been decidedly more stable over the last year. In most backend-breaking LLVM changes, the AVR backend is updated at the same time as all the non-experimental backends.

The backend is still marked as experimental, which means that no emails are sent out upon test failure. The AVR buildbot can be found on the staging buildmaster at http://lab.llvm.org:8014/builders/llvm-avr-linux.

My main priority is integration testing, which needs some work. I’ve got a project that integration tests the backend here, but it cannot actually test LLVM trunk yet until D54334 ([AVR] Automatically link CRT and libgcc from the system avr-gcc) lands in clang, currently pending code review. The simavr emulator has been very helpful here.

Backend implementation/maintenance pain points

The major pain points of an embedded processor backend with relatively exotic properties are mostly the same as they were a few years ago. This includes the greedy register allocator, which can sometimes struggle with the extremely constrains sometimes imposed by AVR.

Another pain point is the DAG type legalizer, which currently assumes that arithmetic and logic operations only need to be split down into the smallest legal integer type. The implicit assumption is that hardware instructions are defined for every operation on the smallest legal integer type. The smallest legal integer type on AVR is 16-bit, which may be placed into 8-bit GPR pairs or 16-bit pointer registers. Only a small portion of the instruction set is 16-bit, with ADD, MUL, DIV, AND, OR, COM, etc only being defined on 8-bit general purpose registers. After DAG type legalization, >=32bit operation nodes are turned into multiple 16-bit operations, but instruction selection cannot ever match them because on AVR, most operations need to be split down once more to several 8-bit operations. The AVR workaround is to create a new pseudo instruction with a pattern for every 8-bit operation that operates on 16-bits. The AVRExpandPseudoInsts pass has a couple thousand lines manually expanding high-level 16-bit operations into hardware 8-bit instructions. A lot of complex AVR backend code could be deleted if LLVM had a way to split these operations down to the 8-bit level required.

Next year

As mentioned above, integration testing is a big priority and will help improve stability of the backend, whilst also increasing confidence in committing future changes. The end goal is to have a constantly-running integration tester that tests every change in LLVM against simulated AVR hardware.

I intend to write an RFC to LLVM-dev about the promotion of the backend from experimental to official in the coming weeks.

Special thanks to all of the helpful contributors that wrote patches, reviewed code, fixed tests, raised issues, discussed problems, and updated the AVR backend at the same time alongside their LLVM API breaking commits :wink:

Happy 2019 everybody,
Dylan

Dylan,
Thanks for all your hard work! Will need to test the latest and greatest! Looking forward to RFC soon, after a few more reviews,
Allen.