12d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===//
22d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//
32d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//                     The LLVM Compiler Infrastructure
42d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//
52d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// This file is distributed under the University of Illinois Open Source
62d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// License. See LICENSE.TXT for details.
72d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//
82d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//===----------------------------------------------------------------------===//
92d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//
102d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// This test suite verifies basic MCJIT functionality such as making function
112d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// calls, using global variables, and compiling multpile modules.
122d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//
132d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor//===----------------------------------------------------------------------===//
142d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
152d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor#include "llvm/ExecutionEngine/MCJIT.h"
162d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor#include "MCJITTestBase.h"
175a88dda4be791426ab4d20a6a6c9c65d66614a27Chandler Carruth#include "gtest/gtest.h"
182d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
192d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylorusing namespace llvm;
202d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
219d7c776d32c8a4d64b37a91c2d627629cf1498efBill Wendlingnamespace {
229d7c776d32c8a4d64b37a91c2d627629cf1498efBill Wendling
232d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylorclass MCJITTest : public testing::Test, public MCJITTestBase {
242d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylorprotected:
252c3e0051c31c3f5b2328b447eadf1cf9c4427442Pirama Arumuga Nainar  void SetUp() override { M.reset(createEmptyModule("<main>")); }
262d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor};
272d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
2870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// FIXME: Ensure creating an execution engine does not crash when constructed
2970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//        with a null module.
3070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor/*
3170c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITTest, null_module) {
3270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createJIT(0);
3370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
3470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor*/
3570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
362d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// FIXME: In order to JIT an empty module, there needs to be
372d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// an interface to ExecutionEngine that forces compilation but
3870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// does not require retrieval of a pointer to a function/global.
392d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor/*
402d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, empty_module) {
412d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  createJIT(M.take());
422d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  //EXPECT_NE(0, TheJIT->getObjectImage())
432d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  //  << "Unable to generate executable loaded object image";
442d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
452d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor*/
462d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
472d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, global_variable) {
482d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
492d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
502d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int initialValue = 5;
512d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
5237ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(M));
532d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  void *globalPtr =  TheJIT->getPointerToGlobal(Global);
54c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  EXPECT_TRUE(nullptr != globalPtr)
552d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Unable to get pointer to global value from JIT";
562d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
572d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_EQ(initialValue, *(int32_t*)globalPtr)
582d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Unexpected initial value of global";
592d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
602d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
612d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, add_function) {
622d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
632d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
642d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Function *F = insertAddFunction(M.get());
6537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(M));
6670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str());
672d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_TRUE(0 != addPtr)
682d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Unable to get pointer to function from JIT";
692d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
7070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ASSERT_TRUE(addPtr != 0) << "Unable to get pointer to function .";
7170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int (*AddPtr)(int, int) = (int(*)(int, int))addPtr ;
7270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(0,   AddPtr(0, 0));
7370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(1,   AddPtr(1, 0));
7470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(3,   AddPtr(1, 2));
7570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(-5,  AddPtr(-2, -3));
7670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(30,  AddPtr(10, 20));
7770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(-30, AddPtr(-10, -20));
7870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(-40, AddPtr(-10, -30));
792d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
802d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
812d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, run_main) {
822d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
832d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
842d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int rc = 6;
852d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Function *Main = insertMainFunction(M.get(), 6);
8637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(M));
8770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str());
8870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_TRUE(0 != ptr)
892d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Unable to get pointer to main() from JIT";
902d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
9170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int (*FuncPtr)(void) = (int(*)(void))ptr;
922d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int returnCode = FuncPtr();
932d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_EQ(returnCode, rc);
942d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
952d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
962d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, return_global) {
972d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
982d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
992d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int32_t initialNum = 7;
1002d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  GlobalVariable *GV = insertGlobalInt32(M.get(), "myglob", initialNum);
1012d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1022d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Function *ReturnGlobal = startFunction<int32_t(void)>(M.get(),
1032d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor                                                        "ReturnGlobal");
1042d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Value *ReadGlobal = Builder.CreateLoad(GV);
1052d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  endFunctionWithRet(ReturnGlobal, ReadGlobal);
1062d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
10737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(M));
10870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str());
1092d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_TRUE(0 != rgvPtr);
1102d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
11170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int32_t(*FuncPtr)(void) = (int32_t(*)(void))rgvPtr;
1122d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_EQ(initialNum, FuncPtr())
1132d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Invalid value for global returned from JITted function";
1142d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
1152d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1162d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// FIXME: This case fails due to a bug with getPointerToGlobal().
1172d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// The bug is due to MCJIT not having an implementation of getPointerToGlobal()
1182d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// which results in falling back on the ExecutionEngine implementation that
1192d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// allocates a new memory block for the global instead of using the same
1202d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below)
1212d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// has the correct initial value, but updates to the real global (accessed by
1222d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// JITted code) are not propagated. Instead, getPointerToGlobal() should return
1232d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor// a pointer into the loaded ObjectImage to reference the emitted global.
1242d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor/*
1252d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, increment_global) {
1262d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
1272d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1282d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int32_t initialNum = 5;
1292d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Function *IncrementGlobal = startFunction<int32_t(void)>(M.get(), "IncrementGlobal");
1302d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  GlobalVariable *GV = insertGlobalInt32(M.get(), "my_global", initialNum);
1312d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Value *DerefGV = Builder.CreateLoad(GV);
1322d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Value *AddResult = Builder.CreateAdd(DerefGV,
1332d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor                                       ConstantInt::get(Context, APInt(32, 1)));
1342d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Builder.CreateStore(AddResult, GV);
1352d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  endFunctionWithRet(IncrementGlobal, AddResult);
1362d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1372d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  createJIT(M.take());
1382d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  void *gvPtr = TheJIT->getPointerToGlobal(GV);
1392d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
1402d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
14170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str());
1422d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_TRUE(0 != vPtr)
1432d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Unable to get pointer to main() from JIT";
1442d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1452d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr;
1462d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1472d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  for(int i = 1; i < 3; ++i) {
1482d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    int32_t result = FuncPtr();
1492d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    EXPECT_EQ(initialNum + i, result);            // OK
1502d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    EXPECT_EQ(initialNum + i, *(int32_t*)gvPtr);  // FAILS
1512d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  }
1522d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
1532d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor*/
1542d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
155abb38fe8dec11b1ea7535f84fac8ad0f0af70addDavid Tweed// PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations.
156abb38fe8dec11b1ea7535f84fac8ad0f0af70addDavid Tweed#if !defined(__arm__)
157abb38fe8dec11b1ea7535f84fac8ad0f0af70addDavid Tweed
1582d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew KaylorTEST_F(MCJITTest, multiple_functions) {
1592d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
1602d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1612d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  unsigned int numLevels = 23;
1622d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  int32_t innerRetVal= 5;
1632d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1642d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Function *Inner = startFunction<int32_t(void)>(M.get(), "Inner");
1652d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  endFunctionWithRet(Inner, ConstantInt::get(Context, APInt(32, innerRetVal)));
1662d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1672d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  Function *Outer;
1682d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  for (unsigned int i = 0; i < numLevels; ++i) {
1692d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    std::stringstream funcName;
1702d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    funcName << "level_" << i;
1712d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    Outer = startFunction<int32_t(void)>(M.get(), funcName.str());
1722d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    Value *innerResult = Builder.CreateCall(Inner);
1732d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    endFunctionWithRet(Outer, innerResult);
1742d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
1752d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    Inner = Outer;
1762d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  }
1772d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
17837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(M));
17970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str());
18070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_TRUE(0 != ptr)
1812d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Unable to get pointer to outer function from JIT";
1822d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
18370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int32_t(*FuncPtr)(void) = (int32_t(*)(void))ptr;
1842d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor  EXPECT_EQ(innerRetVal, FuncPtr())
1852d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor    << "Incorrect result returned from function";
1862d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
1872d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor
188abb38fe8dec11b1ea7535f84fac8ad0f0af70addDavid Tweed#endif /*!defined(__arm__)*/
189abb38fe8dec11b1ea7535f84fac8ad0f0af70addDavid Tweed
19037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen HinesTEST_F(MCJITTest, multiple_decl_lookups) {
19137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  SKIP_UNSUPPORTED_PLATFORM;
19237ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines
19337ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  Function *Foo = insertExternalReferenceToFunction<void(void)>(M.get(), "_exit");
19437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(M));
19537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  void *A = TheJIT->getPointerToFunction(Foo);
19637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  void *B = TheJIT->getPointerToFunction(Foo);
19737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines
19837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  EXPECT_TRUE(A != 0) << "Failed lookup - test not correctly configured.";
19937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  EXPECT_EQ(A, B) << "Repeat calls to getPointerToFunction fail.";
20037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines}
20137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines
2022d6d585c85ce8c56461f17b7b49fff24eed7b8fbAndrew Kaylor}
203