【问题标题】:LLVM: access array parameter in a functionLLVM:访问函数中的数组参数
【发布时间】:2020-02-14 08:18:32
【问题描述】:

我正在尝试使用 LLVM C++ API 编写编译器,并且我正在尝试访问函数中的数组参数。

据我从 clang 的 IR 生成中可以看出,这两个代码具有不同的 LLVM IR 代码:

void foo(void) {
  int a[2];
  a[0] = 1;
  // %1 = getelementptr inbounds [2 x i32], [2 x i32]* %0, i32 0, i32 0
  // store i32 1, i32* %1
void bar(int a[]) {
  a[0] = 1;
  // store i32* %0, i32** %3, align 8
  // %4 = load i32*, i32** %3, align 8
  // %5 = getelementptr inbounds i32, i32* %4, i64 0
  // store i32 1, i32* %5, align 4

如果将数组作为参数传递,我需要先使用builder.CreateStore(),然后使用llvm::GetElementPtrInst::CreateInBounds() 来获取指向索引的指针。

但是,在编写编译器时,我使用 访问者模式 并将 a[0] = 1 之类的代码视为 assign expression。在访问树节点assign_expression时,需要判断是否需要load

有没有办法判断数组是局部定义的变量还是参数?

更新 1: 例如,在 C 中,如果一个函数是这样定义的:

void test(int a[]) {
  a[0] = 1;
}

a[0] = 1 对应的 LLVM C++ 代码如下:

for(auto arg = theFunction->arg_begin(); arg != theFunction->arg_end(); arg ++) {
  auto param = builder.CreateAlloca(llvm::Type::getInt32Ty(context)->getPointerTo());
  builder.CreateStore(arg, param);
}

// a[0] = 1
auto loaded_tmp = builder.CreateLoad(param);
auto value = llvm::GetElementPtrInst::CreateInBounds(tmp, {Const(0), Const(0)}, "", the_basic_block);

但是,当数组在本地定义时,不需要代码auto loaded_tmp = builder.CreateLoad(param);。所以我的问题是:我如何知道我是否需要CreateLoad

更新 2: clang 为以下 C 代码生成的 LLVM IR:

int h(int a[]) {
    a[0] = 1;
    a[1] = 2;
}

define dso_local i32 @h(i32*) #0 {
  %2 = alloca i32, align 4
  %3 = alloca i32*, align 8
  store i32* %0, i32** %3, align 8
  %4 = load i32*, i32** %3, align 8
  %5 = getelementptr inbounds i32, i32* %4, i64 0
  store i32 1, i32* %5, align 4
  %6 = load i32*, i32** %3, align 8
  %7 = getelementptr inbounds i32, i32* %6, i64 1
  store i32 2, i32* %7, align 4
  %8 = load i32, i32* %2, align 4
  ret i32 %8
}

在每个 store 之前都有一个 load 指令

【问题讨论】:

  • 您可以使用例如测试值if(isa<Argument>(value)){… 但我感觉你在做坏事。也许我的直觉是您不应该有时需要加载,它应该总是或都不需要。不管怎样,isa 就是你现在想要的。玩得开心。
  • @arnt 嗨,正如您在我的帖子中看到的,在将数组作为参数传递的函数中,生成的 IR clang 总是在 getelementptr 之前使用 store。但是,在本地定义数组的函数中,没有store。所以我认为需要检查代码a[0] = 1表达式中的数组是本地定义的还是作为参数传递的。感谢您的回复,我会尝试isa 看看是否有效。
  • 哦,等等,我现在明白了。并非 LLVM 需要 clang 所做的一切。有些东西是 LLVM 需要的,有些东西是 clang 自己的架构需要的,还有一些东西是使用中的 C/C++ ABI 需要的,最后 clang 做了很多其他方式也可以做到的事情。
  • @arnt 嗨,我认为我的问题与 LLVM 相关。我已经更新了我的帖子,你可以看看吗?
  • 我不在 C/C++ 编译器中工作。我的编译器永远不会生成这样的商店。在这里猜测一下:Clang 可以创建调试信息,说明该变量可以在某某位置被调试器访问,并发出额外的指令来存储调试器将在其中查找它的变量,以防万一最终会创建调试信息并使用了调试器。这是猜测,我再说一遍,猜测。

标签: c++ llvm llvm-c++-api


【解决方案1】:

有没有办法判断数组是局部定义的变量还是参数?

方法一:

像这样使用isa<Argument>

Analysis/BasicAliasAnalysis.cpp

 167   if (isa<Argument>(V))
 168     return true;

方法二:

使用LLVMGetFirstParam LLVMGetLastParamLLVMGetNextParam 的组合来查找值是否为参数。

见: https://github.com/llvm/llvm-project/blob/master/llvm/lib/IR/Core.cpp#L2456

【讨论】:

  • 感谢您的回复,不过在load指令之前有一个store函数,像下面的llvm ir:store i32* %0, i32** %3; %4 = load i32*, i32** %3,使得要加载的值不是功能...
  • 在分析之前运行 mem2reg 似乎应该摆脱冗余的存储+加载对。如果这不可能,那么您需要遵循 def-use 链直到最后一个,并使用 isa&lt;Argument&gt; 来发挥您的优势。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 2014-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多