News for hackers. Stuff that matters.
Re:Why is this C++ code faster than my hand-written assembly... by mikeash on Tuesday August 22, 2017 @12:09PM (#15073773)
Good nerdsnipe.

I decided to reject your conditions and replace them with my own, for no apparent reason. Mine has some of the redundancy you wish to eliminate, but the loop body is completely branchless, aside from the call to printf, of course, which we're apparently ignoring.

    #include <stdio.h>
    
    #define NUM "\x06" "%zu\n\0"
    #define FIZZ "\x07" "Fizz\n\0"
    #define BUZZ "\x07" "Buzz\n\0"
    
    const char *x =
        NUM
        NUM
        FIZZ
        NUM
        BUZZ
        FIZZ
        NUM
        NUM
        FIZZ
        BUZZ
        NUM
        FIZZ
        NUM
        NUM
        "\xa6" "FizzBuzz\n";
    
    void fizzbuzz(size_t upTo) {
        for(size_t i = 1; i <= upTo; i++) {
            printf(x + 1, i);
            x += *x;
        }
    }
    
    int main(int argc, char **argv) {
        fizzbuzz(100);
    }
Re:Why is this C++ code faster than my hand-written assembly... by pcordes on Tuesday August 22, 2017 @12:41PM (#15074087)
This is almost exactly the same as dmitryg's answer, using a state-machine the same way. It would compile to nearly the same code, but with an extra instruction to sign-extend the first char into a register before adding.

You did remove a level of indirection for the format-strings, though. You could have done that with

    struct state {
        int next;
        char fmt[6];
    };
Anyway, this has probably a 5 cycle loop-carried dependency chain on Skylake, from x += *x; compiling into a 4-cycle latency movsx rax, byte [rdi], then a 1-cycle add rdi, rax. (Or whatever registers the compiler picks).

If you'd stored pointers, you could have got it down to 4 cycles on Skylake for the load-use latency of a simple addressing mode ([reg + disp] where displacement is 0..2047).

Re:Why is this C++ code faster than my hand-written assembly... by raphlinus on Tuesday August 22, 2017 @12:28PM (#15073985)
Good candidate for most evil use of the assumption that char is signed. Incidentally, that's not going to be true on arm[0].

[0]: http://blog.cdleary.com/2012/11/arm-chars-are-unsigned-by-de...

Re:Why is this C++ code faster than my hand-written assembly... by mikeash on Tuesday August 22, 2017 @12:30PM (#15074002)
Haha, whoops! At least it's easy to fix.