
A Plan 9 C compiler for RISC-V [pdf] - fanf2
https://www.geeklan.co.uk/files/oshug69-Miller-criscv.pdf
======
arcticbull
Just double-checking the part of the presentation where they cite Plan 9's C
compiler as "predictable" because it doesn't optimize away a useless loop...
that's because the compiler is missing a bunch of useful optimizations isn't
it?

Specifically they say GCC requires this form for the busy loop to be emitted:

for (int i = 0; i < 1000000; i++) asm volatile ("" ::: "memory");

Where 9c will output a bunch of useless code when you tell it this:

for (int i = 0; i < 1000000; i++);

And this is... a good thing?

~~~
simias
I agree that it's a bit silly. They say:

>Plan 9 C implements C by attempting to follow the programmer’s instructions,
which is surprisingly useful in systems programming.

It's like coding with -fno-strict-aliasing or -fwrapv in GCC, it's perfectly
fine and justifiable but that doesn't mean that it makes sense for a compiler
to default to it IMO because you're basically lulling your devs into writing
into a specific dialect of C instead of the "real" language. It means that
your code is effectively not portable anymore which is probably less of an
issue for low level kernel code but could still easily cause issues as code is
shared between projects. Again, there are situations where it makes sense to
do so but I strongly believe that it should be an explicit choice by the
programmer, not a compiler default.

Now I would argue that the for loop example is even worse than aliasing or
wrapping-related issues because I very rarely write busy timing loops but I do
very often write for loops that I expect the compiler to optimize (drop
useless code, unroll etc...) correctly. So yeah, that really seems like a way
to spin a limitation of the compiler into a "feature" that makes really little
sense.

Also I just checked and gcc 8.2 does output the loop code when building with
-O0 I guess they could alias that to --plan9-mode.

~~~
derefr
> but I do very often write for loops that I expect the compiler to optimize
> (drop useless code, unroll etc...) correctly

I feel like the "Plan 9 C" author would argue that optimizations like that
should be explicitly _enabled_ using inline pragmas, where something that has
an optimization pragma is _requiring_ the compiler to optimize it (so if it
can't be optimized, the compiler should generate an error) and anything
without the pragma _requires_ the compiler to _not_ optimize it. (And then you
can have an "optimize if you can" pragma, too, but its usage would be
comparatively rare to either explicitly requiring or disallowing
optimization.)

Whereas, with regular C compilers— _unlike_ compilers for most other systems
languages—optimizations get turned on by a compiler switch entirely outside of
the code, and then what gets optimized and what doesn't is invisible, and
there are both no guarantees that anything _will_ be optimized, and no
guarantees that anything _won 't_ be optimized (unless you "trick" the
compiler by using things like the asm volatile() above.)

I'm not sure if I personally agree with the PoV I just stated, but I think
that's what _they 're_ thinking.

~~~
wahern
Compilers, including their optimizations, are implemented using abstractions.
The component to remove a chunk of code might query some other component, "are
any objects within this subtree used by anything outside this subtree"? If the
answer is, "no", it gets removed.

Recognizing and preserving special syntax patterns requires _additional_ work
and can add substantial complexity. This is a common dilemma in software
engineering, especially _high_ _quality_ software that applies sophisticated
algorithms. The smarter a compiler in terms of the application of state-of-
the-art algorithms, the more that these rigorous (but sometimes annoying)
optimizations _naturally_ happen. On the other hand, anything that breaks
abstraction boundaries results in complexity which can make comprehension and
maintenance quite burdensome.

If you've ever written code to build and transform an AST it should be obvious
how difficult it can be to add in ad hoc logic that leads to inconsistent
treatment of nodes. Even adding pragma opt-outs can add substantial
complexity. The Plan 9 compiler recognizes this because it basically does no
optimizations. In that sense it behaves much like GCC in preferring simplicity
over ad hoc semantics; both recognize that to "have your cake and eat it too"
is too costly.

Fortunately, C does make it relatively easy to compile different source units
independently. So all you really need is a single mode that disables _all_
optimizations, and put your special code in its own source file. But the trend
is to remove this separate linking step (Go and Rust both do static linking
across the application), and even C compilers are defaulting to so-called LTO
which effectively recompiles the application at link-time and which
deliberately violates previous semantics regarding cross-unit transformations
and optimizations. That's something of a shame.

GCC does permit all manner of function-level attributes, but it adds
substantial complexity, which is why clang and most other compilers don't
support such flexibility to the same degree, and why GCC is often reticent to
support yet another option.

------
Sir_Cmpwn
Nice! I hope they publish their work. plan9 is a great and very portable OS
for experimenting with new architectures, for the reasons outlined in the
slides. You can cross-compile the entire OS for a foreign architecture by
simply setting objtype=arm and running mk (plan9's take on make) - less than 5
minutes later the whole OS is done compiling.

~~~
bakul
It took a minute to compile plan9 kernel from scratch on the original
raspberry pi (running plan9). You can even cross compile a x86 kernel in
similar time. 10 seconds in 9vx emulator running on FreeBSD/amd64. I don’t
recall the details now but a from-scratch Linux kernel compile was 10 or 11
hours (under Linux on the same raspberry pi). Thank goodness it wasn’t written
in C++; the compile time would’ve been so much worse!

C compiler optimizations seems like micro-optimizations when people should be
looking at the bloat elsewhere. Missing the forest for the trees.

C is basically a low level language. A portable assembly language. A
predictable compiler shouldn’t second guess the programmer’s intent. To put
things in perspective, if all the man-years spent on gcc were spent on GNU
Hurd... :-)

~~~
Sir_Cmpwn
fwiw I can compile the Linux kernel, depending on the configuration, in 15-20
minutes. I usually give it 4 cores.

EDIT: On x86. If you don't cross-compile your raspberry pi kernel, you're in
for a bad time.

~~~
bakul
I compiled linux on the raspberry pi just for kicks! Most people don't
recompile the kernel so it doesn't matter but this just goes to show how
_misguided_ our blind quest for micro-performance has been.

------
kragniz
I went to a local RISC-V meetup last night, and it seems like something
interesting to play with. Does anyone know when actual chips might become
affordable? The only board I could find available at the moment is the HiFive
Unleashed, which is $999.

~~~
geokon
There are a handful of micros. The lowfive and a few coming from China

Here is an AI chip:

[https://hackaday.com/2018/10/08/new-part-day-the-risc-v-
chip...](https://hackaday.com/2018/10/08/new-part-day-the-risc-v-chip-with-
built-in-neural-networks/)

It's an interesting proposition b/c they using RISC for the core, but the APUs
are custom - so they can create some lock-in there for themselves (without
lock in it'll just be a race to the bottom with razor thin margins)

And here is RISC-on-an-FPGA in a nice package. It's very Chinese hobbyist
oriented [https://www.cnx-software.com/2018/09/04/licheetang-
anlogic-e...](https://www.cnx-software.com/2018/09/04/licheetang-anlogic-
eg4s20-fpga-board-targets-risc-v-development/)

Both those projects are by Zepan. That guy is a machine

But I'm not quite sure what's holding up general purpose CPUs (even just
something crappy/good-enough).. The way I understand it CPUs aren't just beefy
microcontrollers and they require some extra onchip hardware, but no one has
done that yet for some reason.. Maybe someone knows better :)

~~~
nickik
lowRisc and SiFive, there is no lowfive

~~~
kam
It's a breakout board for the SiFive E310

[https://github.com/mwelling/lofive](https://github.com/mwelling/lofive)

------
jpfr
What are the advantages of using the Plan9 compiler versus TinyCC?

[https://bellard.org/tcc/](https://bellard.org/tcc/)

[https://repo.or.cz/w/tinycc.git](https://repo.or.cz/w/tinycc.git)

~~~
Sir_Cmpwn
tcc only supports x86, and is 4-5 times bigger (lines of code) than the plan9
compiler.

~~~
beagle3
Tcc has supported AMD64 and ARM for ages. It produces reasonably fast code,
usable as a library, and has many other nice features. Worth looking at again
if you last looked when it only supported x86.

~~~
Sir_Cmpwn
Oh, neat, I will. Still, the main advantage of plan9's compiler is its
simplicity.

------
jhallenworld
So which is the easiest compiler to re-target to a new processor? That would
certainly have some value even if it's not the most optimizing compiler.

------
archi42
Hm... A non-optimizing compiler? Nice hobby, but I don't see the point of
this. Even folks doing safety critical stuff (like in failure = dead people)
use -O0 and are craving for some optimizations. E.g. why no DCE? Constant
propagation? With a proper representation (SSA?) some of this near-trivial.

~~~
9fans
The Plan 9 C compiler does perform optimisations including constant folding
and dead code elimination. (Actually it's the linker which eliminates dead
code, so it can remove functions which are not called from any other source
file.) The example loop on the slide however was not dead code or useless: it
was a timing delay loop, an idiom commonly encountered in OS kernels and
embedded applications.

------
henesy
Great to see RISC-V news make it public. Always glad to find more Plan 9 hobby
projects to learn from :)

