Skip to content

feat: doc for llvm-passes #4892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/kr.tree
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
<toc-element toc-title="Reference and tips">
<toc-element toc-title="Target support" topic="native-target-support.md"/>
<toc-element toc-title="Improving compilation time" topic="native-improving-compilation-time.md"/>
<toc-element toc-title="Customizing LLVM passes" topic="native-llvm-passes.md"/>
<toc-element toc-title="License files" topic="native-binary-licenses.md"/>
<toc-element topic="native-faq.md"/>
</toc-element>
Expand Down
7 changes: 6 additions & 1 deletion docs/topics/native/native-improving-compilation-time.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ This feature is [Experimental](components-stability.md#stability-levels-explaine
add the `kotlin.incremental.native=true` option to your `gradle.properties` file. If you face any problems,
create an [issue in YouTrack](https://kotl.in/issue).

### Customize LLVM
<primary-label ref="advanced"/>

If the above tips do not solve your problems, consider [customizing the LLVM backend](native-llvm-passes.md).

## Windows configuration

Windows Security may slow down the Kotlin/Native compiler. You can avoid this by adding the `.konan` directory,
which is located in `%\USERPROFILE%` by default, to Windows Security exclusions. Learn how to [add exclusions to Windows Security](https://support.microsoft.com/en-us/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26).
which is located in `%\USERPROFILE%` by default, to Windows Security exclusions. Learn how to [add exclusions to Windows Security](https://support.microsoft.com/en-us/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26).
89 changes: 89 additions & 0 deletions docs/topics/native/native-llvm-passes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
[//]: # (title: Tips for customizing LLVM backend)
<primary-label ref="advanced"/>

The Kotlin/Native compiler uses [LLVM](https://llvm.org/) to optimize and generate binary executables for different
target platforms. A noticeable part of the compilation time is also spent in LLVM, and for large apps, this can end up
taking an unacceptably long time.

You can customize how Kotlin/Native uses LLVM and adjust the list of optimization passes.

## Examine the build log

Let's take a look at the build log to understand how much compilation time is spent on LLVM optimization passes:

1. Add the `-Xprofile-phases` compiler argument to your build.
2. Run the `linkRelease*` task. By default, a release binary compilation runs the same LLVM optimization passes that clang
would for C++.
3. Examine the generated output in the build log. The log can contain tens of thousands of lines; sections with LLVM
profiling are at the end.

Here is an excerpt from such a run of a simple Kotlin/Native program:

```none
Frontend: 275 msec
PsiToIr: 1186 msec
...
... 30k lines
...
LinkBitcodeDependencies: 476 msec
StackProtectorPhase: 0 msec
MandatoryBitcodeLLVMPostprocessingPhase: 2 msec
===-------------------------------------------------------------------------===
Pass execution timing report
===-------------------------------------------------------------------------===
Total Execution Time: 6.7726 seconds (6.7192 wall clock)

---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
0.9778 ( 22.4%) 0.5043 ( 21.0%) 1.4821 ( 21.9%) 1.4628 ( 21.8%) InstCombinePass
0.3827 ( 8.8%) 0.2497 ( 10.4%) 0.6323 ( 9.3%) 0.6283 ( 9.4%) InlinerPass
0.2815 ( 6.4%) 0.1792 ( 7.5%) 0.4608 ( 6.8%) 0.4555 ( 6.8%) SimplifyCFGPass
...
0.6444 (100.0%) 0.5474 (100.0%) 1.1917 (100.0%) 1.1870 (100.0%) Total

ModuleBitcodeOptimization: 8118 msec
...
LTOBitcodeOptimization: 1399 msec
...
```

The Kotlin/Native compiler runs two separate sequences of LLVM optimizations: the module passes and the link-time
passes. For a typical compilation, the two pipelines are run back to back, and the only real distinction is in which
LLVM optimization passes they run.

In the log above, the two LLVM optimizations are `ModuleBitcodeOptimization` and `LTOBitcodeOptimization`. The formatted
tables are the optimizations' output with timing for each pass.

## Customize LLVM optimization passes

If one of the passes above seems unreasonably long, you can skip it. However, this might hurt runtime performance, so
you should check for changes in the benchmarks' performance afterward.

There is no direct way to disable a given pass. However, you can provide a new list of passes to run by using the
following compiler options:

| **Option** | **Default value for release binary** |
|------------------------|--------------------------------------|
| `-Xllvm-module-passes` | `"default<O3>"` |
| `-Xllvm-lto-passes` | `"internalize,globaldce,lto<O3>"` |

The default values are unfolded to a long list of actual passes, from which you need to exclude the undesired ones.

To get the list of actual passes, run the [`opt`](https://llvm.org/docs/CommandGuide/opt.html) tool, which is
automatically downloaded with the LLVM distribution to the
`~/.konan/dependencies/llvm-{VERSION}-{ARCH}-{OS}-dev-{BUILD}/bin` directory.

For example, to get the list of the link-time passes, run:

```bash
opt -print-pipeline-passes -passes="internalize,globaldce,lto<O3>" < /dev/null
```

This outputs a warning and a long list of passes, which depends on the LLVM version.

There are two differences between the list of passes from the `opt` tool and the passes that Kotlin/Native
compiler actually runs:

* Since `opt` is a debug tool, it includes one or more `verify` passes, which are not normally run.
* Kotlin/Native disables the `devirt` passes since the Kotlin compiler already does them itself.

After disabling any passes, always rerun performance tests to check if the runtime performance degradation is acceptable.