NewLang Project
Yet another programm language
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Loading...
Searching...
No Matches
jit_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
8
9#include "jit.h"
10#include "term.h"
11#include "runtime.h"
12
13using namespace newlang;
14
15TEST(JIT, Function) {
16 // std::filesystem::create_directories("temp");
17 // ASSERT_TRUE(std::filesystem::is_directory("temp"));
18 // //std::remove("temp/brother.sh.temp.nlm");
19
20 TermPtr term = Parser::ParseString("func():Int32");
21 term->m_int_name = "func::";
22 std::string src;
23 src = JIT::MakeFunctionPrototype(term, "");
24 ASSERT_STREQ("newlang::ObjPtr _$$_func$$(newlang::Context *ctx, newlang::Obj &args)", src.c_str()) << src;
25 src = JIT::MakeFunctionPrototype(term, "\\\\dir\\module");
26 ASSERT_STREQ("newlang::ObjPtr _$dir$module$_func$$(newlang::Context *ctx, newlang::Obj &args)", src.c_str()) << src;
27
28 term->push_back(Term::CreateName("arg"));
29 term->push_back(Term::CreateName("arg2"));
30 src = JIT::MakeFunctionPrototype(term, "");
31 ASSERT_STREQ("newlang::ObjPtr _$$_func$$(newlang::Context *ctx, newlang::Obj &args)", src.c_str()) << src;
32 src = JIT::MakeFunctionPrototype(term, "\\\\dir\\module2");
33 ASSERT_STREQ("newlang::ObjPtr _$dir$module2$_func$$(newlang::Context *ctx, newlang::Obj &args)", src.c_str()) << src;
34}
35
36
37
38
39
40
41#include "clang/Driver/Driver.h"
42#include "clang/Driver/Compilation.h"
43#include "clang/Frontend/TextDiagnosticPrinter.h"
44#include "llvm/IR/Module.h"
45#include "llvm/Target/TargetOptions.h"
46#include "llvm/ADT/STLExtras.h"
47#include "llvm/Support/VirtualFileSystem.h"
48#include "llvm/Support/TargetSelect.h"
49
50#include "llvm-c/Core.h"
51#include "llvm-c/Target.h"
52#include "llvm-c/TargetMachine.h"
53
54#include "llvm/IR/LegacyPassManager.h"
55#include "llvm/MC/TargetRegistry.h"
56#include "llvm/Support/CodeGen.h"
57
58#include "llvm/Support/InitLLVM.h"
59
60#include "llvm/Target/TargetMachine.h"
61
62#include "clang/Frontend/CompilerInstance.h"
63#include "clang/CodeGen/CodeGenAction.h"
64
65#include <iostream>
66#include <fcntl.h>
67
68using namespace llvm;
69using namespace llvm::sys;
70
71void writeModuleToFile(llvm::Module *module) {
72 auto TargetTriple = LLVMGetDefaultTargetTriple();
73 InitializeAllTargetInfos();
74 InitializeAllTargets();
75 InitializeAllTargetMCs();
76 InitializeAllAsmParsers();
77 InitializeAllAsmPrinters();
78
79 std::string Error;
80 auto Target = TargetRegistry::lookupTarget(TargetTriple, Error);
81 auto CPU = "generic";
82 auto Features = "";
83
84 TargetOptions opt;
85 auto RM = std::optional<Reloc::Model>();
86 auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM);
87
88 module->setDataLayout(TargetMachine->createDataLayout());
89 module->setTargetTriple(TargetTriple);
90
91 auto Filename = "output.o";
92 std::error_code EC;
93 raw_fd_ostream dest(Filename, EC, sys::fs::OF_None);
94
95 legacy::PassManager pass;
96 auto FileType = CodeGenFileType::ObjectFile;
97
98 if (TargetMachine->addPassesToEmitFile(pass, dest, nullptr, FileType)) {
99 errs() << "TargetMachine can't emit a file of this type";
100 return;
101 }
102 pass.run(*module);
103 dest.flush();
104
105 IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions;
106 clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(errs(), &*DiagOpts);
107 IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
108 clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
109 clang::driver::Driver TheDriver("/uslkjhklhjkr/bin/clang++-12ssss", TargetTriple, Diags);
110
111 auto args = ArrayRef<const char *>{"-g", "output.o", "-o", "xxxxxxxxxxxxxxxxxxxxx"};
112
113 std::unique_ptr<clang::driver::Compilation> C(TheDriver.BuildCompilation(args));
114
115 if (C && !C->containsError()) {
116 SmallVector<std::pair<int, const clang::driver::Command *>, 4> FailingCommands;
117 TheDriver.ExecuteCompilation(*C, FailingCommands);
118 }
119
120// remove(Filename);
121}
122
123std::unique_ptr<llvm::Module> CompileCpp2(std::string source, std::vector<std::string> opts, std::string *asm_code = nullptr) {
124 clang::CompilerInstance compilerInstance;
125 auto& compilerInvocation = compilerInstance.getInvocation();
126
127
128 // Диагностика работы Clang
129 clang::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions;
130 clang::TextDiagnosticPrinter *textDiagPrinter =
131 new clang::TextDiagnosticPrinter(llvm::outs(), &*DiagOpts);
132
133 clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> pDiagIDs;
134
135 clang::DiagnosticsEngine *pDiagnosticsEngine =
136 new clang::DiagnosticsEngine(pDiagIDs, &*DiagOpts, textDiagPrinter);
137
138
139 // Целевая платформа
140 std::string triple = LLVMGetDefaultTargetTriple();
141
142 std::vector<std::string> itemstrs;
143 itemstrs.push_back(triple.insert(0, "-triple="));
144 itemstrs.push_back("-xc++");
145 itemstrs.push_back("-std=c++23");
146
147 itemstrs.insert(itemstrs.end(), opts.begin(), opts.end());
148
149 // itemstrs.push_back("-fno-exceptions");
150 // itemstrs.push_back("-funwind-tables");
151
152 std::vector<const char*> itemcstrs;
153 for (unsigned idx = 0; idx < itemstrs.size(); idx++) {
154 // note: if itemstrs is modified after this, itemcstrs will be full
155 // of invalid pointers! Could make copies, but would have to clean up then...
156 itemcstrs.push_back(itemstrs[idx].c_str());
157 std::cout << itemcstrs.back() << "\n";
158 }
159
160 // Компиляция из памяти
161 // Send code through a pipe to stdin
162 int codeInPipe[2];
163 pipe2(codeInPipe, O_NONBLOCK);
164 write(codeInPipe[1], source.c_str(), source.size());
165 close(codeInPipe[1]); // We need to close the pipe to send an EOF
166 dup2(codeInPipe[0], STDIN_FILENO);
167
168 itemcstrs.push_back("-"); // Read code from stdin
169
170 clang::CompilerInvocation::CreateFromArgs(compilerInvocation,
171 llvm::ArrayRef<const char *>(itemcstrs.data(),
172 itemcstrs.size()), *pDiagnosticsEngine);
173
174 auto& languageOptions = compilerInvocation.getLangOpts();
175 auto& preprocessorOptions = compilerInvocation.getPreprocessorOpts();
176 auto& targetOptions = compilerInvocation.getTargetOpts();
177
178 auto& frontEndOptions = compilerInvocation.getFrontendOpts();
179 // frontEndOptions.ShowStats = true;
180
181 auto& headerSearchOptions = compilerInvocation.getHeaderSearchOpts();
182 // headerSearchOptions.Verbose = true;
183
184 auto& codeGenOptions = compilerInvocation.getCodeGenOpts();
185
186
187 targetOptions.Triple = LLVMGetDefaultTargetTriple();
188 compilerInstance.createDiagnostics(textDiagPrinter, false);
189
190 std::cout << "Using target triple: " << triple;
191
192 LLVMContextRef ctx = LLVMContextCreate();
193 std::unique_ptr<clang::CodeGenAction> action = std::make_unique<clang::EmitLLVMOnlyAction>((llvm::LLVMContext *)ctx);
194
195 assert(compilerInstance.ExecuteAction(*action));
196
197 // Runtime LLVM Module
198 std::unique_ptr<llvm::Module> module = action->takeModule();
199
200 assert(module);
201
202
203 if (asm_code) {
204 llvm::raw_string_ostream asm_stream(*asm_code);
205 module->print(asm_stream, 0, false);
206 }
207 //AssemblyWriter
208
209
210
211
212 // LLVMContextRef context = LLVMContextCreate();
213 // LLVMModuleRef module = LLVMModuleCreateWithNameInContext("test", context);
214
215 // LLVMTypeRef f32 = LLVMFloatTypeInContext(context);
216 // LLVMTypeRef ftype = LLVMFunctionType(f32, 0, 0, 0);
217 // LLVMValueRef ftest = LLVMAddFunction(module, "ftest", ftype);
218 // LLVMBasicBlockRef bb = LLVMAppendBasicBlockInContext(context, ftest, "ftest");
219 // LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
220 // LLVMPositionBuilderAtEnd(builder, bb);
221 // LLVMValueRef v1 = LLVMConstReal(f32, 2.5);
222 // LLVMValueRef v2 = LLVMConstReal(f32, 4.3);
223 // LLVMValueRef result = LLVMBuildFAdd(builder, v1, v2, "f-add");
224 // LLVMBuildRet(builder, result);
225 // LLVMVerifyFunction(ftest, LLVMPrintMessageAction);
226
227 char* errors = 0;
228 // LLVMPrintModuleToFile((LLVMModuleRef)&*module, "include_h_i_function_test.s", &errors);
229 // printf("error: %s\n", errors);
230 // LLVMDisposeMessage(errors);
231
232 // LLVMInitializeAllTargetInfos();
233 // LLVMInitializeAllTargets();
234 // LLVMInitializeAllTargetMCs();
235 // LLVMInitializeAllAsmParsers(); // Для использования ассемблерных вставок!!! (комменатрие в коде)
236 // LLVMInitializeAllAsmPrinters();
237
238 // LLVMTargetRef target;
239 // LLVMGetTargetFromTriple(LLVMGetDefaultTargetTriple(), &target, &errors);
240 // // printf("error: %s\n", errors);
241 // LLVMDisposeMessage(errors);
242 // // printf("target: %s, [%s], %d, %d\n", LLVMGetTargetName(target), LLVMGetTargetDescription(target), LLVMTargetHasJIT(target), LLVMTargetHasTargetMachine(target));
243 // // printf("triple: %s\n", LLVMGetDefaultTargetTriple());
244 // // printf("features: %s\n", LLVMGetHostCPUFeatures());
245 // LLVMTargetMachineRef machine = LLVMCreateTargetMachine(target, LLVMGetDefaultTargetTriple(), "generic", LLVMGetHostCPUFeatures(), LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);
246 //
247 // LLVMSetTarget((LLVMModuleRef)&*module, LLVMGetDefaultTargetTriple());
248 // LLVMTargetDataRef datalayout = LLVMCreateTargetDataLayout(machine);
249 // char* datalayout_str = LLVMCopyStringRepOfTargetData(datalayout);
250 // // printf("datalayout: %s\n", datalayout_str);
251 // LLVMSetDataLayout((LLVMModuleRef)&*module, datalayout_str);
252 // LLVMDisposeMessage(datalayout_str);
253 //
254 // LLVMTargetMachineEmitToFile(machine, (LLVMModuleRef)&*module, "include_h_i_function_test.o", LLVMObjectFile, &errors);
255 // // printf("error: %s\n", errors);
256 // LLVMDisposeMessage(errors);
257
258
259 // Оптимизация IR
260 // llvm::PassBuilder passBuilder;
261 // llvm::LoopAnalysisManager loopAnalysisManager;
262 // llvm::FunctionAnalysisManager functionAnalysisManager;
263 // llvm::CGSCCAnalysisManager cGSCCAnalysisManager;
264 // llvm::ModuleAnalysisManager moduleAnalysisManager;
265 //
266 // passBuilder.registerModuleAnalyses(moduleAnalysisManager);
267 // passBuilder.registerCGSCCAnalyses(cGSCCAnalysisManager);
268 // passBuilder.registerFunctionAnalyses(functionAnalysisManager);
269 // passBuilder.registerLoopAnalyses(loopAnalysisManager);
270 // passBuilder.crossRegisterProxies(loopAnalysisManager, functionAnalysisManager, cGSCCAnalysisManager, moduleAnalysisManager);
271 //
272 // llvm::ModulePassManager modulePassManager = passBuilder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O0);
273 // modulePassManager.run(*module, moduleAnalysisManager);
274
275 return module;
276}
277
278const char * source = ""
279 "#include <stdio.h>\n"
280 "#include \"sys/time.h\"\n"
281 "\n"
282 "\n"
283 "int main(int argc, char* argv[], char* envp[]) {\n"
284 "\n"
285 " // disable unused warning\n"
286 " ((void)(argc)); ((void)(argv)); ((void)(envp));\n"
287 " printf(\"Hello, world!!!!!!!!!!!!!!!!!!\\n\");\n"
288 "\n"
289 " return 0;\n"
290 "};";
291
292TEST(JIT, Embed) {
293
294 std::vector<std::string> argsX{
295 // "-std=c++23", "-stdlib=libc++",
296 // "--print-supported-cpus",
297 "-I", "/usr/include/x86_64-linux-gnu/",
298 "-I", "/usr/lib/gcc/x86_64-linux-gnu/11/include",
299 "-I", "/usr/include",
300 "-I", "/usr/include/linux",
301 "-I", "/usr/local/include",
302 "-o", "hello_embeddddddddddddddddddddd",
303 // "-x", "c++",
304 "hello_embed.cpp"};
305
306 auto module = CompileCpp2(source,argsX);
307
308 writeModuleToFile(module.get());
309
310}
311
312
313
314//TEST(JIT, Embed) {
315//
316//
317// std::filesystem::path path = std::filesystem::path("../examples/hello_embed.src");
318// ASSERT_TRUE(std::filesystem::exists(path));
319//
320// std::ifstream file(path, std::ios::in | std::ios::binary);
321//
322// const auto sz = std::filesystem::file_size(path);
323// ASSERT_TRUE(sz);
324//
325// std::string source(sz, '\0');
326// file.read(source.data(), sz);
327// ASSERT_TRUE(file) << "error: only " << file.gcount() << " could be read";
328// file.close();
329//
330// TermPtr ast = Parser::ParseString(source);
331//
332// JIT trans;
333// std::string hello_embed = trans.MakeApplicationSource(ast);
334//
335// if (!std::filesystem::exists(std::filesystem::path("temp"))) {
336// std::filesystem::create_directories(std::filesystem::path("temp"));
337// }
338// ASSERT_TRUE(std::filesystem::exists(std::filesystem::path("temp")));
339// ASSERT_TRUE(std::filesystem::is_directory(std::filesystem::path("temp")));
340//
341// std::ofstream ofile(std::filesystem::path("temp/hello_embed.cpp"), std::ios::out | std::ios::trunc);
342// ofile << hello_embed;
343// ofile.close();
344//
345// std::string bin_out;
346// ASSERT_TRUE(trans.MakeCppExec(hello_embed, "temp/hello_embed")) << hello_embed;
347//
348// ASSERT_TRUE(std::filesystem::exists(std::filesystem::path("temp/hello_embed")));
349//
350//
351//}
352
353
354
355
356
357
358
359
371//
587//
639//
640//TEST(Compiler, DISABLED_Function) {
641//
642// const char *func_text =
643// "func_sum(arg1, arg2) :- {$arg1 + $arg2;};\n"
644// "func_call(arg1, arg2) :- {func_sum($arg1, $arg2);};";
645//
646// TermPtr funcs;
647// Parser parser(funcs);
648//
649// parser.Parse(func_text);
650// ASSERT_TRUE(funcs);
651// ASSERT_EQ(TermID::BLOCK, funcs->getTermID());
652// ASSERT_EQ(2, funcs->BlockCode().size());
653//
654// TermPtr func1 = funcs->BlockCode()[0];
655//
656// ASSERT_EQ(TermID::PURE_ONCE, func1->getTermID());
657// ASSERT_TRUE(func1->Left());
658// ASSERT_EQ(2, func1->Left()->size());
659//
660// ASSERT_TRUE(func1->Right());
661// TermPtr body1 = func1->Right();
662//
663// // ASSERT_EQ(TermID::LOCAL, body1->getTermID());
664// // ASSERT_TRUE(body1->Left());
665// // ASSERT_TRUE(body1->Right());
666// // ASSERT_STREQ(":=", body1->getText().c_str());
667// // ASSERT_EQ(TermID::RESULT, body1->Left()->getTermID());
668// // ASSERT_STREQ("$$", body1->Left()->getText().c_str());
669// // ASSERT_EQ(TermID::OPERATOR, body1->Right()->getTermID());
670//
671// TermPtr op = body1->Right();
672// // ASSERT_TRUE(op);
673// // ASSERT_TRUE(op->Left());
674// // ASSERT_TRUE(op->Right());
675// // ASSERT_EQ(TermID::TERM, op->Left()->getTermID());
676// // ASSERT_STREQ("+", op->getText().c_str());
677// // ASSERT_STREQ("$arg1", op->Left()->getText().c_str());
678// // ASSERT_STREQ("$arg2", op->Right()->getText().c_str());
679//
680//
681// TermPtr func2 = funcs->BlockCode()[1];
682//
683// ASSERT_EQ(TermID::PURE_ONCE, func2->getTermID());
684// ASSERT_TRUE(func2->Left());
685// ASSERT_EQ(2, func2->Left()->size());
686//
687// // ASSERT_TRUE(func2->Right());
688// // TermPtr body2 = func2->Right();
689// // ASSERT_TRUE(body2);
690// //
691// // ASSERT_TRUE(body2->Left());
692// // ASSERT_TRUE(body2->Right());
693// // ASSERT_EQ(TermID::LOCAL, body2->getTermID());
694// // ASSERT_STREQ(":=", body2->getText().c_str());
695// // ASSERT_EQ(TermID::RESULT, body2->Left()->getTermID());
696// // ASSERT_STREQ("$$", body2->Left()->getText().c_str());
697// //
698// // op = body2->Right();
699// // ASSERT_TRUE(op);
700// // ASSERT_FALSE(op->Left());
701// // ASSERT_FALSE(op->Right());
702// // ASSERT_EQ(TermID::CALL, op->getTermID());
703// // ASSERT_STREQ("func_sum", op->getText().c_str());
704// // ASSERT_EQ(2, op->size());
705// // ASSERT_STREQ("$arg1", (*op)[0]->getText().c_str());
706// // ASSERT_STREQ("$arg2", (*op)[1]->getText().c_str());
707//
708//
709// std::ostringstream sstr;
710// ASSERT_TRUE(Compiler::MakeCppFile(funcs, sstr)); // << sstr.str();
711//
712//
713// std::filesystem::create_directories("temp");
714// ASSERT_TRUE(std::filesystem::is_directory("temp"));
715//
716// std::ofstream file("temp/function_test.temp.cpp");
717// file << sstr.str();
718// file.close();
719//}
720//
721//TEST(Compiler, DISABLED_FuncsTypes) {
722//
723// /*
724// * - Проверка типов аргументов при вызове функций
725// * - Проверка типов возвращаемых значений у функций
726// */
727//
728// RuntimePtr opts = RunTime::Init();
729// Context ctx(opts);
730//
731//#define FUNC_ARG "func_arg(arg1: Int8, arg2): Int8 := { $arg1+$arg2; };"
732//#define FUNC_RES "func_res(arg1: Int8, arg2: Int32): Integer := { $arg2+=$arg1; };"
733//
734// TermPtr func;
735// Parser parser(func);
736//
737// std::ostringstream sstr;
738//
739// // Не соответствие типа функции в операторе
740// parser.Parse(FUNC_ARG FUNC_RES "\n$res:Int8 := func_arg(100, 100); $res += func_res(100, 100);");
741// sstr.str("");
742// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
743//
744// // Компилится без ошибок
745// parser.Parse(FUNC_ARG "\nfunc_arg(Int8(100), 100);");
746// sstr.str("");
747// ASSERT_NO_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx)) << sstr.str();
748//
749// // Не соответствие типа первого аргумента
750// parser.Parse(FUNC_ARG "\nfunc_arg(1000, 100);");
751// sstr.str("");
752// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
753//
754// // Не соответствие типа функции
755// parser.Parse(FUNC_ARG FUNC_RES "\n$res:Int8 := func_res(100, 1000);");
756// sstr.str("");
757// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
758//
759// // Не соответствие типа функции в операторе
760// parser.Parse(FUNC_ARG FUNC_RES "\n$res:Int8 := func_arg(100, 100); $res += func_res(100, 100);");
761// sstr.str("");
762// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
763//
764// // Нет типа у $res как в предыдщем случае
765// parser.Parse(FUNC_ARG FUNC_RES "\n$res := func_arg(100, 100); $res += func_res(100, 100);");
766// sstr.str("");
767// ASSERT_NO_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx)) << sstr.str();
768//
769// // Тип есть, но делается каст возвращаемого типа у функции
770// parser.Parse(FUNC_ARG FUNC_RES "\n$res: Int8 := func_arg(100, 100); $res += Int8(func_res(100, 100));");
771// sstr.str("");
772// ASSERT_NO_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx)) << sstr.str();
773//
774//
775// std::filesystem::create_directories("temp");
776// ASSERT_TRUE(std::filesystem::is_directory("temp"));
777//
778//
779// std::ofstream file("temp/call_types.temp.cpp");
780// file << sstr.str();
781// file.close();
782//
783// std::string out;
784// int exit_code;
785// ASSERT_TRUE(Compiler::GccMakeModule("temp/call_types.temp.cpp",
786// "temp/call_types.temp.nlm", nullptr,
787// &out, &exit_code))
788// << exit_code << " " << out;
789//
790// ASSERT_TRUE(ctx.m_runtime->LoadModule(ctx, "call_types.temp.nlm", false));
791//
792// // Переполнение байтовой переменной $res во время выполнения последнего оператора "+="
793// // Obj args;
794// // ASSERT_TRUE(ctx.m_runtime->m_modules["temp/call_types.temp.nlm"]);
795// // ASSERT_NO_THROW(
796// // ctx.m_runtime->m_modules["temp/call_types.temp.nlm"]->Main(&ctx, args));
797// //@todo Контроль переполнения при операциях для типизированных переменных
798// //????????????????
799// //@todo Такой же как и для остальных операций
800// //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
801// // ASSERT_THROW(opts->m_modules["temp/call_types.temp.nlm"]->Main(&ctx,
802// // args), newlang_exception);
803//
804//#undef FUNC_ARG
805//#undef FUNC_RES
806//
807//}
808
809#endif // BUILD_UNITTEST
Definition nlc.h:59
std::shared_ptr< Term > TermPtr
Definition variable.h:33