0%

XSharp开发思路-Mutable Variable的LLVM IR生成

为什么需要 Mutable Variable?

由于 LLVM 内部优化等原因,LLVM IR 中的寄存器必须遵循SSA原则,即每个寄存器在 SSA 中仅被赋值一次。

但由于 XSharp 需要支持同个变量的多次引用,我们不能直接使用寄存器作为变量的存储单元。

幸运的是,LLVM 并不强制要求栈上的变量保持SSA,所以我们可以考虑将所有变量存放在栈上,

然后再通过 LLVM 提供的 Mem2Reg 工具或者 Pass 进行栈上内存的数据流分析,尽可能地将栈上的变量转换至寄存器上。

原文档在此:LLVM Mutable Variable

而针对 XSharp,我们可以写出如下代码

首先,LLVM 通过AllocaInst分配栈上的变量

1
2
3
4
5
6
7
8
VariableDeclarationNode* varNode = get();
TypeNode* typenode = varNode->type();

auto xsharpType = varNode->type();
auto llvmValue =
builder.CreateAlloca(
llvmTypeFor(xsharpType, context), nullptr,
varNode->name().toStdString());

同时,也可以把函数的参数存在栈上,以下复制自 LLVM Tutorial

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function *FunctionAST::codegen() {
...
Builder->SetInsertPoint(BB);

// Record the function arguments in the NamedValues map.
NamedValues.clear();
for (auto &Arg : TheFunction->args()) {
// Create an alloca for this variable.
AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName());

// Store the initial value into the alloca.
Builder->CreateStore(&Arg, Alloca);

// Add arguments to variable symbol table.
NamedValues[std::string(Arg.getName())] = Alloca;
}

if (Value *RetVal = Body->codegen()) {
...

并用PromoteMemoryToRegisterPass实现 Mem2Reg 的优化

1
2
// Promote allocas to registers.
functionPassManager->add(createPromoteMemoryToRegisterPass());

LLVM 也对性能等问题做了解释 content