2016-03-17 8 views
1

Итак, у меня есть код, который генерирует LLVM IR. После тщательного прочтения руководства мне удалось написать функцию, которая записывает код вроде следующего:Каков правильный способ интеграции кода LLVM с кодом C?

define [1 x i32] @topLevel([3 x i32] %inputArray, 
    [1 x i32] %returnArray) { 
bb0:   
    %node_1 = extractvalue [3 x i32] %inputArray, 0 
    %node_2 = extractvalue [3 x i32] %inputArray, 1 
    %node_3 = extractvalue [3 x i32] %inputArray, 2 
    %node_8 = and i32 %node_1, %node_2 
    %0 = xor i32 %node_8, 1 
    %node_7 = and i32 %node_3, %0 
    %1 = xor i32 %node_3, 1 
    %node_6 = and i32 %1, %node_8 
    %2 = xor i32 %node_6, 1 
    %3 = xor i32 %node_7, 1 
    %node_5 = and i32 %2, %3 
    %node_4 = xor i32 %node_5, 1 
    %4 = insertvalue [1 x i32] %returnArray, i32 %node_4, 0 
    ret [1 x i32] %4 
}   

Однако я получаю некоторые действительно случайные выходы, и я не могу понять, почему.

Итак, я написал некоторый тестовый код на C и попытался скомпилировать его вместе с предыдущей функцией, используя clang.

#include <stdio.h> 

int * topLevel(int*, int*); 

int main() { 
    int i[3] = {0, 0, 0}; 
    int o[1] = {0}; 
    int *r; 

    printf("sizeof(int) = %lu\n", sizeof(int)); 

    int a =0, b = 0,c=0; 
    for (a=0; a < 2; ++a) { 
    for(b=0; b < 2; ++b) { 
     for(c=0; c < 2; ++c) { 
     i[0] = a; 
     i[1] = b; 
     i[2] = c; 
     r = topLevel(i, o); 
     printf("i={%d, %d, %d} o={%d}\n", i[0], i[1], i[2], o[0]); 
     } 
    } 
    } 
} 

Я был действительно оптимистом, чтобы получить правильный результат. Мальчик, я был неправ.

То, что я ожидал, как результат:

sizeof(int) = 4 
i={0, 0, 0} o={0} 
i={0, 0, 1} o={1} 
i={0, 1, 0} o={0} 
i={0, 1, 1} o={1} 
i={1, 0, 0} o={0} 
i={1, 0, 1} o={1} 
i={1, 1, 0} o={1} 
i={1, 1, 1} o={0} 

Однако выход это один, который является фальшивкой:

sizeof(int) = 4 
i={0, 0, 0} o={0} 
i={0, 0, 1} o={0} 
i={0, 1, 0} o={0} 
i={0, 1, 1} o={0} 
i={1, 0, 0} o={0} 
i={1, 0, 1} o={0} 
i={1, 1, 0} o={0} 
i={1, 1, 1} o={0} 

Что я делаю неправильно? Прости. Я хотел бы задать более конкретный вопрос, но я потерян. Я не знаю, с чего начать искать ошибки.

ответ

1

Оказалось, что проблема не связана с моим кодом с кодом LLVM IR.

Ответ проще: EXTRACTVALUE и стоимостные вставки инструкции не предназначены для работы с массивами в памяти . Они предназначены для работы с массивом в регистрах.

Чтобы проиллюстрировать (и проверить) возникшую у меня проблему, я написал 2 простых кода.

Этот первый предназначен для работы с массивами в регистрах и не будет работать с массивами C. Когда он вызывается кодом C, он будет производить мусор:

define [1 x i32] @workWithRegisterArrays([1 x i32] %inputArray, 
             [1 x i32] %returnArray) { 
bb0:   
    %0 = extractvalue [1 x i32] %inputArray, 0 
    %1 = insertvalue [1 x i32] %returnArray, i32 %0, 0 
    ret [1 x i32] %1 
}   

Этот второй код, копирует первый элемент массива из первого Parametr к первому элементу массива из второго параметра. Чтобы работать с массивами в C, вам нужно использовать getelementptr для поиска индекса, а также операции загрузки и хранения для фактического выполнения доступа к памяти.

define void @workWithMemoryArrays(i32* %inputArray, 
            i32* %returnArray) { 
bb0:   

    %elem_in = getelementptr inbounds i32, i32* %inputArray, i32 0 
    %elem_ret = getelementptr inbounds i32, i32* %returnArray, i32 0 
    %val  = load i32, i32* %elem_in 
    store i32 %val, i32* %elem_ret 
    ret void 
}