17#include <llvm/ADT/STLExtras.h>
18#include <llvm/ADT/StringMap.h>
19#include <llvm/ADT/StringMapEntry.h>
20#include <llvm/ADT/StringRef.h>
21#include <llvm/ADT/Twine.h>
22#include <llvm/ADT/iterator.h>
23#include <llvm/BinaryFormat/Dwarf.h>
24#include <llvm/IR/Argument.h>
25#include <llvm/IR/BasicBlock.h>
26#include <llvm/IR/CallingConv.h>
27#include <llvm/IR/Constant.h>
28#include <llvm/IR/Constants.h>
29#include <llvm/IR/DIBuilder.h>
30#include <llvm/IR/DerivedTypes.h>
31#include <llvm/IR/Function.h>
32#include <llvm/IR/GlobalValue.h>
33#include <llvm/IR/GlobalVariable.h>
34#include <llvm/IR/Instruction.h>
35#include <llvm/IR/Instructions.h>
36#include <llvm/IR/IntrinsicInst.h>
37#include <llvm/IR/LegacyPassManager.h>
38#include <llvm/IR/Type.h>
39#include <llvm/IR/Value.h>
40#include <llvm/IR/Verifier.h>
41#include <llvm/Support/Casting.h>
42#include <llvm/Support/CodeGen.h>
43#include <llvm/Support/ErrorHandling.h>
44#include <llvm/Support/Host.h>
45#include <llvm/Support/TargetSelect.h>
46#include <llvm/Support/raw_ostream.h>
47#include <llvm/Target/TargetOptions.h>
49#if __has_include(<llvm/MC/TargetRegistry.h>)
50#include <llvm/MC/TargetRegistry.h>
52#include <llvm/Support/TargetRegistry.h>
62static auto make_cdtor_fn(llvm::IRBuilder<>& builder, llvm::Module& module,
bool is_ctor) -> llvm::Function* {
64 static auto* global_cdtor_fn_ty = llvm::FunctionType::get(builder.getVoidTy(),
false);
66 static auto* global_cdtor_entry_ty =
67 llvm::StructType::get(builder.getInt32Ty(), global_cdtor_fn_ty->getPointerTo(), builder.getInt8PtrTy());
69 static auto* global_cdtor_array_ty = llvm::ArrayType::get(global_cdtor_entry_ty, 1);
71 auto* global_cdtor_fn = llvm::Function::Create(global_cdtor_fn_ty, llvm::Function::ExternalLinkage,
72 (is_ctor ?
"_Ym.__ctor" :
"_Ym.__dtor"), &module);
73 auto* bb = llvm::BasicBlock::Create(module.getContext(),
"entry", global_cdtor_fn);
74 builder.SetInsertPoint(bb);
75 builder.CreateRetVoid();
77 (void)
new llvm::GlobalVariable(
78 module, global_cdtor_array_ty,
true, llvm::GlobalVariable::AppendingLinkage,
79 llvm::ConstantArray::get(
80 global_cdtor_array_ty,
81 llvm::ConstantStruct::get(global_cdtor_entry_ty, builder.getInt32(std::numeric_limits<uint16_t>::max()),
82 global_cdtor_fn, llvm::ConstantPointerNull::get(builder.getInt8PtrTy()))),
83 (is_ctor ?
"llvm.global_ctors" :
"llvm.global_dtors"));
85 return global_cdtor_fn;
89 : m_sources(move(source_files)), m_walker(std::make_unique<semantic::TypeWalker>(*this)) {
90 m_context = std::make_unique<llvm::LLVMContext>();
91 m_module = std::make_unique<llvm::Module>(
"yume", *m_context);
92 m_debug = std::make_unique<llvm::DIBuilder>(*m_module);
93 m_module->addModuleFlag(llvm::Module::Warning,
"Debug Info Version", llvm::DEBUG_METADATA_VERSION);
95 m_builder = std::make_unique<llvm::IRBuilder<>>(*m_context);
97 llvm::InitializeNativeTarget();
98 llvm::InitializeNativeTargetAsmParser();
99 llvm::InitializeNativeTargetAsmPrinter();
101 const string triple = target_triple.value_or(llvm::sys::getDefaultTargetTriple());
102 const auto* target = llvm::TargetRegistry::lookupTarget(triple, error);
104 if (target ==
nullptr) {
106 throw std::exception();
108 const char* cpu =
"generic";
109 const char* feat =
"";
111 for (
const auto& src_file : m_sources) {
112 auto* debug_file = m_debug->createFile(src_file.path.filename().native(), src_file.path.parent_path().native());
113 auto* compile_unit = m_debug->createCompileUnit(llvm::dwarf::DW_LANG_C, debug_file,
"yumec",
false,
"", 0);
114 m_source_mapping.try_emplace(src_file.program.get(), compile_unit);
117 const llvm::TargetOptions opt;
119 unique_ptr<llvm::TargetMachine>(target->createTargetMachine(triple, cpu, feat, opt, llvm::Reloc::Model::PIC_));
121 m_module->setDataLayout(m_target_machine->createDataLayout());
122 m_module->setTargetTriple(triple);
126 m_global_ctor_fn =
make_cdtor_fn(*m_builder, *m_module,
true);
127 m_global_dtor_fn =
make_cdtor_fn(*m_builder, *m_module,
false);
130void Compiler::declare_default_ctor(
Struct& st) {
131 if (st.
ast().is_interface)
134 const bool no_ctors_declared =
137 if (!no_ctors_declared)
140 vector<ast::TypeName> ctor_args;
141 vector<ast::AnyStmt> ctor_body;
142 for (
auto& field : st.
ast().fields) {
143 auto tok = field.token_range();
144 ast::AnyType proxy_type = make_unique<ast::ProxyType>(tok, field.name);
145 ctor_args.emplace_back(field.token_range(), move(proxy_type), field.name);
147 auto implicit_field = make_unique<ast::FieldAccessExpr>(tok, std::nullopt, field.name);
148 auto arg_var = make_unique<ast::VarExpr>(tok, field.name);
149 ctor_body.emplace_back(make_unique<ast::AssignExpr>(tok, move(implicit_field), move(arg_var)));
152 auto& new_ct = st.
body().body.emplace_back(
153 std::make_unique<ast::CtorDecl>(span<Token>{}, move(ctor_args), ast::Compound({}, move(ctor_body))));
166 YUME_ASSERT(st.
ast().is_interface,
"Cannot create vtable for non-interface struct");
168 for (
auto& i : st.
body()) {
169 if (
auto* fn_ast = dyn_cast<ast::FnDecl>(i.raw_ptr())) {
170 if (!fn_ast->abstract())
172 auto* fn = fn_ast->sema_decl;
173 YUME_ASSERT(fn !=
nullptr,
"Semantic Fn not set in FnDecl AST node");
181 m_scope.push_scope();
183 for (
const auto& source : m_sources)
184 for (
auto& i : source.program->body)
188 for (
auto& cn : m_consts)
192 for (
auto& st : m_structs)
196 for (
auto& cn : m_consts) {
197 auto* const_ty =
llvm_type(cn.ast().ensure_ty());
198 cn.llvm =
new llvm::GlobalVariable(*m_module, const_ty,
false, llvm::GlobalVariable::PrivateLinkage,
nullptr,
199 ".const." + cn.name());
203 for (
auto& ct : m_ctors)
208 for (
auto& st : m_structs)
209 declare_default_ctor(st);
212 for (
auto& fn : m_fns)
216 for (
auto& st : m_structs)
217 if (st.
ast().is_interface)
221 m_walker->in_depth =
true;
223 for (
auto& cn : m_consts) {
229 vector<Fn*> extern_fns = {};
230 for (
auto& fn : m_fns) {
231 if (fn.
name() ==
"main")
235 extern_fns.push_back(&fn);
238 if (extern_fns.empty()) {
239 throw std::logic_error(
"Program is missing any declarations with external linkage. Perhaps you meant to declare a "
242 for (
auto* ext : extern_fns)
245 while (!m_decl_queue.empty()) {
246 auto next = m_decl_queue.front();
248 next.visit([](std::monostate ) { },
251 [&](
Struct* ) {
throw std::logic_error(
"Cannot define a struct"); });
254 YUME_ASSERT(m_scope.size() == 1,
"End of compilation should end with only the global scope remaining");
256 m_builder->SetInsertPoint(&m_global_dtor_fn->getEntryBlock(), m_global_dtor_fn->getEntryBlock().begin());
257 destruct_last_scope();
262 if (llvm::verifyModule(*m_module, &errs())) {
263 m_module->print(errs(),
nullptr,
false,
true);
264 throw std::runtime_error(
"Module verification failed");
268void Compiler::walk_types(
DeclLike decl_like) {
269 decl_like.
visit([](std::monostate ) { },
271 m_walker->current_decl = decl;
272 m_walker->body_statement(decl->ast());
273 m_walker->current_decl = {};
280 auto fields = vector<ast::TypeName*>();
281 fields.reserve(s_decl.fields.size());
282 for (
auto& f : s_decl.fields)
283 fields.push_back(&f);
285 auto iter = m_types.known.find(s_decl.name);
286 if (iter == m_types.known.end()) {
287 auto empl = m_types.known.try_emplace(s_decl.name,
288 std::make_unique<ty::Struct>(s_decl.name, move(fields), &st, &st.
get_subs()));
289 YUME_ASSERT((isa<ty::Struct>(*empl.first->second)),
"Struct type must be a struct");
290 st.
self_ty = &*empl.first->second;
294 YUME_ASSERT((isa<ty::Struct>(*iter->second)),
"Struct type must be a struct");
295 auto& existing = cast<ty::Struct>(*iter->second);
297 if (!st.
get_subs().fully_substituted())
300 existing.m_fields = move(fields);
307 if (
auto* fn_decl = dyn_cast<ast::FnDecl>(&stmt)) {
308 vector<GenericKey> generics;
309 vector<unique_ptr<ty::Generic>> primary_generics;
310 for (
auto& i : fn_decl->type_args) {
311 if (i.is_type_parameter()) {
312 primary_generics.emplace_back(std::make_unique<ty::Generic>(i.name));
313 generics.emplace_back(i.name);
315 YUME_ASSERT(i.type.has_value(),
"Non-type generic parameter must have associated value type");
316 generics.emplace_back(i.name, i.type.raw_ptr());
319 auto& fn = m_fns.emplace_back(fn_decl, member, parent, parent_subs, move(generics), move(primary_generics));
320 fn_decl->sema_decl = &fn;
324 if (
auto* s_decl = dyn_cast<ast::StructDecl>(&stmt)) {
326 vector<GenericKey> generics;
327 vector<unique_ptr<ty::Generic>> primary_generics;
328 for (
auto& i : s_decl->type_args) {
329 if (i.is_type_parameter()) {
330 primary_generics.emplace_back(std::make_unique<ty::Generic>(i.name));
331 generics.emplace_back(i.name);
333 YUME_ASSERT(i.type.has_value(),
"Non-type generic parameter must have associated value type");
334 generics.emplace_back(i.name, i.type.raw_ptr());
338 m_structs.emplace_back(*s_decl, member, std::nullopt, parent_subs, move(generics), move(primary_generics));
339 if (!create_struct(st)) {
340 m_structs.pop_back();
345 YUME_ASSERT(m_slice_struct ==
nullptr,
"Can't have multiple slice types");
346 m_slice_struct = &st;
349 for (
auto& f : s_decl->body) {
356 if (
auto* ctor_decl = dyn_cast<ast::CtorDecl>(&stmt)) {
357 auto& ctor = m_ctors.emplace_back(ctor_decl, member, parent, parent_subs);
361 if (
auto* const_decl = dyn_cast<ast::ConstDecl>(&stmt)) {
362 auto& cn = m_consts.emplace_back(*const_decl, member, parent);
367 throw std::runtime_error(
"Invalid top-level statement: "s + stmt.kind_name());
371 llvm::StructType* closure_ty =
nullptr;
372 llvm::Type* memo =
nullptr;
373 auto* erased_closure_ty = compiler.builder()->getInt8PtrTy();
375 if (!type.is_fn_ptr()) {
376 auto closured = vector<llvm::Type*>{};
377 for (
const auto& i : type.closure())
378 closured.push_back(compiler.llvm_type(i));
379 if (closured.empty())
380 closured.push_back(compiler.builder()->getInt8Ty());
385 closure_ty = llvm::StructType::create(closured,
"closure");
388 auto args = vector<llvm::Type*>{};
389 if (closure_ty !=
nullptr)
390 args.push_back(erased_closure_ty);
391 for (
const auto& i : type.args())
392 args.push_back(compiler.llvm_type(i));
394 auto* return_type = compiler.builder()->getVoidTy();
395 if (
auto ret = type.ret(); ret.has_value())
396 return_type = compiler.llvm_type(*ret);
398 auto* fn_ty = llvm::FunctionType::get(return_type, args, type.is_c_varargs());
400 if (type.is_fn_ptr())
401 memo = fn_ty->getPointerTo();
403 memo = llvm::StructType::get(fn_ty->getPointerTo(), erased_closure_ty);
405 type.fn_memo(compiler, fn_ty);
406 type.closure_memo(compiler, closure_ty);
407 type.memo(compiler, memo);
412 llvm::Type* memo =
nullptr;
416 if (type.is_interface()) {
417 memo = llvm::StructType::get(compiler.builder()->getInt8PtrTy(), compiler.builder()->getInt8PtrTy());
419 auto fields = vector<llvm::Type*>{};
420 for (
const auto* i : type.fields())
421 fields.push_back(compiler.llvm_type(i->type->ensure_ty()));
423 memo = llvm::StructType::create(*compiler.context(), fields,
"_"s + type.name());
425 type.memo(compiler, memo);
430 llvm::Type* base =
nullptr;
431 bool interface_self =
false;
433 if (
const auto* int_type = type.base_dyn_cast<
ty::Int>()) {
434 base = llvm::Type::getIntNTy(*m_context, int_type->size());
435 }
else if (
const auto* ptr_type = type.base_dyn_cast<
ty::Ptr>()) {
437 base = llvm::PointerType::getUnqual(llvm_type(ptr_type->pointee()));
438 }
else if (
const auto* struct_type = type.base_dyn_cast<
ty::Struct>()) {
439 llvm::Type* memo = struct_type->memo();
444 interface_self = struct_type->is_interface();
445 }
else if (
const auto* function_type = type.base_dyn_cast<
ty::Function>()) {
446 llvm::Type* memo = function_type->memo();
451 }
else if (type.base_isa<
ty::Nil>()) {
452 base = llvm::Type::getVoidTy(*m_context);
453 }
else if (
const auto* opaque_self_type = type.base_dyn_cast<
ty::OpaqueSelf>()) {
455 return m_builder->getInt8PtrTy();
456 base = llvm_type({opaque_self_type->indirect()});
457 interface_self = llvm::isa<ty::Struct>(opaque_self_type->indirect()) &&
458 llvm::cast<ty::Struct>(opaque_self_type->indirect())->is_interface();
459 }
else if (type.base_isa<
ty::Meta>()) {
460 base = m_builder->getInt8Ty();
462 throw std::logic_error(
"Unknown type base " + type.name());
465 if (type.is_mut() && !interface_self)
466 return base->getPointerTo();
467 if (type.is_opaque_self() && !interface_self)
468 return base->getPointerTo();
474 const auto deref_type = type.
mut_base();
475 if (deref_type.has_value())
476 return destruct(m_builder->CreateLoad(
llvm_type(*deref_type), val,
"dt.deref"), *deref_type);
479 auto base_type = type.
base_cast<
ty::Struct>()->fields().at(0)->ensure_ty().ensure_ptr_base();
480 auto* base_llvm_type =
llvm_type(base_type);
481 auto* ptr = m_builder->CreateExtractValue(val, 0,
"sl.ptr.free");
482 if (!base_type.is_trivially_destructible()) {
483 auto* size = m_builder->CreateExtractValue(val, 1,
"sl.size.free");
485 entrypoint_dtor_builder().CreateAlloca(m_builder->getIntNTy(
ptr_bitsize()), 0,
nullptr,
"sl.dtor.loop.i");
486 m_builder->CreateStore(m_builder->getIntN(
ptr_bitsize(), 0), loop_iter);
487 auto* loop_entry = m_builder->GetInsertBlock();
488 auto* loop_cont = loop_entry->splitBasicBlock(m_builder->GetInsertPoint(),
"sl.dtor.cont");
489 auto* loop_block = llvm::BasicBlock::Create(*m_context,
"sl.dtor.loop", loop_cont->getParent(), loop_cont);
490 auto saved_insert_point = llvm::IRBuilderBase::InsertPoint{loop_cont, loop_cont->begin()};
492 loop_entry->getTerminator()->eraseFromParent();
493 m_builder->SetInsertPoint(loop_entry);
494 m_builder->CreateBr(loop_block);
495 m_builder->SetInsertPoint(loop_block);
496 auto* iter_i = m_builder->CreateLoad(m_builder->getIntNTy(
ptr_bitsize()), loop_iter,
"sl.dtor.i.iter");
497 Val iter_val = m_builder->CreateLoad(
498 base_llvm_type, m_builder->CreateInBoundsGEP(base_llvm_type, ptr, iter_i,
"sl.dtor.i.gep"),
"sl.dtor.i.load");
500 auto* iter_inc = m_builder->CreateAdd(iter_i, m_builder->getIntN(
ptr_bitsize(), 1),
"sl.dtor.i.inc");
501 m_builder->CreateStore(iter_inc, loop_iter);
502 m_builder->CreateCondBr(m_builder->CreateICmpEQ(iter_inc, size), loop_cont, loop_block);
504 m_builder->restoreIP(saved_insert_point);
510 for (
const auto& i : llvm::enumerate(struct_type->fields())) {
511 ty::Type type = i.value()->type->ensure_ty();
513 destruct(m_builder->CreateExtractValue(val, i.index(),
"dt.field"), type);
520 throw std::runtime_error(
"Cannot default-initialize a reference");
521 if (
const auto* int_type = type.base_dyn_cast<
ty::Int>())
522 return m_builder->getIntN(int_type->size(), 0);
523 if (
const auto* ptr_type = type.base_dyn_cast<
ty::Ptr>()) {
524 switch (ptr_type->qualifier()) {
525 default: llvm_unreachable(
"Ptr type cannot hold this qualifier");
527 llvm::ConstantPointerNull::get(llvm::PointerType::getUnqual(llvm_type(ptr_type->pointee())));
531 if (
const auto* struct_type = type.base_dyn_cast<
ty::Struct>()) {
532 auto* llvm_ty = cast<llvm::StructType>(llvm_type(type));
533 Val val = llvm::UndefValue::get(llvm_ty);
535 for (
const auto& i : llvm::enumerate(struct_type->fields()))
536 val = m_builder->CreateInsertValue(val, default_init(i.value()->type->ensure_ty()), i.index());
541 throw std::runtime_error(
"Cannot default-initialize "s + type.name());
545 if (fn.
llvm !=
nullptr)
550 YUME_ASSERT(fn.
fn_ty !=
nullptr,
"Function declaration "s + fn.
name() +
" has no function type set");
551 (void)llvm_type(fn.
fn_ty);
554 string name = fn.
name();
558 auto linkage = fn.
extern_linkage() ? llvm::Function::ExternalLinkage
559 : fn.
local() ? llvm::Function::PrivateLinkage
560 : llvm::Function::InternalLinkage;
561 auto* llvm_fn = llvm::Function::Create(fn_t, linkage, name, m_module.get());
563 llvm_fn->setCallingConv(llvm::CallingConv::X86_INTR);
568 arg_names.insert(arg_names.begin(),
"<closure>");
569 for (
auto [llvm_arg, arg_name] : llvm::zip(llvm_fn->args(), arg_names))
570 llvm_arg.setName(
"arg."s + arg_name);
575 auto* fn_unit = m_source_mapping.at(fn.
member);
576 auto* fn_file = m_debug->createFile(fn_unit->getFilename(), fn_unit->getDirectory());
577 llvm::DIScope* f_context = fn_file;
578 unsigned line_no = fn.
ast().location().begin_line;
579 unsigned scope_line = line_no;
580 auto types = m_debug->getOrCreateTypeArray({});
581 llvm::DISubprogram* subprogram =
582 m_debug->createFunction(f_context, fn.
name(), name, fn_file, line_no, m_debug->createSubroutineType(types),
583 scope_line, llvm::DINode::FlagPrototyped, llvm::DISubprogram::SPFlagDefinition);
584 fn.
llvm->setSubprogram(subprogram);
586 m_decl_queue.emplace(&fn);
587 m_walker->current_decl = &fn;
588 m_walker->body_statement(fn.
ast());
594 auto guard = m_scope.push_scope_guarded();
598 if (m_builder->GetInsertBlock()->getTerminator() ==
nullptr)
599 destruct_last_scope();
604 if (v.
owning && !ty.is_trivially_destructible()) {
606 "Value tracked in scope must be indirect");
614void Compiler::destruct_last_scope() {
615 for (
const auto& i : m_scope.last_scope())
619void Compiler::destruct_all_scopes() {
620 for (
const auto& scope : llvm::reverse(llvm::drop_begin(m_scope.all_scopes())))
621 for (
const auto& i : scope)
625void Compiler::expose_parameter_as_local(ty::Type type,
const string& name,
const ast::AST& ast, Val val) {
627 m_scope.add(name, {.value = val, .ast = ast, .owning =
false});
630 Val alloc = m_builder->CreateAlloca(
llvm_type(type),
nullptr,
"lv."s + name);
631 m_builder->CreateStore(val, alloc);
632 m_scope.add(name, {.value = alloc, .ast = ast, .owning =
false});
635void Compiler::setup_fn_base(Fn& fn) {
637 m_scope.push_scope();
638 m_scope_ctor.reset();
639 auto* bb = llvm::BasicBlock::Create(*m_context,
"entry", fn.llvm);
640 m_builder->SetInsertPoint(bb);
641 m_builder->SetCurrentDebugLocation({});
647 auto arg_offset = fn.fn_ty->closure_memo() ==
nullptr ? 0 : 1;
648 auto llvm_fn_args = llvm::drop_begin(fn.llvm->args(), arg_offset);
650 for (
auto [arg, ast_arg] : llvm::zip(llvm_fn_args, fn.args()))
651 expose_parameter_as_local(ast_arg.type, ast_arg.name, ast_arg.ast, &arg);
655 if (cn.
llvm->hasInitializer())
658 auto* saved_insert_block = m_builder->GetInsertBlock();
659 m_builder->SetInsertPoint(&m_global_ctor_fn->getEntryBlock(), m_global_ctor_fn->getEntryBlock().begin());
662 if ((init.scope !=
nullptr) && init.scope->owning)
663 init.scope->owning =
false;
665 if (isa<llvm::Constant>(init.llvm)) {
666 cn.
llvm->setConstant(
true);
667 auto* const_val = cast<llvm::Constant>(init.llvm);
668 cn.
llvm->setInitializer(const_val);
670 cn.
llvm->setInitializer(llvm::ConstantAggregateZero::get(cn.
llvm->getValueType()));
671 m_builder->CreateStore(init.llvm, cn.
llvm);
674 auto cn_type = cn.
ast().type->ensure_ty();
675 if (!cn_type.is_trivially_destructible()) {
676 m_builder->SetInsertPoint(&m_global_dtor_fn->getEntryBlock(), m_global_dtor_fn->getEntryBlock().begin());
680 m_builder->SetInsertPoint(saved_insert_block);
689 const auto*
interface = fn.self_ty->base_cast<ty::
Struct>()->decl();
690 YUME_ASSERT(interface != nullptr, "Struct not found from struct type?");
691 YUME_ASSERT(interface->ast().is_interface, "Abstract function must be within interface");
693 auto vtable_match = std::ranges::find(interface->vtable_members,
vtable_entry_for(fn));
694 YUME_ASSERT(vtable_match != interface->vtable_members.
end(), "abstract method not found in vtable?");
695 auto vtable_entry_index = std::distance(interface->vtable_members.begin(), vtable_match);
697 auto vtable_deref_args = vector<llvm::Type*>();
698 auto* vtable_deref_ret = m_builder->getVoidTy();
699 for (const auto& arg : vtable_match->args)
700 vtable_deref_args.emplace_back(llvm_type(arg, true));
701 if (auto ret = vtable_match->ret; ret.has_value())
702 vtable_deref_ret =
llvm_type(*ret, true);
704 auto call_args = vector<llvm::Value*>();
705 llvm::FunctionType* call_fn_type = nullptr;
708 if (fn.arg_count() == 1 && fn.arg_names().at(0).empty()) {
709 call_fn_type = llvm::FunctionType::get(vtable_deref_ret, {},
false);
711 call_args.push_back(m_builder->CreateExtractValue(fn.
llvm->args().begin(), 1,
"abs.self"));
712 for (
auto& extra_arg : llvm::drop_begin(fn.
llvm->args()))
713 call_args.emplace_back(&extra_arg);
715 call_fn_type = llvm::FunctionType::get(vtable_deref_ret, vtable_deref_args,
false);
720 auto* vtable_struct_ptr = m_builder->CreateExtractValue(fn.
llvm->args().begin(), 0,
"abs.vt.struct");
721 auto* vtable_ptr_array =
722 m_builder->CreateBitCast(vtable_struct_ptr, m_builder->getInt8PtrTy()->getPointerTo(),
"abs.vt.array");
723 auto* vtable_entry = m_builder->CreateLoad(
724 m_builder->getInt8PtrTy(),
725 m_builder->CreateConstGEP1_32(m_builder->getInt8PtrTy(), vtable_ptr_array, vtable_entry_index,
"abs.vt.entry"),
726 "abs.vt.entry.load");
727 Val call_result = m_builder->CreateCall(
728 call_fn_type, m_builder->CreateBitCast(vtable_entry, call_fn_type->getPointerTo(),
"abs.fn"), call_args);
730 if (call_result.
llvm->getType()->isVoidTy())
731 m_builder->CreateRetVoid();
733 m_builder->CreateRet(call_result);
734 }
else if (isa<ast::FnDecl>(&fn.
ast())) {
735 if (
auto* body = get_if<ast::Compound>(&fn.
fn_body()); body !=
nullptr)
738 if (m_builder->GetInsertBlock()->getTerminator() ==
nullptr) {
739 destruct_all_scopes();
740 m_builder->CreateRetVoid();
743 YUME_ASSERT(fn.
self_ty.has_value(),
"Cannot define constructor when the type being constructed is unknown");
745 const Val base_value = llvm::UndefValue::get(ctor_type);
746 auto* base_alloc = m_builder->CreateAlloca(ctor_type,
nullptr,
"ctor.base");
747 m_builder->CreateStore(base_value, base_alloc);
750 m_scope_ctor.emplace(
InScope{.
value = base_alloc, .ast = fn.
ast(), .owning =
false});
754 destruct_all_scopes();
755 auto* finalized_value = m_builder->CreateLoad(ctor_type, base_alloc);
756 m_builder->CreateRet(finalized_value);
760 YUME_ASSERT(m_scope.size() == 1,
"End of function should end with only the global scope remaining");
765 auto* test_bb = llvm::BasicBlock::Create(*m_context,
"while.test", m_current_fn->
llvm);
766 auto* head_bb = llvm::BasicBlock::Create(*m_context,
"while.head", m_current_fn->
llvm);
767 auto* merge_bb = llvm::BasicBlock::Create(*m_context,
"while.merge", m_current_fn->
llvm);
768 m_builder->CreateBr(test_bb);
769 m_builder->SetInsertPoint(test_bb);
771 m_builder->CreateCondBr(cond_value, head_bb, merge_bb);
772 m_builder->SetInsertPoint(head_bb);
774 m_builder->CreateBr(test_bb);
775 m_builder->SetInsertPoint(merge_bb);
779 auto* merge_bb = llvm::BasicBlock::Create(*m_context,
"if.cont", m_current_fn->
llvm);
780 auto* next_test_bb = llvm::BasicBlock::Create(*m_context,
"if.test", m_current_fn->
llvm, merge_bb);
781 auto* last_branch = m_builder->CreateBr(next_test_bb);
782 bool all_terminated =
true;
785 for (
auto& clause : clauses) {
786 m_builder->SetInsertPoint(next_test_bb);
787 auto* body_bb = llvm::BasicBlock::Create(*m_context,
"if.then", m_current_fn->
llvm, merge_bb);
788 next_test_bb = llvm::BasicBlock::Create(*m_context,
"if.test", m_current_fn->
llvm, merge_bb);
790 last_branch = m_builder->CreateCondBr(condition, body_bb, next_test_bb);
791 m_builder->SetInsertPoint(body_bb);
792 statement(clause.body);
794 if (m_builder->GetInsertBlock()->getTerminator() ==
nullptr) {
795 all_terminated =
false;
796 m_builder->CreateBr(merge_bb);
801 if (else_clause.has_value()) {
802 next_test_bb->setName(
"if.else");
803 m_builder->SetInsertPoint(next_test_bb);
804 statement(*else_clause);
805 if (m_builder->GetInsertBlock()->getTerminator() ==
nullptr) {
806 all_terminated =
false;
807 m_builder->CreateBr(merge_bb);
812 all_terminated =
false;
813 last_branch->setSuccessor(1, merge_bb);
814 next_test_bb->eraseFromParent();
818 merge_bb->eraseFromParent();
820 m_builder->SetInsertPoint(merge_bb);
824 InScope* reset_owning =
nullptr;
829 for (
auto& i : m_scope.last_scope()) {
842 if (val.scope !=
nullptr && val.scope->owning)
843 val.scope->owning =
false;
845 destruct_all_scopes();
847 if (reset_owning !=
nullptr)
848 reset_owning->
owning =
true;
850 if (val.llvm->getType()->isVoidTy() || m_current_fn->
llvm->getReturnType()->isVoidTy())
851 m_builder->CreateRetVoid();
853 m_builder->CreateRet(val);
858 destruct_all_scopes();
859 m_builder->CreateRetVoid();
862auto Compiler::entrypoint_builder() -> llvm::IRBuilder<> {
863 if (m_current_fn ==
nullptr)
864 return {&m_global_ctor_fn->getEntryBlock(), m_global_ctor_fn->getEntryBlock().begin()};
865 return {&m_current_fn->llvm->getEntryBlock(), m_current_fn->llvm->getEntryBlock().begin()};
868auto Compiler::entrypoint_dtor_builder() -> llvm::IRBuilder<> {
869 if (m_current_fn ==
nullptr)
870 return {&m_global_dtor_fn->getEntryBlock(), m_global_dtor_fn->getEntryBlock().begin()};
871 return {&m_current_fn->llvm->getEntryBlock(), m_current_fn->llvm->getEntryBlock().begin()};
879 if (stat.
init->ensure_ty().is_mut()) {
881 m_scope.add(stat.
name, {.value = expr_val, .ast = stat, .owning = false});
885 auto* alloc = entrypoint_builder().CreateAlloca(var_type,
nullptr,
"vdecl."s + stat.
name);
889 if (expr_val.scope !=
nullptr && expr_val.scope->owning)
890 expr_val.scope->owning =
false;
892 m_builder->CreateStore(expr_val, alloc);
893 m_scope.add(stat.
name, {.value = alloc, .ast = stat, .owning = true});
898 if (expr.ensure_ty().base() == m_types.int64().s_ty)
899 return m_builder->getInt64(val);
900 return m_builder->getInt32(val);
903template <>
auto Compiler::expression(
ast::CharExpr& expr) ->
Val {
return m_builder->getInt8(expr.val); }
905template <>
auto Compiler::expression(
ast::BoolExpr& expr) ->
Val {
return m_builder->getInt1(expr.val); }
907void Compiler::make_temporary_in_scope(
Val& val,
const ast::AST& ast,
const string& name) {
908 const string tmp_name = name +
" " + ast.
location().to_string();
910 llvm::MDNode::get(*m_context, llvm::MDString::get(*m_context, std::to_string(m_scope.size()) +
": " + tmp_name));
914 auto* val_ty =
llvm_type(ast_ty.without_mut());
916 if (m_scope.size() > 1) {
917 auto* alloc = entrypoint_builder().CreateAlloca(val_ty,
nullptr, name);
918 alloc->setMetadata(
"yume.tmp", md_node);
921 auto* global =
new llvm::GlobalVariable(*m_module, val_ty,
false, llvm::GlobalVariable::PrivateLinkage,
922 llvm::ConstantAggregateZero::get(val_ty), name);
923 global->setMetadata(
"yume.tmp", md_node);
927 auto [iter, ok] = m_scope.add(tmp_name, {.value = ptr.
llvm, .ast = ast, .owning =
true});
928 m_builder->CreateStore(ast_ty.is_mut() ? m_builder->CreateLoad(val_ty, val.
llvm) : val.
llvm, ptr.
llvm);
929 val.
scope = &iter->second;
936 vector<llvm::Constant*> chars(val.length());
937 for (
unsigned int i = 0; i < val.size(); i++)
938 chars[i] = m_builder->getInt8(val[i]);
940 auto* base_type = m_builder->getInt8Ty();
941 auto* global_string_type = llvm::ArrayType::get(base_type, chars.size());
942 auto* global_init = llvm::ConstantArray::get(global_string_type, chars);
943 auto* global =
new llvm::GlobalVariable(*m_module, global_string_type,
true, llvm::GlobalVariable::PrivateLinkage,
944 global_init,
".str");
946 auto* global_string_ptr = llvm::ConstantExpr::getBitCast(global, m_builder->getInt8PtrTy(0));
948 auto* slice_size = m_builder->getIntN(ptr_bitsize(), val.length());
949 auto* slice_type = cast<llvm::StructType>(llvm_type(expr.ensure_ty()));
951 const Val string_alloc = create_malloc(base_type, slice_size,
"str.ctor.malloc");
952 m_builder->CreateMemCpy(string_alloc, {}, global_string_ptr, {}, slice_size);
954 Val string_slice = llvm::UndefValue::get(slice_type);
955 string_slice = m_builder->CreateInsertValue(string_slice, string_alloc, 0);
956 string_slice = m_builder->CreateInsertValue(string_slice, slice_size, 1);
958 make_temporary_in_scope(string_slice, expr,
"tmps");
964 auto* in_scope = m_scope.find(expr.name);
965 YUME_ASSERT(in_scope !=
nullptr,
"Variable "s + expr.name +
" is not in scope");
966 auto* val = in_scope->value.
llvm;
968 if (!in_scope->ast.ensure_ty().is_mut())
969 return {m_builder->CreateLoad(llvm_type(in_scope->ast.ensure_ty()), val), in_scope};
971 return {val, in_scope};
975 for (
const auto& cn : m_consts)
976 if (cn.referred_to_by(expr))
977 return m_builder->CreateLoad(llvm_type(cn.ast().ensure_ty()), cn.llvm,
"cn." + expr.name);
979 throw std::runtime_error(
"Nonexistent constant called "s + expr.name);
983static auto constexpr const_hash(
const char* input) ->
unsigned {
984 return *input != 0 ?
static_cast<unsigned int>(*input) + 33 *
const_hash(input + 1) : 5381;
987auto Compiler::int_bin_primitive(
const string& primitive,
const vector<Val>& args) -> Val {
988 const auto& a = args.at(0);
989 const auto& b = args.at(1);
992 case const_hash(
"ib_icmp_sgt"): return m_builder->CreateICmpSGT(a, b);
993 case const_hash(
"ib_icmp_ugt"): return m_builder->CreateICmpUGT(a, b);
994 case const_hash(
"ib_icmp_slt"): return m_builder->CreateICmpSLT(a, b);
995 case const_hash(
"ib_icmp_ult"): return m_builder->CreateICmpULT(a, b);
996 case const_hash(
"ib_icmp_eq"): return m_builder->CreateICmpEQ(a, b);
997 case const_hash(
"ib_icmp_ne"): return m_builder->CreateICmpNE(a, b);
998 case const_hash(
"ib_add"): return m_builder->CreateAdd(a, b);
999 case const_hash(
"ib_sub"): return m_builder->CreateSub(a, b);
1000 case const_hash(
"ib_mul"): return m_builder->CreateMul(a, b);
1001 case const_hash(
"ib_and"): return m_builder->CreateAnd(a, b);
1002 case const_hash(
"ib_srem"): return m_builder->CreateSRem(a, b);
1003 case const_hash(
"ib_urem"): return m_builder->CreateURem(a, b);
1004 case const_hash(
"ib_sdiv"): return m_builder->CreateSDiv(a, b);
1005 case const_hash(
"ib_udiv"): return m_builder->CreateUDiv(a, b);
1006 case const_hash(
"ib_shl"): return m_builder->CreateShl(a, b);
1007 case const_hash(
"ib_lshr"): return m_builder->CreateLShr(a, b);
1008 case const_hash(
"ib_ashr"): return m_builder->CreateAShr(a, b);
1009 default:
throw std::runtime_error(
"Unknown binary integer primitive "s + primitive);
1013static inline auto vals_to_llvm(
const vector<Val>& in) -> vector<llvm::Value*> {
1014 auto out = vector<llvm::Value*>{};
1015 for (
const auto& i : in)
1016 out.push_back(i.llvm);
1021auto Compiler::primitive(Fn* fn,
const vector<Val>& args,
const vector<ty::Type>& types,
1022 vector<ast::AnyExpr*>& ast_args) -> optional<Val> {
1023 if (fn->extern_decl())
1024 return m_builder->CreateCall(declare(*fn),
vals_to_llvm(args));
1026 if (!fn->primitive())
1029 auto primitive = get<string>(fn->fn_body());
1031 if (primitive ==
"ptrto")
1033 if (primitive ==
"slice_malloc") {
1034 auto base_ty_type = types.at(0).ensure_ptr_base();
1035 auto* base_type = llvm_type(base_ty_type);
1036 auto slice_size = args.at(1);
1038 return create_malloc(base_type, slice_size,
"sl.ctor.malloc");
1040 if (primitive ==
"default_init") {
1041 auto base_type = types.at(0).ensure_mut_base();
1042 m_builder->CreateStore(default_init(base_type), args.at(0));
1046 if (primitive ==
"set_at") {
1047 auto* result_type = llvm_type(types[0].without_mut().ensure_ptr_base());
1048 llvm::Value* value = args.at(2);
1049 llvm::Value* base = m_builder->CreateGEP(result_type, args.at(0).llvm, args.at(1).llvm,
"p.set_at.gep");
1050 m_builder->CreateStore(value, base);
1051 return llvm::UndefValue::get(m_builder->getVoidTy());
1053 if (primitive ==
"get_at") {
1054 auto* result_type = llvm_type(types[0].without_mut().ensure_ptr_base());
1055 llvm::Value* base = args.at(0);
1056 base = m_builder->CreateGEP(result_type, base, args.at(1).llvm,
"p.get_at.gep");
1059 if (primitive ==
"ptr_cast")
1060 return m_builder->CreateBitCast(args[0], llvm_type(types.at(1).without_meta()),
"builtin.ptr_cast");
1061 if (primitive ==
"ptr_gep") {
1062 return m_builder->CreateGEP(llvm_type(types.at(0).ensure_ptr_base()), args.at(0), args.at(1).llvm,
1065 if (primitive ==
"cast") {
1067 auto* base = ast_args.at(0);
1069 return body_expression(**base);
1071 if (primitive.starts_with(
"ib_"))
1072 return int_bin_primitive(primitive, args);
1073 throw std::runtime_error(
"Unknown primitive "s + primitive);
1077 if (expr.name ==
"->")
1078 return direct_call_operator(expr);
1080 auto* selected = expr.selected_overload;
1081 llvm::Function* llvm_fn =
nullptr;
1083 vector<ast::AnyExpr*> ast_args{};
1084 vector<ty::Type> arg_types{};
1085 vector<Val> llvm_args{};
1087 for (
auto& i : expr.args) {
1088 auto arg = body_expression(*i);
1089 ast_args.push_back(&i);
1090 llvm_args.emplace_back(arg.llvm);
1091 arg_types.push_back(i->ensure_ty());
1096 auto prim = primitive(selected, llvm_args, arg_types, ast_args);
1097 if (prim.has_value()) {
1100 llvm_fn = declare(*selected);
1101 val = m_builder->CreateCall(llvm_fn,
vals_to_llvm(llvm_args));
1104 if (
auto ty = expr.val_ty(); ty.has_value() && !ty->is_trivially_destructible())
1105 make_temporary_in_scope(val, expr,
"tmp");
1111 bool is_and = expr.operation ==
"&&"_a;
1112 string label_base = (is_and ?
"land" :
"lor");
1113 auto* entry_block = m_builder->GetInsertBlock();
1114 auto* rhs_block = llvm::BasicBlock::Create(*m_context, label_base +
".rhs", m_current_fn->llvm);
1115 auto* pass_block = llvm::BasicBlock::Create(*m_context, label_base +
".pass", m_current_fn->llvm);
1116 auto lhs_val = body_expression(*expr.lhs);
1118 m_builder->CreateCondBr(lhs_val, rhs_block, pass_block);
1120 m_builder->CreateCondBr(lhs_val, pass_block, rhs_block);
1121 m_builder->SetInsertPoint(rhs_block);
1122 auto rhs_val = body_expression(*expr.rhs);
1123 m_builder->CreateBr(pass_block);
1124 m_builder->SetInsertPoint(pass_block);
1125 auto* phi = m_builder->CreatePHI(llvm_type(expr.ensure_ty()), 2, label_base +
".phi");
1127 phi->addIncoming(m_builder->getFalse(), entry_block);
1129 phi->addIncoming(m_builder->getTrue(), entry_block);
1130 phi->addIncoming(rhs_val, rhs_block);
1138 if (
const auto* target_var = dyn_cast<ast::VarExpr>(expr.target.raw_ptr())) {
1139 auto* in_scope = m_scope.find(target_var->name);
1140 YUME_ASSERT(in_scope !=
nullptr,
"Variable "s + target_var->name +
" is not in scope");
1144 auto expr_val = body_expression(*expr.value);
1145 if (expr_val.scope !=
nullptr && expr_val.scope->owning)
1146 expr_val.scope->owning =
false;
1148 m_builder->CreateStore(expr_val, in_scope->value.llvm);
1151 if (
auto* field_access = dyn_cast<ast::FieldAccessExpr>(expr.target.raw_ptr())) {
1152 auto& field_base = field_access->base;
1153 const auto [struct_base, base] = [&]() -> tuple<ty::Type, Val> {
1154 if (field_base.has_value()) {
1155 auto base = body_expression(*field_base);
1156 auto struct_base = field_access->base->ensure_ty();
1157 return {struct_base, base};
1159 if (!isa<ast::CtorDecl>(m_current_fn->ast()))
1160 throw std::logic_error(
"Field access without a base is only available in constructors");
1162 auto [value, ast, owning] = *m_scope_ctor;
1163 return {ast.ensure_ty().known_mut(), value};
1166 YUME_ASSERT(struct_base.is_mut(),
"Cannot assign into field of immutable structure");
1168 const string base_name = field_access->field;
1169 const int base_offset = field_access->offset;
1171 auto expr_val = body_expression(*expr.value);
1173 if (expr_val.scope !=
nullptr && expr_val.scope->owning) {
1174 expr_val.scope->owning =
false;
1175 }
else if (!expr.value->ensure_ty().is_trivially_destructible() && expr_val.scope !=
nullptr &&
1176 !expr_val.scope->owning) {
1177 make_dup(expr_val, expr.value);
1179 const auto* struct_type = struct_base.ensure_mut_base().base_cast<
ty::Struct>();
1181 YUME_ASSERT(base_offset >= 0,
"Field access has unknown offset into struct");
1183 auto* gep = m_builder->CreateStructGEP(llvm_type(struct_type), base, base_offset,
"s.sf."s + base_name);
1187 if (field_base.has_value() && !expr.value->ensure_ty().is_trivially_destructible()) {
1188 auto field_type = struct_type->m_fields.at(base_offset)->type->ensure_ty();
1189 destruct(m_builder->CreateLoad(llvm_type(field_type), gep), field_type);
1192 m_builder->CreateStore(expr_val, gep);
1195 throw std::runtime_error(
"Can't assign to target "s + expr.target->kind_name());
1199 auto fn =
Fn{&expr, m_current_fn->
member, m_current_fn->self_ty, &m_current_fn->subs};
1203 expr.llvm_fn = fn.llvm;
1205 Val fn_bundle = llvm::UndefValue::get(fn.fn_ty->memo());
1206 fn_bundle = m_builder->CreateInsertValue(fn_bundle, fn.
llvm, 0);
1208 auto* llvm_closure_ty = fn.fn_ty->closure_memo();
1209 auto* llvm_closure = m_builder->CreateAlloca(llvm_closure_ty);
1212 for (
const auto& i : llvm::enumerate(llvm::zip(expr.closured_names, expr.closured_nodes))) {
1213 auto [name, ast_arg] = i.value();
1214 auto type = ast_arg->ensure_ty();
1215 auto* val = m_scope.find(name);
1216 YUME_ASSERT(val !=
nullptr,
"Captured variable not found in outer scope");
1217 YUME_ASSERT(val->ast.ensure_ty() == type,
"Capture variable does not match expected type: wanted "s + type.name() +
1218 ", but got " + val->ast.ensure_ty().name());
1220 m_builder->CreateStore(val->value,
1221 m_builder->CreateConstInBoundsGEP2_32(llvm_closure_ty, llvm_closure, 0, i.index()));
1226 m_builder->CreateInsertValue(fn_bundle, m_builder->CreateBitCast(llvm_closure, m_builder->getInt8PtrTy()), 1);
1228 auto saved_scope = m_scope;
1229 auto* saved_insert_point = m_builder->GetInsertBlock();
1230 auto* saved_fn = m_current_fn;
1231 auto saved_debug_location = m_builder->getCurrentDebugLocation();
1236 const Val closure_val = m_builder->CreateLoad(
1237 llvm_closure_ty, m_builder->CreateBitCast(fn.llvm->arg_begin(), llvm_closure_ty->getPointerTo()),
"closure");
1240 for (
const auto& i : llvm::enumerate(llvm::zip(expr.closured_names, expr.closured_nodes))) {
1241 auto [name, ast_arg] = i.value();
1242 auto type = ast_arg->ensure_ty();
1243 const Val arg = m_builder->CreateExtractValue(closure_val, i.index());
1244 expose_parameter_as_local(type, name, *ast_arg, arg);
1247 body_statement(expr.body);
1248 if (m_builder->GetInsertBlock()->getTerminator() ==
nullptr)
1249 m_builder->CreateRetVoid();
1251 m_scope = saved_scope;
1252 m_builder->SetInsertPoint(saved_insert_point);
1253 m_current_fn = saved_fn;
1254 m_builder->SetCurrentDebugLocation(saved_debug_location);
1260 YUME_ASSERT(expr.args.size() > 1,
"Direct call must have at least 1 argument");
1261 auto& base_expr = *expr.args[0];
1263 auto call_target_ty = base_expr.ensure_ty();
1265 auto* llvm_fn_ty = call_target_ty.base_cast<
ty::Function>()->fn_memo();
1266 auto* llvm_fn_bundle_ty = llvm_type(call_target_ty.without_mut());
1268 auto base = body_expression(base_expr);
1269 if (call_target_ty.is_mut())
1270 base = m_builder->CreateLoad(llvm_fn_bundle_ty, base.llvm,
"indir.fnptr.deref");
1272 auto* llvm_fn_ptr = m_builder->CreateExtractValue(base, 0,
"fnptr.fn");
1273 auto* llvm_fn_closure = m_builder->CreateExtractValue(base, 1,
"fnptr.closure");
1275 vector<llvm::Value*> args{};
1276 args.reserve(expr.args.size() - 1);
1277 args.push_back(llvm_fn_closure);
1279 for (
auto& i : llvm::drop_begin(expr.args))
1280 args.push_back(body_expression(*i));
1282 return m_builder->CreateCall(llvm_fn_ty, llvm_fn_ptr, args,
1283 llvm_fn_ty->getReturnType()->isVoidTy() ?
"" :
"indir.call");
1287 auto type = expr.ensure_ty();
1288 if (type.without_mut().base_isa<
ty::Struct>()) {
1305 auto* selected_ctor_overload = expr.selected_overload;
1307 auto* llvm_fn = declare(*selected_ctor_overload);
1308 vector<llvm::Value*> llvm_args{};
1309 for (
auto& i : expr.args) {
1310 auto arg = body_expression(*i);
1311 llvm_args.push_back(arg.llvm);
1313 Val base_value = m_builder->CreateCall(llvm_fn, llvm_args);
1323 if (
auto int_type = type.without_mut().try_as<
ty::Int>()) {
1324 YUME_ASSERT(expr.args.size() == 1,
"Numeric cast can only contain a single argument");
1325 auto& cast_from = expr.args[0];
1326 YUME_ASSERT(cast_from->ensure_ty().without_mut().base_isa<
ty::Int>(),
"Numeric cast must convert from int");
1327 auto base = body_expression(*cast_from);
1328 if (cast_from->ensure_ty().without_mut().base_cast<
ty::Int>()->
is_signed())
1329 return m_builder->CreateSExtOrTrunc(base, llvm_type(*int_type));
1330 return m_builder->CreateZExtOrTrunc(base, llvm_type(*int_type));
1366 throw std::runtime_error(
"Can't construct non-struct, non-integer type");
1371auto Compiler::create_malloc(llvm::Type* base_type,
Val slice_size, string_view name) ->
Val {
1372 auto* size_type = m_builder->getIntNTy(ptr_bitsize());
1373 slice_size = m_builder->CreateSExtOrTrunc(slice_size, size_type);
1374 Val alloc_size = llvm::ConstantExpr::getTrunc(llvm::ConstantExpr::getSizeOf(base_type), size_type);
1376 alloc_size = m_builder->CreateMul(slice_size, alloc_size,
"mallocsize");
1379 llvm::FunctionCallee malloc_func = m_module->getOrInsertFunction(
"malloc", m_builder->getInt8PtrTy(), size_type);
1380 auto* m_call = m_builder->CreateCall(malloc_func, alloc_size.
llvm,
"malloccall");
1381 Val result = m_builder->CreateBitCast(m_call, base_type->getPointerTo(), name);
1383 m_call->setTailCall();
1384 if (
auto* fn = dyn_cast<llvm::Function>(malloc_func.getCallee())) {
1385 m_call->setCallingConv(fn->getCallingConv());
1386 if (!fn->returnDoesNotAlias())
1387 fn->setReturnDoesNotAlias();
1393auto Compiler::create_malloc(llvm::Type* base_type, uint64_t slice_size, string_view name) -> Val {
1394 return create_malloc(base_type, m_builder->getIntN(ptr_bitsize(), slice_size), name);
1397auto Compiler::create_free(Val ptr) -> Val {
1398 auto* void_ty = m_builder->getVoidTy();
1399 auto* int_ptr_ty = m_builder->getInt8PtrTy();
1401 llvm::FunctionCallee free_func = m_module->getOrInsertFunction(
"free", void_ty, int_ptr_ty);
1402 auto* result = m_builder->CreateCall(free_func, m_builder->CreateBitCast(ptr, int_ptr_ty));
1403 result->setTailCall();
1404 if (
auto* fn = dyn_cast<llvm::Function>(free_func.getCallee()))
1405 result->setCallingConv(fn->getCallingConv());
1411 auto* slice_size = m_builder->getIntN(ptr_bitsize(), expr.args.size());
1413 YUME_ASSERT(expr.ensure_ty().is_slice(),
"Slice expression must contain slice type");
1414 auto* slice_type = llvm_type(expr.ensure_ty());
1415 auto base_type = expr.ensure_ty().base_cast<
ty::Struct>()->fields().at(0)->ensure_ty().ensure_ptr_base();
1416 auto* base_llvm_type = llvm_type(base_type);
1418 const Val data_ptr = create_malloc(base_llvm_type, slice_size,
"sl.ctor.malloc");
1421 for (
auto& i : expr.args) {
1422 if (!base_type.is_trivially_destructible()) {
1423 auto dup_args = vector<ast::AnyExpr>{};
1424 dup_args.emplace_back(move(i));
1426 std::make_unique<ast::CtorExpr>(expr.token_range(),
ast::AnyType{expr.type->clone()}, move(dup_args));
1427 m_walker->body_expression(*ast_dup);
1430 Val val = body_expression(*i);
1431 m_builder->CreateStore(val, m_builder->CreateConstInBoundsGEP1_32(base_llvm_type, data_ptr, j++));
1434 Val slice_inst = llvm::UndefValue::get(slice_type);
1435 slice_inst = m_builder->CreateInsertValue(slice_inst, data_ptr, 0);
1436 slice_inst = m_builder->CreateInsertValue(slice_inst, slice_size, 1);
1438 make_temporary_in_scope(slice_inst, expr,
"tmpsl");
1445 optional<ty::Type> base_type;
1446 if (expr.base.has_value()) {
1447 base = body_expression(*expr.base);
1448 base_type = expr.base->ensure_ty().mut_base();
1450 YUME_ASSERT(m_scope_ctor.has_value(),
"Cannot access field without receiver outside of a constructor");
1451 base = m_scope_ctor->value;
1452 base_type = m_current_fn->self_ty;
1455 const string base_name = expr.field;
1456 const int base_offset = expr.offset;
1458 if (!expr.ensure_ty().is_mut())
1459 return m_builder->CreateExtractValue(*base, base_offset,
"s.field.nm."s + base_name);
1461 YUME_ASSERT(base_type.has_value(),
"Cannot access field of unknown type");
1462 return m_builder->CreateStructGEP(llvm_type(base_type.value()), *base, base_offset,
"s.field.m."s + base_name);
1466 auto* ast_dup = m_walker->make_dup(ast);
1467 auto* llvm_fn =
declare(*ast_dup);
1468 vector<llvm::Value*> llvm_args{};
1469 llvm_args.push_back(value.
llvm);
1470 value.
llvm = m_builder->CreateCall(llvm_fn, llvm_args);
1473auto Compiler::get_vtable(Struct& st,
const Struct& iface) -> nonnull<llvm::GlobalVariable*> {
1475 auto vtable_entries = vector<llvm::Constant*>();
1476 auto vtable_types = vector<llvm::Type*>();
1477 vtable_entries.resize(iface.vtable_members.size());
1478 vtable_types.resize(iface.vtable_members.size());
1480 for (
const auto& i : st.
body()) {
1481 if (!isa<ast::FnDecl>(*i))
1484 const auto& fn_ast = cast<ast::FnDecl>(*i);
1485 auto* fn = fn_ast.sema_decl;
1486 YUME_ASSERT(fn !=
nullptr,
"Fn not found from fn ast?");
1488 auto vtable_match = std::ranges::find(iface.vtable_members,
vtable_entry_for(*fn));
1489 if (vtable_match == iface.vtable_members.end())
1492 auto index = std::distance(iface.vtable_members.begin(), vtable_match);
1493 vtable_entries[index] = declare(*fn);
1494 vtable_types[index] = fn->fn_ty->memo();
1497 if (std::ranges::any_of(vtable_entries, [](
auto* ptr) {
return ptr ==
nullptr; })) {
1498 std::stringstream str;
1499 str <<
"The struct `" << st.
name() <<
"' implements the interface `" << iface.name()
1500 <<
"', but does not implement an abstract method.\n";
1501 str <<
"These abstract methods were unimplemented:";
1502 for (
const auto& i : llvm::enumerate(vtable_entries)) {
1503 if (i.value() !=
nullptr)
1507 str <<
"\n " << iface.vtable_members.at(i.index()).name;
1509 throw std::runtime_error(str.str());
1512 auto* vtable_struct = llvm::ConstantStruct::getAnon(vtable_entries);
1514 new llvm::GlobalVariable(*m_module, vtable_struct->getType(),
true, llvm::GlobalVariable::PrivateLinkage,
1515 vtable_struct,
".vtable." + iface.name() +
"." + st.
name());
1519 return static_cast<nonnull<llvm::GlobalVariable*>
>(st.
vtable_memo);
1523 auto target_ty = expr.ensure_ty();
1524 auto current_ty = expr.base->ensure_ty();
1525 Val base = body_expression(*expr.base);
1527 if (expr.conversion.dereference) {
1529 YUME_ASSERT(current_ty.is_mut() || current_ty.is_opaque_self(),
1530 "Source type must be mutable or opaque when implicitly derefencing");
1532 current_ty = current_ty.without_mut().without_opaque();
1533 base.
llvm = m_builder->CreateLoad(llvm_type(current_ty), base,
"ic.deref");
1534 if (!current_ty.is_trivially_destructible() && base.
scope !=
nullptr && base.
scope->
owning &&
1535 m_return_value == &expr) {
1536 make_dup(base, expr.base);
1540 if (expr.conversion.kind == ty::Conv::None)
1542 if (expr.conversion.kind == ty::Conv::Int)
1543 return m_builder->CreateIntCast(base, llvm_type(target_ty), current_ty.base_cast<
ty::Int>()->
is_signed(),
"ic.int");
1544 if (expr.conversion.kind == ty::Conv::FnPtr) {
1546 YUME_ASSERT(isa<ast::LambdaExpr>(*expr.base),
"fnptr conversion source must be a lambda");
1548 auto& lambda_expr = cast<ast::LambdaExpr>(*expr.base);
1550 auto fn =
Fn{&lambda_expr,
nullptr, std::nullopt,
nullptr};
1555 auto saved_scope = m_scope;
1556 auto* saved_insert_point = m_builder->GetInsertBlock();
1557 auto* saved_fn = m_current_fn;
1561 body_statement(lambda_expr.body);
1562 if (m_builder->GetInsertBlock()->getTerminator() ==
nullptr && !fn.fn_ty->m_ret.has_value())
1563 m_builder->CreateRetVoid();
1565 m_scope = saved_scope;
1566 m_builder->SetInsertPoint(saved_insert_point);
1567 m_current_fn = saved_fn;
1571 if (expr.conversion.kind == ty::Conv::Virtual) {
1574 const auto* target_st_ty = target_ty.base_cast<
ty::Struct>();
1575 const auto* current_st_ty = current_ty.base_cast<
ty::Struct>();
1577 const auto* target_st = target_st_ty->
decl();
1578 YUME_ASSERT(target_st !=
nullptr,
"Struct not found from struct type?");
1581 auto* current_st = current_st_ty->
decl();
1582 YUME_ASSERT(current_st !=
nullptr,
"Struct not found from struct type?");
1584 auto* vtable = get_vtable(*current_st, *target_st);
1586 Val erased_original =
nullptr;
1587 if (current_ty.is_mut()) {
1588 erased_original = base;
1590 erased_original = entrypoint_builder().CreateAlloca(llvm_type(current_st_ty));
1591 m_builder->CreateStore(base, erased_original);
1594 auto* interface_struct_ty = llvm::StructType::get(m_builder->getInt8PtrTy(), m_builder->getInt8PtrTy());
1595 Val interface_struct = llvm::UndefValue::get(interface_struct_ty);
1597 m_builder->CreateInsertValue(interface_struct, m_builder->CreateBitCast(vtable, m_builder->getInt8PtrTy()), 0);
1598 interface_struct = m_builder->CreateInsertValue(
1599 interface_struct, m_builder->CreateBitCast(erased_original, m_builder->getInt8PtrTy()), 1);
1601 return interface_struct;
1603 throw std::runtime_error(
"Unknown implicit conversion " + expr.conversion.to_string());
1607 YUME_ASSERT(expr.ensure_ty().is_meta(),
"Type expr must have metatype as its type");
1608 return m_builder->getInt8(0);
1614 llvm::legacy::PassManager pass;
1615 auto file_type = binary ? llvm::CGFT_ObjectFile : llvm::CGFT_AssemblyFile;
1617 if (m_target_machine->addPassesToEmitFile(pass, *dest,
nullptr, file_type)) {
1618 errs() <<
"TargetMachine can't emit a file of this type";
1619 throw std::exception();
1622 pass.run(*m_module);
1628 m_builder->SetCurrentDebugLocation({});
1633 const ASTStackTrace guard(
"Codegen: "s + expr.kind_name() +
" expression", expr);
1634 m_builder->SetCurrentDebugLocation({});
1635 if (m_current_fn !=
nullptr && m_current_fn->llvm !=
nullptr) {
1636 if (llvm::DIScope* scope = m_current_fn->llvm->getSubprogram(); scope !=
nullptr) {
1637 m_builder->SetCurrentDebugLocation(
1638 llvm::DILocation::get(scope->getContext(), expr.location().begin_line, expr.location().begin_col, scope));
The Compiler the the primary top-level type during compilation. A single instance is created during t...
auto builder() const -> const auto &
auto body_expression(ast::Expr &expr) -> Val
void body_statement(ast::Stmt &)
auto ptr_bitsize() -> unsigned int
auto llvm_type(ty::Type type, bool erase_opaque=false) -> llvm::Type *
Convert a type into its corresponding LLVM type.
auto direct_call_operator(ast::CallExpr &expr) -> Val
void run()
Begin compilation!
void define(Fn &)
Compile the body of a function or constructor.
void write_object(const char *filename, bool binary)
auto declare(Fn &) -> llvm::Function *
Declare a function/constructor in bytecode, or get an existing declaration.
Compiler(const optional< string > &target_triple, vector< SourceFile > source_files)
auto decl_statement(ast::Stmt &, optional< ty::Type > parent=std::nullopt, ast::Program *member=nullptr, nullable< Substitutions * > parent_subs=nullptr) -> DeclLike
void destruct(Val val, ty::Type type)
Destructs an object val of specified type type.
auto default_init(ty::Type type) -> Val
Default-constructs an object of specified type type.
auto create_struct(Struct &) -> bool
All nodes in the AST tree of the program inherit from this class.
auto kind_name() const -> string
Human-readable string representation of the Kind of this node.
auto location() const -> Loc
The union of the locations of the Tokens making up this node.
auto ensure_ty() const -> ty::Type
Expressions have an associated value and type.
auto has_value() const -> bool
auto raw_ptr() const -> const T *
Statements make up most things in source code.
auto closure_memo() const -> auto *
auto fn_memo() const -> auto *
A built-in integral type, such as I32 or Bool.
auto is_signed() const -> bool
The "self" type of abstract or overriding functions. An extra layer of indirection is introduced for ...
A "qualified" type, with a stackable qualifier, i.e. ptr.
An user-defined struct type with associated fields.
auto decl() const -> nonnull< yume::Struct * >
auto is_interface() const -> bool
A "qualified" type, with a non-stackable qualifier, i.e. mut.
auto is_slice() const noexcept -> bool
auto is_mut() const noexcept -> bool
auto mut_base() const noexcept -> optional< Type >
If this type is a mutable reference, return the base of it (T mut -> T)
auto is_trivially_destructible() const -> bool
auto base_cast() const noexcept -> nonnull< const T * >
auto base_dyn_cast() const noexcept -> nullable< const T * >
auto mangle_name(Fn &fn) -> string
void make_implicit_conversion(ast::OptionalExpr &expr, optional< ty::Type > target_ty)
static auto make_cdtor_fn(llvm::IRBuilder<> &builder, llvm::Module &module, bool is_ctor) -> llvm::Function *
static auto vals_to_llvm(const vector< Val > &in) -> vector< llvm::Value * >
static auto constexpr const_hash(const char *input) -> unsigned
A constexpr-friendly simple string hash, for simple switches with string cases.
static auto vtable_entry_for(const Fn &fn) -> VTableEntry
static auto build_struct_type(Compiler &compiler, const ty::Struct &type) -> llvm::Type *
static auto build_function_type(Compiler &compiler, const ty::Function &type) -> llvm::Type *
auto open_file(nonnull< const char * > filename) -> unique_ptr< llvm::raw_pwrite_stream >
Opens a writeable stream to a file with the given filename relative to the current working directory.
static void create_vtable_for(Struct &st)
static void destruct_indirect(Compiler &compiler, const InScope &v)
auto body_statement(ast::Stmt &stat, auto &&... args)
auto body_expression(ast::Expr &expr, auto &&... args)
A constant declaration in the compiler.
llvm::GlobalVariable * llvm
auto ast() const noexcept -> const auto &
A common base between declarations in the compiler: Fn, Struct and Const. Its value may also be absen...
A function declaration in the compiler.
ast::Program * member
The program this declaration is a member of.
optional< ty::Type > self_ty
If this function is in the body of a struct, this points to its type. Used for the self type.
auto arg_names() const -> vector< string >
auto fn_body() -> ast::FnDecl::Body &
auto primitive() const -> bool
auto compound_body() -> ast::Compound &
auto local() const -> bool
auto extern_decl() const -> bool
auto get_self_ty() const -> optional< ty::Type >
auto arg_types() const -> vector< ty::Type >
llvm::Function * llvm
The LLVM function definition corresponding to this function or constructor.
auto extern_linkage() const -> bool
auto abstract() const -> bool
auto ast() const -> const ast::Stmt &
void make_extern_linkage(bool value=true)
auto has_annotation(const string &name) const -> bool
const ty::Function * fn_ty
auto ret() const -> optional< ty::Type >
auto name() const noexcept -> string
A local variable in function scope. Used to track destructing when the scope ends.
bool owning
Whether the local scope "owns" the variable. Unowned variables are not destructed at the end of the s...
A struct declaration in the compiler.
auto name() const noexcept -> string
auto has_annotation(const string &name) const -> bool
auto body() const noexcept -> const auto &
auto get_subs() const -> const Substitutions &
auto get_self_ty() const noexcept -> optional< ty::Type >
auto ast() const noexcept -> const auto &
std::vector< VTableEntry > vtable_members
nullable< llvm::GlobalVariable * > vtable_memo
optional< ty::Type > self_ty
The type of this struct. Used for the self type.
ast::Program * member
The program this declaration is a member of.
void declare_size_type(Compiler &)
A value of a complied expression.
A logical operator such as || or &&. Since these aren't overloadable, they have their own AST node.
Bool literals (true or false).
A function call or operator.
A statement consisting of multiple other statements, i.e. the body of a function.
A constant. Currently global.
A construction of a struct or cast of a primitive.
Direct access of a field of a struct (::).
An if statement (if), with one or more IfClauses, and optionally an else clause.
optional< Compound > else_clause
vector< IfClause > clauses
Represents an implicit cast to a different type, performed during semantic analysis.
A local definition of an anonymous function.
The top level structure of a file of source code.
Return from a function body.
VarDecl * extends_lifetime
A slice literal, i.e. an array.
static constexpr auto BUILTIN_TYPE_SLICE
Represents a reference to a type.
A declaration of a local variable (let).
A variable, i.e. just an identifier.
auto visit(Us... us) -> decltype(auto)
#define YUME_ASSERT(assertion, message)