简体   繁体   中英

What is the correct way to integrate LLVM code with C code?

So, I have some code that generates LLVM IR. After carefully reading the manual I managed to write a function that writes code like the following:

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
}        

However, I'm getting some really random outputs and I can't figure out WHY.

So I wrote some test code in C, and tried to compile it together with the previous function, using 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]);
      }
    }
  }
}

I was really optimist, that I would get a correct output. Boy, I was wrong.

What I expected as output is:

 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}

However, the output is this one, which is bogus:

 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}

What am I doing wrong? I'm sorry. I would like to ask a more concrete question, but I'm lost. I don't know where to start looking for errors.

It turned out that the problem was not linking my code with the LLVM IR code.

The answer is simpler: the extractvalue and insert value instructions are not intended to work with arrays in memory . They are meant for working with array in registers .

To illustrate (and test) the problem I was having, I wrote 2 simpler codes.

This first one is intended to work with arrays in registers and will not work with C arrays. When it is called by C code, it will produce garbage:

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
}        

This second code, copies the first element of the array from the first parametr to the first element of the array from the second parameter. To work with arrays in C, you need to use the getelementptr to find the index, and the load and store operations to actually perform the memory accesses.

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
}        

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM