What types of optimization LLVM and what types of optimization should their interfaces perform?

Note: I noticed that this question is related to this, so if you are interested in my question, you should definitely read this other and its answers too.

I can think of some optimizations that the OOP interface could do, for example, creating temporary variables to store values ​​from const method calls that are called sequentially, without intermediary non-constant calls to this object, to cut off function calls, but I cannot think of much more. I would like to ask people to create a longer list of examples.

I ask about this because I want to create a small language as a pet project, and I'm not sure how to study this topic well. Maybe this is the case for the wiki community? A complete list of optimizations that LLVM does, and what interfaces should you do yourself, what do you think?

Oh, and I know that different interfaces can have very different needs, but my focus is on programming / OOP languages.

+6
source share
2 answers

It probably depends a lot on the language ... clang (C / C ++) is able to get away, doing very little in terms of optimization in the interface. The only optimization I can think of to execute the generated code is that clang does some devirtualization of C ++ methods in the interface. clang performs some other optimizations, such as constantly folding and removing dead code, but this is mainly done to speed up the compilation process, and not for the performance of the generated code.

EDIT: Actually, thinking about this a bit more, I just remembered another important optimization task for C ++: clang knows a few tricks to use copy constructors in C ++ (google for NRVO).

In some cases, the IR optimization language pack may be useful. There is a SimplifyLibCalls pass that knows how to optimize calls to the standard C library. For the new Objective-C language feature, the ARC clang places some ARC ends in the pipeline; which optimize calls for various Objective-C time functions.

In general, the implementation of optimizations in the interface is generally useful when the code has properties that cannot be encoded in IR (for example, C ++ objects have a constant pointer vtable). And in practice, you most likely want to first implement the creation of silent code and see if there are important cases that are not optimized. Optimizers can perform some surprisingly complex conversions.

See also http://llvm.org/docs/tutorial/LangImpl7.html ; using alloca is one thing that helps optimizers significantly, although this is not optimization itself.

+6
source

There are many, many optimizations that require only as much information as the SSA form used by LLVM. SSA provides many opportunities for analysis in terms of control flow, data flow.

On the other hand, the LLVM RISC language, so much high-level information is lost.

So, answer : front-end is able to perform optimization that requires loss of information after transferring to SSA. Examples that come to my mind:

  • preferred branching optimizations, some examples
    • languages. extensions, such as declaring preferred branches (in the Linux kernel, some branches are marked as almost always executable)
    • implementation of throw and trap exceptions
    • Co-processor implementation and dependency information
    Optimizations
  • which grow exponentially (for example, reduction from cycle, increase code size), you may need to apply to certain places in accordance with high-level information. - may be from the source code (front-end).
  • Functions of the language (it can be a reflection or something else) that translates into structures with a lot of pointers (for example, pointers to pointers ...) that can be difficult to guess at a low level - like at a low level, everything can look like access to the array, while it may have some height-level restrictions that can help with optimization.
  • complex functions can be performed differently depending on the equipment available. Let's take a few examples: matrix multiplication, FFT (compression and compression algorithms), arithmetic of large numbers, etc. Etc .... depending on the underlying equipment, it can be implemented in different ways to achieve maximum performance. After translating the material into LLVM, it can be very, very, very expensive (in terms of computational complexity) to change the implementation with more suitable equipment available. This is why the decision must be made by the interface when compiling to a lower level.

These are just a few ideas, a hope showing the kind of optimizations that might be involved.

+2
source

Source: https://habr.com/ru/post/896655/


All Articles