"Better" is subjective, as an LLVM is not always appropriate for most firmware.

Indeed, note gcc is sometimes intentionally Nerf'ed to suppress optimizations in favor of more repeatable code-motion behavior in real-time systems. Yes this can compile terribly inefficient binaries when inspected, but they are predictable and repeatable builds.

There is sometimes extremely good reasons to be able to inspect exactly what the assembly dump does, and know for sure it won't get randomly permuted in the compilation optimization/abstraction LLVM builds.

This concept is difficult for people who don't understand the subtle difference between guaranteed-latency schedulers, and real-time systems.

Clang is great for a lot of application level things performance wise, but firmware is often not one of those use-cases for really good reasons.

I guess it is true what they say, one day you must become a historian if you are around long enough. lol =3

Most of the benefits here seem to come from being able to use llvm, especially for static analysis; you could do this stuff, still ship binaries from GCC, and come out ahead.
In regular applications, most (serious) companies I’ve worked for used a combo of clang, GCC, and/or MSVC to have the largest list of warnings and bugs.
  • pjmlp
  • ·
  • 1 month ago
  • ·
  • [ - ]
Companies serious about static analysis end up additionally using Sonar, PVS Studio, Insure++, among others, not plain llvm.
My problem with GCC has been that it is sorely lacking in optimizations for a lot of architectures. The particular example I'm thinking of is handling GPIO. In most (all?) architectures, there's a clean way to get single-cycle access to IO, but GCC seems to like using the stupid method which takes 3-5 cycles.

I had to manually massage the C to get efficient assembly. At least GCC understands and respects when you manually write directly to a register. It gets turned into the correct single-cycle instructions.

There's other examples as well, in some architectures you can significantly speed up access to memory by storing a pointer in a special register. GCC just... doesn't. You have to do some nasty tricks with inline assembly and you have to just hope GCC doesn't stomp on that register anyway.

I've heard that clang is supposed to be better in this department, but I haven't felt like burning a couple of days to get it set up.

If I'm working on something that needs to go as fast as possible, I just keep the assembly pulled up all the time. CLion has this integrated and will link each line of C to the corresponding assembly section. It's been a massive help when micro-optimizing.

For embedded, most of the magic happens in the linker, and proprietary binary image optimizer. Thus, indeed one must still declare some things as "volatile" to get repeatable behavior from some compilers.

Notably, some vendors will provide asic optimized standard/DSP libraries for each chip, and this blob is linked into your code. Note, the real fun happens when small firms implement something like math.h sin() incorrectly. =)

Adding layers of abstraction does not often make the problems easier, or safer to handle.

However, we all find our own workflows, and if the product is stable for a year... everyone is happy. =3