<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/57792>57792</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Inconsistency between Interpreter and verifier when referencing a function in another module
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          Il-Capitano
      </td>
    </tr>
</table>

<pre>
    Consider an execution engine having two modules:
```
; ModuleID = 'func1_module'
source_filename = "func1_module"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-windows-gnu"

define i32 @func1() {
entry:
  ret i32 42
}
```
and
```
; ModuleID = 'func2_module'
source_filename = "func2_module"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-windows-gnu"

define i32 @func2() {
entry:
  %0 = call i32 @func1()
  ret i32 %0
}

declare i32 @func1()
```

When I try to execute `@func1` with an interpreter engine, the following error happens:  
`LLVM ERROR: Tried to execute an unknown external function: func1`.  
When using a JIT engine, everything works as expected, and the execution returns 42.

A workaround I found is to use the `Function` object from the module `func1_module` when creating the call `%0 = call i32 @func1()`, but with this method, if I run `verifyModule` on `func2_module`, it fails with the following message:
```
Referencing function in another module!
  %0 = call i32 @func1()
; ModuleID = 'func2_module'
ptr @func1
; ModuleID = 'func1_module'
```
Also note that if I run an optimizer on `@func2`, the call to `@func1` will be deleted, probably because it is invalid IR, so I can't just ignore the verifier.

I've pasted a C++ file at the end of this comment that demonstrates the problem. Uncomment functions at the end of `main` to see the different results.

I tested on the following:
- Windows, with [msys2](https://github.com/msys2/MINGW-packages)'s `mingw-w64-x86_64-llvm` package (version 15.0.0) 
- Ubuntu 20.04 using WSL2, with LLVM-15 installed from the official apt repository

In summary:
- Using a JIT engine and a function declaration (`use_decl_with_jit` function in the attached file): Everything works as expected
- Using an interpreter engine and a function declaration (`use_decl_with_interpreter`): Execution fails
- Using a JIT engine and a function from another module (`no_decl_with_jit`): Verification fails, execution succeeds
- Using an interpreter engine and a function from another module (`no_decl_with_interpreter`): Verification fails, execution succeeds

<details>
<summary>Code to reproduce the problem:</summary>

```
#include <memory>
#include <utility>
#include <string>

#include <llvm/ADT/Triple.h>
#include <llvm/Support/Host.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/MC/TargetRegistry.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Type.h>
#include <llvm/IR/Verifier.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>

using ModulePtr = std::unique_ptr<llvm::Module>;

static ModulePtr create_module(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple,
        std::string const &name
)
{
        auto result = std::make_unique<llvm::Module>(name, context);
        result->setDataLayout(data_layout);
        result->setTargetTriple(target_triple);
        return result;
}

static std::pair<ModulePtr, llvm::Function *> make_func1(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple
)
{
        auto module = create_module(context, data_layout, target_triple, "func1_module");
        auto const i32_type = llvm::Type::getInt32Ty(context);
        auto const fn_type = llvm::FunctionType::get(i32_type, false);
        auto const func1 = llvm::Function::Create(
                fn_type,
                llvm::Function::ExternalLinkage,
                "func1",
                *module
        );

        auto const entry_block = llvm::BasicBlock::Create(context, "entry", func1);
        llvm::IRBuilder<> builder(context);
        builder.SetInsertPoint(entry_block);
        builder.CreateRet(llvm::ConstantInt::get(i32_type, 42));

        llvm::dbgs() << "==== Verifying " << module->getName() << " ====\n";
        llvm::verifyModule(*module, &llvm::dbgs());
        return { std::move(module), func1 };
}

static std::pair<ModulePtr, llvm::Function *> make_func2(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple,
        llvm::Function *func1,
        bool use_decl
)
{
        auto module = create_module(context, data_layout, target_triple, "func2_module");
        auto const i32_type = llvm::Type::getInt32Ty(context);
        auto const fn_type = llvm::FunctionType::get(i32_type, false);
        auto const func2 = llvm::Function::Create(
                fn_type,
                llvm::Function::ExternalLinkage,
                "func2",
                *module
        );

        auto const entry_block = llvm::BasicBlock::Create(context, "entry", func2);
        llvm::IRBuilder<> builder(context);
        builder.SetInsertPoint(entry_block);
        if (use_decl)
        {
                auto const func1_decl = llvm::Function::Create(
                        func1->getFunctionType(),
                        llvm::Function::ExternalLinkage,
                        func1->getName(),
                        *module
                );
                auto const result = builder.CreateCall(func1_decl);
                builder.CreateRet(result);
        }
        else
        {
                auto const result = builder.CreateCall(func1);
                builder.CreateRet(result);
        }

        llvm::dbgs() << "==== Verifying " << module->getName() << " ====\n";
        llvm::verifyModule(*module, &llvm::dbgs());
        return { std::move(module), func2 };
}

static void use_decl_with_jit(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple
)
{
        auto func1_pair = make_func1(context, data_layout, target_triple);
        auto &&func1_module = func1_pair.first;
        auto &&func1 = func1_pair.second;
        auto func2_pair = make_func2(context, data_layout, target_triple, func1, true);
        auto &&func2_module = func2_pair.first;
        auto &&func2 = func2_pair.second;

        llvm::dbgs() << "========\n";
        func1_module->print(llvm::dbgs(), nullptr);
        llvm::dbgs() << "========\n";
        func2_module->print(llvm::dbgs(), nullptr);

        llvm::EngineBuilder builder(std::move(func1_module));

        builder
                .setEngineKind(llvm::EngineKind::JIT)
                .setOptLevel(llvm::CodeGenOpt::None);

        auto engine = std::unique_ptr<llvm::ExecutionEngine>(builder.create());

        engine->addModule(std::move(func2_module));

        auto func2_result = engine->runFunction(func2, {});

        llvm::dbgs() << "========\n";
        llvm::dbgs() << "Result: " << func2_result.IntVal << '\n';
}

static void use_decl_with_interpreter(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple
)
{
        auto func1_pair = make_func1(context, data_layout, target_triple);
        auto &&func1_module = func1_pair.first;
        auto &&func1 = func1_pair.second;
        auto func2_pair = make_func2(context, data_layout, target_triple, func1, true);
        auto &&func2_module = func2_pair.first;
        auto &&func2 = func2_pair.second;

        llvm::dbgs() << "========\n";
        func1_module->print(llvm::dbgs(), nullptr);
        llvm::dbgs() << "========\n";
        func2_module->print(llvm::dbgs(), nullptr);

        llvm::EngineBuilder builder(std::move(func1_module));

        builder
                .setEngineKind(llvm::EngineKind::Interpreter)
                .setOptLevel(llvm::CodeGenOpt::None);

        auto engine = std::unique_ptr<llvm::ExecutionEngine>(builder.create());

        engine->addModule(std::move(func2_module));

        auto func2_result = engine->runFunction(func2, {});

        llvm::dbgs() << "========\n";
        llvm::dbgs() << "Result: " << func2_result.IntVal << '\n';
}

static void no_decl_with_jit(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple
)
{
        auto func1_pair = make_func1(context, data_layout, target_triple);
        auto &&func1_module = func1_pair.first;
        auto &&func1 = func1_pair.second;
        auto func2_pair = make_func2(context, data_layout, target_triple, func1, true);
        auto &&func2_module = func2_pair.first;
        auto &&func2 = func2_pair.second;

        llvm::dbgs() << "========\n";
        func1_module->print(llvm::dbgs(), nullptr);
        llvm::dbgs() << "========\n";
        func2_module->print(llvm::dbgs(), nullptr);

        llvm::EngineBuilder builder(std::move(func1_module));

        builder
                .setEngineKind(llvm::EngineKind::JIT)
                .setOptLevel(llvm::CodeGenOpt::None);

        auto engine = std::unique_ptr<llvm::ExecutionEngine>(builder.create());

        engine->addModule(std::move(func2_module));

        auto func2_result = engine->runFunction(func2, {});

        llvm::dbgs() << "========\n";
        llvm::dbgs() << "Result: " << func2_result.IntVal << '\n';
}

static void no_decl_with_interpreter(
        llvm::LLVMContext &context,
        llvm::DataLayout const &data_layout,
        std::string const &target_triple
)
{
        auto func1_pair = make_func1(context, data_layout, target_triple);
        auto &&func1_module = func1_pair.first;
        auto &&func1 = func1_pair.second;
        auto func2_pair = make_func2(context, data_layout, target_triple, func1, true);
        auto &&func2_module = func2_pair.first;
        auto &&func2 = func2_pair.second;

        llvm::dbgs() << "========\n";
        func1_module->print(llvm::dbgs(), nullptr);
        llvm::dbgs() << "========\n";
        func2_module->print(llvm::dbgs(), nullptr);

        llvm::EngineBuilder builder(std::move(func1_module));

        builder
                .setEngineKind(llvm::EngineKind::Interpreter)
                .setOptLevel(llvm::CodeGenOpt::None);

        auto engine = std::unique_ptr<llvm::ExecutionEngine>(builder.create());

        engine->addModule(std::move(func2_module));

        auto func2_result = engine->runFunction(func2, {});

        llvm::dbgs() << "========\n";
        llvm::dbgs() << "Result: " << func2_result.IntVal << '\n';
}

int main(void)
{
        llvm::LLVMContext context;
        llvm::InitializeAllDisassemblers();
        llvm::InitializeAllTargetInfos();
        llvm::InitializeAllTargets();
        llvm::InitializeAllTargetMCs();
        llvm::InitializeAllAsmParsers();
        llvm::InitializeAllAsmPrinters();

        auto const target_triple = llvm::sys::getDefaultTargetTriple();
        std::string target_error = "";
        auto const target = llvm::TargetRegistry::lookupTarget(target_triple, target_error);
        assert(target);

        auto const target_machine = std::unique_ptr<llvm::TargetMachine>(
                target->createTargetMachine(
                        target_triple,
                        "generic",
                        "",
                        llvm::TargetOptions(),
                        llvm::Reloc::Model::PIC_
                )
        );
        assert(target_machine);
        auto const data_layout = target_machine->createDataLayout();

        // works as expected
        // use_decl_with_jit(context, data_layout, target_triple);

        // error: "LLVM ERROR: Tried to execute an unknown external function: func1"
        use_decl_with_interpreter(context, data_layout, target_triple);

        // works, but verfiyFunction fails for func2_module
        // no_decl_with_jit(context, data_layout, target_triple);

        // works, but verfiyFunction fails for func2_module
        // no_decl_with_interpreter(context, data_layout, target_triple);
}
```
</details>
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztW1tz4rgS_jXkRQUFJiHwkIeEJLPsSWamMtmZR0rYMtFESD6WnCz767db8kU2JsDO7FZqlypCfOlu9fVryVgLFa0vpkpqHrGUUEnY7yzMDFdwJJdcMvJEX7hcEvOqyEpFmWC6M7zs9K87_cvOqJ9_3Onwitxbktk16QzhLziPMxkO5o4RTh2hVlkasnnMBZN0xXLaoE4bOFpD0yUzJKKGCrpWmSmoWXcFirx2k-C8DwfDwH7h6aB-ikejU_vV5cVBPEamQTDuyjEejAoeuPcFLjfHNylPRKnp7-PRHAhf8Y_LSL3q7lJmJY_7jliM_uPDgHRO-9a4DgqekM75lSNh0qTr0p2EpDAS0p8Wgs6vWz1NZXRQBIIDIhD8myMQ7IpAJzjr2zFCKkRL7JqRQvpmrPKxQ0HTtvC3R85-f3tikszA1DUxKi9FMBmICgmjPnnl5gkrlUvD0gQUgcJ1tdoJpsQ8MRIrIdQrVi1LU5VCCScJk1i3YGAx-t3d13ty8_Dw6QGvP6acRf6gMEAmn6V6RUiAISQVBFVAaECGQp1eIdLqnmkclZJfZ4-eTuyFpWvzhLdeVfqsCdUgNGGhYRHeh3S2elfYA1ZlqdRQCD3fP5eWn6YqA44Z2In_uUa9M82sDFDptlATnKUW32EYEqdqZW-73EaqGtqgW1H_MGXUWLgDWpsC6PxdOYEkU7KAyrCxAUs1WTHzpKx1PAZV00yiKHAEj9f35aBKFqoElSqWCXSmXOhCoh_UFdOaLtk2GH5gMUuZDJG0iBgkC3hZgZyUFOU9OCzn98aWxKSVgMMaQ8OSS6EVAa0xstRUjoTcVInhK_4HmONcWNa3c18ZPsiMjfKBywtGIiZYnn9JqhZ0IdZwOaSYSOB9CCGXL1RwSLQHJAJVZiBTgrKGfM80kCylSl3W2bhyltaydQakL4wkVMM4UBTTTnAFH4KoS8Aem_KQwCp2KROq1QrwyBkbsRV0ZZNSw7SlRCUFW_XIb7IgLKKrG9LAzBXlNv_Bfs2cjhGPbWIYqC6dCaPryhIYCPUEf9bSrUyzLvnmkBa9YdOyc3a10msddM6uIVOejEns3CC4hc8SCLJFD1SFE0cV3N7PPn741k1o-Az5qzG1gnNt1YWBXi2a58AuxMsK9c9pIWPG4GONqTw46_V7fYviuV6_LTJpMhLA5dMcgr59uQtKPRHquoMzCKiGHibAyBIPVBzzkAO20QT9kijNjYKO4HtGEp2tVtTrEzDkBtBZFKNVxbkGQO0x1tGoD5k1x6tzVGr-nRs00K9QVIgaQ8MnVJFjYUwQa2_ews-6Qm1t4VDNPAm2nJwOJTZbXNrfD9bVdezJR5Vqwx35YF9tOYXUGw_bSKmCzsKQsaipxT7G76lOqw8OU6vAvmnEjKUd3pSXyoS6maqIYZVC7qWgTcj8YseEGwJs3Fb0NdmNOUQw5DIUWYSzpOkKAMTnqN0EfQU32-4C7NjCrw9WI7H1GdxeXj_C96OdmvWetojLab9kSaJSA0e_KG12USPo3mLhwuLEwAxkf-mPdr74BeA93Ml1Py0ZHtiSg-HrXSyOujz4lFgEPpDrHmocknMvJ8werjIuYHm2F3Ux-dmL-HGd7KfD16K_7SAuUeImn_w1rxwu4AOTMHj4lYqsxm2_Hdi7ucVnnHfA5EKbyNbNZSb5_zM2h_lIId9ezmdfIGh45cuC3mB46Amzk0FWzlHGBfGkkuUlKKDIKHSHgAottNewgLpzC6gQWzsy4KJq7lZVPlNpgqvEit6theZuLbQXBy7vCn8XM7nz0u4JzSz24Hyg7rwVfWZz58Et3gvGVjYgYGn2xHPpxEntAqlmpjIe-GpWb-dxpfKY2zpu2N7gw_VCbkh1o74kywNcmphQjplRBhxNqQwtCgmcCKc3xDqknBW_t1TYEeGi0eEkv5HVlaKkrgJpJlvbM5p6GOxYTkNYRswNwIsds7IcEccdgeiZNMPgce0rsU1cLNukFTGqSQVxxeCodEyFbqaLLxgN2iLWnU2tw_ygwyfXx49ULcJ1ETf5CvqOS5zNNrgKt1p_Nu5c5q4uL9YM2TTHPs-YL4QKnxtGXVHNwyu80TDLSwB8qGMfiFhN8jV-3XWVwLIv4RQFCmSRn22LZn6_9wUDr1lqPiuYZQG5p_MWFqfrg41tpQA-tjRUYhptC_6pzdA2n1ViosVSF4-F0BLrBvBd-XHzvjVWH9wpiFxgEKpg2I8WCRsyiC-kczaVVm6bK2uPBVBMEXYbk1Gbru0ACIXvQbh6QWmFqEkZUoLA-PeCZPAeQbJ1GN-EPOErsoVSghSro38UZIN_G8gG7wJkg3cJss0Q_6Mgy2NcAJdJXqY3-MHL8JauaekPjyoGFtlz6KylVw5t0wb9Xwx5faAKozfpWnKgmQYND3hz5nqXmlIBThxXHtoU09bW8qlrg7bC5gnDCtsdmb30-jkqHTtpsEcnfVE8IpuP_t5he9zR3lxG43zAZldtPbR3f9vsEKAGfPx1hRVfjdaLearNW3xNBs1An2iDw7XVTQOCwxp0MUkgJs12WBQ0LQr2syhoMmxYdHjt7SghPwBYiknq-kZ7xUyJzITAJyvbGtfP0Cf4UX02tHJPlfKW6jXTZqXXl7ntE4KC20NRiJNxQ_yPQ7h8bb3L9vzX2WOt1TrmT4m5Yy9MNNY5EfvAJNxz5x-VZNunKPlj732ehDUfttmHOkUnCMvevcV-NxDGhkZRibhtngx2eNKrTq99VfLTTJZ9P5do8RwQCiD3B1d3e7eWVkkP-ROnS7-h-ab0YP79lYqK5dwNcn542_B_kzi2j2P7OLaP_277mPlYcGwjxzbyVhvZ-KH92D2O3ePYPf673eO4-Dh2jcO6xnHtcewex-5x7B7Htcexi-zsIpDuxL6AHoyxk7TicnvnKLCs_bdQyQ2ngv_BLoW45ppqzVYLwdKilnZzuVfKZjJWh_IcSn8_3Z_jUq8-01QfYgiypLYpb_L4Ken6Za0RNH6x1WvdKX7Vv2YxhYA3XrxraNRsyblwt9Wo47ZnNTJwQ5XmCwu1N3DdNaHUc5YU78023_6b1oZttjKNv3yXTHt6Z-Xeyd0Ldmpv8TrQ8XHQScS6dxBUJ9_4OXzrWyqd4tWFpXsJtuXlBXu79XpT2_xN5d2_sT8woUJ3CJgISG4PP8-m8xqLD_1v-r_w7Pb3Q7x5i3V_na_yY-0t0tawus0n27ZJVARtP8j-pZlgXazLRgelP2WDXbWhcfLWjwE_QXXrsmIf2wtLY74uX41yW9FiqO9aL2xIaHnM9P70-nG_bdmT6zZqVHs9TtjFYDQaDkejcX9wEl0Mo8lwQk8MN4JdzCQmPqAdkyFuOzOvDHd-ertXcNtKsavM7U1MvX193oaWjZ19J1kqLt7YjJW_aY__ukmqcH8knHKtM9ySdXt2fj4JTp4uJqPz4SIcDVh_PKTx6WC8CKNJHNLJJBqenU6iE0EXTOiLztlV5-z6hF8E_SDoTwajAP71B71wFA5CGg8WownrB6eTzmmfwaRA9HDgnkqXJ-mF1WGRwaTktC_AG7q6CRjCl5KxQj6gxZNKL2aiO6UJN2DyiVX5wur7J4cPodQ">