[LLVMdev] Problem with linking modules which use a shared type

Marcus Frenkel marcus.frenkel at FernUni-Hagen.de
Thu Jun 27 03:44:09 PDT 2013


Hi,

I stumbled upon a strange thing regarding types and module linking, which I don't quite get, so maybe someone around here can enlighten me.

Consider the following code, which will create 2 modules m1 and m2, and a named structured type %T = { i32 }; m1 contains only a function definition f(%T), m2 contains a function declaration f(%T) and a function definition h(%T), where h will call f in its body. Note that all functions in m1 and m2 are based upon the same structured type %T:

     LLVMContext context;
     BasicBlock* b;

     // modules
     Module *m1 = new Module( "m1", context ),
            *m2 = new Module( "m2", context );

     // types
     vector<Type*> types;

     types.push_back( IntegerType::get( context, 32 ) );

     Type* sType = StructType::create( types, "T" );

     types.clear();
     types.push_back( sType );

     FunctionType* ft = FunctionType::get( Type::getVoidTy( context ), types, false );

     // m1
     Function* f = Function::Create( ft, GlobalValue::ExternalLinkage, "f", m1 );

     b = BasicBlock::Create( context, "b", f );
     ReturnInst::Create( context, b );

     verifyModule(*m1);

     // m2
     Function* fDecl = Function::Create( ft, GlobalValue::ExternalLinkage, "f", m2 );
     Function* h = Function::Create( ft, GlobalValue::ExternalLinkage, "h", m2 );

     vector<Value*> args;
     args.push_back( h->arg_begin() );

     b = BasicBlock::Create( context, "b", h );
     CallInst::Create( fDecl, args, "", b );
     ReturnInst::Create( context, b );

     verifyModule(*m2);


Each module for itself is okay and passes the verification, leading to the following IR code:

     ; ModuleID = 'm1'

     %T = type { i32 }

     define void @f(%T) {
     b:
       ret void
     }

     =====================
     ; ModuleID = 'm2'

     %T = type { i32 }

     declare void @f(%T)

     define void @h(%T) {
     b:
       call void @f(%T %0)
       ret void
     }


However, if both modules are linked together as per

     // link
     Linker::LinkModules( m1, m2, Linker::DestroySource, nullptr );
     verifyModule(*m1);


the type %T in both modules will not be unified, but instead two separate types %T and %0 will be introduced, leading to the following IR code, which of course won't pass the verification any more due to type incompatibilities in the function call:

     ; ModuleID = 'm1'

     %0 = type { i32 }
     %T = type { i32 }

     define void @f(%0) {
     b:
       ret void
     }

     define void @h(%T) {
     b:
       call void @f(%T %0)
       ret void
     }


Even more strange, if both modules and the types are created separately from each other (meaning, that the type %T is created for both modules anew), but within the same LLVMContext, the call to LinkModules will result in a proper module with a unified type %T.

Is that a bug or a feature of LLVM? I thought that types will be handled at context level and not module level, so that it should be clear that %T in both m1 and m2 can be unified, given that they even are based upon the same llvm::Type type (which becomes even more strange with the fact, that they will be unified, when they are *not* based upon the same llvm::Type type).

Any explanation of that behavior would be much appreciated!


Cheers,
Marcus



More information about the llvm-dev mailing list