#pragma once
#include "cool_tree.h"
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/DIBuilder.h>
#include "llvm/IR/DebugInfoMetadata.h"
#include <llvm/Support/raw_ostream.h>
#if defined _MSC_VER && !defined __clang__
#define __attribute(...)
#endif
class CgenNode;
#pragma region "CgenClassTable"
class CgenClassTable : public cool::SymbolTable<CgenNode> {
public:
CgenClassTable(Classes);
private:
void install_basic_classes();
void install_classes(Classes cs);
void install_class(CgenNode *nd);
void install_special_class(CgenNode *nd);
void build_inheritance_tree();
void set_relations(CgenNode *nd);
void setup_external_functions();
void setup_classes(CgenNode *c, int depth);
void setup();
void code_module();
void code_classes(CgenNode *c);
void code_constants();
void code_main();
CgenNode *root(); public:
int get_num_classes() const { return current_tag; }
private:
std::vector<CgenNode *> nds, special_nds;
int current_tag;
public:
llvm::Function *create_llvm_function(const std::string &funcName,
llvm::Type *retType,
llvm::ArrayRef<llvm::Type *> argTypes,
bool isVarArgs);
llvm::Function *create_function(const std::string &name,
llvm::Type *ret_type,
llvm::ArrayRef<llvm::Type *> arg_types,
llvm::GlobalValue::LinkageTypes linkage);
llvm::Function *create_var_function(const std::string &name,
llvm::Type *ret_type,
llvm::ArrayRef<llvm::Type *> arg_types,
llvm::GlobalValue::LinkageTypes
linkage);
llvm::LLVMContext context;
llvm::IRBuilder<> builder;
llvm::Module the_module;
llvm::DIBuilder di_builder;
llvm::DIFile* di_file;
llvm::DICompileUnit* di_cu;
llvm::Type *i1;
llvm::Type *i8;
llvm::PointerType *ptr;
llvm::Type *i32;
llvm::Type *void_;
llvm::DIBasicType* di1;
llvm::DIBasicType* di8;
llvm::DIBasicType* di32;
llvm::DIDerivedType* dptr;
llvm::DIBasicType* dvoid;
};
#pragma endregion
#pragma region "CgenNode"
class CgenNode : public class__class {
public:
enum Basicness { Basic, NotBasic };
CgenNode(Class_ c, Basicness bstatus, CgenClassTable *class_table)
: class__class((const class__class &) *c), parentnd(0), children(0),
basic_status(bstatus), class_table(class_table), tag(-1), ctx(class_table->context),
i1(class_table->i1), i8(class_table->i8), ptr(class_table->ptr),
i32(class_table->i32), void_(class_table->void_),
type(nullptr), vtable_type(nullptr), vtable(nullptr),
di_builder(class_table->di_builder)
{}
void set_parent(CgenNode *p)
{
assert(this->parentnd == nullptr && p != nullptr);
p->children.push_back(this);
this->parentnd = p;
}
std::optional<CgenNode*> get_direct_parent() const
{
if (parentnd->basic())
return std::nullopt;
return parentnd;
}
int basic() const { return basic_status == Basic; }
std::vector<CgenNode *> &get_children() { return children; }
void set_max_child(int mc) { max_child = mc; }
int get_max_child() const { return max_child; }
int get_tag() const { return tag; }
CgenClassTable *get_classtable() const { return class_table; }
llvm::StructType *type;
llvm::StructType *vtable_type;
llvm::GlobalVariable *vtable;
llvm::DIType* dtype;
std::string get_type_name() const { return name->get_string(); }
std::string get_vtable_type_name() const
{
return "_" + get_type_name() + "_vtable";
}
std::string get_vtable_name() const
{
return "_" + get_type_name() + "_vtable_prototype";
}
std::string get_init_function_name() const { return get_type_name() + "_new"; }
void setup(int tag, int depth);
void layout_features();
void code_class();
void code_init_function(CgenEnvironment *env) const;
void make_vtable_type(CgenEnvironment *env);
std::vector<std::pair<method_class *, llvm::FunctionType *> > methods;
std::vector<std::pair<attr_class *, llvm::Type *> > attributes;
llvm::Function *create_function(const std::string &fName, llvm::FunctionType *ty) const
{
return llvm::Function::Create(ty, llvm::GlobalValue::ExternalLinkage,
this->name->get_string() + "_" + fName,
this->class_table->the_module);
}
static llvm::FunctionType *create_functionty(llvm::Type *retType,
llvm::ArrayRef<llvm::Type *> argTypes)
{
return llvm::FunctionType::get(retType, argTypes, false);
}
void make_vtable_prototype(CgenEnvironment *env);
void premake_type()
{
assert(type == nullptr);
this->type = llvm::StructType::create(ctx,
this->name->get_string());
assert(type != nullptr);
}
void premake_debug_type();
llvm::DIBuilder &di_builder;
std::vector<llvm::Metadata*> dfeats;
private:
CgenNode *parentnd; std::vector<CgenNode *> children; Basicness basic_status; CgenClassTable *class_table;
int tag, max_child;
llvm::LLVMContext &ctx;
llvm::Type *i1;
llvm::Type *i8;
llvm::PointerType *ptr;
llvm::Type *i32;
llvm::Type *void_;
void make_type_forrealz(CgenEnvironment *env);
void make_debug_type(CgenEnvironment* env);
};
#pragma endregion
#pragma region "CgenEnvironment"
class CgenEnvironment {
public:
CgenEnvironment(CgenNode *cur_class)
: cur_class(cur_class),
class_table(*cur_class->get_classtable()),
context(class_table.context),
builder(class_table.builder), the_module(class_table.the_module), data_layout(&the_module),
i1(class_table.i1), i8(class_table.i8), ptr(class_table.ptr),
i32(class_table.i32), void_(class_table.void_)
{
vars.enterscope();
}
CgenNode *get_class() const { return cur_class; }
void set_class(CgenNode *c) { cur_class = c; }
CgenNode *type_to_class(Symbol t) const;
std::pair<llvm::Type*, llvm::Value*> find_in_scopes(Symbol name) const;
std::optional<llvm::Value*> find_if_exists(Symbol name) const;
void add_binding(Symbol name, llvm::Value *val_ptr)
{
vars.insert(name, val_ptr);
}
void open_scope() { vars.enterscope(); }
void close_scope() { vars.exitscope(); }
llvm::Function *get_function(Symbol name) const
{
return the_module.getFunction(name->get_string());
}
llvm::BasicBlock *new_bb_at_end(const std::string &name)
{
return llvm::BasicBlock::Create(context, name,
builder.GetInsertBlock()->getParent());
}
llvm::AllocaInst *insert_alloca_at_head(llvm::Type *ty);
llvm::AllocaInst *insert_alloca_at_head(llvm::Type *, llvm::Twine const &);
llvm::BasicBlock *get_or_insert_abort_block(llvm::Function *f);
llvm::Type *as_type(Symbol) const __attribute((pure));
llvm::Type *as_mostly_boxed_type(Symbol) const __attribute((pure));
llvm::DIType* as_boxed_dtype(Symbol) const __attribute((pure));
llvm::Value* default_value(llvm::Type*) const __attribute((pure));
llvm::Value* conform(llvm::Value* src, llvm::Type* dest_type) __attribute((pure));
private:
cool::SymbolTable<llvm::Value> vars;
CgenNode *cur_class;
public:
CgenClassTable &class_table;
llvm::LLVMContext &context;
llvm::IRBuilder<> &builder;
llvm::Module &the_module;
llvm::DataLayout data_layout;
llvm::Type *i1;
llvm::Type *i8;
llvm::PointerType *ptr;
llvm::Type *i32;
llvm::Type *void_;
};
#pragma endregion