So, welcome to the small device C compiler.
Talks about such short, so I'll try to fit in just a basic stuff.
I'll start with a quick introduction on what the small device C compiler is.
Then I talk about the architectures we target and then just a little bit of what the future
hopefully brings for the small device C compiler.
Okay, so STCC is, as the name says, C compiler.
It tries to support C standards, in particular either C19, 99, 11 and 23.
It's nearly always used as a free-standing implementation.
The only exception I know of is that FASIX, an operating system for some 8-bit systems
use it as a part of a hosted implementation.
Now, those familiar with the C standard know that in a free-standing implementation, you
are more restricted in particular in features from the standard library set.
You can use course, well, on your device there's no file system, there's no point in
using any standard library functions trying to open read or write files.
There are some supporting tools, apart from the compiler itself, in particular SM plus,
a linker and a simulator.
The simulators are usually kind of cycle accurate.
We mostly use them for our regression testing internally, but they are also usable by end
users who want to run their programs on a simulator rather than on real hardware.
It works on many house systems.
Most popular would be Linux and Windows, but it works fine on free BSD and so on.
We target various 8-bit architectures, probably more than any other compiler does, and we have
some unusual optimizations that do make sense on these targets where you really have very
little memory and where both optimizing for code size and for memory use are very important
and often more important than optimizing for speed.
Our user base consists mostly of developers targeting embedded systems.
I guess they make about two-thirds of SDCC users, and the rest are retro gaming and
retro computing enthusiasts because we also support various older 8-bit architectures.
They're similar enough to modern 8-bit microcontrollers that it makes sense to have them all in the
same compiler and many high-level optimizations can be shared.
But I believe that the user base in the end benefits of having both these groups represented
cause sometimes one group or the other is more eager to try some new feature, which of course
helps us finding all the bugs in corner cases and iron out everything, while then more conservative
users that want to wait for longer than getting in a more polished state.
Our latest release was at the end of January, which is very recently, typically we do one
release per year.
So the project is hosted at SourceForge.
We have our issue trackers there.
We have mailing lists for communication.
The users have version repository.
The user weekly for some documentation outside the manual.
And we have a compile farm for nightly regression testing, which means every night on many different
host systems, both in terms of operating system and underlying architecture.
The latest SDCC from Drunk is built and then runs all the regression tests, meaning compiling
a lot of tests, running them on the simulators to see if the results are what they should
be.
There's something between 10,000 or 20,000 tests that are executed that way and also
incorporates a large part of the GCC test suite.
A quick comparison to more known compilers.
We don't see ourselves as a competitor to GCC or LLVM, so the versus up there is just
for a comparison.
Now we specialize in targets that are hard to support in GCC and LLVM.
For GCC or LLVM, you typically want some risk like architecture, many registers, uniform
instructions set.
Then you can use a tritine style register allocator and that's efficient and everything
is nice.
The typical 8-bit architecture is not like that.
If you want to get into the compiler, there's a compiler developer, our learning curve tends
to be less deep than GCC.
Our internal interfaces tend to be more stable than LLVM, which for some people is also a
nice feature.
Talking about the recent release, our main improvements were definitely in the last
two years in standard compliance, in particular ISOC23 support.
This was partially funded as a project by the prototype fund from the German Ministry
of Education and Research and improvements and optimizations, in particular generalized
constant propagation to allow us to narrow variables.
If people use an int as a loop counter, that's typically a waste of memory in an 8-bit target
if that loop doesn't really need the 16-bit that an int has on those targets.
The work in optimizations was partially founded by an LNET via the NGI-0 initiative.
We also got two new parts, namely one for the WDC6502 and one for the SCR800.
One is the MOS6500 derivative and the other is the SET80 derivative.
Let's get to the parts.
The STM8 part is our best one because we generate really good code for the STM8.
It's currently the most advanced part.
It has all the bells, whistles and great features.
We do very well compared to the non-free compilers.
Unfortunately, recently this architecture has become not recommended for new devices.
The manufacturer tries to move their customers to arm.
But just to illustrate how we do versus three other compilers, which are all non-free, in
terms of benchmark scores, we generate the fastest code essentially, except for WEDSTONE,
which is a floating-point benchmark.
We didn't put as much emphasis on it.
And we also generate reasonably small code also for all of these benchmarks here.
This is with the current release in January versus the current versions of these non-free
compilers.
Now our oldest part is for the 8051 and its derivatives.
That's an ancient microcontroller architecture that Intel introduced long, long ago and abandoned
long, long ago.
And there are still many dozens of manufacturers that make compatible devices.
It's a very, very popular common microcontroller architecture.
It's not as nice as STM8.
It was the first supported architecture in STCC.
But in the recent years, it has fallen a bit behind new features that got added for other
architectures, didn't always get added to 8051.
And also many devices made by different manufacturers are also often slightly different, in particular
new features like additional data pointer registers, which are used in different ways.
We have support for the HTC rate and ST rate.
It's current microcontroller architecture by NXP.
The problem is there's not really much of a free open source community around this architecture.
There's individual bits here and there that someone wrote some free software for it.
But in general, it seems a typical sentiment by developers of ST08 programs as well.
We get the, at no monetary cost, we get the development environment for the manufacturer.
Why should we try something else?
And sometimes they complain a bit if the manufacturer drops the part for an older device.
As per DOC, a Taiwanese company that makes billions of microcontrollers each year that are not
that expensive, they were not really meant to be programmed in C.
But we still managed to support them, at least three of the four subarchitectures that exist
we already support.
The largest one, the PDK says, not yet supported.
One thing interesting about these is that they have hardware multishrating support,
which we currently don't support.
What we can do is write a C program, run it on one core and then the other cores run a sampler software.
There's microchip pick.
Those used to be very popular because they were cheap.
The ports are currently un-maintained, but we still get sometimes contributions from users with patches.
It's not like they're completely abandoned.
Maybe sometime a maintainer will step out of these user contributions.
Okay, now we get to the architectures relevant to the retro computing people.
These are a large number of Z80 derived architectures.
The SM83 might be known to most people here as a CPU from the Game Boy,
even though it's also found in some other Japanese appliances and TV remotes.
And then we have the MOS 6502 and its derivatives, which don't even fit on the line anymore.
They're found in old embedded systems, especially those R2K to R3K, those other rabbits.
They were very early IoT devices because they are kind of enhanced Z80 with ethernet or Wi-Fi on support on the chip.
But these architectures are relevant to the retro computing community,
which often doesn't use SDCs directly, but instead via downstream projects.
They package SDCC together with libraries for certain devices that use these things like video game consoles or historic computer systems.
Now, what will the future look like for SDCC?
We're definitely facing a problem at the moment because the SDM8, the architecture for which we're doing really great,
and those rabbit devices that I mentioned on the retro computing side,
are both not recommended for new devices anymore.
Meaning that the architectures for which we really, the architectures where we really do great as a compiler are about to be phased out.
We will keep supporting them, probably unlike many of those commercial compilers.
I mean two of the three commercial compilers for the SDM8 haven't even seen any update for the last two years.
But to stay relevant for current embedded systems, we need to try something else.
And basically this is the idea. The main thing is putting the focus on the MCS-51, the 80-51 again.
It's an ancient architecture. It's not exactly the nicest architecture.
But due to the large number of hardware vendors, it's not likely to die any time soon.
And looking at the reasons why users choose non-free compilers versus SDCC for the 80-51,
the main reason is definitely that the main non-free compiler for this architecture can optimize better for code size.
So this slide about the future is basically a very rough outline for plans for the next two years.
And generating better code in the MCS-51 port is definitely something that we want to do.
We will look a little bit into the SDM8, but due to the lack of community behind it,
there's probably not that much that can be done.
We still try to keep the SDM8 up to the other ports feature-wise, even if maybe not optimization-wise and code generation-wise.
For the PDORC things, it would be nice to be able to support the multishrating better and also support the one remaining subarchitecture.
And then there's this F8 thing, which is basically a very early project to maybe come up with our own architecture.
I've worked on the compiler for a long, long time and very often there was a feeling this could have been done a little bit better in this architecture,
or that could have been done a bit better, it would have made it a much better target for C compilers.
The SDM8, for example, is a really good architecture.
It has things like stack pointer relative addressing modes.
That's one, something that you really want for local variables in C because then you want them on the stacks,
so you have full re-entrance, C standard compliance, everything.
But it has very few registers.
The SDM8 has more registers, but the stack access is a little bit less efficient,
because you have to set up a frame pointer, it goes through index registers and so on.
The dog things have great multithreading, but they don't have the necessary instruction to support good C standard atomics to communicate between the cores.
And out of all those lessons basically learned from other architectures, the F8 is kind of a project to come up with an architecture that,
to say that somebody should become, if it succeeds, something for the 8-bit world,
something like risk 5 is for the rest of the world, and to see that the time is up. Questions?
Thanks for the talk.
Can you maybe give some hints about the internals of the compiler?
The internals of the compiler, okay.
We have a classic Lexiac, sorry, you didn't front-end.
Yeah, I just want to say if you are using an intermediate representation and maybe also the simulator,
does the simulator, since it has to support many architectural uses on intermediate representation, I would be curious about that.
Okay, so the front-end is a classic Lexiac parser.
We have an abstract syntax tree that gets converted into the i-code, which is basically a free address code.
This then gets annotated with some extra information, such as the register allocation,
and then in the individual back-ends, this i-code gets transformed into a sampler code.
The sampler code then goes through a P-Pole optimizer, and that gets unwritten out to the linker.
The simulators, well, that's not my area of expertise.
Daniel Drotos is definitely doing most of the work on that part.
They're written in C++.
They're using the classes and stuff to abstract things away,
but I don't think there's any intermediate representation in the simulator because they need to be fast.
We want to run tens of thousands of tests for every architecture that we support every night,
so performance is definitely a goal for the simulators.
You mentioned code size as one of the areas where STCC lacks behind the proprietary compilers from the vendors.
What kind of factor are we talking about, and are you doing regular statistics about the code size of STCC,
like in terms of different versions and so on?
Yes, we are tracking this throughout work. We have graphs, and we are not lacking in codes that in general compare to other compilers.
I mean, we're doing okay for the STM-8.
Resonance can generate smaller code, but resonance is in every other way the worst compiler for the STM-8 around these days.
I mean, they don't even support C90, and the code is very slow.
It's specifically for the 8051 backend that we, Kyle, generate more compact code.
I need to just to preface my question, saying that I only experienced STCC through the downstream projects,
and I began actually using it in great part thanks to your talk a couple of years ago.
But I have noticed that the compilation step takes a lot longer than other compilers would.
I suppose it's optimizing and evaluating. Why so?
And what would help it? More faster disk, more RAM, faster processor?
What would help the completion time stop a bit?
This depends on the backend. Most backends use what we call the new register allocator,
which definitely was the key to being able to compete this well with other compilers
in generating faster code and also being competitive in code size.
8051 does not yet, but for the C80, this register allocator is used.
It has a parameter, maxEloxPlanout,
that you can set to tell the register allocator how many different possibilities
to consider at each node of an internal representation.
The default value is 3000.
If you set it lower, you get less optimization, lower RAM usage, faster compilation,
but there's people that set the thing to a million and let their program
that in the end fits into 8 kilobytes compile for half an hour,
but they really want it optimized as well as it's possible.
So yes, the most of the compilation time is spent in the register allocator
and the people optimizer, and for the parts that have the new register allocator,
definitely the register allocator, typically more than the people optimizer.
And one interesting thing is this can become provably optimal.
If you also add F-Verbus ASM, you get comments in the sampler that tell you
once if the register allocator found a provably optimal assignment.
Per function.
Okay, I think that's what we have time for for the questions.
So just wanted to say I wish you thank you very much for the fascinating talk on the palace.