Q: When is a boolean not a boolean?

I’ve been running into a module validation error related to phi nodes produced by the GVN pass, where the types of the incoming values aren’t the same instance of IntegerType i1.

I’m not certain I’ve found the root cause of the problem yet, it’s probably due to my handling of LLVMContext & Module life cycles, and this is my first real look at llvm’s source.

This patch at least makes my problem go away;

@@ -2195,11 +2200,11 @@ bool GVN::processInstruction(Instruction *I) {
BasicBlock *Parent = BI->getParent();
bool Changed = false;

  • Value *TrueVal = ConstantInt::getTrue(TrueSucc->getContext());
  • Value *TrueVal = ConstantInt::getTrue(BranchCond->getContext());
    BasicBlockEdge TrueE(Parent, TrueSucc);
    Changed |= propagateEquality(BranchCond, TrueVal, TrueE);
  • Value *FalseVal = ConstantInt::getFalse(FalseSucc->getContext());
  • Value *FalseVal = ConstantInt::getFalse(BranchCond->getContext());
    BasicBlockEdge FalseE(Parent, FalseSucc);
    Changed |= propagateEquality(BranchCond, FalseVal, FalseE);

Any other ideas about where I should look for the root problem? Is there any better documentation on how to deal with multiple LLVMContext instances?

I’m primarily creating multiple contexts to make sure my named structures aren’t renamed during linking.

You’re going to get weird breakage doing that. Types and constants are uniqued per-context, and optimization passes depend on that to perform shallow equality comparisons on them. The only valid way to use multiple contexts is to have multiple completely independent copies of LLVM operating within the same address space.

–Owen

Jeremy Lakeman wrote:

A: When the types are created in different contexts.

I've been running into a module validation error related to phi nodes
produced by the GVN pass, where the types of the incoming values aren't
the same instance of IntegerType i1.

I'm not certain I've found the root cause of the problem yet, it's
probably due to my handling of LLVMContext & Module life cycles, and
this is my first real look at llvm's source.

This patch at least makes my problem go away;

@@ -2195,11 +2200,11 @@ bool GVN::processInstruction(Instruction *I) {
      BasicBlock *Parent = BI->getParent();
      bool Changed = false;

- Value *TrueVal = ConstantInt::getTrue(TrueSucc->getContext());
+ Value *TrueVal = ConstantInt::getTrue(BranchCond->getContext());
      BasicBlockEdge TrueE(Parent, TrueSucc);
      Changed |= propagateEquality(BranchCond, TrueVal, TrueE);

- Value *FalseVal = ConstantInt::getFalse(FalseSucc->getContext());
+ Value *FalseVal = ConstantInt::getFalse(BranchCond->getContext());
      BasicBlockEdge FalseE(Parent, FalseSucc);
      Changed |= propagateEquality(BranchCond, FalseVal, FalseE);

Any other ideas about where I should look for the root problem? Is there
any better documentation on how to deal with multiple LLVMContext instances?

I'm primarily creating multiple contexts to make sure my named
structures aren't renamed during linking.

The purpose of LLVM contexts is to keep two separate users of LLVM entirely separate within the process space. Consider a program that uses an OpenGL library which uses LLVM under the hood, and also uses a sound library which uses LLVM under the hood. Those two libraries should each have their own LLVMContext in order to ensure that they don't interfere with each other.

If you've created IR with two different contexts, they are not allowed to comingle in any way whatsoever.

Could you elaborate on the named structures problem? If you link two modules containing identified structures, they shouldn't get renamed unless their contents are different (where inner identified structs with the same name are again considered equal).

Nick

Ah, I found the root cause of my problem with contexts. It seems I was accidentally creating all BasicBlocks in the default context, hence why changing GVN to use the context of an instruction instead of a block fixed my symptoms.

I’m building a front end for an existing interpreted OO language. I’ve got a pre-built runtime module that defines some commonly used structures and method prototypes.
As I compile other modules, the first thing I do is load this pre-built module from disk and link it in.
Then I’ll compile some methods, getting the type of these identified structures by name when needed, and write out the new module to disk and delete it from memory.
But the context still knows these identified structures, and for some reason the next time I load the same pre-built runtime module from disk and link it these structures are renamed in all the pre-built method prototypes.

I could keep this pre-built module loaded in memory, but I’m calling into llvm through a limited set of language bindings I’ve written and I haven’t added a link mode argument yet. This repeated reloading is an issue I’ll probably tackle soon for improved efficiency anyway.

And I could replace these named structures with unnamed ones. Again I mainly gave them names so I didn’t have to write a language binding to define them at compile time, but I’ve built that interface now so there’s nothing stopping me from changing that behaviour.