4 ms·
This prevents debugging, probably does not really optimize (except 1% in useless microbenchmarks), and increases compiler complexity and the risk of bugs in it.
by xorblurb 10y ago
This prevents debugging, probably does not really optimize (except 1% in useless microbenchmarks), and increases compiler complexity and the risk of bugs in it. A similar thing has already happen in the past: compiler started to introduce speculative writes on code pathes where the write did not occur in the source code, and this broke multithreaded programs -- IIRC there was no threading model at that time (the current one forbid to do that kind of thing, and it is probably impossible to get a sound threading model that does not forbid that) but instead of saying that they were technically allowed to do that compiler authors recognized that because it made multithreaded programs impossible to write, that they had to fix their shit.
In the C standard, crashing is not a specified behavior, so when an obscure architecture crashes on a specific construct, the standard has to technically say that this is undefined behavior. That compiler authors now interpret most of undefined behavior as a license to be stupid on ALL architecture instead using their brain and allowing non-portable programs to exist is not them being smart optimizing all our code-bases for free but just a proof they do not understand a part of what they are doing, including the standard they pretend to know so much.
So the position of "all the standard, nothing but the standard" is utter bullshit. Another example: the current published atomic specification is subtly unsound. Do compiler authors do the right thing instead of trying to implement the broken spec, while waiting for the spec to be fixed? On that point yes -- at least for now. So when, on other subjects, they introduce new bugs in compiled code compared to what all previously known compilers produced - and without proving this really improves performance like crazy to justify taking that kind of risk - they are just being dangerous asses. -O2 has shown to be able to be fast enough without (reasonable) code breaking behavior in the past. In most case you wants to keep the same behavior as -O0 built programs. An optimisation that does not preserve behaviors reasonably expected by skilled programmers and requires that every programmer knows the standard by heart at any point of their work under penalty of crashes and security holes is not an optimisation but a piece of crap. This is blurry but the C / C++ standards are blurry and their usage even more so -- and more importantly they do not forbid to stay safe and sane to begin with -- so trying to do formal logic instead of doing engineering by thinking about the whole picture and history is completely stupid.
- mike_hock 10y agoIn this case, the programmer cannot reasonably expect that a concurrent read produces a meaningful result. There are good reasons to use clean, abstract formal logic over brutish "engineering" that results in a myriad of unmaintainable "if x, y, and z, do this, but not if also a or b, then we do that." That said, I agree that compilers should not needlessly optimize based on undefined behavior in cases where a sensible architecture-specific behavior can be defined (but turning a "read can produce any value" into a "read can produce high 32 bits from old write and low 32 bits from new write" isn't even worth specifying).
- amluto 10y ago> Another example: the current published atomic specification is subtly unsound. Can you explain or point us somewhere?
- gpderetta 10y ago'the current published atomic specification is subtly unsound' Are you talking about memory_order_consume? Although I believe that correctness proofs have so far excluded memory_order_consume, I do not think the current spec has been shown to be unsound; it is just generally regarded as hard to implement and hard to use correctly. In practice most compilers (conformingly) just lower it to memory_order_acquire; even Linus has been considering doing away with all the dependent load trickery in the kernel and just convert all of them to explicit load acquires. x86 and SPARC are TSO machines and have zero cost acquires, modern POWERs can also be run in a similar sane TSO mode and ARM64 has cheap explicit load acquire and store release (which I believe were added explicitly to allow simple mapping of the C and C++ memory model). Even Itanic has (I assume cheap) load acquire and store release operations. Other insane architectures that actually require dependant loads for performance can go and have anatomically impossible sex with themselves. edit: spelling
- jfbastien 10y agoThe latest on consume: http://wg21.link/p0190r0 http://wg21.link/p0190r0 The spec is pretty sound, but unimplemented because that's not how compilers work right now for the generality that consume wants. I think the above proposal is likely to work because it's more restrictive towards how consume works, but we need implementation experience. Linux uses consume extensively for RCU, and I don't think it'll go away soon because of the benefits it provides to Power and ARM. It works through a gentleperson's agreement between Linux's RCU implementation in C and GCC.