NewLang Project
Yet another programm language
Loading...
Searching...
No Matches
llvm_test.cpp
Go to the documentation of this file.
1#ifdef BUILD_UNITTEST
2
3#include "warning_push.h"
4#include <gtest/gtest.h>
5#include "warning_pop.h"
6
7#include "runtime.h"
8
9// https://github.com/rsashka/cpp-jit-llvm
10
11using namespace newlang;
12
13/*
14 * Функции и классы для вызова изнутри JIT
15 */
16namespace ns_stub {
17
18 int func_stub(int arg1, short arg2) {
19 return arg1*arg2;
20 };
21
22 int func_extern_stub() {
23 return 4242;
24 };
25
26 class class_stub {
27 public:
28 int field_1;
29 static int static_field_2;
30
31 static class_stub * create(int a1, int a2) {
32 return new class_stub(a1, a2);
33 }
34
35 class_stub() {
36 printf("Call constructor class_stub()\n");
37 field_1 = 0;
38 }
39
40 class_stub(int arg1, int arg2) {
41 printf("Call constructor class_stub(%d, %d)\n", arg1, arg2);
42 field_1 = arg1;
43 static_field_2 = arg2;
44 }
45
46 virtual ~class_stub() {
47 printf("Call virtual ~class_stub()\n");
48 }
49
50 int method_sum() {
51
52 return field_1 + static_field_2;
53 }
54
55 int method_field1(int arg) {
56
57 return field_1;
58 }
59
60 virtual double method_virt2() {
61
62 return 999999999;
63 }
64
65 virtual float method_virt() {
66
67 return 3.14 + field_1;
68 }
69
70 static float method_static() {
71 return 3.1415;
72 }
73 };
74
75 int class_stub::static_field_2 = 0;
76
77 class class_full {
78 public:
79
80 class_full() {
81 }
82
83 int method() {
84 return 42;
85 }
86 };
87};
88
89/*
90 * Строка прототип для компиляции в JIT
91 */
92const char * func_text_jit = ""
93 "extern \"C\" int printf(const char *, ...);\n"
94 "extern \"C\" int nv_add(int a, int b) {"
95 " printf(\"call nv_add(%d, %d)\\n\", a, b);"
96 " return a + b;"
97 "};\n"
98 ""
99 "extern \"C\" int nv_sub(int a, int b) {"
100 " printf(\"call nv_sub(%d, %d)\\n\", a, b);"
101 " return a - b;"
102 "};\n"
103 "extern \"C\" int run(){"
104 " nv_add(100, 123);"
105 " nv_sub(100, 123);"
106 " return 42;"
107 "};\n"
108 ""
109 "namespace ns_stub {"
110 " class run_internal {"
111 " public:\n"
112 " run_internal(){};"
113 " int method(){"
114 " return 43;"
115 " };"
116 " };"
117 " class class_full {"
118 " public:\n"
119 " class_full();"
120 " int method();"
121 " };"
122 ""
123 " class class_stub {"
124 " public:\n"
125 " static class_stub * create(int, int);"
126 " class_stub();"
127 " class_stub(int arg1, int arg2);"
128 " int method_sum();"
129 " int method_field1(int);"
130 " virtual float method_virt();"
131 " };"
132 ""
133 "};"
134 "extern \"C\" int run_internal(){"
135 " ns_stub::run_internal cl_int;"
136 " printf(\"run_internal.method %d\\n\", cl_int.method());"
137 " return 44;"
138 "};\n"
139 ""
140 "extern \"C\" int run_stub(){"
141 " ns_stub::class_stub *cl = ns_stub::class_stub::create(123, 123);"
142 " printf(\"class_stub.method_sum %d\\n\", cl->method_sum());"
143 " delete cl;"
144 " return 42;"
145 "};\n"
146 ""
147 "extern \"C\" int run_extern();"
148 "extern \"C\" int run_extern_stub(){"
149 " return run_extern();"
150 "};\n"
151 "extern \"C\" int run_virt(){"
152 " ns_stub::class_stub *cl = ns_stub::class_stub::create(124, 125);"
153 " printf(\"class_stub.method_virt %f\\n\", cl->method_virt());"
154 " delete cl;"
155 " return 0;"
156 "};\n"
157 "";
158
159
160
161#define DEBUG_MSG(msg) std::cout << "[DEBUG]: "<<msg<< std::endl;
162
163//void InitializeLLVM() {
164//
165// // We have not initialized any pass managers for any device yet.
166// // Run the global LLVM pass initialization functions.
171// LLVMInitializeNativeTarget();
172// LLVMInitializeNativeAsmParser();
173// LLVMInitializeNativeAsmPrinter();
174// //LLVMInitializeAllAsmParsers(); // Для использования ассемблерных вставок!!! (комменатрие в коде)
175//
176//
187//}
188
189std::unique_ptr<llvm::Module> CompileCpp(std::string source, std::vector<std::string> opts, std::string *asm_code = nullptr) {
190 clang::CompilerInstance compilerInstance;
191 auto& compilerInvocation = compilerInstance.getInvocation();
192
193
194 // Диагностика работы Clang
195 clang::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions;
196 clang::TextDiagnosticPrinter *textDiagPrinter =
197 new clang::TextDiagnosticPrinter(llvm::outs(), &*DiagOpts);
198
199 clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> pDiagIDs;
200
201 clang::DiagnosticsEngine *pDiagnosticsEngine =
202 new clang::DiagnosticsEngine(pDiagIDs, &*DiagOpts, textDiagPrinter);
203
204
205 // Целевая платформа
206 std::string triple = LLVMGetDefaultTargetTriple();
207
208 std::vector<std::string> itemstrs;
209 itemstrs.push_back(triple.insert(0, "-triple="));
210 itemstrs.push_back("-xc++");
211 itemstrs.push_back("-std=c++23");
212
213 itemstrs.insert(itemstrs.end(), opts.begin(), opts.end());
214
215 // itemstrs.push_back("-fno-exceptions");
216 // itemstrs.push_back("-funwind-tables");
217
218 std::vector<const char*> itemcstrs;
219 for (unsigned idx = 0; idx < itemstrs.size(); idx++) {
220 // note: if itemstrs is modified after this, itemcstrs will be full
221 // of invalid pointers! Could make copies, but would have to clean up then...
222 itemcstrs.push_back(itemstrs[idx].c_str());
223 std::cout << itemcstrs.back() << "\n";
224 }
225
226 // Компиляция из памяти
227 // Send code through a pipe to stdin
228 int codeInPipe[2];
229 pipe2(codeInPipe, O_NONBLOCK);
230 write(codeInPipe[1], source.c_str(), source.size());
231 close(codeInPipe[1]); // We need to close the pipe to send an EOF
232 dup2(codeInPipe[0], STDIN_FILENO);
233
234 itemcstrs.push_back("-"); // Read code from stdin
235
236 clang::CompilerInvocation::CreateFromArgs(compilerInvocation,
237 llvm::ArrayRef<const char *>(itemcstrs.data(),
238 itemcstrs.size()), *pDiagnosticsEngine);
239
240 auto& languageOptions = compilerInvocation.getLangOpts();
241 auto& preprocessorOptions = compilerInvocation.getPreprocessorOpts();
242 auto& targetOptions = compilerInvocation.getTargetOpts();
243
244 auto& frontEndOptions = compilerInvocation.getFrontendOpts();
245 // frontEndOptions.ShowStats = true;
246
247 auto& headerSearchOptions = compilerInvocation.getHeaderSearchOpts();
248 // headerSearchOptions.Verbose = true;
249
250 auto& codeGenOptions = compilerInvocation.getCodeGenOpts();
251
252
253 targetOptions.Triple = LLVMGetDefaultTargetTriple();
254 compilerInstance.createDiagnostics(textDiagPrinter, false);
255
256 DEBUG_MSG("Using target triple: " << triple);
257
258 LLVMContextRef ctx = LLVMContextCreate();
259 std::unique_ptr<clang::CodeGenAction> action = std::make_unique<clang::EmitLLVMOnlyAction>((llvm::LLVMContext *)ctx);
260
261 assert(compilerInstance.ExecuteAction(*action));
262
263 // Runtime LLVM Module
264 std::unique_ptr<llvm::Module> module = action->takeModule();
265
266 assert(module);
267
268
269 if (asm_code) {
270 llvm::raw_string_ostream asm_stream(*asm_code);
271 module->print(asm_stream, 0, false);
272 }
273 //AssemblyWriter
274
275
276
277
278 // LLVMContextRef context = LLVMContextCreate();
279 // LLVMModuleRef module = LLVMModuleCreateWithNameInContext("test", context);
280
281 // LLVMTypeRef f32 = LLVMFloatTypeInContext(context);
282 // LLVMTypeRef ftype = LLVMFunctionType(f32, 0, 0, 0);
283 // LLVMValueRef ftest = LLVMAddFunction(module, "ftest", ftype);
284 // LLVMBasicBlockRef bb = LLVMAppendBasicBlockInContext(context, ftest, "ftest");
285 // LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
286 // LLVMPositionBuilderAtEnd(builder, bb);
287 // LLVMValueRef v1 = LLVMConstReal(f32, 2.5);
288 // LLVMValueRef v2 = LLVMConstReal(f32, 4.3);
289 // LLVMValueRef result = LLVMBuildFAdd(builder, v1, v2, "f-add");
290 // LLVMBuildRet(builder, result);
291 // LLVMVerifyFunction(ftest, LLVMPrintMessageAction);
292
293 char* errors = 0;
294 // LLVMPrintModuleToFile((LLVMModuleRef)&*module, "include_h_i_function_test.s", &errors);
295 // printf("error: %s\n", errors);
296 // LLVMDisposeMessage(errors);
297
298 // LLVMInitializeAllTargetInfos();
299 // LLVMInitializeAllTargets();
300 // LLVMInitializeAllTargetMCs();
301 // LLVMInitializeAllAsmParsers(); // Для использования ассемблерных вставок!!! (комменатрие в коде)
302 // LLVMInitializeAllAsmPrinters();
303
304 // LLVMTargetRef target;
305 // LLVMGetTargetFromTriple(LLVMGetDefaultTargetTriple(), &target, &errors);
306 // // printf("error: %s\n", errors);
307 // LLVMDisposeMessage(errors);
308 // // printf("target: %s, [%s], %d, %d\n", LLVMGetTargetName(target), LLVMGetTargetDescription(target), LLVMTargetHasJIT(target), LLVMTargetHasTargetMachine(target));
309 // // printf("triple: %s\n", LLVMGetDefaultTargetTriple());
310 // // printf("features: %s\n", LLVMGetHostCPUFeatures());
311 // LLVMTargetMachineRef machine = LLVMCreateTargetMachine(target, LLVMGetDefaultTargetTriple(), "generic", LLVMGetHostCPUFeatures(), LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);
312 //
313 // LLVMSetTarget((LLVMModuleRef)&*module, LLVMGetDefaultTargetTriple());
314 // LLVMTargetDataRef datalayout = LLVMCreateTargetDataLayout(machine);
315 // char* datalayout_str = LLVMCopyStringRepOfTargetData(datalayout);
316 // // printf("datalayout: %s\n", datalayout_str);
317 // LLVMSetDataLayout((LLVMModuleRef)&*module, datalayout_str);
318 // LLVMDisposeMessage(datalayout_str);
319 //
320 // LLVMTargetMachineEmitToFile(machine, (LLVMModuleRef)&*module, "include_h_i_function_test.o", LLVMObjectFile, &errors);
321 // // printf("error: %s\n", errors);
322 // LLVMDisposeMessage(errors);
323
324
325 // Оптимизация IR
326 // llvm::PassBuilder passBuilder;
327 // llvm::LoopAnalysisManager loopAnalysisManager;
328 // llvm::FunctionAnalysisManager functionAnalysisManager;
329 // llvm::CGSCCAnalysisManager cGSCCAnalysisManager;
330 // llvm::ModuleAnalysisManager moduleAnalysisManager;
331 //
332 // passBuilder.registerModuleAnalyses(moduleAnalysisManager);
333 // passBuilder.registerCGSCCAnalyses(cGSCCAnalysisManager);
334 // passBuilder.registerFunctionAnalyses(functionAnalysisManager);
335 // passBuilder.registerLoopAnalyses(loopAnalysisManager);
336 // passBuilder.crossRegisterProxies(loopAnalysisManager, functionAnalysisManager, cGSCCAnalysisManager, moduleAnalysisManager);
337 //
338 // llvm::ModulePassManager modulePassManager = passBuilder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O0);
339 // modulePassManager.run(*module, moduleAnalysisManager);
340
341 return module;
342}
343
344llvm::orc::ThreadSafeModule createDemoModule() {
345 auto ctx = std::make_unique<llvm::LLVMContext>();
346 auto M = std::make_unique<llvm::Module>("test", *ctx);
347
348 // Create the add1 function entry and insert this entry into module M. The
349 // function will have a return type of "int" and take an argument of "int".
350 llvm::Function *Add1F = llvm::Function::Create(
351 llvm::FunctionType::get(llvm::Type::getInt32Ty(*ctx),{llvm::Type::getInt32Ty(*ctx)}, false),
352 llvm::Function::ExternalLinkage, "add1", M.get());
353
354 // Add a basic block to the function. As before, it automatically inserts
355 // because of the last argument.
356 llvm::BasicBlock *BB = llvm::BasicBlock::Create(*ctx, "EntryBlock", Add1F);
357
358 // Create a basic block builder with default parameters. The builder will
359 // automatically append instructions to the basic block `BB'.
360 llvm::IRBuilder<> builder(BB);
361
362 // Get pointers to the constant `1'.
363 llvm::Value *One = builder.getInt32(1);
364
365 // Get pointers to the integer argument of the add1 function...
366 assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
367 llvm::Argument *ArgX = &*Add1F->arg_begin(); // Get the arg
368 ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
369
370 // Create the add instruction, inserting it into the end of BB.
371 llvm::Value *Add = builder.CreateAdd(One, ArgX);
372
373 // Create the return instruction and add it to the basic block
374 builder.CreateRet(Add);
375
376 return llvm::orc::ThreadSafeModule(std::move(M), std::move(ctx));
377}
378
379TEST(LLVM, JIT) {
380
381 llvm::ExitOnError ExitOnErr;
382
383 ASSERT_TRUE(RunTime::LLVMInitialize());
384 // InitLLVM X(argc, argv);
385
386
387 // cl::ParseCommandLineOptions(argc, argv, "HowToUseLLJIT");
388 // ExitOnErr.setBanner(std::string(argv[0]) + ": ");
389
390 std::string asm_source;
391
392 // Create an LLJIT instance.
393 auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
394 // auto M = createDemoModule();
395 auto module = CompileCpp(func_text_jit,{}, &asm_source);
396
397 std::error_code EC;
398 llvm::raw_fd_ostream OS("nv_add_JIT.bc", EC, llvm::sys::fs::OpenFlags::OF_None);
399 llvm::WriteBitcodeToFile(*module, OS);
400 OS.flush();
401
402 auto M = llvm::orc::ThreadSafeModule(std::move(module), std::make_unique<llvm::LLVMContext>());
403
404
405 std::ofstream asm_file("nv_add_JIT.s", std::ios::trunc);
406 asm_file << asm_source;
407 asm_file.close();
408
409
410
411
412 std::string dump;
413 llvm::raw_string_ostream err(dump);
414
415
416 llvm::orc::ExecutionSession &ES = J->getExecutionSession();
417
418 // JITDylib *plat = ES.getJITDylibByName("<Platform>");
419 // assert(plat);
420 // dump.clear();
421 // plat->dump(err);
422 // std::cout << "<Platform>:\n" << dump << "\n";
423 //
424 // JITDylib *proc = ES.getJITDylibByName("<Process Symbols>");
425 // assert(proc);
426 // dump.clear();
427 // proc->dump(err);
428 // std::cout << "<Process Symbols>:\n" << dump << "\n";
429
430
431 ExitOnErr(J->addIRModule(std::move(M)));
432 // ExitOnErr(J->addObjectFile(std::move(M)));
433 // Adds an object file to the given JITDylib.
434 //Error addObjectFile(std::unique_ptr<MemoryBuffer> Obj)
435
436
437
438
439 // Функция с именем run_extern отсуствует (JIT session error: Symbols not found: [ run_extern ])
440 // Подставим вместо нее указатель на другу функцию, но с таким же прототипом (func_extern_stub)
441 const llvm::orc::SymbolStringPtr Foo = ES.intern("run_extern");
442 const llvm::orc::ExecutorSymbolDef FooSym(llvm::orc::ExecutorAddr::fromPtr(&ns_stub::func_extern_stub), llvm::JITSymbolFlags::Exported | llvm::JITSymbolFlags::Absolute);
443 auto as = llvm::orc::absoluteSymbols({
444 {Foo, FooSym}
445 });
446
447 ASSERT_FALSE(J->getMainJITDylib().define(as));
448
449
450 llvm::Expected<llvm::orc::ExecutorAddr> test = J->lookup("nv_add");
451 ASSERT_TRUE(!!test) << "lookup error:\n" << toString(test.takeError()) << ": lookup error3\n";
452
453 DEBUG_MSG("Retrieving nv_add/nv_sub functions...");
454
455 auto addAddr = ExitOnErr(J->lookup("nv_add"));
456 int (*add)(int, int) = addAddr.toPtr<int(int, int) >();
457 ASSERT_TRUE(add);
458
459 int res = add(40, 2);
460 ASSERT_TRUE(42 == res);
461
462 auto subAddr = ExitOnErr(J->lookup("nv_sub"));
463 int (*sub)(int, int) = subAddr.toPtr<int(int, int) >();
464 ASSERT_TRUE(sub);
465
466 res = sub(50, 7);
467 ASSERT_TRUE(43 == res);
468
469
470
471 printf("Call: run_internal\n");
472 auto run_internalAddr = ExitOnErr(J->lookup("run_internal"));
473 int (*run_internal)() = run_internalAddr.toPtr<int() >();
474 ASSERT_TRUE(run_internal);
475
476 res = run_internal();
477 ASSERT_TRUE(44 == res);
478
479
480 // Линкер удаяет не используемый код,
481 // и если нет обращения к методу то его будет нельзя вызвать в JIT
482 // JIT session error: Symbols not found: [ _ZN7ns_stub10class_stub6createEii, _ZN7ns_stub10class_stub10method_sumEv ]
483 ns_stub::class_stub *cl = ns_stub::class_stub::create(0, 0);
484 printf("Check run_stub.method %d\n", cl->method_sum());
485 printf("Check run_stub.method_virt %f\n", cl->method_virt());
486 delete cl;
487
488
489 printf("Call: run_stub\n");
490 auto run_stubAddr = ExitOnErr(J->lookup("run_stub"));
491 int (*run_stub)() = run_stubAddr.toPtr<int() >();
492 ASSERT_TRUE(run_stub);
493
494 res = run_stub();
495 ASSERT_TRUE(42 == res);
496
497
498 printf("Call: run_extern_stub\n");
499 auto run_extern_stubAddr = ExitOnErr(J->lookup("run_extern_stub"));
500 int (*run_extern_stub)() = run_extern_stubAddr.toPtr<int() >();
501 assert(run_extern_stub);
502
503 res = run_extern_stub();
504 ASSERT_TRUE(4242 == res);
505
506
507 /*
508 *
509 * Так нельзя !!!!!
510 * Виртуальные методы изнутри JIT вызываются неправильно при некорректном заголовочном файле!
511 *
512 * ERROR !!!!
513 * Virtual methods from within JIT are called incorrectly when the header file is incorrect!
514 *
515 */
516
517 // printf("Call: run_virt\n");
518 // auto run_virtAddr = ExitOnErr(J->lookup("run_virt"));
519 // int (*run_virt)() = run_virtAddr.toPtr<int() >();
520 // ASSERT_TRUE(run_virt);
521 //
522 // res = run_virt();
523 // ASSERT_TRUE(0 == res);
524}
525
526
527#include "object.h"
528#include "runtime.h"
529
530extern "C" bool include_h_i_function_test();
531
532using namespace newlang;
533
534TEST(LLVM, Include_h_i_GTF) {
535
536 ObjPtr obj = Obj::None();
537
538 ASSERT_STREQ("_", obj->toString().c_str());
539 ASSERT_ANY_THROW(auto _ = static_cast<bool> (*obj));
540 ASSERT_ANY_THROW(auto _ = static_cast<int8_t> (*obj));
541 ASSERT_ANY_THROW(auto _ = static_cast<uint8_t> (*obj));
542 ASSERT_ANY_THROW(auto _ = static_cast<int16_t> (*obj));
543 ASSERT_ANY_THROW(auto _ = static_cast<uint16_t> (*obj));
544 ASSERT_ANY_THROW(auto _ = static_cast<int32_t> (*obj));
545 ASSERT_ANY_THROW(auto _ = static_cast<uint32_t> (*obj));
546 ASSERT_ANY_THROW(auto _ = static_cast<int64_t> (*obj));
547 ASSERT_ANY_THROW(auto _ = static_cast<uint64_t> (*obj));
548 ASSERT_ANY_THROW(auto _ = static_cast<float> (*obj));
549 ASSERT_ANY_THROW(auto _ = static_cast<double> (*obj));
550 ASSERT_ANY_THROW(auto _ = static_cast<std::string> (*obj));
551 ASSERT_ANY_THROW(auto _ = static_cast<std::wstring> (*obj));
552
553 (*obj) = false;
554 LOG_DEBUG("(*obj) = false;");
555
556 ASSERT_EQ(false, static_cast<bool> (*obj));
557 ASSERT_EQ(0, static_cast<int8_t> (*obj));
558 ASSERT_EQ(0, static_cast<uint8_t> (*obj));
559 ASSERT_EQ(0, static_cast<int16_t> (*obj));
560 ASSERT_EQ(0, static_cast<uint16_t> (*obj));
561 ASSERT_EQ(0, static_cast<int32_t> (*obj));
562 ASSERT_EQ(0, static_cast<uint32_t> (*obj));
563 ASSERT_EQ(0, static_cast<int64_t> (*obj));
564 ASSERT_EQ(0, static_cast<uint64_t> (*obj));
565 ASSERT_STREQ("0", static_cast<std::string> (*obj).c_str());
566 ASSERT_STREQ(L"0", static_cast<std::wstring> (*obj).c_str());
567 ASSERT_FLOAT_EQ(0, static_cast<float> (*obj));
568 ASSERT_DOUBLE_EQ(0, static_cast<double> (*obj));
569
570 (*obj) = true;
571 LOG_DEBUG("(*obj) = true;");
572
573 ASSERT_EQ(true, static_cast<bool> (*obj));
574 ASSERT_EQ(1, static_cast<int8_t> (*obj));
575 ASSERT_EQ(1, static_cast<uint8_t> (*obj));
576 ASSERT_EQ(1, static_cast<int16_t> (*obj));
577 ASSERT_EQ(1, static_cast<uint16_t> (*obj));
578 ASSERT_EQ(1, static_cast<int32_t> (*obj));
579 ASSERT_EQ(1, static_cast<uint32_t> (*obj));
580 ASSERT_EQ(1, static_cast<int64_t> (*obj));
581 ASSERT_EQ(1, static_cast<uint64_t> (*obj));
582 ASSERT_STREQ("1", static_cast<std::string> (*obj).c_str());
583 ASSERT_STREQ(L"1", static_cast<std::wstring> (*obj).c_str());
584 ASSERT_FLOAT_EQ(1, static_cast<float> (*obj));
585 ASSERT_DOUBLE_EQ(1, static_cast<double> (*obj));
586
587 (*obj) = -200;
588 LOG_DEBUG("(*obj) = -200;");
589
590 ASSERT_EQ(true, static_cast<bool> (*obj));
591 ASSERT_ANY_THROW(auto _ = static_cast<int8_t> (*obj));
592 ASSERT_ANY_THROW(auto _ = static_cast<uint8_t> (*obj));
593 ASSERT_EQ(-200, static_cast<int16_t> (*obj));
594 ASSERT_ANY_THROW(auto _ = static_cast<uint16_t> (*obj));
595 ASSERT_EQ(-200, static_cast<int32_t> (*obj));
596 ASSERT_ANY_THROW(auto _ = static_cast<uint32_t> (*obj));
597 ASSERT_EQ(-200, static_cast<int64_t> (*obj));
598 ASSERT_ANY_THROW(auto _ = static_cast<uint64_t> (*obj));
599 ASSERT_STREQ("-200", static_cast<std::string> (*obj).c_str());
600 ASSERT_STREQ(L"-200", static_cast<std::wstring> (*obj).c_str());
601 ASSERT_FLOAT_EQ(-200, static_cast<float> (*obj));
602 ASSERT_DOUBLE_EQ(-200, static_cast<double> (*obj));
603
604 (*obj) = 200;
605 LOG_DEBUG("(*obj) = 200;");
606
607 ASSERT_EQ(true, static_cast<bool> (*obj));
608 ASSERT_ANY_THROW(auto _ = static_cast<int8_t> (*obj));
609 ASSERT_EQ(200, static_cast<uint8_t> (*obj));
610 ASSERT_EQ(200, static_cast<int16_t> (*obj));
611 ASSERT_EQ(200, static_cast<uint16_t> (*obj));
612 ASSERT_EQ(200, static_cast<int32_t> (*obj));
613 ASSERT_EQ(200, static_cast<uint32_t> (*obj));
614 ASSERT_EQ(200, static_cast<int64_t> (*obj));
615 ASSERT_EQ(200, static_cast<uint64_t> (*obj));
616 ASSERT_STREQ("200", static_cast<std::string> (*obj).c_str());
617 ASSERT_STREQ(L"200", static_cast<std::wstring> (*obj).c_str());
618 ASSERT_FLOAT_EQ(200, static_cast<float> (*obj));
619 ASSERT_DOUBLE_EQ(200, static_cast<double> (*obj));
620
621 ObjPtr obj2 = Obj::CreateValue(123);
622 (*obj) += (*obj2);
623 ASSERT_EQ(323, static_cast<int16_t> (*obj));
624 ASSERT_EQ(323, static_cast<uint16_t> (*obj));
625 ASSERT_STREQ("323", static_cast<std::string> (*obj).c_str());
626 ASSERT_STREQ(L"323", static_cast<std::wstring> (*obj).c_str());
627
628
629 ASSERT_NO_THROW(
630 ASSERT_TRUE(include_h_i_function_test())
631 );
632
633}
634
635extern "C" bool float_compare(float val1, float val2) {
636 if (! (val1 == val2)) {
637 LOG_RUNTIME("FAIL: float_compare %.20f %.20f!", val1, val2);
638 }
639 return true; //std::fabs(val1 - val2) <= std::numeric_limits<float>::epsilon();
640}
641
642extern "C" bool double_compare(double val1, double val2) {
643 if (! (val1 == val2)) {
644 LOG_RUNTIME("FAIL: double_compare %.20f %.20f!", val1, val2);
645 }
646 return true; //std::fabs(val1 - val2) <= std::numeric_limits<double>::epsilon();
647}
648
649TEST(LLVM, Include_h_i_JIT) {
650
651 llvm::ExitOnError ExitOnErr;
652
653 ASSERT_TRUE(RunTime::LLVMInitialize());
654
655 std::string include_test_cpp = ReadFile("../src/test/include_test.cpp");
656 ASSERT_TRUE(include_test_cpp.size() > 1000);
657
658
659 std::string opt_str = ReadFile("../src/build_options.txt");
660 ASSERT_TRUE(opt_str.size() > 100);
661
662 std::vector<std::string> opts = Macro::SplitChar(opt_str, " \t\r\n");
663
664 opts.push_back("-I../src");
665 opts.push_back("-DBUILD_UNITTEST");
666 opts.push_back("-DBUILD_DEBUG ");
667 opts.push_back("-DLOG_LEVEL_NORMAL=LOG_LEVEL_DEBUG");
668
669 // opts.push_back("-emit-llvm");
670 // opts.push_back("-S");
671 // opts.push_back("-o");
672 // opts.push_back("LLVM_out.ll");
673 // -emit-llvm -S multiply.c -o multiply.ll
674
675 // opts.push_back("-ferror-limit=2");
676 for (auto &elem : opts) {
677 if (elem.find("-D") == 0) {
678 elem += " ";
679 }
680 std::cout << elem << "\n";
681 }
682
683 ASSERT_TRUE(opts.size() > 20);
684
685
686 //InitLLVM X(argc, argv);
687 // InitializeNativeTarget();
688 // InitializeNativeTargetAsmPrinter();
689 // ThreadSafeContext context(std::make_unique<LLVMContext>());
690 //
691 // ExitOnError ExitOnErr;
692 //
693 // jitlink::InProcessMemoryManager MemMgr;
694 //
695 // auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());
696 // JTMB.setCodeModel(CodeModel::Small);
697 //
698 // auto jit =
699 // ExitOnErr(LLJITBuilder()
700 // .setJITTargetMachineBuilder(std::move(JTMB))
701 // .setObjectLinkingLayerCreator([&](ExecutionSession &ES, const Triple &TT) {
702 // return std::make_unique<ObjectLinkingLayer>(ES, MemMgr);
703 // })
704 // .create());
705
706
707 std::string asm_source;
708 // Create an LLJIT instance.
709 auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
710
711 auto module = CompileCpp(include_test_cpp, opts, &asm_source);
712 std::error_code EC;
713 llvm::raw_fd_ostream OS("Include_h_i_JIT.bc", EC, llvm::sys::fs::OpenFlags::OF_None);
714 WriteBitcodeToFile(*module, OS);
715 OS.flush();
716
717 auto M = llvm::orc::ThreadSafeModule(std::move(module), std::make_unique<llvm::LLVMContext>());
718
719 std::ofstream asm_file("Include_h_i_JIT.s", std::ios::trunc);
720 asm_file << asm_source;
721 asm_file.close();
722
723
724
725 std::string dump;
726 llvm::raw_string_ostream err(dump);
727
728
729 llvm::orc::ExecutionSession &ES = J->getExecutionSession();
730
731
732 // // Функция с именем run_extern отсуствует (JIT session error: Symbols not found: [ run_extern ])
733 // // Подставим вместо нее указатель на другу функцию, но с таким же прототипом (func_extern_stub)
734 // const SymbolStringPtr Foo = ES.intern("include_h_i_function_test");
735 // const ExecutorSymbolDef FooSym(ExecutorAddr::fromPtr(&include_h_i_function_test), llvm::JITSymbolFlags::Exported | llvm::JITSymbolFlags::Absolute);
736 // auto as = absoluteSymbols({
737 // {Foo, FooSym}
738 // });
739 //
740 // ASSERT_FALSE(J->getMainJITDylib().define(as));
741
742 ExitOnErr(J->addIRModule(std::move(M)));
743
744 // auto ffi = ExitOnErr(errorOrToExpected(MemoryBuffer::getFileAsStream("include_h_i_function_test.o")));
745 // ExitOnErr(J->addObjectFile(std::move(ffi)));
746
747
748 ES.dump(err);
749
750 // JITDylib *plat = ES.getJITDylibByName("<Platform>");
751 // assert(plat);
752 // dump.clear();
753 // plat->dump(err);
754 // std::cout << "<Platform>:\n" << dump << "\n";
755 //
756 // JITDylib *proc = ES.getJITDylibByName("<Process Symbols>");
757 // assert(proc);
758 // dump.clear();
759 // proc->dump(err);
760 // std::cout << "<Process Symbols>:\n" << dump << "\n";
761
762
763 llvm::Expected<llvm::orc::ExecutorAddr> test = J->lookup("include_h_i_function_test");
764 ASSERT_TRUE(!!test) << "lookup error:\n" << toString(test.takeError()) << "\n" << dump << ":lookup error!!!!\n";
765
766 auto funcAddr = ExitOnErr(J->lookup("include_h_i_function_test"));
767 bool (*include_h_i_function_test)() = funcAddr.toPtr<bool() >();
768 ASSERT_TRUE(include_h_i_function_test);
769
770 ASSERT_TRUE(include_h_i_function_test());
771}
772
773#endif // BUILD_UNITTEST
#define LOG_RUNTIME(format,...)
Definition logger.h:26
#define LOG_DEBUG(...)
Definition logger.h:119
Definition nlc.h:59
std::shared_ptr< Obj > ObjPtr
Definition variable.h:28
std::string ReadFile(const char *fileName)
Definition runtime.cpp:1952
const char * toString(TermID type)
Definition term.h:126