14113
Joined 13 years ago
Joined 13 years ago
It's not strictly true to say that it's "being conservative". What is more correct is to say that floating point operations have different semantics to integer operations, and an optimisation that retains the semantics of an expression over integers may not do so when applied to an expression over integers. Hence, it may be possible to apply one optimisation to an integer expression, but applying that to a floating-point expression may result in a different program meaning.
C/C++ compilers give you a way out of this with the `--ffast-math` flag, which essentially allows compilers to relax the constraints on floating-point optimisation passes.
For an example of how this works in GCC, take a look here: https://gcc.gnu.org/wiki/FloatingPointMath
If you're solely interested in single-core performance, then I would agree that they are a good stress test, but I think for a processor that is being sold on it's parallelism, they are not a great benchmark.
I wish this was the case. Unfortunately, companies that work on non-Chromium browsers need to employ dedicated web compatibility teams to either a) help website users fix non-standard (i.e. Chrome only) HTML/CSS/JS, or b) replicate Chromium-like behaviour for specific (very popular) websites so that they work "correctly".
There's also the websites that deliberately block certain browsers which is what tools like "chrome-mask"[1] are built to solve.
[1] https://addons.mozilla.org/en-GB/firefox/addon/chrome-mask/
I accept that if you're extremely used to writing this style of C code, it might be something that you're used to, and understand implicitly. As a C++ engineer that infrequently comes across this precise pattern, having the precedence made explicit makes it much easier to understand.
block
statement (assignment)
expression
operator (dereference)
operator (post-increment)
variable
expression
variable *lwr = x; lwr++;
This could be be represented with something like this (and this is a very vague approximation of an AST): block
statement (assignment)
expression
operator (dereference)
variable
expression
variable
statement
expression
operator (post-increment)
variable
The second form, that looks this in the source: *lwr++ = x
might look like this in the AST: block
statement (assignment)
expression
operator (post-increment)
operator (dereference)
variable
expression
variable
If these two ASTs are to take the same form in the compilation pipeline, there needs to be some kind of pass that transforms one into the other.As for why the second form is faster (or rather, why the compiler can generate faster code): There is likely an optimisation pass somewhere in llvm that recognises a pattern that this fits into, which allows it to generate branchless instructions. For instance, in the second form, there is a pattern of:
operator (post-increment)
operator (dereference)
that might be recognised by a pass. In the former form, the two operators are far apart in the tree, so a pass would have to "look further" to match them up. A single pass likely won't do this, either for (compiler) performance reasons, or for correctness reasons.Finding which pass that is can be non-trivial, as it's more than a matter of enabling individual passes until one works. It might be that an earlier pass does some code reshaping that allows the relevant pass to work. My suggestion would be to dump the llvm ir at the end, and find the rough pattern that you're looking for, then re-run the compilation with `-mllvm -print-after-all` to see what the IR looks like after each pass, and then manually "look back" until you can't see the pattern any more.
cmp ecx, 1
je .LBB0_3
vs cmp ecx, 2
jne .LBB0_2
LBB0_3 and LBBO_2 were the same in both outputs (up to alpha renaming).Oddly, both sources seemed to be quite sensitive to match switch and enum reordering, resulting in very different generated code. Possibly something to look into further.