calima wrote: ↑Fri Apr 09, 2021 11:39 pm
coto wrote: ↑Fri Apr 09, 2021 9:06 pm
ROM code generated by official tools are expected to behave better than open source counter parts, like GCC compilers.
In my experience, IBM, Nintendo, AMD and Nvidia compilers suck in comparison to gcc.
From what I can tell, customer environment use either custom or paid compilers, which are guaranteed to work better. On ARM, GCC emits buggy relocation code. (You can see here:
http://forums.nesdev.com/viewtopic.php?f=23&t=18659), since i've switched to Clang, the binaries produce much better code (albeit ~%20 slower). This translates to having usable and not undefined behavior binaries. On GCC, a test case I had to do literally everytime I added interrupt code in the ARM9 interrupt handler was to create a multiple of two buffer (32K, 64K,128K) so linked code would actually boot, and cross fingers expecting code not to explode.
On the NintendoDS, Codewarrior didn't use any Nintendo inhouse compiler, but RVCT (ARM), and it produces excellent code since it's paid. There are some homebrew using such compiler like moonshell and code just works (you just need to read moonshell2 source code, the hand-made inline ARM code into C code requires a few pass of translation units to understand and link not only objects but also the processor registers to carefully not break anything)... for both ARMv4t and ARMv5te code.
GCC It's known to have decreased code quality (because of either LTO or optimized codepaths):
-
https://pagure.io/fesco/issue/2020
-
https://opensource.apple.com/source/cla ... rison.html
-
https://lwn.net/Articles/582697/
I haven't touched the LLVM code base in years, but way back when, I tried to use it as embedded JIT. (And I wound up writing the first version of llvm-config, so it could be easily linked as a JIT.)
Along the way, I tripped over a compiler bug. I can't remember the details now, but I wound up diving into the LLVM C++ code to fix it. And the code was *nice*—there once major intermediate representation, based on a strongly-typed assembly language with a very small number of operations. I was able to find my way around the code base and make my patch without unnecessary pain. Even better, I could dump the intermediate representation as an LLVM "assembly" file at any step of the compilation process, which made debugging very civilized.
So I'm not surprised that LLVM has since gone on to be quite successful. The architecture was always very approachable and very pleasant to hack on. At least at the time, that was not really the case with GCC.
Many people would rather put their code under GPL than have to interface to an unstable API. If the new "modular" GCC can provide useful, *stable* API's that are developed to meet a broad class of use cases, it could gain significant mindshare.
Full disclosure: I'm an LLVM developer. Hopefully this will help clarify the sense in which LLVM is useful as a library:
LLVM does have stable C API's, but doing anything nontrivial with them usually will require exposing something else from C++-land, and so you end up having to get involved with upstream.
One thing to keep in mind is that LLVM's C++ API's "simply exposes LLVM's internals". LLVM's is "library-based", if you define "library" as "a well-factored body of code that does something". However, if you include any notion of compatibility or attention to external use cases in your notion of library, then LLVM doesn't really qualify.
LLVM is like a bunch of libraries that evolve in lock-step. I sometimes describe it as "LLVM is loosely coupled from a software architecture standpoint, but very tightly coupled from a development standpoint".
Also, LLVM is developed with very little attention to external use cases. Most software libraries exist solely to serve external use cases. What is exposed as stable in LLVM's C API is basically "the minimal amount of stuff we can expose right now to meet the use cases of the users that have come barking at us". The C++ API's are literally the internal include/ dir. LLVM has no "public" include/ dir with its "public headers": all the headers in include/ (except for the C API) are evolved in lock-step with the goal of cleaner, better code, and no attention to backwards compatibility.
I'm not saying that this is a good or bad thing (actually, as I mentioned in another thread, this is a very strong disincentive for keeping private branches, which is a really good thing IMO). Personally, as an LLVM developer, I really like the freedom of not having to worry about backwards compatibility 99.9% of the time, even though I'm modifying ostensibly public interfaces. However, it's a headache for users.
Personally, I would not want GCC to go that same route. Or at least, I would like to see GCC learn from this aspect of LLVM and not end up in exactly the same situation. I have no clue what to do differently though.
I should also mention that LLVM does have a few important points of compatibility besides just the C API:
- The textual and bitcode format of LLVM IR, and its semantics.
- The syntax and semantics of the code that Clang translates (as you would expect from any production-quality compiler)
- The commandline options accepted by Clang (as you would expect from any production-quality compiler)
(hell yes to the last paragraph, I can relate to that since I took the same route developing ToolchainGenericDS and code emitted acts as a lockstep codebase (newlib+tgds librarian format + tgds project). This allows to add features without breaking older code, otherwise there'd be a bug with older code itself.
https://alibabatech.medium.com/gcc-vs-c ... 9ede2be378
From the benchmarking tests above, we can see that Clang offers more advantages for the construction of large projects while GCC is always advantageous in performance optimization. The bla depends on your specific application
In addition to performance comparison, I would like to share the advantages and disadvantages of GCC and Clang and LLVM:
Anyway to get to the point, yes, GCC helps to emit good binaries as long as you run a set of unit tests otherwise be prepared to waste years maintaining broken crap, as opposed to Clang's steady emitted code quality. Which DO resembles a paid compiler, it's just a matter of doing a side-by-side comparison of official ROM code against Clang emitted code, you'll see cleaner code. Now doing the same against GCC... yuck.
As a side note, Clang tend to break (and cause code section errors) when using nested pre processor code (like using pre processed defines accesing a struct member at least 5 times, then using them inside a switch statement), in GCC it compiles right away.