LLVM stuff I couldn’t find good examples for.

While venturing into the world of LLVM I had trouble figuring out a couple of things, most of the time because people would show IR but not the actual api calls to get there. So I decided to set up this page as a reference for myself and others for things that seem a little strange/hard to figure out and I’ll likely be adding more to it overtime as I run into more weird stuff.

Getting the runtime size of types

If you want to create the equivalent of the c++ sizeof in LLVM it can be a bit of a pain because you don’t know the sizes of some things (pointers) at the IR stage. If you know the target architecture I believe there are ways to grab the size directly from llvm::Type, but if you’re making a cross platform compiler where you can compile on one architecture and then run on another it’s not so easy.

The most common work around seems to be creating a null pointer to the type you want to get the size of, then treating it like an array, grabbing the second index, then converting that offset pointer to an int. In C/C++ that would look like this:

int size = (int)&((T*)0)[1]

If you run any optimization passes with a target architecture set this’ll be optimized out to a constant leaving us with exactly what we want. The LLVM code I use looks like this:

llvm::Type* type = typeThatYouWantTheSizeof;
llvm::Value* nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(type, 0));
llvm::Value* offset = builder.CreateGEP(type, nullValue, llvm::ConstantInt::get(llvmCtx, llvm::APInt(16, 1)));
llvm::Value* sizeOfType = builder.CreatePtrToInt(offset, llvm::Type::getInt64Ty(llvmCtx), "typeSize");

Getting a struct member

The api for this is not necessarily complicated it’s just not explained ANYWHERE. So it took a little trial and error to figure out.

llvm::Value* baseValue = structToGetMembersFrom;
int memberIndex = memberYouWantToAccess;
llvm::Value* memberPtr = ctx.builder.CreateStructGEP(baseValue->getType()->getContainedType(0), baseValue, memberIndex);

The first argument to GEP or get element pointer, is the STRUCT type that your are working with. This messed me up so many times and it will probably mess me up again. I intuitively always put the type of the member I’m trying to access there, probably some part of my brain thinking that I’m doing casting, but no. The command figures out member offsets and types from the struct type provided, that way the second argument, the pointer to the struct, can be an opaque/void pointer and the command will still work. You’d think it’d be able to implicitly be able to deduce the struct type from the pointer like I do here, and it used to be able too but that function has been marked as deprecated, likely around the time they introduced opaque pointers, which won’t work with an implicit method.

Liked it? Take a second to support WireWhiz on Patreon!
Become a patron at Patreon!