1337b124aSJeffrey Yasskin //===- ExecutionEngineTest.cpp - Unit tests for ExecutionEngine -----------===//
2337b124aSJeffrey Yasskin //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6337b124aSJeffrey Yasskin //
7337b124aSJeffrey Yasskin //===----------------------------------------------------------------------===//
8337b124aSJeffrey Yasskin
99a67b073SChandler Carruth #include "llvm/ADT/STLExtras.h"
10130cec21SChandler Carruth #include "llvm/ExecutionEngine/Interpreter.h"
11ce3f573aSDavid Blaikie #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
129fb823bbSChandler Carruth #include "llvm/IR/DerivedTypes.h"
139fb823bbSChandler Carruth #include "llvm/IR/GlobalVariable.h"
149fb823bbSChandler Carruth #include "llvm/IR/LLVMContext.h"
159fb823bbSChandler Carruth #include "llvm/IR/Module.h"
16ce3f573aSDavid Blaikie #include "llvm/Support/DynamicLibrary.h"
174d723baaSNAKAMURA Takumi #include "llvm/Support/ManagedStatic.h"
18337b124aSJeffrey Yasskin #include "gtest/gtest.h"
19337b124aSJeffrey Yasskin
20337b124aSJeffrey Yasskin using namespace llvm;
21337b124aSJeffrey Yasskin
22337b124aSJeffrey Yasskin namespace {
23337b124aSJeffrey Yasskin
24337b124aSJeffrey Yasskin class ExecutionEngineTest : public testing::Test {
25dbf2c21eSNAKAMURA Takumi private:
26dbf2c21eSNAKAMURA Takumi llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
27dbf2c21eSNAKAMURA Takumi
28337b124aSJeffrey Yasskin protected:
ExecutionEngineTest()292a8a2795SRafael Espindola ExecutionEngineTest() {
30*0eaee545SJonas Devlieghere auto Owner = std::make_unique<Module>("<main>", Context);
312a8a2795SRafael Espindola M = Owner.get();
322a8a2795SRafael Espindola Engine.reset(EngineBuilder(std::move(Owner)).setErrorStr(&Error).create());
33337b124aSJeffrey Yasskin }
34337b124aSJeffrey Yasskin
SetUp()35f817c1cbSAlexander Kornienko void SetUp() override {
3666f09ad0SCraig Topper ASSERT_TRUE(Engine.get() != nullptr) << "EngineBuilder returned error: '"
37f6f9f1ddSDylan Noblesmith << Error << "'";
38337b124aSJeffrey Yasskin }
39337b124aSJeffrey Yasskin
NewExtGlobal(Type * T,const Twine & Name)40229907cdSChris Lattner GlobalVariable *NewExtGlobal(Type *T, const Twine &Name) {
41337b124aSJeffrey Yasskin return new GlobalVariable(*M, T, false, // Not constant.
4266f09ad0SCraig Topper GlobalValue::ExternalLinkage, nullptr, Name);
43337b124aSJeffrey Yasskin }
44337b124aSJeffrey Yasskin
45f6f9f1ddSDylan Noblesmith std::string Error;
4603b42e41SMehdi Amini LLVMContext Context;
472a8a2795SRafael Espindola Module *M; // Owned by ExecutionEngine.
482a8a2795SRafael Espindola std::unique_ptr<ExecutionEngine> Engine;
49337b124aSJeffrey Yasskin };
50337b124aSJeffrey Yasskin
TEST_F(ExecutionEngineTest,ForwardGlobalMapping)51337b124aSJeffrey Yasskin TEST_F(ExecutionEngineTest, ForwardGlobalMapping) {
5203b42e41SMehdi Amini GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
53337b124aSJeffrey Yasskin int32_t Mem1 = 3;
54337b124aSJeffrey Yasskin Engine->addGlobalMapping(G1, &Mem1);
55337b124aSJeffrey Yasskin EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G1));
563dac3f7fSLang Hames EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable("Global1"));
57337b124aSJeffrey Yasskin int32_t Mem2 = 4;
58337b124aSJeffrey Yasskin Engine->updateGlobalMapping(G1, &Mem2);
59337b124aSJeffrey Yasskin EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1));
6066f09ad0SCraig Topper Engine->updateGlobalMapping(G1, nullptr);
6166f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G1));
62337b124aSJeffrey Yasskin Engine->updateGlobalMapping(G1, &Mem2);
63337b124aSJeffrey Yasskin EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1));
64337b124aSJeffrey Yasskin
6503b42e41SMehdi Amini GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
6666f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G2))
67337b124aSJeffrey Yasskin << "The NULL return shouldn't depend on having called"
68337b124aSJeffrey Yasskin << " updateGlobalMapping(..., NULL)";
69337b124aSJeffrey Yasskin // Check that update...() can be called before add...().
70337b124aSJeffrey Yasskin Engine->updateGlobalMapping(G2, &Mem1);
71337b124aSJeffrey Yasskin EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G2));
72337b124aSJeffrey Yasskin EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1))
73337b124aSJeffrey Yasskin << "A second mapping shouldn't affect the first.";
74337b124aSJeffrey Yasskin }
75337b124aSJeffrey Yasskin
TEST_F(ExecutionEngineTest,ReverseGlobalMapping)76337b124aSJeffrey Yasskin TEST_F(ExecutionEngineTest, ReverseGlobalMapping) {
7703b42e41SMehdi Amini GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
78337b124aSJeffrey Yasskin
79337b124aSJeffrey Yasskin int32_t Mem1 = 3;
80337b124aSJeffrey Yasskin Engine->addGlobalMapping(G1, &Mem1);
81337b124aSJeffrey Yasskin EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1));
82337b124aSJeffrey Yasskin int32_t Mem2 = 4;
83337b124aSJeffrey Yasskin Engine->updateGlobalMapping(G1, &Mem2);
8466f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
85337b124aSJeffrey Yasskin EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2));
86337b124aSJeffrey Yasskin
8703b42e41SMehdi Amini GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global2");
88337b124aSJeffrey Yasskin Engine->updateGlobalMapping(G2, &Mem1);
89337b124aSJeffrey Yasskin EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1));
90337b124aSJeffrey Yasskin EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2));
9166f09ad0SCraig Topper Engine->updateGlobalMapping(G1, nullptr);
92337b124aSJeffrey Yasskin EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1))
93337b124aSJeffrey Yasskin << "Removing one mapping doesn't affect a different one.";
9466f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem2));
95337b124aSJeffrey Yasskin Engine->updateGlobalMapping(G2, &Mem2);
9666f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
97337b124aSJeffrey Yasskin EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem2))
98337b124aSJeffrey Yasskin << "Once a mapping is removed, we can point another GV at the"
99337b124aSJeffrey Yasskin << " now-free address.";
100337b124aSJeffrey Yasskin }
101337b124aSJeffrey Yasskin
TEST_F(ExecutionEngineTest,ClearModuleMappings)102307c053fSJeffrey Yasskin TEST_F(ExecutionEngineTest, ClearModuleMappings) {
10303b42e41SMehdi Amini GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
104307c053fSJeffrey Yasskin
105307c053fSJeffrey Yasskin int32_t Mem1 = 3;
106307c053fSJeffrey Yasskin Engine->addGlobalMapping(G1, &Mem1);
107307c053fSJeffrey Yasskin EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1));
108307c053fSJeffrey Yasskin
109307c053fSJeffrey Yasskin Engine->clearGlobalMappingsFromModule(M);
110307c053fSJeffrey Yasskin
11166f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
112307c053fSJeffrey Yasskin
11303b42e41SMehdi Amini GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global2");
114307c053fSJeffrey Yasskin // After clearing the module mappings, we can assign a new GV to the
115307c053fSJeffrey Yasskin // same address.
116307c053fSJeffrey Yasskin Engine->addGlobalMapping(G2, &Mem1);
117307c053fSJeffrey Yasskin EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1));
118307c053fSJeffrey Yasskin }
119307c053fSJeffrey Yasskin
TEST_F(ExecutionEngineTest,DestructionRemovesGlobalMapping)120f98e981cSJeffrey Yasskin TEST_F(ExecutionEngineTest, DestructionRemovesGlobalMapping) {
12103b42e41SMehdi Amini GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
122f98e981cSJeffrey Yasskin int32_t Mem1 = 3;
123f98e981cSJeffrey Yasskin Engine->addGlobalMapping(G1, &Mem1);
124f98e981cSJeffrey Yasskin // Make sure the reverse mapping is enabled.
125f98e981cSJeffrey Yasskin EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1));
126f98e981cSJeffrey Yasskin // When the GV goes away, the ExecutionEngine should remove any
127f98e981cSJeffrey Yasskin // mappings that refer to it.
128f98e981cSJeffrey Yasskin G1->eraseFromParent();
12966f09ad0SCraig Topper EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
130f98e981cSJeffrey Yasskin }
131f98e981cSJeffrey Yasskin
TEST_F(ExecutionEngineTest,LookupWithMangledAndDemangledSymbol)132ce3f573aSDavid Blaikie TEST_F(ExecutionEngineTest, LookupWithMangledAndDemangledSymbol) {
133ce3f573aSDavid Blaikie int x;
134ce3f573aSDavid Blaikie int _x;
135ce3f573aSDavid Blaikie llvm::sys::DynamicLibrary::AddSymbol("x", &x);
136ce3f573aSDavid Blaikie llvm::sys::DynamicLibrary::AddSymbol("_x", &_x);
137ce3f573aSDavid Blaikie
1383b514554SLang Hames // RTDyldMemoryManager::getSymbolAddressInProcess expects a mangled symbol,
1393b514554SLang Hames // but DynamicLibrary is a wrapper for dlsym, which expects the unmangled C
1403b514554SLang Hames // symbol name. This test verifies that getSymbolAddressInProcess strips the
14175601bf7SLang Hames // leading '_' on Darwin, but not on other platforms.
14275601bf7SLang Hames #ifdef __APPLE__
1432f27b2feSLang Hames EXPECT_EQ(reinterpret_cast<uint64_t>(&x),
1442f27b2feSLang Hames RTDyldMemoryManager::getSymbolAddressInProcess("_x"));
1453b514554SLang Hames #else
1462f27b2feSLang Hames EXPECT_EQ(reinterpret_cast<uint64_t>(&_x),
1472f27b2feSLang Hames RTDyldMemoryManager::getSymbolAddressInProcess("_x"));
1483b514554SLang Hames #endif
149ce3f573aSDavid Blaikie }
150ce3f573aSDavid Blaikie
151337b124aSJeffrey Yasskin }
152