在LLVM IR中提取数组索引变量和for循环迭代变量

问题描述 投票:0回答:1

我想编写一个 LLVM 传递来获取程序的数组索引信息和 for 循环索引信息。考虑以下访问二维数组的非常简单的程序。

int main()
{
    int i, j, arr2d[5][10];
    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 10; j++)
        {
            arr2d[i][j] = i * j;
        }
    }
    return 0;
}

数组由变量 i 和 j 索引。循环也由变量 i 和 j 索引。如果我有程序的 IR 文件,是否可以从 LLVM 传递中知道数组索引变量和循环控制变量?

从 IR 文件看来,这些值可以回溯到 i 和 j。但不知道如何一次性完成?

例如,在程序的IR文件中可以看到它可能会像这样回溯:

GEP 计算最终左值:

%21 = getelementptr inbounds [10 x i32], [10 x i32]* %18, i64 0, i64 %20

追踪j:

%20 = sext i32 %19 to i64
%19 = load i32, i32* %3, align 4
%3 = alloca i32, align 4 // Allocation of j

追踪我:

%18 = getelementptr inbounds [5 x [10 x i32]], [5 x [10 x i32]]* %4, i64 0, i64 %17
%17 = zext i32 %16 to i64
%16 = load i32, i32* %2
%2 = alloca i32, align 4 // Allocation of i

数组索引和循环索引是否可以回溯到%2和%3?这个问题展示了如何获取常量索引而不是变量索引。

llvm llvm-ir
1个回答
0
投票

可能吗?是的。大多数情况下。

在 IR 中,循环通常如下所示:有四个块,我将其称为 a、b、c 和 d。

块 a 在循环之前。 a 通常设置循环变量的初始值,但重要的是 a 在循环之前。用 LLVM 的话说,它支配循环,这意味着如果循环被执行,那么 a 就被执行了。

b 块包含循环测试。它通常包含一个 phi,它是用于控制/结束循环的变量的当前值,例如本例中的 i 和 j,并且以条件分支到 c 和 d 结束。

块 c 包含循环体。它以 b 的分支结束。

块 d 是循环之后执行的任何内容。它与循环无关,只是了解它可以帮助您理解总体结构。许多循环包含比这更多的块(例如,如果有内部循环,c 将是几个块),但这是一般想法。 LLVM 包含可以帮助您找到这些的代码,即使在复杂的情况下,也可以查看 LoopInfo 的一些用法来查找一些示例。

b 块是您的案例中有趣的一个。结束它的条件分支包含一个操作数,该操作数以某种方式从同一块中的 phi 生成。可能有多个 phi,在这种情况下,循环变量就是最终通向分支的 phi。 (如果分支中涉及多个 phi,那么您手头上有一些不寻常的代码,这根本不是不寻常的。在处理一百个常见的循环之前,您将遇到一个不寻常的循环,并且必须做出决定该怎么办。)

查找循环变量可能涉及对用于在条件分支中生成条件操作数的值进行递归搜索。这并不像听起来那么复杂。你可能会看到,分支中的条件操作数是同一块中的一条指令,它是一个加载,而加载的指针操作数是同一块中的另一条指令,它是一个gep,而gep的索引操作数是 phi。这样的连锁店很典型。

它可能有点复杂,但这应该足以编写足够的代码来通过第一个单元测试。 (LoopInfo 提供的信息可帮助您解决复杂问题,例如

int g=0;while(e && e->f[g++]){…}
中的空指针检查,您可以稍后将其添加为单元测试,但不能立即添加。)

© www.soinside.com 2019 - 2024. All rights reserved.