How should I manage the life cycle of llvm instance like llvm::BasicBlock ?

I am new to the llvm, and am following some tutorials to convert some AST to LLVM IR.

I’ve noticed that many API in llvm returns a pointer, like the llvm::BasicBlock::Create

besides this, classes like llvm::Function,llvm::Type,, llvm::Value seems all follow this pattern.

From my experience, the objects that the returned pointer point to are not new-ed by me, so I should not delete them. Is this right?

Is there some rationale behind the llvm API design? and how should I manage the life cycle of the object these pointer point to?

In general, each of these objects is owned by its container (even where this isn’t true, such as when it’s actually owned by its container’s container, it’s a useful mental model). If you want to delete an instruction or a basic block, erase it from its parent. Make sure that nothing else refers to it first (e.g. that terminators don’t point to a removed basic block). For Values, there are helpers such as replaceAllUsesWith, which guarantee that eraseFromParent is safe by updating all users to point to something else.

Most of the time, the best way to think about LLVM memory management is to not think about it at all. If a basic block is deleted, assume all instructions in it are deleted. If a function is deleted, assume all basic blocks in it are deleted. If a module is deleted, assume all functions and globals in it are deleted. In an LLVM context is deleted, assume all modules, types, and so on that are owned by it are deleted.

Anything that you create is generally associated with some owning value (with LLVMContext as the owner of last resort) and this is the object responsible for cleaning up the value.

1 Like

Thanks! It’s really clear and helpful.