Hacker News new | ask | show | jobs
by IshKebab 27 days ago
There are still modern CPUs that don't support misaligned access. It would be insane for C to mandate that misaligned accesses are supported.

However I do agree that just saying "the behaviour is undefined" is an unhelpful cop-out. They could easily say something like "non-atomic misaligned accesses either succeed or trap" or something like that.

> In the end it's the CPU and not the compiler which decides whether an unaligned access is a problem or not.

Not just the CPU - memory decides as well. MMIO devices often don't support misaligned accesses.

3 comments

> They could easily say something like "non-atomic misaligned accesses either succeed or trap" or something like that.

That means that the compiler must emit the read, even if the value is already known or never used, as it might trap. There is a reason for the UB!

No it doesn't. Compilers are only required to emit the read for volatile types. If the type is non-volatile, misaligned, and can be optimised out then it would be perfectly fine to omit it (that would be the "succeed" option).
If a trap is observable behaviour, then the compiler either needs to add code, that checks for the condition and then traps explicitly or it needs to actually perform the read. Currently it can be optimized out, because it is UB.
I think you misunderstood my suggestion. It isn't that misaligned accesses must either all succeed or all fail. That's not possible in general because of MMIO devices.

The suggestion is that each individual access must either succeed or trap. Those are the only possible outcomes, but different accesses can result in different outcomes.

And you misunderstand me. Your proposal means, that the compiler, must emit an individual access with the right values at the right time. If an access may succeed or fail, then the compiler can not just convert it into an aligned read, or not a read at all.

If your proposal includes, that a trapping access gets treated by the compiler as if it didn't and the compiler emits code that performs all kind of side-effects, that are logically independent if it would not trap, before the access, then you are back to undefined behaviour under a different name.

You're merely attacking his particular suggestion and using this as an argument to defend UB, when those are completely independent concerns.

What people want is for a compiler that assumes that all pointers are aligned to use an aligned store or load instruction whenever the compiler wants to issue such an instruction. There is no need for UB here.

In other words, they want the compiler to stick with the decision it made and not randomly say "I can't do the thing I've been doing correctly for decades, because that's UB, my hands are tied, I must ruin the code, there's no other way."

Yes, I am "attacking" his particular suggestion with the reasoning of this particular UB. I disagree that these concerns are independent, as the reasoning for the UB is often, that any choice per se would be limiting the possible compiler behaviour. It is not a particular choice, that would be limiting, but the act of picking one per se.

> What people want is for a compiler that assumes that all pointers are aligned to use an aligned store or load instruction whenever the compiler wants to issue such an instruction.

That requires a mental model of a compiler, that runs through the code linearly and emits instructions in the order defined by the code. That's not what is happening. Current compilers model the value flow through the code, and then emit a program that happen to output the same values for the valid input.

> In other words, they want the compiler to stick with the decision it made

What instead often happens is, that the compiler doesn't even emit a decision at all, because that is completely irrelevant.

On hardware that doesn't support it, misaligned loads could be compiled to multiple loads and shifts. Probably not great for performance, and it doesn't work if you need it to be atomic, but it isn't impossible.
That is only really possible if you know the pointer is misaligned at compile time (which does happen, e.g. for packed structs). The examples in the article are for runtime misalignment. It would be crazy to generate code so that every function checked if every access was aligned at runtime.

(Note the normal way to handle that if the hardware doesn't actually support it is for the access to trap and then the OS or firmware emulates it.)

That still requires detecting when a misaligned load happens.
For x86 SSE there are aligned instructions that will trap on unaligned access.