Fernando Magno Quintao Pereira via llvm-dev
2020-Dec-29 20:02 UTC
[llvm-dev] Difference between clang -Oz and opt -Oz
Dear LLVMers, Why does opt -Oz and clang -Oz produce different codes? And could someone point me to some documentation/discussion that explains the differences between them? Regards, Fernando ------------------ Example ====== This program below ends up with 74 instructions with opt -Oz, and 22 instructions with clang -Oz (LLVM 10.0). Opt unrolls the loop 2x, whereas clang doesn't: void prefix_sum(int *src, int *dst, int N) { if (0 < N) { int i = 0; do { int tmp = 0; int j = 0; if (j < i) { do { tmp += src[j]; j++; } while (j < i); dst[i] = tmp; } i++; } while (i < N); } } I can see some optimizations with clang, that might not run with opt when I do: echo 'int;' | clang -xc -Oz - -o /dev/null -\#\#\# Would that be the reason for the difference?
Fāng-ruì Sòng via llvm-dev
2020-Dec-29 21:58 UTC
[llvm-dev] Difference between clang -Oz and opt -Oz
On Tue, Dec 29, 2020 at 12:02 PM Fernando Magno Quintao Pereira via llvm-dev <llvm-dev at lists.llvm.org> wrote:> > Dear LLVMers, > > Why does opt -Oz and clang -Oz produce different codes? And could > someone point me to some documentation/discussion that explains the > differences between them? > > Regards, > > Fernando > > ------------------ > > Example > ======> > This program below ends up with 74 instructions with opt -Oz, and 22 > instructions with clang -Oz (LLVM 10.0). Opt unrolls the loop 2x, > whereas clang doesn't: > > void prefix_sum(int *src, int *dst, int N) { > if (0 < N) { > int i = 0; > do { > int tmp = 0; > int j = 0; > if (j < i) { > do { > tmp += src[j]; > j++; > } while (j < i); > dst[i] = tmp; > } > i++; > } while (i < N); > } > } > > I can see some optimizations with clang, that might not run with opt when I do: > > echo 'int;' | clang -xc -Oz - -o /dev/null -\#\#\# > > Would that be the reason for the difference?clang -fno-legacy-pass-manager -S -emit-llvm -Oz populates the pipeline with PassBuilder::buildPerModuleDefaultPipeline If you use clang -fno-legacy-pass-manager -S -emit-llvm -Oz -Xclang -disable-llvm-passes opt -S -passes='default<Oz>' the behavior will be quite similar, though the variable naming will be different. --- If you invoke clang -fno-legacy-pass-manager -S -emit-llvm -O0 -Xclang -disable-llvm-passes followed by opt -S -passes='default<Oz>' calls clang -O0 adds optnone and (for most functions) noinline function attributes. (llvm::PassInstrumentation::runBeforePass<llvm::Function, ...> skips passes if the function has the optnone attribute.) clang -Oz adds optsize and minsize function attributes. noinline/optsize/minsize can affect optimization passes' heuristics. You can drop optnone with clang -fno-legacy-pass-manager -S -emit-llvm -O0 -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes however, noinline is still there. You can use -O1 clang -fno-legacy-pass-manager -S -emit-llvm -O1 -Xclang -disable-llvm-passes however, there is still a llvm.loop.unroll.disable metadata difference. clang -fno-legacy-pass-manager -S -emit-llvm -O2 -Xclang -disable-llvm-passes