Почему LLVM выдает ошибку "аргументы несовместимого типа" при создании массива?
Я использую LLVM и библиотеку llvmpy.
Моя цель - создать что-то похожее на следующий код C:
int a[] = {1, 2};
int b[] = {1, 2, 3};
int c[] = {1};
int* ptrs[] = {a, b, c};
Ниже приводится вывод IR из приведенной выше выдержки:
%1 = alloca i32, align 4
%a = alloca [2 x i32], align 4
%b = alloca [3 x i32], align 4
%c = alloca [1 x i32], align 4
%ptrs = alloca [3 x i32*], align 16
store i32 0, i32* %1
%2 = bitcast [2 x i32]* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast ([2 x i32]* @main.a to i8*), i64 8, i32 4, i1 false)
%3 = bitcast [3 x i32]* %b to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* bitcast ([3 x i32]* @main.b to i8*), i64 12, i32 4, i1 false)
%4 = bitcast [1 x i32]* %c to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* bitcast ([1 x i32]* @main.c to i8*), i64 4, i32 4, i1 false)
%5 = getelementptr inbounds [3 x i32*]* %ptrs, i64 0, i64 0
%6 = getelementptr inbounds [2 x i32]* %a, i32 0, i32 0
store i32* %6, i32** %5
%7 = getelementptr inbounds i32** %5, i64 1
%8 = getelementptr inbounds [3 x i32]* %b, i32 0, i32 0
store i32* %8, i32** %7
%9 = getelementptr inbounds i32** %7, i64 1
%10 = getelementptr inbounds [1 x i32]* %c, i32 0, i32 0
store i32* %10, i32** %9
%11 = load i32* %1
ret i32 %11
Мне кажется, я понял это достаточно хорошо - он просто захватывает указатели на заголовок каждого отдельного массива, а затем использует getelementptr
пройтись по массиву хранения и вставить каждый указатель.
Вот то, что я придумал в llvmpy
:
pointers = []
for array in arrays:
# Store each of the { 1, ... } arrays in memory.
type = Type.array(Type.int(), len(arrays))
ptr = builder.alloca_array(type, Constant.int(Type.int(), len(arrays)))
builder.store(array, ptr)
# And keep track of their pointers.
indices = [ Constant.int(Type.int(), 0), Constant.int(Type.int(), 0) ]
head = builder.gep(ptr, indices)
pointers.append(head)
# Finally, construct the array to hold the pointers.
type = Type.pointer(Type.int())
array = Constant.array(type, pointers)
return array
Но я получаю ошибку:
include / llvm / Support / Casting.h: 219: имя типа cast_retty::ret_type llvm::cast_or_null(llvm::Value *): утверждение `isa(Val) && " аргумент cast_or_null() несовместимого типа!"'не выполнено.
в строке, содержащей код:
array = Constant.array(type, pointers)
Когда я проверяю тип указателей и тип массива, они оба кажутся int32*
, Что я делаю неправильно? И является Value
универсальный заполнитель, который должен быть разыгран?
1 ответ
То, что вы делаете, эквивалентно написанию следующего, нелегального, IR:
%x = getelementptr ...
%y = getelementptr ...
%z = getelementptr ...
%array = [ i32* %x, i32* %y, i32* %z ]
Почему незаконно? Потому что вы пытаетесь создать постоянный массив (вы используете Constant
класс - так Constant.array
эквивалентно использованию []
синтаксис литерала массива выше), который содержит непостоянные значения (%x
, %y
а также %z
). Если вы хотите хранить эти указатели в массиве, вы должны alloca
сначала массив, потом store
каждый указатель по очереди внутри него.