zoecarver
zoecarver

Reputation: 6403

Segmentation fault - accessing array elements passed from LLVM IR code

I have a program that works fine when I run it using C++ however, when I call it from my LLVM IR code it does not work.

Function (library/library.cpp)

extern "C" DLLEXPORT double *DOT(double A[3][3], double B[3][3]) {
  std::cout << A[0][0] << std::endl;
...
}

LLVM IR (out.ll)

declare [3 x double] @DOT([3 x [3 x double]], [3 x [3 x double]])
...
%a1 = load [3 x [3 x double]], [3 x [3 x double]]* %a
%b2 = load [3 x [3 x double]], [3 x [3 x double]]* %b
%calltmp = call [3 x double] @DOT([3 x [3 x double]] %a1, [3 x [3 x double]] %b2)

I did not include the full program to save space but, if it is useful just ask and I will update the question.

Error (built)

[1]    3086 segmentation fault  ./built

I use the following command to compile the code:

clang++ library/library.cpp out.ll -o built

Info

This works:

std::cout << A[0] << std::endl; // 0x1

This does not:

std::cout << A[0][0] << std::endl;

Upvotes: 1

Views: 111

Answers (1)

sepp2k
sepp2k

Reputation: 370172

You declared your function with the wrong signature:

First, your function returns a pointer to double, not an array of doubles. This is pretty clear to see as the C++ code literally says double * as the return type.

The less obvious problem is that the types of your arguments are "pointer to array of double", not "array of array to double". This is because C and C++ do not support function parameters of array types, but decided, quite confusingly, to still accept the syntax for array types in parameter lists, but simply treat it as if it declared a pointer. So double A[3][3] in a parameter list (and only there) is just a more confusing way to write double (*A)[3].

So in conclusion your declaration should be:

declare double* @DOT([3 x double]*, [3 x double]*)

Accordingly, you should also change your calling code to call @DOT with pointers of the right type.

Upvotes: 2

Related Questions