37 karma · joined June 22, 2015
Can you provide a link to the source code?
GCC uses a separate representation (RTL) for their backend that is not in SSA form [2]. LLVM stays in SSA form for some backend phases but lowers the SSA form before register allocation (as also mentioned in [1]).
I took a quick look at the C2 and the Graal compiler. C2 seems to use LLVM's code generator (and thus lowers SSA before register allocation) but Graal seems to support SSA-based register allocation, nice.
[1] https://news.ycombinator.com/item?id=11210948
[2] https://en.wikibooks.org/wiki/GNU_C_Compiler_Internals/GNU_C...
It's impossible to have one edge pointing to multiple reaching definitions.
I think having a decoupled spilling phase is nice feature of the SSA-based scheme. However, I don't say that LLVM (or GCC) should switch to the SSA-based scheme. I just appreciate that the Go compiler switched to the SSA-based scheme, because it may bring some new insights to the research community.
libfirm never goes out of SSA (since it uses a graph-based representation it's simply impossible: the data dependency edges need one target). It converts the programm to CSSA and assigns the same register to all phi operands. When finally emitting the program, phi nodes emit nothing.
I missed some references to corresponding papers in the source code. For instance, is the register allocator an implementation of "Linear Scan Register Allocation on SSA Form" [2]?
Also some facts mention in comments [3] are a bit scary but I guess this will be resolved over time.
[1] http://pp.ipd.kit.edu/firm/
[2] http://www.christianwimmer.at/Publications/Wimmer10a/Wimmer1...
[3] https://github.com/golang/go/blob/master/src/cmd/compile/int...
[1] https://github.com/golang/go/blob/master/src/cmd/compile/int...
[2] http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun1...
Nevertheless, I agree that superoptimizers ofter find optimizations that are not considered by the compiler engineers. Another good example is the Optgen tool [1] that also identified missing (machine-independent) optimizations in all production compilers.
int eight(int a) { int b; if (a) { b = 1; } else { b = a; } b += 3; if (a) { return b + b; } else { return b + 5; } }
you duplicate the "b += 3;" but both branches can be optimized afterwards. In fact, the function always returns 8.
The goal of an optimization pass is to improve the performance of an average, and that's exactly what the IR superoptimization does.
Of course there a cases where preventing an IR optimization can trigger a more powerful one and the resulting code gets better. However, in general I would say it's the other way around: Performing the IR superoptimization leads to better code quality.
In summary, no approache subsumes the other one. Thus, it is worthwhile to have them both.
The LLVM implementation is more mature from a software point of view, but libFirm's implementation supports more PBQP reductions, and thus may find a better PBQP solution.