4 ms·
> Or for overflow, "x[i] = 0;" cannot be compiled to "movl [x+RAX*4], 0" if i is an "unsigned int". This is another pet peeve of mine. Why does almost every j
by xscott 4y ago
> Or for overflow, "x[i] = 0;" cannot be compiled to "movl [x+RAX*4], 0" if i is an "unsigned int".
This is another pet peeve of mine. Why does almost every justification about UB and signed overflow involve using a 32 bit integer on a 64 bit platform? Change those int variables to ssize_t (or size_t if you must), and it's good.
Instead of creating and jumping through insane hoops to improve bad code, they should warn you that there are performance costs for using the wrong sized integer as an array subscript.
Edit: Oops, I missed the point on the first one. So I removed a bad example.
- danuker 4y ago> using a 32 bit integer on a 64 bit platform? Not about integers, but in general: maybe 64-bit is overkill. The trend in ML has been to reduce size: "We have demonstrated DNN training [using nVidia GPUs] with 8-bit floating point numbers (FP8) that achieves 2−4× speedup [compared to FP32 computation] without compromise in accuracy [on most CNN/DNN test accuracy degradation is ~0% stochastically, but max 2% on specific ImageNet runs]." https://arxiv.org/abs/1812.08011 https://arxiv.org/abs/1812.08011
- xscott 4y agoIt's not obvious unless you read and think about the assembly, but bonzini's point was that using a 32 bit signed int (which is not allowed to overflow) means the compiler can cleverly promote it to use register RAX as an index without any other shenanigans to deal with 32 bit overflow. RAX is a 64 bit register for integers or pointers. There are reasons why this might be advantageous over using EAX, which is the name for the low 32 bits of RAX. It's very possible that bonzini is referring to the example in the following link: https://www.youtube.com/watch?v=yG1OZ69H_-o&t=2357s https://www.youtube.com/watch?v=yG1OZ69H_-o&t=2357s Back to your overall point though, you're right that there's frequently an advantage to having your bulk data use smaller data types. It's better for caching and memory bandwidth, and it opens up more possibilities for parallelization with SIMD or GPU magic. However, it's really a false economy for things like loop indices. It doesn't matter if you declare your variable to be int8_t using just 1 byte, because it's probably going to tie up an entire 64 bit register anyways. There are ways to use only parts of registers, so you can pretend you have more registers, but these cause dependency stalls and are generally not good for modern processors, or at least not a win for speed. To a lesser extent, it's a false economy with floating point on the CPU too. Your 32 bit float is likely taking up an entire 128 bit (or larger) SIMD register, and the operations generally have the same latency and throughput as their 64 bit (double) equivalent. The rules can be very different on a GPU of course.
- bonzini 4y ago> There are reasons why this might be advantageous over using EAX, which is the name for the low 32 bits of RAX. EAX is not available in addresses. > It's very possible that bonzini is referring to the example in the following link Not intentionally but yes.
- xscott 4y ago> EAX is not available in addresses. Is this a relevant correction? If there is a point, ignore the following. You seem to like the ATT syntax, which I avoid whenever I can. However, if there isn't a specific point, and we're just being pedantic or having a pissing match, copy the following: mov rbx, [rax + 4*rax] mov rbx, [eax + 4*eax] movss xmm0, [rax + 4*rax] movss xmm0, [eax + 4*eax] into https://defuse.ca/online-x86-assembler.htm https://defuse.ca/online-x86-assembler.htm with the x64 option enabled. Your original example had float, so I included that as well. They all assemble, and the difference is in the REX prefix. I haven't looked at it in a few years, and I've forgotten a lot of details, but I wrote my own x86-64 assembler for fun. And of course, like most assemblers, I improvised my own syntax and naming convention. In particular, I didn't make a distinction between EAX and RAX (or AX or ALO). To me, it's just register A, and I gave the opcodes more descriptive names to indicate the bit width. I figure if gas can do something like ATT syntax, I can do my own my way.