c - 将 LLVM 代码与 C 代码集成的正确方法是什么?

标签 c llvm jit

所以,我有一些生成 LLVM IR 的代码。仔细阅读手册后,我设法编写了一个函数,其代码如下:

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}

我做错了什么?对不起。我想问一个更具体的问题,但我迷路了。我不知道从哪里开始寻找错误。

最佳答案

事实证明,问题不在于将我的代码与 LLVM IR 代码链接起来。

答案更简单:extractvalue 和 insert value 指令不打算处理内存中的数组。它们用于处理寄存器中的数组。

为了说明(和测试)我遇到的问题,我编写了 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
}        

这第二个代码,将数组的第一个元素从第一个参数复制到数组的第一个元素从第二个参数。 要在 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
}        

关于c - 将 LLVM 代码与 C 代码集成的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36070261/

相关文章:

java - 使用 int 然后递增它比同时做两者慢吗?

c - qsort 比较全零

c - Shell/C 信号量

c - LED 条形指示器在相邻值内闪烁以及如何避免这种情况(嵌入式 C)

c++ - 将空指针传递给 LLVM IRBuilder CreateCall

c++ - 使用现代 LLVM 运行默认优化管道

你能在 Clang 编译的 C 语言中内联 LLVM 位代码吗?

java - 在java中动态加载Jar文件

linux - 获取关于段错误或崩溃的指令指针(针对 x86 JIT 编译器项目)?

c - 为什么以下代码不允许我使用fgets获得用户输入,但不能使用scanf?