How to replace the initializer content of a global Array - llvm

In LLVM IR, I have a global array of type [4 x i32]:
#data = local_unnamed_addr global [4 x i32] [i32 17, i32 31, i32 55, i32 7], align 4
Using a module pass, I want to modify the initializers of this array, in the original example {17, 31, 55, 7}.
I am able to detect the global data. globalData holds a reference to the GlobalVariable. Then I determine if it is initialized and an array type.
if(globalData.hasInitializer()) {
auto arrayType = globalData.getInitializer()->getType();
if(arrayType->isArrayTy()) {
SmallVector<Constant *, 4> arrayContent(4); // How to get the dimension?
// How to get each Constant from the orginal initializer?
Constant* initializer = ConstantArray::get((ArrayType*) arrayType, arrayContent);
globalData.setInitializer(initializer);
}
}
However, I am missing how to get dimension of the array, the original integer initializers, and how to properly set the new initializer.
Right now, executing the showed code does not update the initializer array.

Related

Is there a literal for the empty array in Chapel?

I'm trying to make an empty array in Chapel. An array of one element can be made like this:
var a: [1..1] int = (1);
But when I try
var b: [1..0] int = ();
I get
syntax error: near ')'
Is there an empty array literal in Chapel? I haven't been able to find an example.
EDIT
The reason I am trying to get an empty array is that I would like to implement get this function working for empty arrays:
proc sum_of_even_squares(a) {
// Does this work for empty arrays? Probably not.
return + reduce ([x in a] if x % 2 == 0 then x*x else 0);
}
assert(sum_of_even_squares([7]) == 0);
assert(sum_of_even_squares([7, 3]) == 0);
assert(sum_of_even_squares([7, 3, -8]) == 64);
assert(sum_of_even_squares([7, 3, -8, 4]) == 80);
But I am unable to form an empty array literal.
Generally, in Chapel, to declare an empty thing, you specify its type but no initialization, such as
var i:int;
But to declare an integer initialized with a value, you'd probably leave off the type:
var j = 2;
In this case, simply omitting the initializer makes it work.
var b: [1..0] int;
Relatedly, (1) is not declaring an array literal but rather a tuple literal. The syntax [1] would declare an array literal. At present, zero-length tuples are not supported in the compiler implementation. It might be easier to get zero-length array literals to work, but it doesn't seem to work right now either (in 1.15).
And how would a zero-length array literal know the type of the elements? For this reason I don't think it could help in your specific case.

Creating an unmodifiable 2d array in c++

Quick background, I have some experience with java and currently new to c++.
My question comes from an assignment in which we had to create 4 different magic squares, but for the nature of this particular question they can be any 2d array, so long as they are "exact" in values, only that they appear differently from each one. What I mean by that is if one 2d array looked like:
1 2 3
4 5 6
7 8 9
the next one would be rotated 90 degrees
7 4 1
8 5 2
9 6 3
and so on..
To make the first matrix I simply made a 2d array and created it using the magic square algorithm (irrelevant)
int** square = new int*[size]();
for (int i = 0; i<size; i++) {
square[i] = new int[size]();
}
//set values to square .. irrelevant to show, could be anything
//way down the code
int** secondSquare = square;
For the second third and fourth ones all I would need to do is rotate the previous one to get the next rotated square. My problem however wasn't that I could not flip the arrays, but that while trying to flip them the values for the first square were also changing.
Obviously this is more of a problem about being able to access the data in square and not change it while trying to add them to secondSquare.
I tried making it so square was a modifiable pointer w constant unmodifiable values.
const int** square = new int*[size];
The problem with this is that I have to assign values after to square so this cannot be done. Also when I initialize secondSquare it gives me an error since it is of type int** and not const int**.
Any better ways to handle problems with accessing data without changing values and setting both arrays (or objects really) properly on initialization?
You would do well to avoid using raw pointers and new entirely . That should really come in the advanced section of any C++ course.
Here is one way:
array< array<int,3>, 3> square = {{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }};
square[1][1] = 12; // optional
const auto &c_square = square;
Now c_square is a const accessor of square that you can use later and avoid risk of modifying square.
The problem is int** secondSquare = square; copies the address of the square pointer to secondSquare. So in the end you have two (three, four) pointers pointing to exact same place in memory. Think about it like you have one square created but you try to access it through four different pointers.
What you want to do is to allocate memory for 4 different int** pointers.
To create a 2d array, you would declare it as const:
const int array_2d[3][3] =
{
0, 1, 2,
3, 4, 5,
6, 7, 8
};
In my experience, the better method is to declare it as static const so you are telling the compiler that there is only 1 read only instance:
static const int array_2d[3][3] =
{
0, 1, 2,
3, 4, 5,
6, 7, 8
};
The static allows for the compiler to place the data in a read-only section of the executable and access it directly, rather than copying it from Read-Only to the stack before usage (I've seen compilers emit this kind of code).

How do I make multi dimensional in C++?

I have this array
int sequence[2][3][2][2][50][2] = {
{
{1},
{{
{2, 4},
{3, 5}
},
{255,0,0}
}
},
{
{2},
{{
{3, 4},
{2, 6}
},
{0,0,255}
}
}
};
Whenever I try to index the first multi dimensional array, using
int frame[2] = {sequence[1]}
I get this error "invalid conversion for 'int (*)[2][2][50][2]' to 'int' [-fpermissive]
What am I doing wrong?
Whenever I try to index the first multi dimensional array, using
int frame[2] = {sequence[1]}
Let's simplify the syntax you use:
int frame[2] = {/*list of ints*/}
This initializes a one dimensional array of 2 int, using a brace-enclosed list of integers.
An element of your outermost multi-dimensional array with arity k, is also a multi-dimensional array (with arity k-1). It is not an int.
So, there is nothing wrong with how you index the multi-dimensional array. What is wrong, is trying to initialize an array if int with a multi-dimensional array as the first value.
How should I initialize it then?
It is impossible to answer because it is not clear which of the integer values within the multi-dimensional array you want to use to initialize.
Here is a syntactically correct way to initialize frame:
int frame[2] = {sequence[0][0][0][0][0][0], sequence[0][0][0][0][0][1]};
It uses the values in the first subarray of the first subarray of the first subarray of the first subarray of the first subarray of the outermost array.

When should I use ConstantDataArray versus ConstantArray?

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 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.

C++ Initialize array pointer

How do I initialize a pointer to a literal array?
I want *grid to point to the new allocated int array {1, 2, 3}.
int *grid = new int[3];
*grid = {1, 2, 3};
thank you.
You can't initialize a dynamically allocated array that way. Neither you can assign to an array(dynamic or static) in that manner. That syntax is only valid when you initialize a static array, i.e.
int a[4] = {2, 5, 6, 4};
What I mean is that even the following is illegal:
int a[4];
a = {1, 2, 3, 4}; //Error
In your case you can do nothing but copy the velue of each element by hand
for (int i = 1; i<=size; ++i)
{
grid[i-1] = i;
}
You might avoid an explicit loop by using stl algorithms but the idea is the same
Some of this may have become legal in C++0x, I am not sure.
#above grid points to the address location where the first element of the array grid[] is stored. Since in C++ arrays are stored in contiguous memory location, you can walk through your array by just incrementing grid and dereferencing it.
But calling grid an (int*) isnt correct though.
I'm not sure if this is obvious but you can do this in one line.
int *grid = new int[3] {1, 2, 3};
Since this is C++ we are talking about you can also split it into
two files. Where your .h file contains:
int *grid;
And your .cpp file contains:
grid = new int[3] {1, 2, 3};
Use the following code, grid is a pointer, grid[] is an element of that pointer.
int grid[] = {1 , 2 , 3};