[DAGCombiner] Expand combining of FP logical ops to sign-setting FP ops
[llvm-core.git] / unittests / ExecutionEngine / Orc / ObjectTransformLayerTest.cpp
blob6ad3c19ada95f6732d50b844ae30969db32c17fa
1 //===- ObjectTransformLayerTest.cpp - Unit tests for ObjectTransformLayer -===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
14 #include "llvm/ExecutionEngine/Orc/NullResolver.h"
15 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
16 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
17 #include "llvm/IR/Module.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "gtest/gtest.h"
21 using namespace llvm::orc;
23 namespace {
25 // stand-in for object::ObjectFile
26 typedef int MockObjectFile;
28 // stand-in for llvm::MemoryBuffer set
29 typedef int MockMemoryBuffer;
31 // Mock transform that operates on unique pointers to object files, and
32 // allocates new object files rather than mutating the given ones.
33 struct AllocatingTransform {
34 std::shared_ptr<MockObjectFile>
35 operator()(std::shared_ptr<MockObjectFile> Obj) const {
36 return std::make_shared<MockObjectFile>(*Obj + 1);
40 // Mock base layer for verifying behavior of transform layer.
41 // Each method "T foo(args)" is accompanied by two auxiliary methods:
42 // - "void expectFoo(args)", to be called before calling foo on the transform
43 // layer; saves values of args, which mock layer foo then verifies against.
44 // - "void verifyFoo(T)", to be called after foo, which verifies that the
45 // transform layer called the base layer and forwarded any return value.
46 class MockBaseLayer {
47 public:
48 MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
50 template <typename ObjPtrT> llvm::Error addObject(VModuleKey K, ObjPtrT Obj) {
51 EXPECT_EQ(MockKey, K) << "Key should pass through";
52 EXPECT_EQ(MockObject + 1, *Obj) << "Transform should be applied";
53 LastCalled = "addObject";
54 return llvm::Error::success();
57 template <typename ObjPtrT> void expectAddObject(VModuleKey K, ObjPtrT Obj) {
58 MockKey = K;
59 MockObject = *Obj;
62 void verifyAddObject() {
63 EXPECT_EQ("addObject", LastCalled);
64 resetExpectations();
67 llvm::Error removeObject(VModuleKey K) {
68 EXPECT_EQ(MockKey, K);
69 LastCalled = "removeObject";
70 return llvm::Error::success();
73 void expectRemoveObject(VModuleKey K) { MockKey = K; }
74 void verifyRemoveObject() {
75 EXPECT_EQ("removeObject", LastCalled);
76 resetExpectations();
79 llvm::JITSymbol findSymbol(const std::string &Name,
80 bool ExportedSymbolsOnly) {
81 EXPECT_EQ(MockName, Name) << "Name should pass through";
82 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
83 LastCalled = "findSymbol";
84 MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
85 return llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
87 void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
88 MockName = Name;
89 MockBool = ExportedSymbolsOnly;
91 void verifyFindSymbol(llvm::JITSymbol Returned) {
92 EXPECT_EQ("findSymbol", LastCalled);
93 EXPECT_EQ(cantFail(MockSymbol.getAddress()),
94 cantFail(Returned.getAddress()))
95 << "Return should pass through";
96 resetExpectations();
99 llvm::JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
100 bool ExportedSymbolsOnly) {
101 EXPECT_EQ(MockKey, K) << "VModuleKey should pass through";
102 EXPECT_EQ(MockName, Name) << "Name should pass through";
103 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
104 LastCalled = "findSymbolIn";
105 MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
106 return llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
108 void expectFindSymbolIn(VModuleKey K, const std::string &Name,
109 bool ExportedSymbolsOnly) {
110 MockKey = K;
111 MockName = Name;
112 MockBool = ExportedSymbolsOnly;
114 void verifyFindSymbolIn(llvm::JITSymbol Returned) {
115 EXPECT_EQ("findSymbolIn", LastCalled);
116 EXPECT_EQ(cantFail(MockSymbol.getAddress()),
117 cantFail(Returned.getAddress()))
118 << "Return should pass through";
119 resetExpectations();
122 llvm::Error emitAndFinalize(VModuleKey K) {
123 EXPECT_EQ(MockKey, K) << "VModuleKey should pass through";
124 LastCalled = "emitAndFinalize";
125 return llvm::Error::success();
128 void expectEmitAndFinalize(VModuleKey K) { MockKey = K; }
130 void verifyEmitAndFinalize() {
131 EXPECT_EQ("emitAndFinalize", LastCalled);
132 resetExpectations();
135 void mapSectionAddress(VModuleKey K, const void *LocalAddress,
136 llvm::JITTargetAddress TargetAddr) {
137 EXPECT_EQ(MockKey, K);
138 EXPECT_EQ(MockLocalAddress, LocalAddress);
139 EXPECT_EQ(MockTargetAddress, TargetAddr);
140 LastCalled = "mapSectionAddress";
142 void expectMapSectionAddress(VModuleKey K, const void *LocalAddress,
143 llvm::JITTargetAddress TargetAddr) {
144 MockKey = K;
145 MockLocalAddress = LocalAddress;
146 MockTargetAddress = TargetAddr;
148 void verifyMapSectionAddress() {
149 EXPECT_EQ("mapSectionAddress", LastCalled);
150 resetExpectations();
153 private:
154 // Backing fields for remembering parameter/return values
155 std::string LastCalled;
156 VModuleKey MockKey;
157 MockObjectFile MockObject;
158 std::string MockName;
159 bool MockBool;
160 llvm::JITSymbol MockSymbol;
161 const void *MockLocalAddress;
162 llvm::JITTargetAddress MockTargetAddress;
163 MockMemoryBuffer MockBuffer;
165 // Clear remembered parameters between calls
166 void resetExpectations() {
167 LastCalled = "nothing";
168 MockKey = 0;
169 MockObject = 0;
170 MockName = "bogus";
171 MockSymbol = llvm::JITSymbol(nullptr);
172 MockLocalAddress = nullptr;
173 MockTargetAddress = 0;
174 MockBuffer = 0;
178 // Test each operation on ObjectTransformLayer.
179 TEST(ObjectTransformLayerTest, Main) {
180 MockBaseLayer M;
182 ExecutionSession ES(std::make_shared<SymbolStringPool>());
184 // Create one object transform layer using a transform (as a functor)
185 // that allocates new objects, and deals in unique pointers.
186 ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M);
188 // Create a second object transform layer using a transform (as a lambda)
189 // that mutates objects in place, and deals in naked pointers
190 ObjectTransformLayer<MockBaseLayer,
191 std::function<std::shared_ptr<MockObjectFile>(
192 std::shared_ptr<MockObjectFile>)>>
193 T2(M, [](std::shared_ptr<MockObjectFile> Obj) {
194 ++(*Obj);
195 return Obj;
198 // Test addObject with T1 (allocating)
199 auto K1 = ES.allocateVModule();
200 auto Obj1 = std::make_shared<MockObjectFile>(211);
201 M.expectAddObject(K1, Obj1);
202 cantFail(T1.addObject(K1, std::move(Obj1)));
203 M.verifyAddObject();
205 // Test addObjectSet with T2 (mutating)
206 auto K2 = ES.allocateVModule();
207 auto Obj2 = std::make_shared<MockObjectFile>(222);
208 M.expectAddObject(K2, Obj2);
209 cantFail(T2.addObject(K2, Obj2));
210 M.verifyAddObject();
211 EXPECT_EQ(223, *Obj2) << "Expected mutation";
213 // Test removeObjectSet
214 M.expectRemoveObject(K2);
215 cantFail(T1.removeObject(K2));
216 M.verifyRemoveObject();
218 // Test findSymbol
219 std::string Name = "foo";
220 bool ExportedOnly = true;
221 M.expectFindSymbol(Name, ExportedOnly);
222 llvm::JITSymbol Sym1 = T2.findSymbol(Name, ExportedOnly);
223 M.verifyFindSymbol(std::move(Sym1));
225 // Test findSymbolIn
226 Name = "bar";
227 ExportedOnly = false;
228 M.expectFindSymbolIn(K1, Name, ExportedOnly);
229 llvm::JITSymbol Sym2 = T1.findSymbolIn(K1, Name, ExportedOnly);
230 M.verifyFindSymbolIn(std::move(Sym2));
232 // Test emitAndFinalize
233 M.expectEmitAndFinalize(K1);
234 cantFail(T2.emitAndFinalize(K1));
235 M.verifyEmitAndFinalize();
237 // Test mapSectionAddress
238 char Buffer[24];
239 llvm::JITTargetAddress MockAddress = 255;
240 M.expectMapSectionAddress(K1, Buffer, MockAddress);
241 T1.mapSectionAddress(K1, Buffer, MockAddress);
242 M.verifyMapSectionAddress();
244 // Verify transform getter (non-const)
245 auto Mutatee = std::make_shared<MockObjectFile>(277);
246 auto Out = T2.getTransform()(Mutatee);
247 EXPECT_EQ(*Mutatee, *Out) << "Expected in-place transform";
248 EXPECT_EQ(278, *Mutatee) << "Expected incrementing transform";
250 // Verify transform getter (const)
251 auto OwnedObj = std::make_shared<MockObjectFile>(288);
252 const auto &T1C = T1;
253 OwnedObj = T1C.getTransform()(std::move(OwnedObj));
254 EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
256 volatile bool RunStaticChecks = false;
257 if (!RunStaticChecks)
258 return;
260 // Make sure that ObjectTransformLayer implements the object layer concept
261 // correctly by sandwitching one between an ObjectLinkingLayer and an
262 // IRCompileLayer, verifying that it compiles if we have a call to the
263 // IRComileLayer's addModule that should call the transform layer's
264 // addObject, and also calling the other public transform layer methods
265 // directly to make sure the methods they intend to forward to exist on
266 // the ObjectLinkingLayer.
268 // We'll need a concrete MemoryManager class.
269 class NullManager : public llvm::RuntimeDyld::MemoryManager {
270 public:
271 uint8_t *allocateCodeSection(uintptr_t, unsigned, unsigned,
272 llvm::StringRef) override {
273 return nullptr;
275 uint8_t *allocateDataSection(uintptr_t, unsigned, unsigned, llvm::StringRef,
276 bool) override {
277 return nullptr;
279 void registerEHFrames(uint8_t *, uint64_t, size_t) override {}
280 void deregisterEHFrames() override {}
281 bool finalizeMemory(std::string *) override { return false; }
284 // Construct the jit layers.
285 RTDyldObjectLinkingLayer BaseLayer(ES, [](VModuleKey) {
286 return RTDyldObjectLinkingLayer::Resources{
287 std::make_shared<llvm::SectionMemoryManager>(),
288 std::make_shared<NullResolver>()};
291 auto IdentityTransform = [](std::unique_ptr<llvm::MemoryBuffer> Obj) {
292 return Obj;
294 ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
295 TransformLayer(BaseLayer, IdentityTransform);
296 auto NullCompiler = [](llvm::Module &) {
297 return std::unique_ptr<llvm::MemoryBuffer>(nullptr);
299 IRCompileLayer<decltype(TransformLayer), decltype(NullCompiler)>
300 CompileLayer(TransformLayer, NullCompiler);
302 // Make sure that the calls from IRCompileLayer to ObjectTransformLayer
303 // compile.
304 cantFail(CompileLayer.addModule(ES.allocateVModule(),
305 std::unique_ptr<llvm::Module>()));
307 // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
308 // compile.
309 VModuleKey DummyKey = ES.allocateVModule();
310 cantFail(TransformLayer.emitAndFinalize(DummyKey));
311 TransformLayer.findSymbolIn(DummyKey, Name, false);
312 TransformLayer.findSymbol(Name, true);
313 TransformLayer.mapSectionAddress(DummyKey, nullptr, 0);
314 cantFail(TransformLayer.removeObject(DummyKey));