Re: Self hosting OS/Compiler from scratch
Posted: Mon Jan 27, 2014 7:58 pm
Hi,
For example, imagine you've got 12 different versions of a "u32 findGreatestCommonDivisor(u32 first, u32 second)" function. Maybe 9 of them can't be executed on the CPU; one is high level language code, one is 32-bit 80x86 with SSE and one is 32-bit 80x86 without SSE. Compiler can generate code for the 3 different versions, give them the same inputs and check that they all return the same outputs. Of course it might not be able to test every possible combination of input values (at least, not quickly enough), but it can certainly test the edge cases and a few thousand "random" values (and maybe just keep on going until someone presses a "cancel" button). Also; for a distributed system you could push it out to remote systems, increasing the number of versions you can test (e.g. the PowerPC assembly version and the ARM assembly version and the 80x86 assembly version, all being compared to the high level code version at the same time on different computers).
For "pure functions" (no side effects) this is relatively easy, and there's good reasons for the compiler to detect if a function is pure or not anyway. Beyond that it gets tricky.
For example, if the function reads/writes to memory, then you'd have to make sure any memory that will be read is the same for all versions beforehand, and check that any memory modified is the same for all versions after. Another problem is when the function happens to use the kernel API - you can check if all versions pass the same arguments to the same kernel API function, but checking any further than that is likely to be difficult or impossible.
For the "tricky" cases, the simplest way is to require a unit test to set things up properly and test the results. In that case you'd be testing to make sure all versions (that can be run) pass the unit test; rather than making sure each version produces the same output from the same inputs without any unit test.
Cheers,
Brendan
Ah - no, not different specialisations and not understanding the behaviour. The same function (same data types, same parameters), just with several versions in different languages and optimised for different CPU features.Owen wrote:Yes, you can have a version for each (its' somewhat convoluted, but that's what happens when you're past the edge of the language standard. Of course, somebody could submit a proposal to the C++ standards committee to support this; you might even unify the syntax with that of the C++AMP extentsion which enables running a subset of C++ on the GPU. Even better, somebody could teach LLVM how to compile multiple versions automatically.)Brendan wrote:Can you have 6 different versions in assembly language (e.g. one for 32-bit 80x86 without SSE, one for 32-bit 80x86 with SSE, a few for 64-bit 80x86, some for ARM, etc); and have all of them grouped next with the high level code so that it's obvious what the intended functionality is? Will the compiler be able to compile the high level version and one or more assembly versions and make sure they both function the same?
How is the compiler supposed to understand the behavior of "std::sort" without omniscience? If your answer to that is "you write some tests"... well, you can write your tests in C++ as well. And then you could explicitly test those specializations.
For example, imagine you've got 12 different versions of a "u32 findGreatestCommonDivisor(u32 first, u32 second)" function. Maybe 9 of them can't be executed on the CPU; one is high level language code, one is 32-bit 80x86 with SSE and one is 32-bit 80x86 without SSE. Compiler can generate code for the 3 different versions, give them the same inputs and check that they all return the same outputs. Of course it might not be able to test every possible combination of input values (at least, not quickly enough), but it can certainly test the edge cases and a few thousand "random" values (and maybe just keep on going until someone presses a "cancel" button). Also; for a distributed system you could push it out to remote systems, increasing the number of versions you can test (e.g. the PowerPC assembly version and the ARM assembly version and the 80x86 assembly version, all being compared to the high level code version at the same time on different computers).
For "pure functions" (no side effects) this is relatively easy, and there's good reasons for the compiler to detect if a function is pure or not anyway. Beyond that it gets tricky.
For example, if the function reads/writes to memory, then you'd have to make sure any memory that will be read is the same for all versions beforehand, and check that any memory modified is the same for all versions after. Another problem is when the function happens to use the kernel API - you can check if all versions pass the same arguments to the same kernel API function, but checking any further than that is likely to be difficult or impossible.
For the "tricky" cases, the simplest way is to require a unit test to set things up properly and test the results. In that case you'd be testing to make sure all versions (that can be run) pass the unit test; rather than making sure each version produces the same output from the same inputs without any unit test.
Now we're converting the original "general purpose slop" into something better suited for specific cases. E.g. originally it used a generic sort, then we decide it'd be better to switch to a hash or something for one specific case.Owen wrote:What? Now we are sorting hash tables?Brendan wrote:If you decide that for strings you're doing a lot of lookups/searching and want to switch to a hash or something instead of an array (and end up wanting a merge sort for the rare cases that you do sort) then guess what, it's all spread everywhere. It's completely idiotic.
Given that the topic is about writing an OS and compiler from scratch, there's nothing bogus about this argument at all. Everything is easy if someone else does all the hard stuff for you.Owen wrote:Bogus argument detected! "Implementing this is hard so its worthless to me?"Brendan wrote:And how long did it take you to learn C++, write any/all libraries you've used, write your C++ compiler twice from scratch, and implement the optimiser that did the vectorisation?
Did your compiler tell you there's a potential bug on every single line of that code? Hint: See if you can write a list of all the cases that overflows can/will cause incorrect results.
Cheers,
Brendan