I'm using the LLVM 3.3 C++-API. My code creates arrays using ConstantArray::get
, and multidimensional arrays with recursive code (the innermost rank is first converted to a vector of Constant*s, as above, then that is used to initialize the next-innermost rank, and so on).
I tried to optimize this by saying that if an array's element type satisfies the ConstantDataArray::isElementTypeCompatible
predicate, then it should be initialized using ConstantDataArray::get
.
Here's a more concrete example to show what I mean:
Say the array I want to create would be declared like this in C++:
int x[2][3] = {{1,2,3},{4,5,6}};
The innermost rank (type int[3]) is a simple array type, so two CDAs are created.
The next rank is an array of two int[3]s. It is not a simple type, so a regular
ConstantArray
is created. The argument is anArrayRef<Constant*>
containing the two CDAs.
At step 3, ConstantArray
complains because the initializer does not have exactly the right type. Here's the message:
.../llvm-3.3.src/lib/IR/Constants.cpp:754:
static llvm::Constant* llvm::ConstantArray::get(llvm::ArrayType*,
llvm::ArrayRef<llvm::Constant*>):
Assertion `V[i]->getType() == Ty->getElementType()
&& "Wrong type in array element initializer"' failed.
I though ConstantDataArray
was a substitute for ConstantArray
when the element type is simple enough, but maybe I have it wrong. What's the correct way to understand it?
Update
This looks like a bug in my code (outside of LLVM). ConstantDataArray
does appear to be a transparent substitute for ConstantArray
.
Here's the code I put together to demonstrate the problem. It actually runs through without any complaints from LLVM:
// int[2][3] = {{1,2,3},{4,5,6}};
IntegerType* i64 = IntegerType::get(mod->getContext(), 64);
Constant* one = ConstantInt::get(i64, 1);
Constant* two = ConstantInt::get(i64, 2);
Constant* three = ConstantInt::get(i64, 3);
Constant* four = ConstantInt::get(i64, 4);
Constant* five = ConstantInt::get(i64, 5);
Constant* six = ConstantInt::get(i64, 6);
ArrayType* int_3 = ArrayType::get(i64, 3);
ArrayType* int_2_3 = ArrayType::get(int_3, 2);
// Constant* array123 = ConstantArray::get(int_3, std::vector<Constant*>{one,two,three});
Constant* array123 = ConstantDataArray::get(mod->getContext(), std::vector<uint64_t>{1,2,3});
// Constant* array456 = ConstantArray::get(int_3, std::vector<Constant*>{four,five,six});
Constant* array456 = ConstantDataArray::get(mod->getContext(), std::vector<uint64_t>{4,5,6});
Constant* array = ConstantArray::get(int_2_3, std::vector<Constant*>{array123, array456});
In case anyone is interested, the assertion stems from my reversing the array extents. int[2][3]
is an array of two arrays of three. I'm overloading operator[]
to build an array type as i64[2][3]
, where i64
is an object that holds an IntegerType*
and overloads operator[]
. The problem is that this builds an array of three arrays of two.