Skip to content
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

申领对WritingAnLLVMNewPMPass.md的翻译 #239

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
214 changes: 65 additions & 149 deletions sources/llvm/WritingAnLLVMNewPMPass.md
Original file line number Diff line number Diff line change
@@ -1,87 +1,50 @@
---
status: collected
status: translating
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我看你已经把翻译都放上来了,所以建议你直接修改status为translate

title: "Writing an LLVM Pass"
author: Linux Kernel Community
collector: tttturtle-russ
collected_date: 20240807
translator: JadeSnow7
translating_date: 20241116
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那这样也要改成translated_date

link: https://github.com/llvm/llvm-project/blob/main/llvm/docs/WritingAnLLVMNewPMPass.rst
---
# Writing an LLVM Pass
# 编写LLVM Pass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

英文两边如果是中文要加空格分割


::: program
opt
:::
## 简介 \-\-- 什么是LLVM Pass?

::: {.contents local=""}
:::
本文介绍了新的pass管理机制(New Pass Manager,NPM)。LLVM对代码生成管道使用的是传统的pass管理机制(Legacy Pass Manager)。详情参阅
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

英文两边如果是中文要加空格分割

`WritingAnLLVMPass` 和
`NewPassManager`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这是英文句号


## Introduction \-\-- What is a pass?
LLVM pass框架是LLVM系统中一个非常重要的组成部分,因为大多数编译器最值得关注的部分都在LLVM pass上。Pass执行着编译器的各种转换和优化工作,它们提供这些转换工作所需要的分析结果,并且最重要的是,它们为编译器代码提供了一种组织技术。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

英文两边如果是中文要加空格分割。请全文进行检测,如果两边是其他符号,可以参考Wiki 中的中文翻译指北来确认


:::: warning
::: title
Warning
:::
与传统pass管理器下的pass不同,传统pass管理器通过继承定义pass接口,而新pass管理器下的pass则依赖于基于概念的多态性,这意味着没有显式的接口(有关详细信息,请参见 `PassManager.h` 中的注释)。所有LLVM pass都继承自CRTP混入 `PassInfoMixin<PassT>` 。pass应该有一个run()方法,该方法返回一个 `PreservedAnalyses` ,并接受某些IR单元以及一个分析管理器作为输入。例如,函数pass将具有如下方法:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRTP混入

mixin是CPP中的一个特殊的类,同时也是LLVM新一代Pass管理器的实现。这里是名词,而不是动词,我的建议是保留英语专有名词

`PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)` ;

This document deals with the new pass manager. LLVM uses the legacy pass
manager for the codegen pipeline. For more details, see
`WritingAnLLVMPass`{.interpreted-text role="doc"} and
`NewPassManager`{.interpreted-text role="doc"}.
::::
我们将向您展示如何构建一个pass,包括设置构建、创建pass,到执行和测试它。查看现有的pass总是学习细节的一个好方法。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass 前后要有空格


The LLVM pass framework is an important part of the LLVM system, because
LLVM passes are where most of the interesting parts of the compiler
exist. Passes perform the transformations and optimizations that make up
the compiler, they build the analysis results that are used by these
transformations, and they are, above all, a structuring technique for
compiler code.

Unlike passes under the legacy pass manager where the pass interface is
defined via inheritance, passes under the new pass manager rely on
concept-based polymorphism, meaning there is no explicit interface (see
comments in `PassManager.h` for more details). All LLVM passes inherit
from the CRTP mix-in `PassInfoMixin<PassT>`. The pass should have a
`run()` method which returns a `PreservedAnalyses` and takes in some
unit of IR along with an analysis manager. For example, a function pass
would have a
`PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);`
method.
## 快速开始 \-\-- 编写hello world

We start by showing you how to construct a pass, from setting up the
build, creating the pass, to executing and testing it. Looking at
existing passes is always a great way to learn details.

## Quick Start \-\-- Writing hello world
在这里,我们将介绍如何编写一个类似于“Hello World”的 Pass。这个“HelloWorld” Pass 的设计目的很简单,就是打印出正在编译的程序中所有非外部函数的名字。它不会对程序进行任何修改,仅仅是对其进行检查。

Here we describe how to write the \"hello world\" of passes. The
\"HelloWorld\" pass is designed to simply print out the name of
non-external functions that exist in the program being compiled. It does
not modify the program at all, it just inspects it.
下面的代码已经存在;您可以自由地创建一个不同名称的 Pass,并与 HelloWorld 源文件一起放置。

The code below already exists; feel free to create a pass with a
different name alongside the HelloWorld source files.

### Setting up the build {#writing-an-llvm-npm-pass-build}
### 设置构建 {#writing-an-llvm-npm-pass-build}

First, configure and build LLVM as described in
`GettingStarted`{.interpreted-text role="doc"}.
首先,按照《入门指南》中所述配置和构建 LLVM。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

保留原有格式


Next, we will reuse an existing directory (creating a new directory
involves messing around with more CMake files than we want). For this
example, we\'ll use `llvm/lib/Transforms/Utils/HelloWorld.cpp`, which
has already been created. If you\'d like to create your own pass, add a
new source file into `llvm/lib/Transforms/Utils/CMakeLists.txt`
(assuming you want your pass in the `Transforms/Utils` directory.
接下来,我们将重用一个已有的目录(创建一个新的目录会涉及比我们想要的更多的 CMake 文件操作)。在这个例子中,我们将使用 `llvm/lib/Transforms/Utils/HelloWorld.cpp` ,这个文件已经被创建好了。如果你想创建自己的 Pass,可以在 `llvm/lib/Transforms/Utils/CMakeLists.txt` 中添加一个新的源文件(假设你想把你的 Pass 放在 `Transforms/Utils` 目录下)。

Now that we have the build set up for a new pass, we need to write the
code for the pass itself.
现在我们已经为新的 Pass 设置好了构建环境,接下来我们需要编写 Pass 本身的代码。

### Basic code required {#writing-an-llvm-npm-pass-basiccode}
### 基本代码要求 {#writing-an-llvm-npm-pass-basiccode}

Now that the build is setup for a new pass, we just have to write it.
既然已经为新的 Pass 设置好了构建环境,我们现在只需要编写 Pass 的代码。

First we need to define the pass in a header file. We\'ll create
`llvm/include/llvm/Transforms/Utils/HelloWorld.h`. The file should
contain the following boilerplate:
首先,我们需要在一个头文件中定义这个 Pass。我们将创建 `llvm/include/llvm/Transforms/Utils/HelloWorld.h` 文件。该文件应包含以下样板代码:

``` c++
#ifndef LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
Expand All @@ -101,73 +64,46 @@ public:
#endif // LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
```

This creates the class for the pass with a declaration of the `run()`
method which actually runs the pass. Inheriting from
`PassInfoMixin<PassT>` sets up some more boilerplate so that we don\'t
have to write it ourselves.

Our class is in the `llvm` namespace so that we don\'t pollute the
global namespace.
这段描述说明了如何创建一个 Pass 类,并声明 run() 方法,该方法实际执行 Pass 的功能。通过继承 `PassInfoMixin<PassT>` ,我们可以避免亲自编写一些样板代码。我们的类位于 llvm 命名空间中,以避免污染全局命名空间。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和原文格式保持一致


Next we\'ll create `llvm/lib/Transforms/Utils/HelloWorld.cpp`, starting
with
接下来,我们将创建 llvm/lib/Transforms/Utils/HelloWorld.cpp 文件,并从以下内容开始:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和原文格式保持一致


``` c++
#include "llvm/Transforms/Utils/HelloWorld.h"
```

\... to include the header file we just created.

``` c++
using namespace llvm;
```
#include "llvm/Transforms/Utils/HelloWorld.h" // 包含我们刚刚创建的头文件

\... is required because the functions from the include files live in
the llvm namespace. This should only be done in non-header files.
using namespace llvm; // 因为包含文件中的函数位于 llvm 命名空间中,所以需要这条语句。这应该只在非头文件中使用。

Next we have the pass\'s `run()` definition:

``` c++
PreservedAnalyses HelloWorldPass::run(Function &F,
FunctionAnalysisManager &AM) {
errs() << F.getName() << "\n";
return PreservedAnalyses::all();
// Pass 的 `run` 方法定义
PreservedAnalyses HelloWorldPass::run(Function &F, FunctionAnalysisManager &AM) {
errs() << F.getName() << "\n"; // 打印函数名到标准错误输出
return PreservedAnalyses::all(); // 返回值表示所有的分析(例如支配树)在该 Pass 之后仍然有效,因为我们没有修改任何函数
}
```

\... which simply prints out the name of the function to stderr. The
pass manager will ensure that the pass will be run on every function in
a module. The `PreservedAnalyses` return value says that all analyses
(e.g. dominator tree) are still valid after this pass since we didn\'t
modify any functions.
该代码简单地将函数的名称打印到标准错误输出(stderr)。pass manager将确保这个pass会在模块中的每个函数上运行。`PreservedAnalyses` 的返回值表示所有分析(例如支配树)在此pass之后仍然有效,因为我们没有修改任何函数。

That\'s it for the pass itself. Now in order to \"register\" the pass,
we need to add it to a couple places. Add the following to
`llvm/lib/Passes/PassRegistry.def` in the `FUNCTION_PASS` section
这就是该pass本身的内容。现在,为了“注册”这个 Pass,我们需要在几个地方添加一些代码。
在 `llvm/lib/Passes/PassRegistry.def` 中添加 Pass
`llvm/lib/Passes/PassRegistry.def` 文件的 FUNCTION_PASS 部分添加以下内容:

``` c++
FUNCTION_PASS("helloworld", HelloWorldPass())
```

\... which adds the pass under the name \"helloworld\".
这将 Pass 注册为名为 `"helloworld"` 的函数级 Pass。

`llvm/lib/Passes/PassRegistry.def` is #include\'d into
`llvm/lib/Passes/PassBuilder.cpp` multiple times for various reasons.
Since it constructs our pass, we need to also add the proper #include in
`llvm/lib/Passes/PassBuilder.cpp`:
在 `llvm/lib/Passes/PassBuilder.cpp` 中包含头文件
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

由于不同的原因,llvm/lib/Passes/PassBuilder.cpp 包含了多次 llvm/lib/Passes/PassRegistry.def。由于其负责构建我们的 pass,所以我们也需要在 llvm/lib/Passes/PassBuilder.cpp 包含正确的头文件。

由于 `llvm/lib/Passes/PassRegistry.def` 被多次包含在 `llvm/lib/Passes/PassBuilder.cpp` 中,我们需要在 `PassBuilder.cpp` 中添加正确的 `#include` 语句:

``` c++
#include "llvm/Transforms/Utils/HelloWorld.h"
```

This should be all the code necessary for our pass, now it\'s time to
compile and run it.

### Running a pass with `opt`
现在我们已经完成了 Pass 的所有必要代码,接下来是编译和运行它。
### 使用 `opt` 运行pass

Now that you have a brand new shiny pass, we can build
`opt`{.interpreted-text role="program"} and use it to run some LLVM IR
through the pass.
现在你已经有了一个全新的pass,我们可以构建 `opt`并使用它将一些 LLVM IR 代码通过该pass处理。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opt后面与中文要有空格


``` console
$ ninja -C build/ opt
Expand All @@ -190,12 +126,9 @@ bar

Our pass ran and printed the names of functions as expected!

### Testing a pass
### 测试 Pass

Testing our pass is important to prevent future regressions. We\'ll add
a lit test at `llvm/test/Transforms/Utils/helloworld.ll`. See
`TestingGuide`{.interpreted-text role="doc"} for more information on
testing.
测试我们的 Pass 非常重要,以防止将来出现回归问题。我们将在 llvm/test/Transforms/Utils/helloworld.ll 添加一个 lit 测试。有关测试的更多信息,请参阅《测试指南》。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和原文格式保持一致


``` llvm
$ cat llvm/test/Transforms/Utils/helloworld.ll
Expand All @@ -213,15 +146,14 @@ define void @bar() {
}

$ ninja -C build check-llvm
# runs our new test alongside all other llvm lit tests
# 运行我们的新测试以及其他所有的 `LLVM lit` 测试
```

## FAQs
## 常见问题解答 (FAQs)

### Required passes
### 必需的 Pass

A pass that defines a static `isRequired()` method that returns true is
a required pass. For example:
一个定义了静态 `isRequired()` 方法并返回 `true` 的 Pass 被认为是必需的 Pass。例如:

``` c++
class HelloWorldPass : public PassInfoMixin<HelloWorldPass> {
Expand All @@ -232,68 +164,52 @@ public:
};
```

A required pass is a pass that may not be skipped. An example of a
required pass is `AlwaysInlinerPass`, which must always be run to
preserve `alwaysinline` semantics. Pass managers are required since they
may contain other required passes.
必需的 Pass 是指不能被跳过的 Pass。例如,`AlwaysInlinerPass` 是一个必需的 Pass,因为它必须始终运行以保持 `alwaysinline` 语义。Pass 管理器也是必需的,因为它们可能包含其他必需的 Pass。

An example of how a pass can be skipped is the `optnone` function
attribute, which specifies that optimizations should not be run on the
function. Required passes will still be run on `optnone` functions.
一个 Pass 可能被跳过的例子是 `optnone` 函数属性,它指定不应该对该函数运行优化。然而,即使对于带有 `optnone` 属性的函数,必需的 Pass 仍然会被运行。

For more implementation details, see
`PassInstrumentation::runBeforePass()`.
有关更多实现细节,请参阅 `PassInstrumentation::runBeforePass()`。

### Registering passes as plugins
### 注册 Pass 插件

LLVM provides a mechanism to register pass plugins within various tools
like `clang` or `opt`. A pass plugin can add passes to default
optimization pipelines or to be manually run via tools like `opt`. For
more information, see `NewPassManager`{.interpreted-text role="doc"}.
LLVM 提供了一种机制,可以在诸如 clang 或 opt 等工具中注册 Pass 插件。Pass 插件可以将 Pass 添加到默认的优化管道中,或者通过像 opt 这样的工具手动运行。更多详细信息,请参阅 `NewPassManager` 文档。

Create a CMake project at the root of the repo alongside other projects.
This project must contain the following minimal `CMakeLists.txt`:
创建 CMake 项目
在仓库根目录下创建一个新的 CMake 项目,与其他项目并列。该项目必须包含以下最小的 `CMakeLists.txt` 文件:

``` cmake
add_llvm_pass_plugin(MyPassName source.cpp)
```

See the definition of `add_llvm_pass_plugin` for more CMake details.

The pass must provide at least one of two entry points for the new pass
manager, one for static registration and one for dynamically loaded
plugins:

- `llvm::PassPluginLibraryInfo get##Name##PluginInfo();`
- `extern "C" ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() LLVM_ATTRIBUTE_WEAK;`
Pass 必须至少提供两个入口点之一,一个用于静态注册,另一个用于动态加载插件:

Pass plugins are compiled and linked dynamically by default. Setting
`LLVM_${NAME}_LINK_INTO_TOOLS` to `ON` turns the project into a
statically linked extension.
- llvm::PassPluginLibraryInfo get##Name##PluginInfo();
- extern "C" ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() LLVM_ATTRIBUTE_WEAK;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

与原文格式一致

Pass 插件默认是动态编译和链接的。将 `LLVM_${NAME}_LINK_INTO_TOOLS` 设置为 ON 可以将项目转换为静态链接扩展。

For an in-tree example, see `llvm/examples/Bye/`.
对于树中的例子,可以参考 `llvm/examples/Bye/`.

To make `PassBuilder` aware of statically linked pass plugins:
使 PassBuilder 获取静态链接的 Pass 插件:

``` c++
// Declare plugin extension function declarations.
// 声明插件扩展函数声明
#define HANDLE_EXTENSION(Ext) llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
#include "llvm/Support/Extension.def"

...

// Register plugin extensions in PassBuilder.
// PassBuilder 中注册插件扩展
#define HANDLE_EXTENSION(Ext) get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);
#include "llvm/Support/Extension.def"
```

To make `PassBuilder` aware of dynamically linked pass plugins:
使 PassBuilder 获取动态链接的 Pass 插件:

``` c++
// Load plugin dynamically.
// 动态加载插件
auto Plugin = PassPlugin::Load(PathToPlugin);
if (!Plugin)
report_error();
// Register plugin extensions in PassBuilder.
Plugin.registerPassBuilderCallbacks(PB);
// PassBuilder 中注册插件扩展
Plugin->registerPassBuilderCallbacks(PB);
```