如何正确访问 LLVM 数组中的非常量索引?
How to correctly access a non-constant index in an LLVM array?
我一直在尝试处理 LLVM 中的数组,但我无法访问非常量索引处的元素。常量索引工作正常。当我 运行 我的程序时,它立即退出。在我的具体示例中,我尝试使用 for 循环将 0 到 5 的元素设置为它们各自的值。这是 LLVM 的输出(禁用优化):
Read function definition:define double @main() {
entry:
%i = alloca double, align 8
%test = alloca [100 x double]*, align 8
store double 0.000000e+00, [100 x double]* %test, align 8
store double 0.000000e+00, double %i, align 8
br label %loop
loop: ; preds = %latch, %entry
%i1 = phi double [ 0.000000e+00, %entry ], [ %nextvar, %latch ]
%i2 = load double, double %i, align 8
%cmptmp = fcmp ult double %i2, 5.000000e+00
%booltmp = uitofp i1 %cmptmp to double
%loopcond = fcmp one double %booltmp, 0.000000e+00
br i1 %loopcond, label %body, label %afterloop
body: ; preds = %loop
%i3 = load double, double %i, align 8
%casttmp = fptosi double %i3 to i32
%reftmp = getelementptr [100 x double], [100 x double]* %test, i32 0, i32 %casttmp
store double 5.000000e+00, double* %reftmp, align 8
br label %latch
latch: ; preds = %body
%i4 = load double, double %i, align 8
%nextvar = fadd double %i4, 1.000000e+00
store double %nextvar, double %i, align 8
br label %loop
afterloop: ; preds = %loop
%reftmp5 = getelementptr [100 x double], [100 x double]* %test, i32 0, i32 0
%loadtmp = load double, double* %reftmp5, align 8
%calltmp = call double @print(double %loadtmp)
ret double %calltmp
}
发生数组访问的最重要的块是正文。这是代码的样子,以帮助解决应该发生的事情:
fun main() {
mut test: number[100]
for(i = 0, i < 5) {
test[i] = 5
}
print(test[0])
}
打印是一个经过 100% 测试并且可以正常工作的外部函数。
分配前的打印语句似乎也不 运行。如果有人发现任何错误,那就太好了!
PS:在我的语言中,所有数字都是双精度数,所以 i 也是双精度数,这就是我将其转换为整数的原因。
编辑:我使用 clang 和 c++ 编译了相同的代码,它给出了以下 llvm 输出:
define dso_local noundef i32 @main() #0 !dbg !207 {
%1 = alloca i32, align 4
%2 = alloca [100 x double], align 16
%3 = alloca double, align 8
store i32 0, i32* %1, align 4
call void @llvm.dbg.declare(metadata [100 x double]* %2, metadata !210, metadata !DIExpression()), !dbg !215
call void @llvm.dbg.declare(metadata double* %3, metadata !216, metadata !DIExpression()), !dbg !218
store double 0.000000e+00, double* %3, align 8, !dbg !218
br label %4, !dbg !219
4: ; preds = %13, %0
%5 = load double, double* %3, align 8, !dbg !220
%6 = fcmp olt double %5, 5.000000e+00, !dbg !222
br i1 %6, label %7, label %16, !dbg !223
7: ; preds = %4
%8 = load double, double* %3, align 8, !dbg !224
%9 = load double, double* %3, align 8, !dbg !226
%10 = fptosi double %9 to i32, !dbg !226
%11 = sext i32 %10 to i64, !dbg !227
%12 = getelementptr inbounds [100 x double], [100 x double]* %2, i64 0, i64 %11, !dbg !227
store double %8, double* %12, align 8, !dbg !228
br label %13, !dbg !229
13: ; preds = %7
%14 = load double, double* %3, align 8, !dbg !230
%15 = fadd double %14, 1.000000e+00, !dbg !230
store double %15, double* %3, align 8, !dbg !230
br label %4, !dbg !231, !llvm.loop !232
16: ; preds = %4
%17 = getelementptr inbounds [100 x double], [100 x double]* %2, i64 0, i64 2, !dbg !235
%18 = load double, double* %17, align 16, !dbg !235
%19 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), double noundef %18), !dbg !236
%20 = load i32, i32* %1, align 4, !dbg !237
ret i32 %20, !dbg !237
}
看起来和我拥有的几乎一模一样。我不明白,为什么这行不通...
Edit2:我已将数组的基本类型更改为 char - i8,然后所有这些都有效。我很困惑。我想知道这是否与对齐有关?在 clang-llvm 上是 16,在我这里是 8
store double 0.000000e+00, [100 x double]* %test, align 8
这看起来 ill-typed。 %test
的类型是 [100 x double]**
,而不是 [100 x double]*
(alloca T
会给你一个 T*
类型的指针),并且在任何情况下,存储一个双精度你应该有一个 double*
.
类型的指针
作为一条建议:如果您正在使用 API,您应该在完成创建模块后调用 verifyModule
。当您的代码是 ill-formed 时它会告诉您(如果您将代码生成为文本然后使用 llc
进行编译,它应该会告诉您相同的信息)并且允许您捕获这样的问题马上。
我一直在尝试处理 LLVM 中的数组,但我无法访问非常量索引处的元素。常量索引工作正常。当我 运行 我的程序时,它立即退出。在我的具体示例中,我尝试使用 for 循环将 0 到 5 的元素设置为它们各自的值。这是 LLVM 的输出(禁用优化):
Read function definition:define double @main() {
entry:
%i = alloca double, align 8
%test = alloca [100 x double]*, align 8
store double 0.000000e+00, [100 x double]* %test, align 8
store double 0.000000e+00, double %i, align 8
br label %loop
loop: ; preds = %latch, %entry
%i1 = phi double [ 0.000000e+00, %entry ], [ %nextvar, %latch ]
%i2 = load double, double %i, align 8
%cmptmp = fcmp ult double %i2, 5.000000e+00
%booltmp = uitofp i1 %cmptmp to double
%loopcond = fcmp one double %booltmp, 0.000000e+00
br i1 %loopcond, label %body, label %afterloop
body: ; preds = %loop
%i3 = load double, double %i, align 8
%casttmp = fptosi double %i3 to i32
%reftmp = getelementptr [100 x double], [100 x double]* %test, i32 0, i32 %casttmp
store double 5.000000e+00, double* %reftmp, align 8
br label %latch
latch: ; preds = %body
%i4 = load double, double %i, align 8
%nextvar = fadd double %i4, 1.000000e+00
store double %nextvar, double %i, align 8
br label %loop
afterloop: ; preds = %loop
%reftmp5 = getelementptr [100 x double], [100 x double]* %test, i32 0, i32 0
%loadtmp = load double, double* %reftmp5, align 8
%calltmp = call double @print(double %loadtmp)
ret double %calltmp
}
发生数组访问的最重要的块是正文。这是代码的样子,以帮助解决应该发生的事情:
fun main() {
mut test: number[100]
for(i = 0, i < 5) {
test[i] = 5
}
print(test[0])
}
打印是一个经过 100% 测试并且可以正常工作的外部函数。 分配前的打印语句似乎也不 运行。如果有人发现任何错误,那就太好了! PS:在我的语言中,所有数字都是双精度数,所以 i 也是双精度数,这就是我将其转换为整数的原因。
编辑:我使用 clang 和 c++ 编译了相同的代码,它给出了以下 llvm 输出:
define dso_local noundef i32 @main() #0 !dbg !207 {
%1 = alloca i32, align 4
%2 = alloca [100 x double], align 16
%3 = alloca double, align 8
store i32 0, i32* %1, align 4
call void @llvm.dbg.declare(metadata [100 x double]* %2, metadata !210, metadata !DIExpression()), !dbg !215
call void @llvm.dbg.declare(metadata double* %3, metadata !216, metadata !DIExpression()), !dbg !218
store double 0.000000e+00, double* %3, align 8, !dbg !218
br label %4, !dbg !219
4: ; preds = %13, %0
%5 = load double, double* %3, align 8, !dbg !220
%6 = fcmp olt double %5, 5.000000e+00, !dbg !222
br i1 %6, label %7, label %16, !dbg !223
7: ; preds = %4
%8 = load double, double* %3, align 8, !dbg !224
%9 = load double, double* %3, align 8, !dbg !226
%10 = fptosi double %9 to i32, !dbg !226
%11 = sext i32 %10 to i64, !dbg !227
%12 = getelementptr inbounds [100 x double], [100 x double]* %2, i64 0, i64 %11, !dbg !227
store double %8, double* %12, align 8, !dbg !228
br label %13, !dbg !229
13: ; preds = %7
%14 = load double, double* %3, align 8, !dbg !230
%15 = fadd double %14, 1.000000e+00, !dbg !230
store double %15, double* %3, align 8, !dbg !230
br label %4, !dbg !231, !llvm.loop !232
16: ; preds = %4
%17 = getelementptr inbounds [100 x double], [100 x double]* %2, i64 0, i64 2, !dbg !235
%18 = load double, double* %17, align 16, !dbg !235
%19 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), double noundef %18), !dbg !236
%20 = load i32, i32* %1, align 4, !dbg !237
ret i32 %20, !dbg !237
}
看起来和我拥有的几乎一模一样。我不明白,为什么这行不通...
Edit2:我已将数组的基本类型更改为 char - i8,然后所有这些都有效。我很困惑。我想知道这是否与对齐有关?在 clang-llvm 上是 16,在我这里是 8
store double 0.000000e+00, [100 x double]* %test, align 8
这看起来 ill-typed。 %test
的类型是 [100 x double]**
,而不是 [100 x double]*
(alloca T
会给你一个 T*
类型的指针),并且在任何情况下,存储一个双精度你应该有一个 double*
.
作为一条建议:如果您正在使用 API,您应该在完成创建模块后调用 verifyModule
。当您的代码是 ill-formed 时它会告诉您(如果您将代码生成为文本然后使用 llc
进行编译,它应该会告诉您相同的信息)并且允许您捕获这样的问题马上。