6 ms·
> And because compilers are largely deterministic closed-system problems -- for each input, there is one and only output Not even close! Optimization and code
by nayuki 3y ago
> And because compilers are largely deterministic closed-system problems -- for each input, there is one and only output
Not even close! Optimization and code generation is a fantastically hard problem full of heuristics and tradeoffs.
There is definitely more than one way to compile C source code to x86 binary code. There is even more than one way to compile TypeScript to JavaScript if you consider things like whitespace, indentation, and constant folding.
The rest of the article is alright.
- mathisfun123 3y ago+1 Ya that's a hilariously naive take (the quoted line not your response) given PGO, to say nothing of MLGO.
- ehaliewicz2 3y agoPretty sure he means given a single compiler.
- WalterBright 3y agoThe compiler is deterministic - for the same inputs, you'll get the same outputs. Unless you've got memory corruption in it.
- burjui 3y agoOr unless you iterate over randomized hashtables to produce some output, e.g. function sections in an executable. Though that doesn't change the semantics and is basically rearranging coins in your pocket.
- eru 3y agoMany optimizers (and other algorithms used in compilers) can benefit from some random bits. Though, of course, in practice you can use pseudo-random bits and fix the seed.
- WalterBright 3y agoHaving a compiler produce different code for the same source is a recipe for "I can't reproduce your bug and can't fix it".
- mfranc42 3y agoHe probably meant that a compiler is a pure function for a given source file and a set of flags. Of course, if you change a compiler or flags, you can get something radically different, but you shouldn't get something radically different because it's Tuesday, midnight, your username starts with n, you have more than 3 hard drives, or because it reads some bytes from /dev/urandom. It's bit of a stretch, sure, but I don't expect my performance problems to go away by recompiling stuff over and over again without changing either the code or flags and expecting the optimizer to make a better decision next time. It doesn't work that way.
- mathisfun123 3y ago>and expecting the optimizer to make a better decision next time. It doesn't work that way But in practice it does work exactly that way because of PGO and if we're precluding PGO then the observation is as banal as "programs that have no side-effects are pure". Like I get that the post is trying to paint some beautiful picture about how compiler passes are abstract beautiful transformations of representations of programs but it's not a useful picture at all.
- slavapestov 3y ago> Like I get that the post is trying to paint some beautiful picture about how compiler passes are abstract beautiful transformations of representations of programs but it's not a useful picture at all. It is actually a very useful picture especially to a beginner. PGO is an edge case and not used a whole lot in practice. Many compilers do not support it at all, even production compilers. Someone learning to write a compiler does not need to think about PGO. And besides, a compiler with PGO is still a pure function of source + flags + profile.
- mathisfun123 3y ago>PGO is an edge case and not used a whole lot in practice. Many compilers do not support it at all, even production compilers. Both clang and gcc support `-fprofile-generate`. Beyond that generic infrastructure, in my area (DL compilers) if you're not doing PGO/autotuning you're not serious. >Someone learning to write a compiler does not need to think about PGO. That's like saying someone learning to write a compiler doesn't need to think about optimization at all - sure maybe the first time. But then every time after that it should be at the forefront of your mind.
- armchairhacker 3y agoThere are multiple valid ways to compile a source with the same semantics, but a decent compiler should absolutely be deterministic. Imagine libraries which compile fine 99% of the time, but produce the wrong semantics every 1%: - Bug in your program? Could be a dependency of a dependency built wrong, better do a full clean and rebuild. - All of your pre-release tests passed? The code you shipped doesn't work, because you hit that unlucky 1%. Imagine how bad this would be back when software was released on CDs... - Have 70 dependencies which are like this (not hard in the webscale era)? Now your CI needs to retry every build up to 10 times, because every build has a ~63.4% chance of failing. And there's still ~1% chance your CI fails anyways because you got 10 unlucky builds in a row. I'm sure there are more stories of these kinds of issues...
- eru 3y ago> There are multiple valid ways to compile a source with the same semantics, but a decent compiler should absolutely be deterministic. Imagine libraries which compile fine 99% of the time, but produce the wrong semantics every 1%: That's not the only kind of non-determinism, you know? Lots of algorithms benefits from access to random bits, too.
- armchairhacker 3y agoThe context is > for each input, there is one and only output A randomized algorithm which uses non-determinism but produces the same output is OK. Also, psuedo-randomness is OK as long as the same program compiled in the same version of the compiler always gets the same seed. But if the algorithm can produce different output causing the same program to compile to different assembly, that's a problem. Unless you can formally prove that every possible variation will have the same behavior, but formal methods + non-determinism is hard, so it usually isn't worth it. Even random hash order in hashmaps can create problems: see https://github.com/rust-lang/rust/issues/84447 https://github.com/rust-lang/rust/issues/84447 and https://github.com/rust-lang/rust/pull/82272#issuecomment-825124318 https://github.com/rust-lang/rust/pull/82272#issuecomment-82..., though this is a very small issue in the diagnostic reporter and not a case of 2 valid programs with different semantics.
- nayuki 3y agoSo, the downvotes and replies warrants a follow-up comment. I support deterministic compilers due to deterministic builds. For a given input source code, compiler executable, and command-line flags, it should always produce the same binary, regardless of the time of day, random number generator, I/O, threading, environment, etc. My refutation of the article is that he made it sound like a compiler is like computing Fibonacci numbers - here are all the valid inputs, here is how each one maps to its one and only correct output answer, so fill in the code to accomplish that. Also in the previous paragraph he wrote: > Because the most basic compiler architecture is standard, you have limited boundaries and degrees of freedom when designing one. This might sound restricting, but actually, it's freeing because you get to play in a predictable sandbox.