I've been trying to tackle arrays in LLVM, but I am not able to access elements at a non-constant index. Constant indexing works correctly. When I run my program, it just immediately exits. In my specific example, I am trying to use a for loop to set the elements for 0 to 5 to their respective value. This is what LLVM outputs (with optimizations disabled):
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
}
The most important block in which the array access happens, is body. This is how the code looks, to help with what's supposed to happen:
fun main() {
mut test: number[100]
for(i = 0, i < 5) {
test[i] = 5
}
print(test[0])
}
Print is an external function that is 100% tested and it works correctly. Print statements before the allocation don't seem to run either. If anyone notices anything wrong, it would be great! PS: in my language, all numbers are doubles, so i is a double too, that's why I'm casting it to an integer.
Edit: I compiled the same code using clang and c++, and it gave the following llvm output:
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
}
Which looks almost identical to what I have. I don't understand, why wouldn't this work...
Edit2: I've changed the base type of the array to char - i8, and then all of this works. I'm confused. I wonder if it has to do with the alignment? On clang-llvm, it's 16, at me, it's 8
store double 0.000000e+00, [100 x double]* %test, align 8
This looks ill-typed. %test
has the type [100 x double]**
, not [100 x double]*
(alloca T
will give you a pointer of type T*
) and, in any case, to store a single double you should have a pointer of type double*
.
As a piece of advice: If you're using the API, you should be calling verifyModule
on your module when you're finished creating it. It will tell you when your code is ill-formed (and if you're generating the code as text and then compiling with llc
, it should tell you the same) and will allow you to catch problems like this right away.