4#include <gtest/gtest.h>
18 int func_stub(
int arg1,
short arg2) {
22 int func_extern_stub() {
29 static int static_field_2;
31 static class_stub * create(
int a1,
int a2) {
32 return new class_stub(a1, a2);
36 printf(
"Call constructor class_stub()\n");
40 class_stub(
int arg1,
int arg2) {
41 printf(
"Call constructor class_stub(%d, %d)\n", arg1, arg2);
43 static_field_2 = arg2;
46 virtual ~class_stub() {
47 printf(
"Call virtual ~class_stub()\n");
52 return field_1 + static_field_2;
55 int method_field1(
int arg) {
60 virtual double method_virt2() {
65 virtual float method_virt() {
67 return 3.14 + field_1;
70 static float method_static() {
75 int class_stub::static_field_2 = 0;
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);"
99 "extern \"C\" int nv_sub(int a, int b) {"
100 " printf(\"call nv_sub(%d, %d)\\n\", a, b);"
103 "extern \"C\" int run(){"
109 "namespace ns_stub {"
110 " class run_internal {"
117 " class class_full {"
123 " class class_stub {"
125 " static class_stub * create(int, int);"
127 " class_stub(int arg1, int arg2);"
129 " int method_field1(int);"
130 " virtual float method_virt();"
134 "extern \"C\" int run_internal(){"
135 " ns_stub::run_internal cl_int;"
136 " printf(\"run_internal.method %d\\n\", cl_int.method());"
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());"
147 "extern \"C\" int run_extern();"
148 "extern \"C\" int run_extern_stub(){"
149 " return run_extern();"
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());"
161#define DEBUG_MSG(msg) std::cout << "[DEBUG]: "<<msg<< std::endl;
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();
195 clang::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts =
new clang::DiagnosticOptions;
196 clang::TextDiagnosticPrinter *textDiagPrinter =
197 new clang::TextDiagnosticPrinter(llvm::outs(), &*DiagOpts);
199 clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> pDiagIDs;
201 clang::DiagnosticsEngine *pDiagnosticsEngine =
202 new clang::DiagnosticsEngine(pDiagIDs, &*DiagOpts, textDiagPrinter);
206 std::string triple = LLVMGetDefaultTargetTriple();
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");
213 itemstrs.insert(itemstrs.end(), opts.begin(), opts.end());
218 std::vector<const char*> itemcstrs;
219 for (
unsigned idx = 0; idx < itemstrs.size(); idx++) {
222 itemcstrs.push_back(itemstrs[idx].c_str());
223 std::cout << itemcstrs.back() <<
"\n";
229 pipe2(codeInPipe, O_NONBLOCK);
230 write(codeInPipe[1], source.c_str(), source.size());
231 close(codeInPipe[1]);
232 dup2(codeInPipe[0], STDIN_FILENO);
234 itemcstrs.push_back(
"-");
236 clang::CompilerInvocation::CreateFromArgs(compilerInvocation,
237 llvm::ArrayRef<const char *>(itemcstrs.data(),
238 itemcstrs.size()), *pDiagnosticsEngine);
240 auto& languageOptions = compilerInvocation.getLangOpts();
241 auto& preprocessorOptions = compilerInvocation.getPreprocessorOpts();
242 auto& targetOptions = compilerInvocation.getTargetOpts();
244 auto& frontEndOptions = compilerInvocation.getFrontendOpts();
247 auto& headerSearchOptions = compilerInvocation.getHeaderSearchOpts();
250 auto& codeGenOptions = compilerInvocation.getCodeGenOpts();
253 targetOptions.Triple = LLVMGetDefaultTargetTriple();
254 compilerInstance.createDiagnostics(textDiagPrinter,
false);
256 DEBUG_MSG(
"Using target triple: " << triple);
258 LLVMContextRef ctx = LLVMContextCreate();
259 std::unique_ptr<clang::CodeGenAction> action = std::make_unique<clang::EmitLLVMOnlyAction>((llvm::LLVMContext *)ctx);
261 assert(compilerInstance.ExecuteAction(*action));
264 std::unique_ptr<llvm::Module> module = action->takeModule();
270 llvm::raw_string_ostream asm_stream(*asm_code);
271 module->print(asm_stream, 0, false);
344llvm::orc::ThreadSafeModule createDemoModule() {
345 auto ctx = std::make_unique<llvm::LLVMContext>();
346 auto M = std::make_unique<llvm::Module>(
"test", *ctx);
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());
356 llvm::BasicBlock *BB = llvm::BasicBlock::Create(*ctx,
"EntryBlock", Add1F);
360 llvm::IRBuilder<> builder(BB);
363 llvm::Value *One = builder.getInt32(1);
366 assert(Add1F->arg_begin() != Add1F->arg_end());
367 llvm::Argument *ArgX = &*Add1F->arg_begin();
368 ArgX->setName(
"AnArg");
371 llvm::Value *Add = builder.CreateAdd(One, ArgX);
374 builder.CreateRet(Add);
376 return llvm::orc::ThreadSafeModule(std::move(M), std::move(ctx));
381 llvm::ExitOnError ExitOnErr;
383 ASSERT_TRUE(RunTime::LLVMInitialize());
390 std::string asm_source;
393 auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
395 auto module = CompileCpp(func_text_jit,{}, &asm_source);
398 llvm::raw_fd_ostream OS(
"nv_add_JIT.bc", EC, llvm::sys::fs::OpenFlags::OF_None);
399 llvm::WriteBitcodeToFile(*module, OS);
402 auto M = llvm::orc::ThreadSafeModule(std::move(module), std::make_unique<llvm::LLVMContext>());
405 std::ofstream asm_file(
"nv_add_JIT.s", std::ios::trunc);
406 asm_file << asm_source;
413 llvm::raw_string_ostream err(dump);
416 llvm::orc::ExecutionSession &ES = J->getExecutionSession();
431 ExitOnErr(J->addIRModule(std::move(M)));
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({
447 ASSERT_FALSE(J->getMainJITDylib().define(as));
450 llvm::Expected<llvm::orc::ExecutorAddr> test = J->lookup(
"nv_add");
451 ASSERT_TRUE(!!test) <<
"lookup error:\n" <<
toString(test.takeError()) <<
": lookup error3\n";
453 DEBUG_MSG(
"Retrieving nv_add/nv_sub functions...");
455 auto addAddr = ExitOnErr(J->lookup(
"nv_add"));
456 int (*add)(int, int) = addAddr.toPtr<
int(
int,
int) >();
459 int res = add(40, 2);
460 ASSERT_TRUE(42 == res);
462 auto subAddr = ExitOnErr(J->lookup(
"nv_sub"));
463 int (*sub)(int, int) = subAddr.toPtr<
int(
int,
int) >();
467 ASSERT_TRUE(43 == res);
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);
476 res = run_internal();
477 ASSERT_TRUE(44 == res);
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());
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);
495 ASSERT_TRUE(42 == res);
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);
503 res = run_extern_stub();
504 ASSERT_TRUE(4242 == res);
530extern "C" bool include_h_i_function_test();
534TEST(LLVM, Include_h_i_GTF) {
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));
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));
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));
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));
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));
621 ObjPtr obj2 = Obj::CreateValue(123);
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());
630 ASSERT_TRUE(include_h_i_function_test())
635extern "C" bool float_compare(
float val1,
float val2) {
636 if (! (val1 == val2)) {
637 LOG_RUNTIME(
"FAIL: float_compare %.20f %.20f!", val1, val2);
642extern "C" bool double_compare(
double val1,
double val2) {
643 if (! (val1 == val2)) {
644 LOG_RUNTIME(
"FAIL: double_compare %.20f %.20f!", val1, val2);
649TEST(LLVM, Include_h_i_JIT) {
651 llvm::ExitOnError ExitOnErr;
653 ASSERT_TRUE(RunTime::LLVMInitialize());
655 std::string include_test_cpp =
ReadFile(
"../src/test/include_test.cpp");
656 ASSERT_TRUE(include_test_cpp.size() > 1000);
659 std::string opt_str =
ReadFile(
"../src/build_options.txt");
660 ASSERT_TRUE(opt_str.size() > 100);
662 std::vector<std::string> opts = Macro::SplitChar(opt_str,
" \t\r\n");
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");
676 for (
auto &elem : opts) {
677 if (elem.find(
"-D") == 0) {
680 std::cout << elem <<
"\n";
683 ASSERT_TRUE(opts.size() > 20);
707 std::string asm_source;
709 auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
711 auto module = CompileCpp(include_test_cpp, opts, &asm_source);
713 llvm::raw_fd_ostream OS(
"Include_h_i_JIT.bc", EC, llvm::sys::fs::OpenFlags::OF_None);
714 WriteBitcodeToFile(*module, OS);
717 auto M = llvm::orc::ThreadSafeModule(std::move(module), std::make_unique<llvm::LLVMContext>());
719 std::ofstream asm_file(
"Include_h_i_JIT.s", std::ios::trunc);
720 asm_file << asm_source;
726 llvm::raw_string_ostream err(dump);
729 llvm::orc::ExecutionSession &ES = J->getExecutionSession();
742 ExitOnErr(J->addIRModule(std::move(M)));
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";
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);
770 ASSERT_TRUE(include_h_i_function_test());
#define LOG_RUNTIME(format,...)
std::shared_ptr< Obj > ObjPtr
std::string ReadFile(const char *fileName)
const char * toString(TermID type)