170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//===- MCJITMultipeModuleTest.cpp - Unit tests for the MCJIT---------------===//
270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//
370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//                     The LLVM Compiler Infrastructure
470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//
570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// This file is distributed under the University of Illinois Open Source
670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// License. See LICENSE.TXT for details.
770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//
870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//===----------------------------------------------------------------------===//
970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//
1070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// This test suite verifies MCJIT for handling multiple modules in a single
1170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// ExecutionEngine by building multiple modules, making function calls across
1270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// modules, accessing global variables, etc.
1370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor//===----------------------------------------------------------------------===//
1470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
1570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor#include "llvm/ExecutionEngine/MCJIT.h"
1670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor#include "MCJITTestBase.h"
1770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor#include "gtest/gtest.h"
1870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
1970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylorusing namespace llvm;
2070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
2170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylornamespace {
2270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
239d7c776d32c8a4d64b37a91c2d627629cf1498efBill Wendlingclass MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
249d7c776d32c8a4d64b37a91c2d627629cf1498efBill Wendling
2570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// FIXME: ExecutionEngine has no support empty modules
2670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor/*
2770c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
2870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
2970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
3070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createJIT(M.take());
3170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  // JIT-compile
3270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_NE(0, TheJIT->getObjectImage())
3370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor    << "Unable to generate executable loaded object image";
3470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
3570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->addModule(createEmptyModule("<other module>"));
3670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->addModule(createEmptyModule("<other other module>"));
3770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
3870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  // JIT again
3970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_NE(0, TheJIT->getObjectImage())
4070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor    << "Unable to generate executable loaded object image";
4170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
4270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor*/
4370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
4470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Helper Function to test add operation
4570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylorvoid checkAdd(uint64_t ptr) {
4670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function.";
4770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int (*AddPtr)(int, int) = (int (*)(int, int))ptr;
4870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(0, AddPtr(0, 0));
4970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(1, AddPtr(1, 0));
5070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(3, AddPtr(1, 2));
5170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(-5, AddPtr(-2, -3));
5270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(30, AddPtr(10, 20));
5370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(-30, AddPtr(-10, -20));
5470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(-40, AddPtr(-10, -30));
5570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
5670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
5770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylorvoid checkAccumulate(uint64_t ptr) {
5870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function.";
5970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int32_t (*FPtr)(int32_t) = (int32_t (*)(int32_t))(intptr_t)ptr;
6070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(0, FPtr(0));
6170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(1, FPtr(1));
6270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(3, FPtr(2));
6370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(6, FPtr(3));
6470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(10, FPtr(4));
6570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(15, FPtr(5));
6670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
6770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
6870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// FIXME: ExecutionEngine has no support empty modules
6970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor/*
7070c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
7170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
7270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
7370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createJIT(M.take());
7470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  // JIT-compile
7570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_NE(0, TheJIT->getObjectImage())
7670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor    << "Unable to generate executable loaded object image";
7770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
7870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->addModule(createEmptyModule("<other module>"));
7970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->addModule(createEmptyModule("<other other module>"));
8070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
8170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  // JIT again
8270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_NE(0, TheJIT->getObjectImage())
8370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor    << "Unable to generate executable loaded object image";
8470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
8570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor*/
8670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
8770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
8870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Function FB },
8970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FA then FB
9070c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, two_module_case) {
9170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
9270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
9336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
9470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB;
9570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createTwoModuleCase(A, FA, B, FB);
9670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
9737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
9837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
9970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
10070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
10170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
10270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
10370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB->getName().str());
10470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
10570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
10670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
10770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
10870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Function FB },
10970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FB then FA
11070c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, two_module_reverse_case) {
11170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
11270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
11336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
11470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB;
11570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createTwoModuleCase(A, FA, B, FB);
11670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
11737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
11837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
11970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
12070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
12170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->finalizeObject();
12270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
12370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
12470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FA->getName().str());
12570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
12670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
12770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
12870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
12970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB which calls FA },
13070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FB then FA
13170c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, two_module_extern_reverse_case) {
13270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
13370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
13436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
13570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB;
13670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createTwoModuleExternCase(A, FA, B, FB);
13770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
13837ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
13937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
14070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
14170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
14270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->finalizeObject();
14370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
14470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
14570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FA->getName().str());
14670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
14770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
14870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
14970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
15070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB which calls FA },
15170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FA then FB
15270c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, two_module_extern_case) {
15370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
15470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
15536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
15670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB;
15770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createTwoModuleExternCase(A, FA, B, FB);
15870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
15937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
16037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
16170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
16270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
16370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
16470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
16570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB->getName().str());
16670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
16770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
16870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
16970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA1, Function FA2 which calls FA1 },
17070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA1, Function FB which calls FA1 },
17170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FB then FA2
17270c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, two_module_consecutive_call_case) {
17370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
17470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
17536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
17670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA1, *FA2, *FB;
17770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createTwoModuleExternCase(A, FA1, B, FB);
17870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  FA2 = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(A.get(), FA1);
17970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
18037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
18137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
18270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
18370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
18470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->finalizeObject();
18570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
18670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
18770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FA2->getName().str());
18870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
18970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
19070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
19170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// TODO:
19270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Extern Global GVB, Global Variable GVA, Function FA loads GVB },
19370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern Global GVA, Global Variable GVB, Function FB loads GVA },
19470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
19570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
19670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Global Variable GVA, Function FA loads GVA },
19770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Global Variable GVB, Function FB loads GVB },
19870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FB then FA
19970c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, two_module_global_variables_case) {
20070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
20170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
20236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
20370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB;
20470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  GlobalVariable *GVA, *GVB;
20570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  A.reset(createEmptyModule("A"));
20670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  B.reset(createEmptyModule("B"));
20770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
20870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int32_t initialNum = 7;
20970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  GVA = insertGlobalInt32(A.get(), "GVA", initialNum);
21070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  GVB = insertGlobalInt32(B.get(), "GVB", initialNum);
21170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  FA = startFunction<int32_t(void)>(A.get(), "FA");
21270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  endFunctionWithRet(FA, Builder.CreateLoad(GVA));
21370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  FB = startFunction<int32_t(void)>(B.get(), "FB");
21470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  endFunctionWithRet(FB, Builder.CreateLoad(GVB));
21570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
21637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
21737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
21870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
21970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t FBPtr = TheJIT->getFunctionAddress(FB->getName().str());
22070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  TheJIT->finalizeObject();
22170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_TRUE(0 != FBPtr);
22270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  int32_t(*FuncPtr)(void) = (int32_t(*)(void))FBPtr;
22370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(initialNum, FuncPtr())
22470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor    << "Invalid value for global returned from JITted function in module B";
22570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
22670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t FAPtr = TheJIT->getFunctionAddress(FA->getName().str());
22770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_TRUE(0 != FAPtr);
22870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  FuncPtr = (int32_t(*)(void))FAPtr;
22970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  EXPECT_EQ(initialNum, FuncPtr())
23070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor    << "Invalid value for global returned from JITted function in module A";
23170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
23270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
23370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
23470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB which calls FA },
23570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module C { Extern FA, Function FC which calls FA },
23670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FC, FB, FA
23770c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, three_module_case) {
238ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover  SKIP_UNSUPPORTED_PLATFORM;
239ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover
24036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B, C;
24170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB, *FC;
24270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createThreeModuleCase(A, FA, B, FB, C, FC);
24370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
24437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
24537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
24637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(C));
24770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
24870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
24970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
25070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
25170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB->getName().str());
25270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
25370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
25470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FA->getName().str());
25570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
25670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
25770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
25870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
25970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB which calls FA },
26070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module C { Extern FA, Function FC which calls FA },
26170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FA, FB, FC
26270c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, three_module_case_reverse_order) {
263ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover  SKIP_UNSUPPORTED_PLATFORM;
264ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover
26536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B, C;
26670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB, *FC;
26770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createThreeModuleCase(A, FA, B, FB, C, FC);
26870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
26937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
27037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
27137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(C));
27270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
27370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
27470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
27570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
27670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB->getName().str());
27770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
27870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
27970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FC->getName().str());
28070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
28170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
28270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
28370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
28470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB which calls FA },
28570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module C { Extern FB, Function FC which calls FB },
28670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FC, FB, FA
28770c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, three_module_chain_case) {
288ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover  SKIP_UNSUPPORTED_PLATFORM;
289ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover
29036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B, C;
29170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB, *FC;
29270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
29370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
29437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
29537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
29637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(C));
29770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
29870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
29970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
30070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
30170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB->getName().str());
30270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
30370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
30470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FA->getName().str());
30570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
30670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
30770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
30870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Function FA },
30970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB which calls FA },
31070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module C { Extern FB, Function FC which calls FB },
31170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FA, FB, FC
31270c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, three_modules_chain_case_reverse_order) {
313ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover  SKIP_UNSUPPORTED_PLATFORM;
314ea246d6af8f112001c8b13ffcc9c4fcc6ad992a2Tim Northover
31536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B, C;
31670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB, *FC;
31770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
31870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
31937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
32037ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
32137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(C));
32270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
32370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
32470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
32570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
32670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB->getName().str());
32770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
32870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
32970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FC->getName().str());
33070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAdd(ptr);
33170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
33270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
33370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Extern FB, Function FA which calls FB1 },
33470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
33570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FA, then FB1
33670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// FIXME: this test case is not supported by MCJIT
33770c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, cross_module_dependency_case) {
33870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
33970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
34036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
34170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB1, *FB2;
34270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
34370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
34437ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
34537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
34670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
34770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
34870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAccumulate(ptr);
34970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
35070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB1->getName().str());
35170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAccumulate(ptr);
35270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
35370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
35470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Extern FB, Function FA which calls FB1 },
35570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
35670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FB1 then FA
35770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// FIXME: this test case is not supported by MCJIT
35870c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, cross_module_dependency_case_reverse_order) {
35970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
36070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
36136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
36270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB1, *FB2;
36370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
36470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
36537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
36637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
36770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
36870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
36970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAccumulate(ptr);
37070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
37170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FA->getName().str());
37270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAccumulate(ptr);
37370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
37470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
37570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module A { Extern FB1, Function FA which calls FB1 },
37670c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
37770c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// execute FB1 then FB2
37870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor// FIXME: this test case is not supported by MCJIT
37970c1ea493e6156eccde5270c139ef423b19ab580Andrew KaylorTEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) {
38070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  SKIP_UNSUPPORTED_PLATFORM;
38170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
38236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  std::unique_ptr<Module> A, B;
38370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  Function *FA, *FB1, *FB2;
38470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
38570c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
38637ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  createJIT(std::move(A));
38737ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  TheJIT->addModule(std::move(B));
38870c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
38970c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
39070c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAccumulate(ptr);
39170c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor
39270c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  ptr = TheJIT->getFunctionAddress(FB2->getName().str());
39370c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor  checkAccumulate(ptr);
39470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
395ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
396ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines// Test that FindFunctionNamed finds the definition of
397ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines// a function in the correct module. We check two functions
398ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines// in two different modules, to make sure that for at least
399ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines// one of them MCJIT had to ignore the extern declaration.
400ebe69fe11e48d322045d5949c83283927a0d790bStephen HinesTEST_F(MCJITMultipleModuleTest, FindFunctionNamed_test) {
401ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  SKIP_UNSUPPORTED_PLATFORM;
402ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
403ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  std::unique_ptr<Module> A, B;
404ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  Function *FA, *FB1, *FB2;
405ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
406ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
407ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  createJIT(std::move(A));
408ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  TheJIT->addModule(std::move(B));
409ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
410ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EXPECT_EQ(FA, TheJIT->FindFunctionNamed(FA->getName().data()));
411ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EXPECT_EQ(FB1, TheJIT->FindFunctionNamed(FB1->getName().data()));
412ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines}
413ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
41470c1ea493e6156eccde5270c139ef423b19ab580Andrew Kaylor}
415