Why is x[i]=if faster than if... x[i]=

Viewed 129

This has me baffled/intrigued, why is this code

[see assembly]

void maxArray(double* x, double* y) {
    for (int i = 0; i < 65536; i++) {
        x[i] = ((y[i] > x[i]) ? y[i] : x[i]);
    }
}

...faster than this code?

[see assembly]

void maxArray(double* x, double* y) {
    for (int i = 0; i < 65536; i++) {
        if (y[i] > x[i]) x[i] = y[i];
    }
}

and for the record the resulting assembly in the first one is identical to the expanded version:

inline double fn(double a, double b) {
    if (a > b) {
        return a;
    } else {
        return b;
    }
}
void maxArray(double* x, double* y) {
    for (int i = 0; i < 65536; i++) {
        x[i] = fn(y[i], x[i]);
    }
}

[see assembly]

I get the difference. The first one is setting x[i] to a condition, and the middle is conditionally setting x[i]. Both have conditions though, so both have branches? Is it because the expanded if statement for the latter is optimized into the vector assembly max command, and the former is, for some reason not recognized as a max function?

gcc 10.3 x86_64 -Ofast -march=native

1 Answers

It should be clear from the generated assembly code. In the first case you get:

# x[i] = ((y[i] > x[i]) ? y[i] : x[i])

vmovupd ymm1, YMMWORD PTR [rsi+rax
vmaxpd  ymm0, ymm1, YMMWORD PTR [rdi+rax]
vmovupd YMMWORD PTR [rdi+rax], ymm0

While in the second case you get:

# if (y[i] > x[i]) x[i] = y[i];

vmovupd  ymm0, YMMWORD PTR [rsi+rax]
vcmppd   k1, ymm0, YMMWORD PTR [rdi+rax], 14
kortestb k1, k1
je       .L3
vmovupd  YMMWORD PTR [rdi+rax]{k1}, ymm0

As you can see in the first snippet, the compiler used the VMAXPD specialized instruction to compute the maximum of two double precision floating point values, without branching. In the second snippet though, there is a compare (VCMPPD) followed by a test (KORTESTB) and a branch (JE).

Related