Frage

I'm writing a LLVM pass (it's a LoopPass) that needs to insert pthread functions calls like pthread_create() and pthread_join() into the IR. I know how to create and insert a function call into IR, but I am having trouble to get the pthread representation of Function* in LLVM.

Here's what I have:

Function *pthread_create_func = currentModule->getFunction("pthread_create"); but it returns NULL.

As a comparison Function *printf_func = currentModule->getFunction("printf"); will return the correct Function* that allows me to insert a new function call to printf into IR.

I have #include "pthread.h" in my pass and -pthread right after clang -emit-llvm but it still can't find pthread_create or other pthread_* functions somehow.

War es hilfreich?

Lösung

When you make the call:

currentModule->getFunction("pthread_create");

LLVM looks up to see if there already is a function declaration with this name. The return of NULL indicates that the existing IR did not declare this function, which contrasts with printf that has been declared.

Instead, you want to ask LLVM to get or insert the function you need. By insert, we mean add a declaration for the function. This call requires the complete type information for the function being inserted. As I happen to have some code that basically does this for pthread_create, I've copied a snippet here and will explain further:

// The following are Type*: int64Ty, int32Ty, pthreadTy
// Request the types using context, like int32Ty = Type::getInt32Ty(M.getContext());
// funVoidPtrVoidTy is a FunctionType*, constructed in a similar manner as below
if (M.getPointerSize() == llvm::Module::Pointer64)
{
    pthreadTy = int64Ty;
}
else
{
    pthreadTy = int32Ty;
}

Type* argsPTC[] = {pthreadTy->getPointerTo(),
                   voidPtrTy,
                   static_cast<Type *>(funVoidPtrVoidTy)->getPointerTo(),
                   voidPtrTy};
FunctionType* pthreadCreateTy = FunctionType::get(int32Ty, 
                                                  ArrayRef<Type*>(argsPTC,4), 
                                                  false);
Function *pthread_create_func = M.getOrInsertFunction("pthread_create",
                                                      pthreadCreateTy);

pthread_create has the following type signature:

int pthread_create(pthread_t * thread, const pthread_attr_t * attr, \
                   void * (*start_routine)(void *), void * arg)

To insert this function, we need to assemble a list of the type of the arguments.

First, the pthread_t type varies in size, depending on whether you are on a 32- or 64-bit machine, therefore to have the correct type signature needs to take this into account (or you can hardcode it, if you are only concerned with one architecture).

Second, for my purposes, I was able to avoid resolving %union.pthread_attr_t*, and treat it as a void*, but that may not work for you.

Third, funVoidPtrVoidTy was a FunctionType that represents the start_routine to pthread_create.

Fourth, the last argument is actually a void pointer, being the unknown argument passed to the start_routine.

With the four argument types in an array, a function type is created. Briefly, we've requested the type of a function that returns a 32-bit integer (int32Ty) and takes in the four types as arguments (ArrayRef...), and finally does not take in a varg type (false).

At last, we can request the module to add a declaration for the function we want, and away we go using the Function* in IR we create.

Andere Tipps

You need a declaration of the pthread_create function in your IR. It works for printf because LLVM recognizes printf as a builtin. I suggest you compile a simple C program that uses pthread_create with clang -emit-llvm and look at the produced IR.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top