Exercises for Week 45#
This week’s exercises are about getting to know how to use LLVM’s
getelementptr (GEP) instruction.
Tuples#
Create an LLVM struct for tuples, called
Tuple, consisting of twoi64fields.Create the following LLVM functions:
create_tuplethat takes twoi64arguments and returns a tuple initialized with these arguments. Use the Cmallocfunction to allocate the tuple on the heap. Discuss in class what size argument to pass tomalloc.get_firstthat takes a tuple and returns its first element.get_secondthat takes a tuple and returns its second element.set_firstthat takes a tuple, and ani64value and performs an in-place update of the first element of the tuple.set_secondthat takes a tuple, and ani64value and performs an in-place update of the second element of the tuple.swap_elementsthat in-place swaps the first and the second elements of the tuple.
Write an LLVM program that tests the functionality of the above functions.
Modify your
create_tuplefunction so that the allocation takes place on stack instead of the heap. Does the program created in step (3) above still work? If yes, can you come up with a program that works in the heap-allocated version ofcreate_tuplebut does not work in the stack-allocated version?Write an LLVM function
swap_tuple_arraythat takes three arguments:a pointer to an array of tuples
an
i64integerian
i64integerj
This function should swap the elements
iandjin the provided array.Write an LLVM program that tests the functionality of the above functions.
Consider two alternative implementations of the Tuple
as an LLVM array of two fields.
as an LLVM pointer.
How would your implementation of the above functions change in each case?
Nested GEPs#
Consider the following C program
#include <stdlib.h>
struct B {
int p;
int *f;
int q;
};
struct A {
int g;
};
void update_two (struct A** a, struct B b) {
a[b.f[2]]->g = b.p + b.q;
}
int main() {
struct A **a = malloc(10 * sizeof(struct A*));
for (int i = 0; i < 10; ++i) {
a[i] = malloc(sizeof(struct A));
a[i]->g = 0;
}
struct B b;
update_two (a,b);
int array_for_f[3] = {0, 1, 4};
b.f = array_for_f;
return 0;
}
Compile the above function to LLVM, using -emit-llvm -S flag passed to clang. Modify the LLVM code for function update_two to use as few GEPs as possible.
Note
Counting the number of GEPs is generally not a meaningful metric for the quality of code generation. We use it here only as an exercise device to learn GEP.