4 ms·
Almost impossible to do efficiently. Let's consider a tiny example: void copy(int* in, int* out) { for(int i = 0; i < 10; ++i) { *out = *in;
by CJefferson 9y ago
Almost impossible to do efficiently. Let's consider a tiny example:
void copy(int* in, int* out) {
for(int i = 0; i < 10; ++i)
{ *out = *in; ++out; ++in; }
}
Now, in C it is undefined behaviour if either o in or out point into the stack where the variables i, in and out live. Maybe their values will change, maybe they won't. In practice, this code will be optimised to some code that just stores in and out in registers.
Now let's imagine we want to make it defined. Then the statement '* out = * in' would have to become something like:
1) Write the current values of i, in and out to memory (in case * in overlaps with any of their locations.
2) Read * in into a register
3) Write *out from that register
4) Re-read i, in and out from memory, in case they just changed.
Now, you could make that more efficient by adding to the start of the function a check which looked to see if either 'in' or 'out' pointed anywhere near the stack, but there is still going to be a significant cost. If you plan for this from the start with your language, you can drive the costs much lower.
The main thing that separates C from assembler is that you do not have to worry about what values are in registers, and which are in memory. However, that means any code which writes to memory provides a place where this can make a difference.
- staticassertion 9y agoYou can express what you're talking about (non aliasing mutable pointers) for free, at compile time. In fact, you can't express this in C (or, restricted, whatever), so I do wonder if your assumption that because it's UB it'll compile to the optimal code is true.
- CJefferson 9y agoI think you are thinking about the memory that 'in' and 'out' point to aliasing each other. That's handled with the "restricted" keyword, as you say. I'm talking about something else, the issue of 'in' and 'out' pointing into the stack, so writing to them changing the value of the local variables. That is basically treated as UB by every C compiler, and no compiler I am aware of provides any switches which would make it easier to handle, it's just horrible and your code behaves in different ways depending on the compiler and optimisation level.
- Asooka 9y agoOh, you can fix it pretty simple "The compiler can always assume writes to memory via one object don't change values in memory accessed via any other object." Then, if you know your code can overlap, you can use some invalidate function to mark that "memory accessed via this object was changed by some statement prior, make sure to re-read values cached in registers". Because that's the odd case where you're doing something unusual. In general, "The compiler is allowed to optimise things assuming that spooky action at a distance isn't happening". You already have something very similar for atomics, which might be hidden behind a standard library, but in any case are a sequence of "lock the bus, read/write, memory barrier", telling your CPU and your compiler that memory access cannot be reordered around the memory barrier.
- Sohcahtoa82 9y ago> Now, in C it is undefined behaviour if either o in or out point into the stack where the variables i, in and out live Seems to me that that could only happen if you had some other bug clobbering the values of in and out, or you're passing something to the function that you shouldn't be. In either case, it's an error on the side of the programmer. > If you plan for this from the start with your language, you can drive the costs much lower. It shouldn't be the job of the language or compiler to make up for the shortcomings of the programmer besides maybe code generation optimization.