4 ms·
I didn't look at the code, but I often use something similar in assembly when hyper-optimizing loops. The fastest memcpy-like loop structure I've found on x64 i
by nkurz 10y ago
I didn't look at the code, but I often use something similar in assembly when hyper-optimizing loops. The fastest memcpy-like loop structure I've found on x64 involves using a negative offset from the end of the region, which is then incremented until it hits zero.
The advantage of this construct is that you can use the flags set by the increment to test for loop termination, rather than needing an additional comparison. The problem in C is that the compiler tends to "unoptimize" it for you after seemingly innocuous changes.
Anyway, the loop ends up looking something like this:
char *end = start + size;
size_t neg = -size;
do {
register = *(end + neg);
process(register);
neg += advance;
} while (neg);
For certain loops this construct shaves off 1 cycle per iteration, at the cost of ~1 cycle of initial setup cost. I'm wagering that he was doing something similar, but just kept the name "size" after the negation, rather than switching to "neg" as I did here.
- DblPlusUngood 10y ago> The advantage of this construct is that you can use the flags set by the increment to test for loop termination, rather than needing an additional comparison. I don't understand your optimization. ZF is also set for dec, so why not just use dec and not negate the size?
- nkurz 10y agoSticking with a positive value and using dec or sub works if you just have a loop counter or if it's acceptable to process the data in your buffer backwards, but switching to negative lets you go through the buffer in standard ascending order. Sometimes data dependencies require this, and sometimes ascending works better for prefetching.
- _nalply 10y agoYour theory sounds way better than mine.