Hacker News new | past | comments | ask | show | jobs | submit login

> You can cast literally any optimization into this shape

Tell me how these use UB: integer constant folding, unused load removal, optimal use of GP registers to minimize stack spilling

>sane assumptions

"sane" here is doing a lot of work. Assuming overflow won't happen is not a sane assumption, assuming some other thread won't randomly write into your stack memory is.




> unused load removal

Oh come on, this is like the most UB-centric thing in the entire compiler. The compiler uses UB to know that it has enumerated all uses of a memory location, as any pointer that didn't get its value from the data dependency tree that compiler used had to use UB to compute the address. (Be it from buffer overflow, use after end-of-lifetime, random integer converted to pointer, etc.)


I might be using the wrong terminology, what I'm talking about is removing e.g. `int x = *ptr` where x is then not used in scope (more realistically, `(*struct_inst).member` shouldn't bother to load the other members of the struct). What you're doing sounds like removing a global it detects is never used, which I agree relies too much on UB and should not be done.


Aside from the possible trap ("segfault") mention in the sibling comment, the first example relies on absence of UB because with UB you could enumerate the contents of the stack to find where `x` is living, and discover it isn't there, contra the spec. Even allocating variables directly into registers and never onto the stack relies on UB.


Why is it UB to use registers to store variables? This seems like an implementation detail. The ISO C spec doesn't even have the word "stack" as far as ctrl-f can show me.


> Why is it UB to use registers to store variables?

It isn't; that sentence is even a type error. UB is not a property of compiler output. It's a property of compiler input.

The use of registers to store variables between uses (when those variables never have their address taken) relies on the lack of any defined behavior which would allow the program to determine this is being done. The fact you can't find this in the spec is precisely because it is not defined.


If any object can potentially be reached by forging pointers or enumerating all memory locations, you can't even keep local variables in registers around potential stores to unknown pointers (or ever, in a multithreaded program).


Removing a load is visible behaviour if the load would have trapped for example.

Everybody agrees that compilers should only do sane optimizations. Nobody agrees on which subset is sane.


That's fair, I'll concede that I make some implicit assumptions. But the magnitude of people who hit problems and accidentally hit UB should give a strong indication that a lot of things done now are not close to sane.


Lobbying the standard body to reduce the amount of UB in the C standard is a perfectly reasonable position. Requiring compilers to DWIM is not.


> integer constant folding

    int a = 10;
    int var1;
    int b = 20;

    foo(&var1);

    int c = a + b;
You'd like to constant fold c? Better assume no UB:

    void foo(int* x) { *(x-1) = 0; }
> unused load removal

Same idea as above.

> Assuming overflow won't happen is not a sane assumption

If the alternative is loops being much slower when you request optimizations, then maybe it is. Consult your compiler manuals if this default irks you.


Okay, yes, you are technically right. What I mean is, making an assumption _other than_ that the code won't alter stack/heap/instruction memory that the implementation is using (e.g. aliasing, overflow, use of NULL)


Sorry, I'm tired of playing whack-a-mole with what are obviously sane assumptions to you. I literally mentioned out-of-bounds writes as a "universal UB" example, you asked me to demonstrate how UB is relevant in a few optimizations, I did, and now you shift goalposts.

My original point was that compilers don't specifically abuse UB to sleight you. You're trying hard to draw a line in the sand between different degrees of UB so that you can label one side as "not sane", with (what appears to be) the sole intent of concluding malice on the compiler author side. Please accept that the related tradeoffs have been discussed, and that a default was chosen (if you are curious for a recent instance of this, see [0]).

If you are ok with leaving performance on the table by disabling overflow being UB, you are literally free to do that. You're also free to lobby the standard bodies to alter their carefully considered choices. But you're not going to get anywhere by labeling any of this "insane".

[0]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p090...


Isn't TBAA exactly the assumption that the program won't alter the stack/head/instruction memory in an illegal way?




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: