Creating a struct containing a pointer to itself in LLVM - llvm

I'm currently using LLVM to build a JIT. There are some C structs that I would like to be able to use in my JIT'd IR. One of them has the following layout:
struct myStruct {
int depth;
myStruct* parent;
}
When compiling with clang and using -S -emit-llvm, I get the following, which seems absolutely reasonable:
type myStruct = { i32, myStruct* }
Alright. Now, if I want to do the same using the LLVM API, I'm not quite sure how I should do it. The following (expectedly) does not work:
auto intType = IntegerType::get(context, 32); // 32 bits integer
Type* myStructPtrType = nullptr; // Pointer to myStruct
// The following crashes because myStructPtrType is null:
auto myStructType = StructType::create(context, { intType, myStructPtrType }, "myStruct"); // myStruct
myStructPtrType = PointerType::get(myStructType, 0); // Initialise the pointer type now
I don't really know how to proceed here.
Any suggestions are welcome.

I was able to answer the question thanks #arnt's comment. In case anyone has the same goal/problem. The idea is first to create an opaque type, then fetch the pointer type to this opaque type, then set the aggregate body (which is the key of the solution) using setBody.
Here is some code:
auto intType = IntegerType::get(context, 32); // 32 bits integer
auto myStructType = StructType::create(context, "myStruct"); // Create opaque type
auto myStructPtrType = PointerType::get(myStructType, 0); // Initialise the pointer type now
myStructType->setBody({ intType, myStructPtrType }, /* packed */ false); // Set the body of the aggregate

Related

Const struct initialization with custom elements in C++

I am porting some C code to C++ and I am trying to initialize a struct with some values.
I want the struct to be stored in flash (const) and not in RAM, and its values are typedef'd elements.
Originally, I had it like this:
typedef struct
{
typeA_t elementA;
typeB_t elementB;
uint8_t elementC;
} structTypeA_t;
And to instantiate them in flash, I simply did the following:
const structTypeA_t sA = {
.elementA = ONE,
.elementB = TWO,
.elementC = 3
};
I know that this type of initializing is not allowed in C++. How can I achieve it in C++?
Designated initializers are not in C++ (yet, but look for C++20). So you do it almost the same way, but without names - position of the argument defines the field it initializes:
const structTypeA_t sA = {ONE,
TWO,
3
};
If you always need to initialize with the same values, then you can just define the struct like this:
struct structTypeA_t
{
typeA_t elementA = ONE;
typeB_t elementB = TWO;
uint8_t elementC = 3;
};
You can now instantiate it without an initializer:
const structTypeA_t sA;

Save reference to void pointer in a vector during loop iteration

Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}

How can I create a struct parameter for a llvm IR call instruction?

I want to insert a function call instruction into an IR file. But there are some problems when I tried to create a struct parameter.
function:
"__myfun(int addr,struct buginfor struct_var)"
the struct is:
typedef struct buginfor{
int line;
char *str1;
char *str2;
};
my code:
Value* args[] = { addr };
// struct parameter create
Value *struct_line = ConstantInt::get(IntegerType::get(M->getContext(), 64), 4);
Value *struct_filename= llvm::PointerType::get(IntegerType::get(M->getContext(), 8),20);//20 bytes
Value *struct_dir= llvm::PointerType::get(IntegerType::get(M->getContext(), 8),100);//100 tytes
Type* struct_Ty[] = { struct_line->getType(),struct_filename->getType(),struct_dir->getType()};
llvm::StructType * struct_var= llvm::StructType::create(M->getContext(),"buginfor");
struct_var->setBody(struct_Ty);
Value* arg2 = struct_var;
Type* argsTy[] = { addr->getType(),arg2->getType()};
FunctionType *funcTy = FunctionType::get(Type::getVoidTy(M->getContext()), ArrayRef<Type*>(argsTy, 2), false);
Function *hook;
hook = cast<Function>( M->getOrInsertFunction("__myfun", funcTy, attribute(M)));
CallInst *newInst = CallInst::Create(hook, ArrayRef<Value *>(args, 1), "");
anyone can tell me the right way to create a struct parameter like buginfor?
ps:
I want to get the three parameter and make it a llvm IR constantstruct
DILocation Loc(N); // DILocation is in DebugInfo.h
unsigned Line = Loc.getLineNumber();
StringRef File = Loc.getFilename();
StringRef Dir = Loc.getDirectory();
It seems like you'll want to create a ConstantStruct or an undef struct and then insert values in to it with insertvalue instructions. Depending on if you have constants or runtime values.

Is list initialization of new struct{} using variables compiler specific?

Using Visual Studio 2013 and C++ compiler to write yet another linked list and happened across this by trial and error. Is this specific to Visual C++ or part of the standard?
I really like this syntax. It's super clean. If you've written a linked list lib before you know you can chase pointers around until your brain is tied in knots. This syntax though is crystal clear.
Lots of this stuff with static initializer values, but using function args as initializers? Haven't seen that yet.
It would be comforting to know if the GCC C/C++ compiler produces the expected result. Anyone?
typedef struct link_in_list {
struct link_in_list *next;
int32_t key;
int32_t value;
} LINK, *pLINK;
// ----------------------------------------------------------------------------
pLINK prepend_list(pLINK head, int32_t key, int32_t value)
{
if (NULL == head) {
// initialize with a constant, variable, and expression
return new LINK{ NULL, key, (key * key) };
} else {
// initialize with stack variables
return new LINK{ head, key, value };
}
}
This is called list initialization and was introduced in C++11. It's different from direct initialization in a bunch of ways that I would like to point out:
int x{3.5}; // illegal - narrowing
int x(3.5); // fine, x is 3, but does this make sense?
T fun(); // this is a function returning a T
T fun{}; // this is a default constructed object
// of type T
std::vector<int> v(10, 20); // 10 elems: 20, 20, 20, ..., 20
std::vector<int> v{10, 20}; // 2 elems: 10, 20
But outside of those cases, it's pretty similar to direct initialization. So no, it's not compiler specific - as long as the compiler in question supports the new language standard.
One addition in functionality is that if T is an "aggregate" (that is, an array, or a class type that has no private/protected members, no user-provided constructors, no base classes, no virtual methods), then list initialization is equivalent to aggregate initialization.
That is:
struct Foo {
int a;
char b;
double c;
};
int i = 1;
char c = 'b';
double d = 42.;
Foo f{i, c, d};
Foo g = {i, c, d};
Those lines are equivalent.

metaprogramming : using a const array

I'm new to metaprogramming, and I am having a const-related issue when using a tab with it.
Let's say we have several "types". Each of the types have different version, and we shall be able to handle all vesrion for each type. For that, we use a struct that contains standard info about the type, and an array containing info for each version.
The thing is, each type does not have the same number of versions. Also, the versions numbers are not very high, so I prefer not to use dynamic allocation of the said tables. But if I do static allocation, I need to have a table with the same size for each instance of the structure. That means, I have to get the highest version value and use it as the size of the array.
Here I come : I want to create a small metaprogramming template which gives the highest version value # compile time, so I can have a fixed size of the array that will surely contains the necerrasy info for each type. But I get a compile error.
Here is a simplified sample code that reproduce the issue (the error follows it)
#include <stdio.h>
// change values here
#define VERSION_ALPHA 3
#define VERSION_BETA 5
#define VERSION_GAMMA 2
// different available types
enum TYPES
{
T_ALPHA = 0,
T_BETA,
T_GAMMA,
T_COUNT, // number of types
};
// to access versions more easily from code
static const int typeVersions[T_COUNT] =
{
VERSION_ALPHA,
VERSION_BETA,
VERSION_GAMMA
};
// this meta is used to get the highest version values between all types
template<int i>
class HighestVersion
{
private:
// version of type -1
enum
{
PREVIOUS = HighestVersion<i-1>::VALUE
};
public:
// current max value
enum
{
VALUE = (typeVersions[i] > PREVIOUS ? typeVersions[i] : PREVIOUS)
};
};
// first version
template<>
class HighestVersion<0>
{
public:
// current max value
enum
{
VALUE = typeVersions[0]
};
};
// highest version macro
#define HIGHEST_VERSION HighestVersion<T_COUNT>::VALUE
// holds info about a single type
struct TypeInfo
{
char * s_pName; // name of the type as string
unsigned int s_Flags[HIGHEST_VERSION]; // flags for each available version of this type
};
int main()
{
// instanciate
TypeInfo infos[T_COUNT];
// do stuff, set name, load flags....
/*...*/
// for test purpose, print max version value (should print 5 in this situation)
printf("%d\n", HIGHEST_VERSION);
}
The compiler says :
error C2057: expected constant expression
# the lines
VALUE = (typeVersions[i] > PREVIOUS ? typeVersions[i] : PREVIOUS)
and
VALUE = typeVersions[0]
It seems that the compiler tells me that the table's contents are not constant. I assume it's because the table is interpreted as a pointer which is no constant in that case (so if the pointer changes the contents are not the same). Is there a way to correct that so I can use the script ? It will make the user to not need to manually set the size of that table...
Thanks in advance :)
I'm sure not it's even possible to make this work with a static array.
A possible alternative is a trait class:
template<TYPES>
struct typeVersions;
// specializations for each type
template<>
struct typeVersions<T_ALPHA> { static const int version = VERSION_ALPHA; };
template<>
struct typeVersions<T_BETA> { static const int version = VERSION_BETA; };
// etc...
You'd use it like this:
enum {
VALUE = typeVersions<i>::version
};
As jrok said, it is likely not possible to do this with a static array. But neither is it
necessary to create a trait-specialization for each type-version if you have an adequately
conforming C++11 compiler.
I see that you are using VC++ and you are probably committed to it, which regrettably means the only adequately conforming C++11 compiler you might have or lay your hands right now on is VC++ 2013 Preview. If you can use that then the simple variadic template solution illustrated by the following modification of your program will work for you:
#include <stdio.h>
// change values here
#define VERSION_ALPHA 3
#define VERSION_BETA 5
#define VERSION_GAMMA 2
// different available types
enum TYPES
{
T_ALPHA = 0,
T_BETA,
T_GAMMA,
T_COUNT, // number of types
};
template<int ...Versions>
struct versions_list
{
static_assert(sizeof ...(Versions),
"Cannot have 0 versions");
};
template<int Only>
struct versions_list<Only>
{
static const int max = Only;
};
template<int First, int Last>
struct versions_list<First,Last>
{
static const int max = First > Last ? First : Last;
};
template<int First, int Second, int ...Rest>
struct versions_list<First,Second,Rest...>
{
static const int tail_max = versions_list<Second,Rest...>::max;
static const int max = First > tail_max ? First : tail_max;
};
// Update your version list here:
typedef versions_list<VERSION_ALPHA, VERSION_BETA, VERSION_GAMMA> typeVersions;
#define HIGHEST_VERSION typeVersions::max
// holds info about a single type
struct TypeInfo
{
char * s_pName; // name of the type as string
unsigned int s_Flags[HIGHEST_VERSION]; // flags for each available version of this type
};
int main()
{
// instanciate
TypeInfo infos[T_COUNT];
// do stuff, set name, load flags....
/*...*/
// for test purpose, print max version value (should print 5 in this situation)
printf("%d\n", HIGHEST_VERSION);
}
The HIGHEST_VERSION macro is really pointless here: you could just delete its definition and replace all occurrences with typeVersions::max.
By the way, if you really want to use C's stdio API in a C++ program rather than the C++
iostream API, strictly you ought to use #include <cstdio>, not #include <stdio.h>
I am not sure if this can be done with C-style arrays, but if you have compiler support for C++11 then please check my solution:
#include <array>
#include <iostream>
template <int Size, int Indice>
struct HighestValue
{
static int get(std::array<int, Size> checkedArray) {
return std::max(HighestValue<Size, Indice - 1>::get(checkedArray), checkedArray[Indice]);
}
};
template <int Size>
struct HighestValue<Size, 0>
{
static int get(std::array<int, Size> checkedArray) {
return checkedArray[0];
}
};
template<size_t Size>
int checkMax(std::array<int, Size> checkedArray)
{
return HighestValue<Size, Size - 1>::get(checkedArray);
}
int main()
{
std::array<int, 7> test {1, 5, 2, 3, 123, 5, 2};
std::cout << checkMax(test);
}
Currently I do not have spare time to play with this, but I am sure it could be improved further.