topazc
codegen.cpp
Go to the documentation of this file.
1
6
12#include <filesystem>
13#include <fstream>
14
16 for (const AST::StmtPtr& stmt : stmts) {
17 generate_stmt(*stmt);
18 }
19}
20
22 if (auto vds = dynamic_cast<AST::VarDeclStmt*>(&stmt)) {
24 }
25 else if (auto vas = dynamic_cast<AST::VarAsgnStmt*>(&stmt)) {
27 }
28 else if (auto fds = dynamic_cast<AST::FuncDeclStmt*>(&stmt)) {
30 }
31 else if (auto fcs = dynamic_cast<AST::FuncCallStmt*>(&stmt)) {
33 }
34 else if (auto rs = dynamic_cast<AST::ReturnStmt*>(&stmt)) {
36 }
37 else if (auto ies = dynamic_cast<AST::IfElseStmt*>(&stmt)) {
39 }
40 else if (auto wcs = dynamic_cast<AST::WhileCycleStmt*>(&stmt)) {
42 }
43 else if (auto dwcs = dynamic_cast<AST::DoWhileCycleStmt*>(&stmt)) {
45 }
46 else if (auto fcs = dynamic_cast<AST::ForCycleStmt*>(&stmt)) {
48 }
49 else if (auto bs = dynamic_cast<AST::BreakStmt*>(&stmt)) {
51 }
52 else if (auto cs = dynamic_cast<AST::ContinueStmt*>(&stmt)) {
54 }
55 else if (auto ms = dynamic_cast<AST::ModuleStmt*>(&stmt)) {
57 }
58 else if (auto ums = dynamic_cast<AST::UseModuleStmt*>(&stmt)) {
60 }
61 else if (auto es = dynamic_cast<AST::ExternStmt*>(&stmt)) {
63 }
64 else {
65 throw_exception(SUB_CODEGEN, "Unsupported statement. Please check your Topaz compiler version and fix the problematic section of the code", stmt.line, file_name, is_debug);
66 }
67}
68
70 llvm::Type *type = type_to_llvm(vds.type);
71 llvm::Value *val = llvm::Constant::getNullValue(type);
72 if (vds.expr != nullptr) {
73 val = generate_expr(*vds.expr);
74 }
75 if (val->getType() != type) {
76 val = implicitly_cast(val, type);
77 }
78 llvm::Value *var = nullptr;
79 if (variables.size() == 1) {
80 var = new llvm::GlobalVariable(*module, type, vds.type.is_const, llvm::GlobalValue::ExternalLinkage, llvm::dyn_cast<llvm::Constant>(val), vds.name);
81 }
82 else {
83 var = builder.CreateAlloca(type, nullptr, vds.name + ".alloca");
84 builder.CreateStore(val, var);
85 }
86 variables.top().emplace(vds.name, var);
87}
88
90 llvm::Value *var_inst = nullptr;
91 auto vars = variables;
92 while (!vars.empty()) {
93 auto vars_it = vars.top().find(vas.name);
94 if (vars_it != vars.top().end()) {
95 var_inst = vars_it->second;
96 }
97 vars.pop();
98 }
99 if (var_inst == nullptr) {
100 std::stringstream ss;
101 ss << "Variable \033[0m'" << vas.name << "'\033[31m does not exists";
103 }
104 builder.CreateStore(generate_expr(*vas.expr), var_inst);
105}
106
108 llvm::Type *ret_type = type_to_llvm(fds.ret_type);
109 std::vector<llvm::Type*> args;
110 std::string func_name = get_mangled_name(fds.name);
111 size_t args_count = fds.args.size();
112 for (size_t i = 0; i < args_count; i++) {
113 args.push_back(type_to_llvm(fds.args[i].type));
114 switch (fds.args[i].type.type) {
115 case AST::TYPE_BOOL:
116 func_name += ".bool";
117 break;
118 case AST::TYPE_CHAR:
119 func_name += ".char";
120 break;
121 case AST::TYPE_SHORT:
122 func_name += ".short";
123 break;
124 case AST::TYPE_INT:
125 func_name += ".int";
126 break;
127 case AST::TYPE_LONG:
128 func_name += ".long";
129 break;
130 case AST::TYPE_FLOAT:
131 func_name += ".float";
132 break;
133 case AST::TYPE_DOUBLE:
134 func_name += ".double";
135 break;
136 case AST::TYPE_TRAIT:
137 func_name += ".T_" + fds.args[i].type.name;
138 break;
139 case AST::TYPE_CLASS:
140 func_name += ".C_" + fds.args[i].type.name;
141 break;
142 }
143 if (fds.args[i].type.is_const) {
144 func_name += "_const";
145 }
146 if (fds.args[i].type.is_ptr) {
147 func_name += "_ptr";
148 }
149 }
150 llvm::FunctionType *func_type = llvm::FunctionType::get(ret_type, args, false);
151 llvm::Function *func = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage, func_name, *module);
152
153 llvm::BasicBlock *entry = llvm::BasicBlock::Create(context, "entry", func);
154 builder.SetInsertPoint(entry);
155
156 variables.push({});
157 if (functions.find(get_mangled_name(fds.name)) == functions.end()) {
158 functions.emplace(get_mangled_name(fds.name), std::vector<llvm::Function*>{func});
159 }
160 else {
161 functions.at(get_mangled_name(fds.name)).push_back(func);
162 }
163 functions_ret_types.push(ret_type);
164 size_t index = 0;
165 for (llvm::Argument& arg : func->args()) {
166 arg.setName(fds.args[index].name);
167 llvm::AllocaInst *arg_alloca = builder.CreateAlloca(arg.getType(), nullptr, fds.args[index].name);
168 builder.CreateStore(&arg, arg_alloca);
169 variables.top().emplace(fds.args[index].name, arg_alloca);
170 index++;
171 }
172 bool have_ret_in_global = false;
173 for (auto& stmt : fds.block) {
174 if (dynamic_cast<AST::ReturnStmt*>(&*stmt)) {
175 if (have_ret_in_global) {
176 continue;
177 }
178 have_ret_in_global = true;
179 }
180 generate_stmt(*stmt);
181 }
182 if (!have_ret_in_global) {
183 if (fds.ret_type.type == AST::TYPE_NOTH) {
184 builder.CreateRetVoid();
185 }
186 else if (fds.ret_type.type <= AST::TYPE_DOUBLE) {
187 builder.CreateRet(llvm::Constant::getNullValue(type_to_llvm(fds.ret_type)));
188 }
189 else {
190 throw_exception(SUB_CODEGEN, "Not all paths return a value", fds.line, file_name, is_debug);
191 }
192 }
193 variables.pop();
195}
196
198 std::vector<llvm::Function*> function_candidates = functions.at(get_mangled_name(fcs.name));
199 std::vector<llvm::Value*> args;
200 for (auto& arg : fcs.args) {
201 args.push_back(generate_expr(*arg));
202 }
203
204 size_t last_score = SIZE_MAX;
205 size_t best_candidate_index = 0;
206 size_t candidate_index = 0;
207 for (auto& candidate : function_candidates) {
208 auto candidate_args_it = candidate->args();
209 size_t score = 0;
210 size_t index = 0;
211 for (auto& arg : candidate_args_it) {
212 llvm::Type *candidate_arg_type = arg.getType();
213 llvm::Type *calling_arg_type = generate_expr(*fcs.args[index])->getType();
214
215 if (candidate_arg_type != calling_arg_type) {
216 if (candidate_arg_type->isIntegerTy() && calling_arg_type->isIntegerTy()) {
217 score++;
218 }
219 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isFloatingPointTy()) {
220 score++;
221 }
222 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isIntegerTy()) {
223 score += 2;
224 }
225 else {
226 score += 99;
227 }
228 }
229
230 index++;
231 }
232
233 if (score <= last_score) {
234 best_candidate_index = candidate_index;
235 last_score = score;
236 }
237
238 candidate_index++;
239 }
240
241 builder.CreateCall(function_candidates[best_candidate_index], args, function_candidates[best_candidate_index]->getName() + ".call");
242}
243
245 if (rs.expr != nullptr) {
246 llvm::Value *val = generate_expr(*rs.expr);
247 if (val->getType() != functions_ret_types.top()) {
248 val = implicitly_cast(val, functions_ret_types.top());
249 }
250 builder.CreateRet(val);
251 }
252 else {
253 builder.CreateRetVoid();
254 }
255}
256
258 llvm::Function *parent = builder.GetInsertBlock()->getParent();
259 llvm::Value *cond_val = generate_expr(*ies.cond);
260 llvm::BasicBlock *then_bb = llvm::BasicBlock::Create(context, "if.then", parent);
261 llvm::BasicBlock *else_bb = llvm::BasicBlock::Create(context, "if.else", parent);
262 llvm::BasicBlock *merge_bb = llvm::BasicBlock::Create(context, "if.merge", parent);
263
264 builder.CreateCondBr(cond_val, then_bb, else_bb ? else_bb : merge_bb);
265
266 builder.SetInsertPoint(then_bb);
267 variables.push({});
268 for (auto& stmt : ies.then_block) {
269 generate_stmt(*stmt);
270 }
271 variables.pop();
272
273 if (builder.GetInsertBlock()->getTerminator() == nullptr) {
274 builder.CreateBr(merge_bb);
275 }
276
277 builder.SetInsertPoint(else_bb);
278 variables.push({});
279 for (auto& stmt : ies.else_block) {
280 generate_stmt(*stmt);
281 }
282 variables.pop();
283
284 if (builder.GetInsertBlock()->getTerminator() == nullptr) {
285 builder.CreateBr(merge_bb);
286 }
287 builder.SetInsertPoint(merge_bb);
288}
289
291 llvm::Function *parent = builder.GetInsertBlock()->getParent();
292 llvm::BasicBlock *cond_bb = llvm::BasicBlock::Create(context, "while.cond", parent);
293 llvm::BasicBlock *body_bb = llvm::BasicBlock::Create(context, "while.body", parent);
294 llvm::BasicBlock *exit_bb = llvm::BasicBlock::Create(context, "while.exit", parent);
295
296 builder.CreateBr(cond_bb);
297 builder.SetInsertPoint(cond_bb);
298 llvm::Value *cond_value = generate_expr(*wcs.cond);
299
300 builder.CreateCondBr(cond_value, body_bb, exit_bb);
301 builder.SetInsertPoint(body_bb);
302 variables.push({});
303 loop_blocks.emplace(exit_bb, cond_bb);
304 for (auto& stmt : wcs.block) {
305 generate_stmt(*stmt);
306 }
307 loop_blocks.pop();
308 variables.pop();
309
310 builder.CreateBr(cond_bb);
311 builder.SetInsertPoint(exit_bb);
312}
313
315 llvm::Function *parent = builder.GetInsertBlock()->getParent();
316 llvm::BasicBlock *cond_bb = llvm::BasicBlock::Create(context, "do.while.cond", parent);
317 llvm::BasicBlock *body_bb = llvm::BasicBlock::Create(context, "do.while.body", parent);
318 llvm::BasicBlock *exit_bb = llvm::BasicBlock::Create(context, "do.while.exit", parent);
319
320 builder.CreateBr(body_bb);
321 builder.SetInsertPoint(body_bb);
322 variables.push({});
323 loop_blocks.emplace(exit_bb, cond_bb);
324 for (auto& stmt : dwcs.block) {
325 generate_stmt(*stmt);
326 }
327 loop_blocks.pop();
328 variables.pop();
329
330 builder.CreateBr(cond_bb);
331 builder.SetInsertPoint(cond_bb);
332 llvm::Value *cond_value = generate_expr(*dwcs.cond);
333 builder.CreateCondBr(cond_value, body_bb, exit_bb);
334
335 builder.SetInsertPoint(exit_bb);
336}
337
339 llvm::Function *parent = builder.GetInsertBlock()->getParent();
340 llvm::BasicBlock *indexator_bb = llvm::BasicBlock::Create(context, "for.indexator", parent);
341 llvm::BasicBlock *cond_bb = llvm::BasicBlock::Create(context, "for.cond", parent);
342 llvm::BasicBlock *iteration_bb = llvm::BasicBlock::Create(context, "for.iteration", parent);
343 llvm::BasicBlock *body_bb = llvm::BasicBlock::Create(context, "for.body", parent);
344 llvm::BasicBlock *exit_bb = llvm::BasicBlock::Create(context, "for.exit", parent);
345
346 builder.CreateBr(indexator_bb);
347 builder.SetInsertPoint(indexator_bb);
349
350 builder.CreateBr(cond_bb);
351 builder.SetInsertPoint(cond_bb);
352 llvm::Value *condition_value = generate_expr(*fcs.cond);
353
354 builder.CreateCondBr(condition_value, body_bb, exit_bb);
355 builder.SetInsertPoint(body_bb);
356 variables.push({});
357 loop_blocks.emplace(exit_bb, iteration_bb);
358 for (auto& stmt : fcs.block) {
359 generate_stmt(*stmt);
360 }
361 loop_blocks.pop();
362 variables.pop();
363
364 builder.CreateBr(iteration_bb);
365 builder.SetInsertPoint(iteration_bb);
367
368 builder.CreateBr(cond_bb);
369 builder.SetInsertPoint(exit_bb);
370}
371
373 builder.CreateBr(loop_blocks.top().first);
374}
375
379
381 current_path.push(PathPart{.name=ms.name, .object=PathPart::OBJ_MODULE});
382
383 for (auto& stmt : ms.block) {
384 generate_stmt(*stmt);
385 }
386
387 current_path.pop();
388}
389
391 std::string all_name;
392 for (size_t i = 0; i < ums.path.size(); i++) {
393 all_name += ums.path[i];
394 if (i != ums.path.size() - 1) {
395 all_name += "-";
396 }
397 }
398 std::filesystem::path path_to_mod_without_ext;
399 for (size_t i = 0; i < ums.path.size(); i++) {
400 path_to_mod_without_ext += "/" + ums.path[i];
401 }
402 std::filesystem::path path_to_mod_without_ext_in_libs = libs_path + path_to_mod_without_ext.string();
403 std::string path_to_mod_without_ext_in_libs_as_str = path_to_mod_without_ext_in_libs.string();
404 std::ifstream file;
405 if (std::filesystem::is_directory(path_to_mod_without_ext_in_libs_as_str)) {
406 if (std::filesystem::exists(path_to_mod_without_ext_in_libs_as_str + "/main.tp")) {
407 file = std::ifstream(path_to_mod_without_ext_in_libs_as_str + "/main.tp");
408 std::ostringstream content;
409 content << file.rdbuf();
410 file.close();
411 Lexer lex(content.str(), path_to_mod_without_ext_in_libs_as_str + "/main.tp", is_debug);
412 std::vector<Token> tokens = lex.tokenize();
413 Parser parser(tokens, is_debug);
414 std::vector<AST::StmtPtr> stmts = parser.parse();
415 SemanticAnalyzer semantic(stmts, libs_path, path_to_mod_without_ext_in_libs_as_str + "/main.tp", is_debug);
416 semantic.analyze();
417 std::map<std::string, SemanticAnalyzer::ModuleInfo*> modules = semantic.get_modules();
418 size_t current_path_size = current_path.size();
419 for (auto& module : modules) {
420 std::vector<PathPart> resolved_name = get_resolved_name(module.first);
421 current_path.push({resolved_name.back().name, PathPart::OBJ_MODULE});
422 auto functions = semantic.get_functions();
423 for (auto& func : module.second->functions) {
424 auto candidates_at_functions = functions.at(get_mangled_name(func.first));
425 for (auto& candidate : candidates_at_functions) {
426 generate_func_decl_stmt(*std::make_unique<AST::FuncDeclStmt>(func.second.first, func.first,
427 std::move(candidate->args), candidate->ret_type, std::move(candidate->block), -1));
428 }
429 }
430 }
431 for (size_t i = current_path.size() - current_path_size; i > 0; i--) {
432 current_path.pop();
433 }
434 }
435 }
436 else {
437 std::string path_to_file;
438 for (const auto& entry : std::filesystem::recursive_directory_iterator(libs_path)) {
439 if (entry.path().filename() == ums.path.back() + ".tp" && !std::filesystem::is_directory(entry.path())) {
440 path_to_file = entry.path();
441 file = std::ifstream(path_to_file);
442 break;
443 }
444 }
445 if (!file.is_open()) {
446 std::stringstream ss;
447 ss << "Module \033[0m'" << all_name << "'\033[31m does not exists";
449 }
450 std::ostringstream content;
451 content << file.rdbuf();
452 file.close();
453 Lexer lex(content.str(), path_to_mod_without_ext_in_libs_as_str + ".tp", is_debug);
454 std::vector<Token> tokens = lex.tokenize();
455 Parser parser(tokens, is_debug);
456 std::vector<AST::StmtPtr> stmts = parser.parse();
457 SemanticAnalyzer semantic(stmts, libs_path, path_to_mod_without_ext_in_libs_as_str + ".tp", is_debug);
458 semantic.analyze();
459 std::map<std::string, SemanticAnalyzer::ModuleInfo*> modules = semantic.get_modules();
460 size_t current_path_size = current_path.size();
461 for (auto& module : modules) {
462 std::vector<PathPart> resolved_name = get_resolved_name(module.first);
463 current_path.push({resolved_name.back().name, PathPart::OBJ_MODULE});
464 auto functions = semantic.get_functions();
465 for (auto& func : module.second->functions) {
466 auto candidates_at_functions = functions.at(get_mangled_name(func.first));
467 for (auto& candidate : candidates_at_functions) {
468 generate_func_decl_stmt(*std::make_unique<AST::FuncDeclStmt>(func.second.first, func.first,
469 std::move(candidate->args), candidate->ret_type, std::move(candidate->block), -1));
470 }
471 }
472 }
473 for (size_t i = current_path.size() - current_path_size; i > 0; i--) {
474 current_path.pop();
475 }
476 }
477}
478
480 for (auto& stmt : es.block) {
481 auto func = dynamic_cast<AST::FuncDeclStmt*>(&*stmt);
482 std::vector<llvm::Type*> args_types;
483 for (auto& arg : func->args) {
484 args_types.push_back(type_to_llvm(arg.type));
485 }
486 llvm::FunctionType *func_type = llvm::FunctionType::get(type_to_llvm(func->ret_type), args_types, false);
487 llvm::Function *function = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage, get_mangled_name(func->name), *module);
488 if (functions.find(get_mangled_name(func->name)) == functions.end()) {
489 functions.emplace(get_mangled_name(func->name), std::vector<llvm::Function*>{function});
490 }
491 else {
492 functions.at(get_mangled_name(func->name)).push_back(function);
493 }
494 }
495}
496
498 if (auto lit = dynamic_cast<AST::Literal*>(&expr)) {
499 return generate_literal_expr(*lit);
500 }
501 else if (auto be = dynamic_cast<AST::BinaryExpr*>(&expr)) {
502 return generate_binary_expr(*be);
503 }
504 else if (auto ue = dynamic_cast<AST::UnaryExpr*>(&expr)) {
505 return generate_unary_expr(*ue);
506 }
507 else if (auto ve = dynamic_cast<AST::VarExpr*>(&expr)) {
508 return generate_var_expr(*ve);
509 }
510 else if (auto fce = dynamic_cast<AST::FuncCallExpr*>(&expr)) {
511 return generate_func_call_expr(*fce);
512 }
513 else if (auto oce = dynamic_cast<AST::ChainObjects*>(&expr)) {
514 return generate_obj_chain_expr(*oce);
515 }
516 else {
517 throw_exception(SUB_CODEGEN, "An unsupported expression was encountered during compilation. Please check your Topaz compiler version and fix the problematic section of the code", expr.line, file_name, is_debug);
518 }
519}
520
522 auto& value = lit.value.value;
523
524 switch (lit.type.type) {
525 case AST::TYPE_CHAR:
526 return llvm::ConstantInt::get(type_to_llvm(lit.type), llvm::APInt(8, std::get<char8_t>(value)));
527 case AST::TYPE_SHORT:
528 return llvm::ConstantInt::get(type_to_llvm(lit.type), llvm::APInt(16, std::get<int16_t>(value)));
529 case AST::TYPE_INT:
530 return llvm::ConstantInt::get(type_to_llvm(lit.type), llvm::APInt(32, std::get<int32_t>(value)));
531 case AST::TYPE_LONG:
532 return llvm::ConstantInt::get(type_to_llvm(lit.type), llvm::APInt(64, std::get<int64_t>(value)));
533 case AST::TYPE_FLOAT:
534 return llvm::ConstantFP::get(type_to_llvm(lit.type), llvm::APFloat(std::get<float_t>(value)));
535 case AST::TYPE_DOUBLE:
536 return llvm::ConstantFP::get(type_to_llvm(lit.type), llvm::APFloat(std::get<double_t>(value)));
537 case AST::TYPE_BOOL:
538 return llvm::ConstantInt::get(type_to_llvm(lit.type), llvm::APInt(1, std::get<bool>(value)));
540 llvm::Constant *str_const = llvm::ConstantDataArray::getString(context, std::get<std::string>(value), true);
541 llvm::GlobalVariable *str_var = new llvm::GlobalVariable(*module, str_const->getType(), true, llvm::GlobalValue::PrivateLinkage, str_const, "string.lit");
542 return str_var;
543 }
544 default:
545 throw_exception(SUB_CODEGEN, "An unsupported literal type was encountered during compilation. Please check your Topaz compiler version and fix the problematic section of the code", lit.line, file_name, is_debug);
546 }
547}
548
550 llvm::Value *left = generate_expr(*be.left_expr);
551 llvm::Type *left_type = left->getType();
552 llvm::Value *right = generate_expr(*be.right_expr);
553 llvm::Type *right_type = right->getType();
554
555 llvm::Type *common_type = get_common_type(left_type, right_type);
556 if (left_type != common_type) {
557 left = implicitly_cast(left, common_type);
558 left_type = left->getType();
559 }
560 else if (right_type != common_type) {
561 right = implicitly_cast(right, common_type);
562 right_type = right->getType();
563 }
564 switch (be.op.type) {
565 case TOK_OP_PLUS:
566 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
567 return builder.CreateFAdd(left, right, "fadd.tmp");
568 }
569 return builder.CreateAdd(left, right, "add.tmp");
570 case TOK_OP_MINUS:
571 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
572 return builder.CreateFSub(left, right, "fsub.tmp");
573 }
574 return builder.CreateSub(left, right, "sub.tmp");
575 case TOK_OP_MULT:
576 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
577 return builder.CreateFMul(left, right, "fmul.tmp");
578 }
579 return builder.CreateMul(left, right, "mul.tmp");
580 case TOK_OP_DIV:
581 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
582 return builder.CreateFDiv(left, right, "fdiv.tmp");
583 }
584 return builder.CreateSDiv(left, right, "div.tmp");
585 case TOK_OP_MODULO:
586 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
587 return builder.CreateFRem(left, right, "frem.tmp");
588 }
589 return builder.CreateSRem(left, right, "rem.tmp");
590 case TOK_OP_EQ_EQ:
591 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
592 return builder.CreateFCmpUEQ(left, right, "feq.tmp");
593 }
594 return builder.CreateICmpEQ(left, right, "eq.tmp");
595 case TOK_OP_NOT_EQ_EQ:
596 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
597 return builder.CreateNeg(builder.CreateFCmpUEQ(left, right, "feq.tmp"), "fnoteq.tmp");
598 }
599 return builder.CreateNeg(builder.CreateICmpEQ(left, right, "eq.tmp"), "noteq.tmp");
600 case TOK_OP_GT:
601 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
602 return builder.CreateFCmpUGT(left, right, "fgt.tmp");
603 }
604 return builder.CreateICmpSGT(left, right, "gt.tmp");
605 case TOK_OP_GT_EQ:
606 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
607 return builder.CreateFCmpUGE(left, right, "fge.tmp");
608 }
609 return builder.CreateICmpSGE(left, right, "ge.tmp");
610 case TOK_OP_LS:
611 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
612 return builder.CreateFCmpULT(left, right, "flt.tmp");
613 }
614 return builder.CreateICmpSLT(left, right, "lt.tmp");
615 case TOK_OP_LS_EQ:
616 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
617 return builder.CreateFCmpULE(left, right, "fle.tmp");
618 }
619 return builder.CreateICmpSLE(left, right, "le.tmp");
620 case TOK_OP_L_AND:
621 return builder.CreateLogicalAnd(left, right, "land.tmp");
622 case TOK_OP_L_OR:
623 return builder.CreateLogicalAnd(left, right, "lor.tmp");
624 default:
625 throw_exception(SUB_CODEGEN, "An unsupported binary operator was encountered during compilation. Please check your Topaz compiler version and fix the problematic section of the code", be.line, file_name, is_debug);
626 }
627}
628
630 llvm::Value *raw_value = nullptr;
631 auto vars = variables;
632 if (auto ve = dynamic_cast<AST::VarExpr*>(&*ue.expr)) {
633 while (!vars.empty()) {
634 auto vars_it = vars.top().find(ve->name);
635 if (vars_it != vars.top().end()) {
636 raw_value = vars_it->second;
637 break;
638 }
639 vars.pop();
640 }
641 }
642 llvm::Value *value = generate_expr(*ue.expr);
643
644 switch (ue.op.type) {
645 case TOK_OP_MINUS:
646 if (value->getType()->isFloatingPointTy()) {
647 return builder.CreateFNeg(value, "neg.tmp");
648 }
649 return builder.CreateNeg(value, "neg.tmp");
650 case TOK_OP_L_NOT:
651 if (value->getType()->isFloatingPointTy()) {
652 return builder.CreateFCmpOEQ(value, builder.getInt32(0), "lnot.tmp");
653 }
654 return builder.CreateICmpEQ(value, builder.getInt32(0), "lnot.tmp");
655 case TOK_OP_MULT:
656 return builder.CreateLoad(value->getType(), value);
657 case TOK_OP_REF: {
658 return raw_value;
659 }
660 default:
661 throw_exception(SUB_CODEGEN, "An unsupported unary operator was encountered during compilation. Please check your Topaz compiler version and fix the problematic section of the code", ue.line, file_name, is_debug);
662 }
663}
664
666 auto vars = variables;
667 while (!vars.empty()) {
668 auto vars_it = vars.top().find(ve.name);
669 if (vars_it != vars.top().end()) {
670 llvm::Type *type = nullptr;
671 if (auto global = llvm::dyn_cast<llvm::GlobalVariable>(vars_it->second)) {
672 type = global->getValueType();
673 if (functions_ret_types.empty()) {
674 return global->getInitializer();
675 }
676 }
677 else if (auto local = llvm::dyn_cast<llvm::AllocaInst>(vars_it->second)) {
678 type = local->getAllocatedType();
679 }
680 return builder.CreateLoad(type, vars_it->second, ve.name + ".load");
681 }
682 vars.pop();
683 }
684 std::stringstream ss;
685 ss << "Variable \033[0m'" << ve.name << "'\033[31m does not exists";
687}
688
690 auto function_candidates = functions.at(get_mangled_name(fce.name));
691 std::vector<llvm::Value*> args;
692 for (auto& arg : fce.args) {
693 args.push_back(generate_expr(*arg));
694 }
695
696 size_t last_score = SIZE_MAX;
697 size_t best_candidate_index = 0;
698 size_t candidate_index = 0;
699 for (auto& candidate : function_candidates) {
700 auto candidate_args_it = candidate->args();
701 size_t score = 0;
702 size_t index = 0;
703 for (auto& arg : candidate_args_it) {
704 llvm::Type *candidate_arg_type = arg.getType();
705 llvm::Type *calling_arg_type = generate_expr(*fce.args[index])->getType();
706
707 if (candidate_arg_type != calling_arg_type) {
708 if (candidate_arg_type->isIntegerTy() && calling_arg_type->isIntegerTy()) {
709 score++;
710 }
711 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isFloatingPointTy()) {
712 score++;
713 }
714 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isIntegerTy()) {
715 score += 2;
716 }
717 else {
718 score += 99;
719 }
720 }
721
722 index++;
723 }
724
725 if (score <= last_score) {
726 best_candidate_index = candidate_index;
727 last_score = score;
728 }
729
730 candidate_index++;
731 }
732
733 return builder.CreateCall(function_candidates[best_candidate_index], args, function_candidates[best_candidate_index]->getName() + ".call");
734}
735
737 llvm::Value *value = nullptr; // Value of target object
738 size_t current_path_size = current_path.size();
739 for (size_t i = 0; i < co.chain.size(); i++) {
740 if (auto ve = dynamic_cast<AST::VarExpr*>(&*co.chain[i])) {
741 current_path.push({ve->name, PathPart::OBJ_MODULE});
742 }
743 else if (auto fce = dynamic_cast<AST::FuncCallExpr*>(&*co.chain[i])) {
744 value = generate_func_call_expr(*fce);
745 }
746 }
747 for (size_t i = current_path.size() - current_path_size; i > 0; i--) {
748 current_path.pop();
749 }
750 return value;
751}
752
754 llvm::Type *base_type = nullptr;
755 switch (type.type) {
756 case AST::TYPE_CHAR:
757 base_type = llvm::Type::getInt8Ty(context);
758 break;
759 case AST::TYPE_SHORT:
760 base_type = llvm::Type::getInt16Ty(context);
761 break;
762 case AST::TYPE_INT:
763 base_type = llvm::Type::getInt32Ty(context);
764 break;
765 case AST::TYPE_LONG:
766 base_type = llvm::Type::getInt64Ty(context);
767 break;
768 case AST::TYPE_FLOAT:
769 base_type = llvm::Type::getFloatTy(context);
770 break;
771 case AST::TYPE_DOUBLE:
772 base_type = llvm::Type::getDoubleTy(context);
773 break;
774 case AST::TYPE_BOOL:
775 base_type = llvm::Type::getInt1Ty(context);
776 break;
777 case AST::TYPE_NOTH:
778 base_type = llvm::Type::getVoidTy(context);
779 break;
780 default:
781 throw_exception(SUB_CODEGEN, "Unsupported type", -1, file_name, is_debug);
782 }
783 if (type.is_ptr) {
784 return llvm::PointerType::get(context, 0);
785 }
786 return base_type;
787}
788
789llvm::Type *CodeGenerator::get_common_type(llvm::Type *left, llvm::Type *right) {
790 if (left == right) {
791 return left;
792 }
793 else if (left->isIntegerTy() || right->isIntegerTy()) {
794 if (left->isIntegerTy() && right->isIntegerTy()) {
795 unsigned left_width = left->getIntegerBitWidth();
796 unsigned right_width = right->getIntegerBitWidth();
797
798 return left_width > right_width ? left : right;
799 }
800 else if (left->isFloatingPointTy() || right->isFloatingPointTy()) {
801 return left->isFloatingPointTy() ? left : right;
802 }
803 }
804 else if (left->isFloatingPointTy() && right->isFloatingPointTy()) {
805 return left->isDoubleTy() && right->isFloatTy() ? left : right;
806 }
807 else if (left->isDoubleTy() || right->isDoubleTy()) {
808 return llvm::Type::getDoubleTy(context);
809 }
810 return nullptr;
811}
812
813llvm::Value *CodeGenerator::implicitly_cast(llvm::Value *val, llvm::Type *expected_type) {
814 llvm::Type *val_type = val->getType();
815 if (val_type == expected_type) {
816 return val;
817 }
818 else if (val_type->isIntegerTy() && expected_type->isIntegerTy()) {
819 unsigned long value_width = val_type->getIntegerBitWidth();
820 unsigned long expected_width = expected_type->getIntegerBitWidth();
821
822 if (value_width > expected_width) {
823 return builder.CreateTrunc(val, expected_type, "trunc.tmp");
824 }
825 else {
826 return builder.CreateSExt(val, expected_type, "sext.tmp");
827 }
828 }
829 else if (val_type->isFloatingPointTy() && expected_type->isFloatingPointTy()) {
830 if (val_type->isFloatTy() && expected_type->isDoubleTy()) {
831 return builder.CreateFPExt(val, expected_type, "fpext.tmp");
832 }
833 else {
834 return builder.CreateFPTrunc(val, expected_type, "fptrunc.tmp");
835 }
836 }
837 else if (val_type->isIntegerTy() && expected_type->isFloatingPointTy()) {
838 return builder.CreateSIToFP(val, expected_type, "sitofp.tmp");
839 }
840 else if (val_type->isPointerTy()) {
841 return builder.CreatePointerCast(val, expected_type, "ptrcast.tmp");
842 }
843 return nullptr;
844}
845
846std::string CodeGenerator::get_mangled_name(std::string base_name) {
847 std::string res;
848 auto path = current_path;
849 while (!path.empty()) {
850 PathPart part = path.top();
851 if (part.object == PathPart::OBJ_MODULE) {
852 res = part.name + "-" + res;
853 }
854 else {
855 res = part.name + "#" + res;
856 }
857 path.pop();
858 }
859 return res + base_name;
860}
861
862std::vector<CodeGenerator::PathPart> CodeGenerator::get_resolved_name(std::string mangled_name) {
863 std::vector<PathPart> res;
864 std::string name;
865 for (const char c : mangled_name) {
866 if (c == '-') {
867 res.push_back({name, PathPart::OBJ_MODULE});
868 name = "";
869 }
870 else if (c == '#') {
871 res.push_back({name, PathPart::OBJ_CLASS});
872 name = "";
873 }
874 else {
875 name += c;
876 }
877 }
878 res.push_back({name, PathPart::OBJ_MODULE});
879 return res;
880}
Binary expression container.
Definition ast.hpp:219
ExprPtr right_expr
Definition ast.hpp:223
ExprPtr left_expr
Definition ast.hpp:222
Statement of break.
Definition ast.hpp:401
Chain of objects expression container.
Definition ast.hpp:273
std::vector< ExprPtr > chain
Definition ast.hpp:275
Statement of break.
Definition ast.hpp:410
Statement of do-while cycle.
Definition ast.hpp:375
std::vector< StmtPtr > block
Definition ast.hpp:378
Base class of expression.
Definition ast.hpp:117
uint32_t line
Definition ast.hpp:119
Statement of extern calls.
Definition ast.hpp:444
std::vector< StmtPtr > block
Definition ast.hpp:447
Statement of for cycle.
Definition ast.hpp:387
StmtPtr indexator
Definition ast.hpp:389
StmtPtr iteration
Definition ast.hpp:391
ExprPtr cond
Definition ast.hpp:390
std::vector< StmtPtr > block
Definition ast.hpp:392
Function calling expression container.
Definition ast.hpp:261
std::string name
Definition ast.hpp:263
std::vector< ExprPtr > args
Definition ast.hpp:264
Statement of functions calling.
Definition ast.hpp:328
std::vector< ExprPtr > args
Definition ast.hpp:331
std::string name
Definition ast.hpp:330
Statement of functions declaration.
Definition ast.hpp:313
std::vector< StmtPtr > block
Definition ast.hpp:319
std::vector< Argument > args
Definition ast.hpp:317
std::string name
Definition ast.hpp:316
Statement of control flow operator.
Definition ast.hpp:351
ExprPtr cond
Definition ast.hpp:353
std::vector< StmtPtr > else_block
Definition ast.hpp:355
std::vector< StmtPtr > then_block
Definition ast.hpp:354
Base class of literal.
Definition ast.hpp:133
Type type
Definition ast.hpp:135
Value value
Definition ast.hpp:136
Statement of module definition.
Definition ast.hpp:419
std::string name
Definition ast.hpp:423
std::vector< StmtPtr > block
Definition ast.hpp:424
Statement of 'return'.
Definition ast.hpp:340
ExprPtr expr
Definition ast.hpp:342
Base class of statement.
Definition ast.hpp:106
uint32_t line
Definition ast.hpp:108
Unary expression container.
Definition ast.hpp:234
ExprPtr expr
Definition ast.hpp:237
Statement of import the module.
Definition ast.hpp:433
std::vector< std::string > path
Definition ast.hpp:435
Statement of assignment of variable.
Definition ast.hpp:300
std::string name
Definition ast.hpp:302
ExprPtr expr
Definition ast.hpp:303
Statement of variable declaration.
Definition ast.hpp:286
ExprPtr expr
Definition ast.hpp:290
std::string name
Definition ast.hpp:291
Variable expression container.
Definition ast.hpp:248
std::string name
Definition ast.hpp:250
Statement of while cycle.
Definition ast.hpp:363
std::vector< StmtPtr > block
Definition ast.hpp:366
void generate_while_cycle_stmt(AST::WhileCycleStmt &wcs)
Method for generating LLVM IR code for while cycle.
Definition codegen.cpp:290
void generate_module_stmt(AST::ModuleStmt &ms)
Method for generating LLVM IR code for module definition.
Definition codegen.cpp:380
void generate_do_while_cycle_stmt(AST::DoWhileCycleStmt &dwcs)
Method for generating LLVM IR code for do-while cycle.
Definition codegen.cpp:314
void generate_var_asgn_stmt(AST::VarAsgnStmt &vas)
Method for generating LLVM IR code for variable assignment.
Definition codegen.cpp:89
llvm::Value * generate_var_expr(AST::VarExpr &ve)
Method for generating LLVM IR code for variable expressions.
Definition codegen.cpp:665
void generate_extern_stmt(AST::ExternStmt &es)
Method for generating LLVM IR code for extern calls.
Definition codegen.cpp:479
llvm::LLVMContext context
Definition codegen.hpp:29
llvm::Type * get_common_type(llvm::Type *left, llvm::Type *right)
Method for getting comon type between two types.
Definition codegen.cpp:789
std::string get_mangled_name(std::string base_name)
Method for getting mangled name.
Definition codegen.cpp:846
llvm::Value * generate_func_call_expr(AST::FuncCallExpr &fce)
Method for generating LLVM IR code for function calling expressions.
Definition codegen.cpp:689
void generate_func_call_stmt(AST::FuncCallStmt &fcs)
Method for generating LLVM IR code for function calling.
Definition codegen.cpp:197
void generate_continue_stmt(AST::ContinueStmt &cs)
Method for generating LLVM IR code for continue statement.
Definition codegen.cpp:376
void generate_use_module_stmt(AST::UseModuleStmt &ums)
Method for generating LLVM IR code for import the module.
Definition codegen.cpp:390
void generate_break_stmt(AST::BreakStmt &bs)
Method for generating LLVM IR code for break statement.
Definition codegen.cpp:372
std::vector< PathPart > get_resolved_name(std::string mangled_name)
Method for getting resolved name by mangled name.
Definition codegen.cpp:862
void generate_var_decl_stmt(AST::VarDeclStmt &vds)
Method for generating LLVM IR code for variable definition.
Definition codegen.cpp:69
void generate_if_else_stmt(AST::IfElseStmt &ies)
Method for generating LLVM IR code for control flow operators.
Definition codegen.cpp:257
std::string file_name
Definition codegen.hpp:26
void generate_return_stmt(AST::ReturnStmt &rs)
Method for generating LLVM IR code for 'return'.
Definition codegen.cpp:244
std::string libs_path
Definition codegen.hpp:25
std::stack< std::map< std::string, llvm::Value * > > variables
Definition codegen.hpp:32
llvm::Value * generate_literal_expr(AST::Literal &lit)
Method for generating LLVM IR code for literals.
Definition codegen.cpp:521
void generate_for_cycle_stmt(AST::ForCycleStmt &fcs)
Method for generating LLVM IR code for for cycle.
Definition codegen.cpp:338
std::vector< AST::StmtPtr > & stmts
Definition codegen.hpp:27
std::map< std::string, std::vector< llvm::Function * > > functions
Definition codegen.hpp:33
llvm::Value * generate_obj_chain_expr(AST::ChainObjects &co)
Method for generating LLVM IR code for chain of objects expression.
Definition codegen.cpp:736
std::unique_ptr< llvm::Module > module
Definition codegen.hpp:31
std::stack< std::pair< llvm::BasicBlock *, llvm::BasicBlock * > > loop_blocks
Definition codegen.hpp:35
llvm::Value * generate_binary_expr(AST::BinaryExpr &be)
Method for generating LLVM IR code for binary expressions.
Definition codegen.cpp:549
llvm::Value * generate_expr(AST::Expr &expr)
Method for generating LLVM IR code for expressions.
Definition codegen.cpp:497
void generate_stmt(AST::Stmt &stmt)
Method for generating LLVM IR code for passing statement.
Definition codegen.cpp:21
llvm::Value * generate_unary_expr(AST::UnaryExpr &ue)
Method for generating LLVM IR code for unary expressions.
Definition codegen.cpp:629
llvm::Value * implicitly_cast(llvm::Value *val, llvm::Type *expected_type)
Method for implicitly cast value to expected type.
Definition codegen.cpp:813
std::stack< llvm::Type * > functions_ret_types
Definition codegen.hpp:34
llvm::Type * type_to_llvm(AST::Type type)
Method for converting AST::Type to llvm::Type.
Definition codegen.cpp:753
void generate_func_decl_stmt(AST::FuncDeclStmt &fds)
Method for generating LLVM IR code for function definition.
Definition codegen.cpp:107
std::stack< PathPart > current_path
Definition codegen.hpp:51
llvm::IRBuilder builder
Definition codegen.hpp:30
void generate()
Method for generating LLVM IR code.
Definition codegen.cpp:15
Lexer class.
Definition lexer.hpp:15
std::vector< Token > tokenize()
Method for tokenizing source code.
Definition lexer.cpp:10
Parser class.
Definition parser.hpp:14
std::vector< AST::StmtPtr > parse()
Method for parsing tokens into AST tree.
Definition parser.cpp:10
void analyze()
Method for analyze all statements.
Definition semantic.cpp:15
std::map< std::string, ModuleInfo * > get_modules() const
Method for getting modules from semantic.
Definition semantic.hpp:120
std::map< std::string, std::vector< std::shared_ptr< FunctionInfo > > > get_functions() const
Method for getting functions from semantic.
Definition semantic.hpp:129
Header file for defining compiler code generator.
void throw_exception(SubsystemType type, std::string msg, uint32_t line, std::string file_name, bool is_debug)
Function for throwing exception.
Definition exception.cpp:30
Header file for defining thrown exceptions by the compiler.
@ SUB_CODEGEN
Definition exception.hpp:18
@ SUB_SEMANTIC
Definition exception.hpp:17
Header file for defining the lexer.
std::unique_ptr< Stmt > StmtPtr
Definition ast.hpp:125
@ TYPE_STRING_LIT
Definition ast.hpp:28
@ TYPE_INT
Definition ast.hpp:23
@ TYPE_CHAR
Definition ast.hpp:21
@ TYPE_FLOAT
Definition ast.hpp:25
@ TYPE_BOOL
Definition ast.hpp:20
@ TYPE_LONG
Definition ast.hpp:24
@ TYPE_DOUBLE
Definition ast.hpp:26
@ TYPE_TRAIT
Definition ast.hpp:29
@ TYPE_CLASS
Definition ast.hpp:30
@ TYPE_NOTH
Definition ast.hpp:27
@ TYPE_SHORT
Definition ast.hpp:22
Header file for defining parser.
Header file for defining semantic analyzer.
Structure for describing the type.
Definition ast.hpp:37
bool is_ptr
Definition ast.hpp:41
bool is_const
Definition ast.hpp:40
TypeValue type
Definition ast.hpp:38
std::variant< bool, char8_t, int16_t, int32_t, int64_t, float_t, double_t, std::string > value
Definition ast.hpp:72
Structure of part of path to object.
Definition codegen.hpp:40
enum CodeGenerator::PathPart::Object object
TokenType type
Definition token.hpp:93
@ TOK_OP_DIV
Definition token.hpp:60
@ TOK_OP_EQ_EQ
Definition token.hpp:65
@ TOK_OP_LS
Definition token.hpp:69
@ TOK_OP_GT_EQ
Definition token.hpp:68
@ TOK_OP_NOT_EQ_EQ
Definition token.hpp:66
@ TOK_OP_L_OR
Definition token.hpp:73
@ TOK_OP_PLUS
Definition token.hpp:52
@ TOK_OP_L_NOT
Definition token.hpp:71
@ TOK_OP_L_AND
Definition token.hpp:72
@ TOK_OP_MODULO
Definition token.hpp:62
@ TOK_OP_MULT
Definition token.hpp:58
@ TOK_OP_REF
Definition token.hpp:74
@ TOK_OP_GT
Definition token.hpp:67
@ TOK_OP_MINUS
Definition token.hpp:55
@ TOK_OP_LS_EQ
Definition token.hpp:70