When should I use ConstantDataArray versus ConstantArray?

2.5k views Asked by At

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:

  1. Say the array I want to create would be declared like this in C++:

    int x[2][3] = {{1,2,3},{4,5,6}};

  2. The innermost rank (type int[3]) is a simple array type, so two CDAs are created.

  3. 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 an ArrayRef<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.

0

There are 0 answers