error while linking modules with exception handling demo code

Hi,

I am building a module X with an arithmetic function foo, a module Y
with an arithmetic function foo2 that invokes foo. For the invocation
be a proper one (being able to handle exceptions correctly) i
incorporated a third module that has defined exception-handling code
that i've taken from the ExceptionDemo sample. First i'll post the
module dump, the failed assertion and then i'll explain a bit about
how do i generate the code:

this is the module ExecutableCodeModule dump, which is the module that
is used by the ExecutionEngine (not using new MCJIT, but it is not
relevant for this question, since the error happens during linkage).
It contains definitions from the ExceptionDemo sample AND the foo
function of module X already linked

(modules are being linked with
linker()->LinkModules(ExecutableCodeModule , moduleToLink,
llvm::Linker::PreserveSource, &errorMsg);

Exception Demo is from
https://llvm.org/svn/llvm-project/llvm/trunk/examples/ExceptionDemo/ExceptionDemo.cpp

; ModuleID = 'ExecutableCodeModule'

@typeInfo0 = constant { i32 } zeroinitializer
@typeInfo1 = constant { i32 } { i32 1 }
@typeInfo2 = constant { i32 } { i32 2 }
@typeInfo3 = constant { i32 } { i32 3 }
@typeInfo4 = constant { i32 } { i32 4 }
@typeInfo5 = constant { i32 } { i32 5 }
@typeInfo6 = constant { i32 } { i32 6 }

declare void @print32Int(i32, i8*)

declare void @print64Int(i64, i8*)

declare void @printStr(i8*)

declare void @throwCppException(i32)

declare void @deleteOurException(i8*)

declare i8* @createOurException(i32)

declare i32 @_Unwind_RaiseException(i8*) noreturn

declare i32 @_Unwind_Resume(i8*) noreturn

declare i32 @ourPersonality(i32, i32, i64, i8*, i8*)

declare i32 @llvm.eh.typeid.for(i8*) nounwind readnone

define i32 @foo(i32) {
  %g = alloca i32
  %bar = alloca i32
  store i32 %0, i32* %bar
  %"argument read" = load i32* %bar
  %addtmp = add i32 %"argument read", 2
  store i32 %addtmp, i32* %g
  %"argument read1" = load i32* %bar
  %read = load i32* %g
  %"Code::Op::Mul" = mul i32 %"argument read1", %read
  ret i32 %"Code::Op::Mul"
}

this is module Y, which is where foo2 is generated. When it is
supposed to invoke foo, i've placed
createCatchWrappedInvokeFunction(*module, *excptModule,
                                                    buildParameters.builder,

*buildParameters.getFunctionPassManager(),
                                                    *result, //result
is llvm::Function pointing to foo in module X
                                                    "invoke foo",
                                                    numExceptionTypesToCatch,
                                                    innerExceptionTypesToCatch);

(at the end i put the code for createCatchWrappedInvokeFunction, which
is slightly modified to allow for things like printStr and
createOurException that exists in the separate exception handling
module to be used in the module Y)

; ModuleID = 'Y'

@0 = linker_private constant [52 x i8] c"Gen: Executing finally block
finally in invoke foo\0A\00"
@1 = linker_private constant [52 x i8] c"Gen: Executing catch block
typeInfo6 in invoke foo\0A\00"
@2 = linker_private constant [52 x i8] c"Gen: Executing catch block
typeInfo2 in invoke foo\0A\00"
@3 = linker_private constant [52 x i8] c"Gen: Executing catch block
typeInfo4 in invoke foo\0A\00"
@4 = linker_private constant [43 x i8] c"Gen: In end block: exiting in
invoke foo.\0A\00"
@5 = linker_private constant [34 x i8] c"Gen: No exception in invoke foo!\0A\00"
@6 = linker_private constant [34 x i8] c"Gen: Foreign exception received.\0A\00"
@7 = linker_private constant [67 x i8] c"Gen: Exception type <%d>
received (stack unwound) in invoke foo.\0A\00"

define i32 @foo2(i32) {
  %h = alloca i32
  %g = alloca i32
  %bar = alloca i32
  store i32 %0, i32* %bar
  %"argument read" = load i32* %bar
  %"Code::Op::Mul" = mul i32 %"argument read", 5
  store i32 %"Code::Op::Mul", i32* %g
  %read = load i32* %g
}

define void @"invoke foo"(i32 %exceptTypeToThrow) {
entry:
  %caughtResultStorage = alloca { i8*, i32 }
  store { i8*, i32 } zeroinitializer, { i8*, i32 }* %caughtResultStorage
  %exceptionStorage = alloca i8*
  store i8* null, i8** %exceptionStorage
  %exceptionCaught = alloca i8
  store i8 0, i8* %exceptionCaught
  %0 = invoke i32 @foo(i32 %exceptTypeToThrow)
          to label %normal unwind label %exception

normal: ; preds = %entry
  call void @printStr(i8* getelementptr inbounds ([34 x i8]* @5, i32 0, i32 0))
  br label %finally

exception: ; preds = %entry
  %1 = landingpad { i8*, i32 } personality i32 (i32, i32, i64, i8*,
i8*)* @ourPersonality
          cleanup
          catch { i32 }* @typeInfo6
          catch { i32 }* @typeInfo2
          catch { i32 }* @typeInfo4
  %2 = extractvalue { i8*, i32 } %1, 0
  %3 = extractvalue { i8*, i32 } %1, 1
  store { i8*, i32 } %1, { i8*, i32 }* %caughtResultStorage
  store i8* %2, i8** %exceptionStorage
  store i8 1, i8* %exceptionCaught
  %4 = bitcast i8* %2 to { i64 }*
  %5 = getelementptr inbounds { i64 }* %4, i32 0, i32 0
  %6 = load i64* %5
  %7 = icmp eq i64 %6, 8026094035810743040
  br i1 %7, label %exceptionRoute, label %externalException

exceptionRoute: ; preds = %exception
  %8 = getelementptr i8* %2, i64 4294967280
  %9 = bitcast i8* %8 to { { i32 } }*
  %10 = getelementptr inbounds { { i32 } }* %9, i32 0, i32 0
  %11 = getelementptr inbounds { i32 }* %10, i32 0, i32 0
  %12 = load i32* %11
  call void @print32Int(i32 %12, i8* getelementptr inbounds ([67 x
i8]* @7, i32 0, i32 0))
  switch i32 %3, label %finally [
    i32 1, label %typeInfo6
    i32 2, label %typeInfo2
    i32 3, label %typeInfo4
  ]
  store i32 %0, i32* %h
  %"argument read" = load i32* %bar
  %read = load i32* %h
  %addtmp = add i32 %"argument read", %read
  ret i32 %addtmp

externalException: ; preds = %exception
  call void @printStr(i8* getelementptr inbounds ([34 x i8]* @6, i32 0, i32 0))
  br label %finally

unwindResume: ; preds = %finally
  %13 = load { i8*, i32 }* %caughtResultStorage
  resume { i8*, i32 } %13

end: ; preds = %finally, %finally
  call void @printStr(i8* getelementptr inbounds ([43 x i8]* @4, i32 0, i32 0))
  %14 = load i8** %exceptionStorage
  call void @deleteOurException(i8* %14)
  ret void

finally: ; preds =
%exceptionRoute, %externalException, %normal, %typeInfo4, %typeInfo2,
%typeInfo6
  call void @printStr(i8* getelementptr inbounds ([52 x i8]* @0, i32 0, i32 0))
  %15 = load i8* %exceptionCaught
  switch i8 %15, label %end [
    i8 2, label %end
    i8 1, label %unwindResume
  ]

typeInfo6: ; preds = %exceptionRoute
  call void @printStr(i8* getelementptr inbounds ([52 x i8]* @1, i32 0, i32 0))
  store i8 2, i8* %exceptionCaught
  br label %finally

typeInfo2: ; preds = %exceptionRoute
  call void @printStr(i8* getelementptr inbounds ([52 x i8]* @2, i32 0, i32 0))
  store i8 2, i8* %exceptionCaught
  br label %finally

typeInfo4: ; preds = %exceptionRoute
  call void @printStr(i8* getelementptr inbounds ([52 x i8]* @3, i32 0, i32 0))
  store i8 2, i8* %exceptionCaught
  br label %finally
}

this is the failed assertion i get during the call to Linker::LinkModules

While deleting: i32 (i32)* %foo
Use still stuck around after Def is destroyed: %0 = invoke i32
@foo(i32 %exceptTypeToThrow)
          to label %normal unwind label %exception
hivecompilerlibtests: Value.cpp:75: virtual llvm::Value::~Value():
Assertion `use_empty() && "Uses remain when a value is destroyed!"'
failed.

As a separate but probably related detail, the function 'invoke foo'
is not being inserted in the foo2 IR. The foo2 invoke generation looks
like this:

llvm::Module* module =
Compiler::Services::SymbolResolver::getInstance()->resolveOrCreateModule(
buildParameters.getLLVMContext() ,
buildParameters.getModuleDefinition() );
                        HAssertMsg( 0 != module , " null module ");
                        llvm::Module* excptModule =
Compiler::Services::SymbolResolver::getInstance()->resolveOrCreateNativeExceptionHandlingModule(
buildParameters.getLLVMContext() ); //,
buildParameters.getModuleDefinition() );
                        HAssertMsg( 0 != excptModule , " null
exception module ");
                        HDebugLogLevel("inside BuildIRExpression:, "
<< dynSym.getSymbolName() << " module resolved? " << excptModule, 0);
                        Exceptions::InvokeFunctionResult invokeResult
= Exceptions::createCatchWrappedInvokeFunction(*module, *excptModule,
                                                    buildParameters.builder,

*buildParameters.getFunctionPassManager(),
                                                    *result,

std::string("invoke ")+ fnDecl->functionName.get(),
                                                    numExceptionTypesToCatch,
                                                    innerExceptionTypesToCatch);

the exceptionModule is being generated as:

Compiler::Detail::Exceptions::initialiseExceptionHandlingStaticStuff(ctx);
llvm::Module* excptModule = new
llvm::Module("NativeExceptionHandlingModule" ,
ctx);Compiler::Detail::Exceptions::createStandardUtilityFunctions(6, *
excptModule);

my slightly modified version of ExceptionDemo is appended as an attachment

ExceptionHandling.tar.bz2 (5.32 KB)

Hi Charles, can you reduce to two .ll files that cause llvm-link to assert?

Ciao, Duncan.

define i32 @foo2(i32) {
  %h = alloca i32
  %g = alloca i32
  %bar = alloca i32
  store i32 %0, i32* %bar
  %"argument read" = load i32* %bar
  %"Code::Op::Mul" = mul i32 %"argument read", 5
  store i32 %"Code::Op::Mul", i32* %g
  %read = load i32* %g
}

I tried to reproduce the assert, but llvm-link fails to parse this as
it is a missing a return.

Cheers,
Rafael