#define EXTERN
#include "cgen.h"
#include <cmath>
#include <sstream>
#include <string>
#include <llvm/Support/FileSystem.h>
#ifdef _MSC_VER
#undef assert
#define assert(c) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]\n", #c, __LINE__); __debugbreak(); } while (0)
#define assertm(c, msg) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]: %s\n", #c, __LINE__, msg); __debugbreak(); } while (0)
#elif defined __x86_64__
#undef assert
#define assert(c) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]\n", #c, __LINE__); asm ("int3; nop"); } while (0)
#define assertm(c, msg) do if (!(c)) { fprintf(stderr, "Assertion %s failed [%d]: %s\n", #c, __LINE__, msg); asm ("int3; nop"); } while (0)
#endif
extern int cgen_debug, curr_lineno;
using namespace llvm;
EXTERN Symbol
Object,
IO, String, Int, Bool, Main,
cool_abort, type_name, cool_copy, out_string, out_int, in_string, in_int,
length, concat, substr,
val,
No_class, No_type, SELF_TYPE, self,
arg, arg2, newobj, Mainmain, prim_string, prim_int, prim_bool;
namespace
{
std::string as_string(Symbol) __attribute((pure));
std::vector<Expression> unfuck(Expressions) __attribute((pure));
std::vector<Formal> unfuck(Formals) __attribute((pure));
std::vector<Feature> unfuck(Features) __attribute((pure));
std::pair<Type*, Value*> resolve_opaque(Value*) __attribute((pure));
std::pair<std::string, std::string> split(const std::string&, char) __attribute((pure));
template<class T, class R>
std::vector<R> map(std::vector<T> src, std::function<R(T const &)> mapper) __attribute((pure, optimize("O3")));
void initialize_constants()
{
Object = idtable.add_string("Object");
IO = idtable.add_string("IO");
String = idtable.add_string("String");
Int = idtable.add_string("Int");
Bool = idtable.add_string("Bool");
Main = idtable.add_string("Main");
cool_abort = idtable.add_string("abort");
type_name = idtable.add_string("type_name");
cool_copy = idtable.add_string("copy");
out_string = idtable.add_string("out_string");
out_int = idtable.add_string("out_int");
in_string = idtable.add_string("in_string");
in_int = idtable.add_string("in_int");
length = idtable.add_string("length");
::concat = idtable.add_string("concat");
substr = idtable.add_string("substr");
val = idtable.add_string("val");
No_class = idtable.add_string("_no_class");
No_type = idtable.add_string("_no_type");
SELF_TYPE = idtable.add_string("SELF_TYPE");
self = idtable.add_string("self");
arg = idtable.add_string("arg");
arg2 = idtable.add_string("arg2");
newobj = idtable.add_string("_newobj");
Mainmain = idtable.add_string("main");
prim_string = idtable.add_string("sbyte*");
prim_int = idtable.add_string("int");
prim_bool = idtable.add_string("bool");
}
}
#pragma region "CgenClassTable"
CgenClassTable::CgenClassTable(Classes classes)
: nds(), current_tag(0), context(), builder(this->context),
the_module(stringtable.get_file(), this->context), di_builder(the_module)
{
if (cgen_debug)
std::cerr << "Building CgenClassTable" << std::endl;
i1 = Type::getInt1Ty(this->context);
i8 = Type::getInt8Ty(this->context);
i32 = Type::getInt32Ty(this->context);
ptr = i8->getPointerTo();
void_ = Type::getVoidTy(this->context);
#ifdef EMIT_DBG
the_module.addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION);
di_file = di_builder.createFile(stringtable.get_file(), ".");
di_cu = di_builder.createCompileUnit(dwarf::DW_LANG_C, di_file, "ibn222_ece479k_lab2",
false, (cgen_debug) ? "-d" : "", 0);
di1 = di_builder.createBasicType("bool", 1, dwarf::DW_ATE_signed);
di8 = di_builder.createBasicType("cbool", 8, dwarf::DW_ATE_signed);
di32 = di_builder.createBasicType("int", 32, dwarf::DW_ATE_signed);
dptr = di_builder.createPointerType(di8, 64, 0, std::nullopt, "opaque_ptr");
dvoid = di_builder.createNullPtrType();
#endif
enterscope();
install_basic_classes();
install_classes(classes);
build_inheritance_tree();
setup();
code_module();
exitscope();
#ifdef EMIT_DBG
di_builder.finalize();
#endif
}
void CgenClassTable::install_basic_classes()
{
curr_lineno = 0;
Symbol filename = stringtable.add_string("<basic class>");
Class_ noclasscls = class_(No_class, No_class, nil_Features(), filename);
install_special_class(new CgenNode(noclasscls, CgenNode::Basic, this));
delete noclasscls;
Class_ selftypecls = class_(SELF_TYPE, No_class, nil_Features(), filename);
install_special_class(new CgenNode(selftypecls, CgenNode::Basic, this));
delete selftypecls;
Class_ primstringcls =
class_(prim_string, No_class, nil_Features(), filename);
install_special_class(new CgenNode(primstringcls, CgenNode::Basic, this));
delete primstringcls;
Class_ primintcls = class_(prim_int, No_class, nil_Features(), filename);
install_special_class(new CgenNode(primintcls, CgenNode::Basic, this));
delete primintcls;
Class_ primboolcls = class_(prim_bool, No_class, nil_Features(), filename);
install_special_class(new CgenNode(primboolcls, CgenNode::Basic, this));
delete primboolcls;
Class_ objcls = class_(
Object, No_class,
append_Features(
append_Features(single_Features(method(cool_abort, nil_Formals(),
Object, no_expr())),
single_Features(method(type_name, nil_Formals(),
String, no_expr()))),
single_Features(
method(cool_copy, nil_Formals(), SELF_TYPE, no_expr()))),
filename);
install_class(new CgenNode(objcls, CgenNode::Basic, this));
delete objcls;
Class_ intcls = class_(
Int, Object, single_Features(attr(val, prim_int, no_expr())), filename);
install_class(new CgenNode(intcls, CgenNode::Basic, this));
delete intcls;
Class_ boolcls = class_(
Bool, Object, single_Features(attr(val, prim_bool, no_expr())),
filename);
install_class(new CgenNode(boolcls, CgenNode::Basic, this));
delete boolcls;
Class_ stringcls =
class_(String, Object,
append_Features(
append_Features(
append_Features(
single_Features(
attr(val, prim_string, no_expr())),
single_Features(
method(length, nil_Formals(), Int,
no_expr()))),
single_Features(method(::concat,
single_Formals(
formal(arg, String)),
String, no_expr()))),
single_Features(
method(substr,
append_Formals(
single_Formals(formal(arg, Int)),
single_Formals(formal(arg2, Int))),
String, no_expr()))),
filename);
install_class(new CgenNode(stringcls, CgenNode::Basic, this));
delete stringcls;
Class_ iocls = class_(
IO, Object,
append_Features(
append_Features(
append_Features(
single_Features(method(out_string,
single_Formals(formal(arg, String)),
SELF_TYPE, no_expr())),
single_Features(method(out_int,
single_Formals(formal(arg, Int)),
SELF_TYPE, no_expr()))),
single_Features(
method(in_string, nil_Formals(), String, no_expr()))),
single_Features(method(in_int, nil_Formals(), Int, no_expr()))),
filename);
install_class(new CgenNode(iocls, CgenNode::Basic, this));
delete iocls;
}
void CgenClassTable::install_classes(Classes cs)
{
for (auto cls: cs) {
install_class(new CgenNode(cls, CgenNode::NotBasic, this));
}
}
void CgenClassTable::install_class(CgenNode* nd)
{
Symbol name = nd->get_name();
if (!this->find(name)) {
nds.push_back(nd);
this->insert(name, nd);
}
nd->premake_type();
}
void CgenClassTable::install_special_class(CgenNode* nd)
{
Symbol name = nd->get_name();
if (!this->find(name)) {
special_nds.push_back(nd);
this->insert(name, nd);
}
}
void CgenClassTable::build_inheritance_tree()
{
for (auto node: nds)
set_relations(node);
}
void CgenClassTable::set_relations(CgenNode* nd)
{
Symbol parent = nd->get_parent();
auto parent_node = this->find(parent);
if (!parent_node) {
throw std::runtime_error("Class " + nd->get_name()->get_string() +
" inherits from an undefined class " +
parent->get_string());
}
nd->set_parent(parent_node);
}
void CgenClassTable::setup_external_functions()
{
create_llvm_function("strcmp", i32, {ptr, ptr}, false);
create_llvm_function("printf", i32, {ptr}, true);
create_llvm_function("abort", void_, {}, false);
create_llvm_function("malloc", ptr, {i32}, false);
create_llvm_function("free", void_, {ptr}, false);
auto* ObjectTy = ptr;
create_function("Object_new", ObjectTy, {}, GlobalValue::ExternalLinkage);
auto* IntTy = ptr;
create_function("Int_new", IntTy, {}, GlobalValue::ExternalLinkage);
create_function("Int_init", IntTy, {IntTy, i32}, GlobalValue::ExternalLinkage);
auto* BoolTy = ptr;
create_function("Bool_new", BoolTy, {}, GlobalValue::ExternalLinkage);
create_function("Bool_init", BoolTy, {BoolTy, i8}, GlobalValue::ExternalLinkage);
auto* StringTy = ptr;
create_function("String_new", StringTy, {}, GlobalValue::ExternalLinkage);
auto* IoTy = ptr;
create_function("IO_new", IoTy, {}, GlobalValue::ExternalLinkage);
}
void CgenClassTable::setup_classes(CgenNode* c, int depth)
{
c->setup(current_tag++, depth);
for (auto child: c->get_children()) {
setup_classes(child, depth + 1);
}
c->set_max_child(current_tag - 1);
}
void CgenClassTable::setup()
{
setup_external_functions();
setup_classes(root(), 0);
}
void CgenClassTable::code_module()
{
code_constants();
code_classes(root());
code_main();
if (cgen_debug)
std::cerr << "\n";
}
void CgenClassTable::code_classes(CgenNode* c)
{
if (c->get_type_name() == "Object") {
if (cgen_debug)
std::cerr << "\n\nEmitting classes\n";
c->code_class();
}
std::vector classes{c->get_children()};
for (auto const i: classes)
i->code_class();
for (auto* i: classes)
code_classes(i);
}
void CgenClassTable::code_constants()
{
if (cgen_debug)
std::cerr << "\n\nEmitting constants\n";
stringtable.code_string_table(this);
}
void CgenClassTable::code_main()
{
if (cgen_debug)
std::cerr << "\n\nEmitting main\n";
auto* fn = create_function("main", i32, {},
GlobalValue::ExternalLinkage);
auto* bb = BasicBlock::Create(this->context, "main_entry_point", fn);
builder.SetInsertPoint(bb);
auto* main_new = the_module.getFunction("Main_new");
assertm(main_new, "Main_new exists");
auto* main = builder.CreateCall(main_new, {});
auto* main_main = the_module.getFunction("Main_main");
assertm(main_main, "Main_main exists");
auto* main_returned = builder.CreateCall(main_main, {main});
builder.CreateRet(builder.getInt32(0));
}
CgenNode* CgenClassTable::root()
{
auto root = this->find(Object);
if (!root) {
throw std::runtime_error("Class Object is not defined.");
}
return root;
}
Function* CgenClassTable::create_llvm_function(const std::string &funcName,
Type* retType,
ArrayRef<Type *> argTypes,
bool isVarArgs)
{
assert(retType);
auto* ft = FunctionType::get(retType, argTypes, isVarArgs);
auto* func = Function::Create(ft, Function::ExternalLinkage, funcName,
this->the_module);
if (!func) {
errs() << "Function creation failed for function " << funcName;
llvm_unreachable("Function creation failed");
}
return func;
}
Function* CgenClassTable::create_function(const std::string &name,
Type* ret_type,
ArrayRef<Type *> arg_types,
GlobalValue::LinkageTypes linkage)
{
assert(ret_type);
auto* ft = FunctionType::get(ret_type, arg_types, false);
auto* func = Function::Create(ft, linkage, name,
this->the_module);
if (!func) {
errs() << "Function creation failed for function " << name;
llvm_unreachable("Function creation failed");
}
return func;
}
Function* CgenClassTable::create_var_function(const std::string &name,
Type* ret_type,
ArrayRef<Type *> arg_types,
GlobalValue::LinkageTypes linkage)
{
assert(ret_type);
auto* ft = FunctionType::get(ret_type, arg_types, true);
auto* func = Function::Create(ft, linkage, name,
this->the_module);
if (!func) {
errs() << "Function creation failed for function " << name;
llvm_unreachable("Function creation failed");
}
return func;
}
#pragma endregion
#pragma region "stringtab"
void StrTable::code_string_table(CgenClassTable* ct)
{
if (cgen_debug)
std::cerr << "Emitting string table\n";
for (auto &[_, entry]: this->_table) {
entry.code_def(ct);
}
}
std::string StrTable::get_file() const
{
auto it = _table.cbegin();
for (int i = 0; i < _table.size() - 1; ++i)
it++;
return it->first;
}
void StringEntry::code_def(CgenClassTable* ct)
{
if (cgen_debug)
std::cerr << "\tEmitting \"" << this->str << "\"\n";
auto* string = ct->find(String);
auto* gstr = ct->builder.CreateGlobalStringPtr(this->str, "", 0, &ct->the_module);
auto* init = ConstantStruct::get(string->type, {string->vtable, gstr});
ptr = new GlobalVariable(ct->the_module, string->type, true,
GlobalValue::InternalLinkage, init);
}
void StringEntry::code_ref(CgenClassTable *ct)
{
}
void IntEntry::code_ref(CgenClassTable *ct)
{
}
#pragma endregion
#pragma region "CgenNode"
void CgenNode::setup(int const tag, int const depth)
{
if (cgen_debug)
std::cerr << "Setting up " << get_type_name() << "\n";
this->tag = tag;
auto* env = new CgenEnvironment(this);
layout_features();
this->make_vtable_type(env);
this->make_type_forrealz(env);
this->make_vtable_prototype(env);
if (cgen_debug) {
std::cerr << "\t";
this->type->print(errs(), true), errs() << "\n";
std::cerr << "\t";
this->vtable_type->print(errs(), true), errs() << "\n";
}
if (!basic())
class_table->create_function(get_init_function_name(), type->getPointerTo(), {}, GlobalValue::ExternalLinkage);
delete env;
}
void CgenNode::layout_features()
{
if (parentnd && parentnd->get_type_name() != "_no_class") {
methods.insert(methods.end(), parentnd->methods.begin(), parentnd->methods.end());
attributes.insert(attributes.end(), parentnd->attributes.begin(), parentnd->attributes.end());
}
for (int i = features->first(); features->more(i); i = features->next(i))
features->nth(i)->layout_feature(this);
}
void CgenNode::code_class()
{
if (basic())
return;
if (cgen_debug)
std::cerr << "\n\nEmitting " + get_type_name() << "\n";
auto* env = new CgenEnvironment(this);
if (cgen_debug)
std::cerr << "Emitting methods\n";
for (auto [m, _]: methods) {
if (cgen_debug)
std::cerr << "\tEmitting " << m->qualified_name << "\n";
m->code(env);
}
this->code_init_function(env);
delete env;
}
void CgenNode::code_init_function(CgenEnvironment* env) const
{
assert(type != nullptr);
assert(vtable_type != nullptr);
assert(vtable != nullptr);
if (cgen_debug)
std::cerr << "Emitting constructor " << get_init_function_name() << "\n";
auto* init = env->the_module.getFunction(get_init_function_name());
assert(init);
auto* bb = BasicBlock::Create(env->context, "constructor", init);
auto* gbb = BasicBlock::Create(env->context, "alloc_success", init);
auto* abort = env->get_or_insert_abort_block(init);
env->builder.SetInsertPoint(bb);
assert(type->isSized());
auto* heap = env->builder.CreateCall(env->the_module.getFunction("malloc"), {
ConstantInt::get(i32,
env->data_layout.getTypeAllocSize(type))
});
Value* is_nullptr = env->builder.CreateICmpEQ(heap, ConstantPointerNull::get(ptr));
env->builder.CreateCondBr(is_nullptr, abort, gbb);
env->builder.SetInsertPoint(gbb);
auto* mem = env->insert_alloca_at_head(type->getPointerTo(), "n.mem");
env->builder.CreateStore(heap, mem);
auto* hptr = env->builder.CreateLoad(type->getPointerTo(), mem, "n.hptr");
env->builder.CreateStore(vtable, env->builder.CreateStructGEP(type, hptr, 0, "n.set_vtbl"));
env->open_scope();
env->add_binding(self, mem);
for (int i = 0; i < attributes.size(); ++i) {
auto* val = attributes.at(i).first->code(env); auto* attrptr = env->builder.CreateStructGEP(type, hptr, i + 1, "n.attrptr_" + attributes.at(i).first->get_name()->get_string());
if (val == ConstantPointerNull::get(env->ptr))
env->builder.CreateStore(env->conform(env->default_value(attributes.at(i).second), env->ptr), attrptr);
else
env->builder.CreateStore(env->conform(val, env->ptr), attrptr);
}
env->close_scope();
env->builder.CreateRet(env->builder.CreateLoad(type->getPointerTo(), mem));
}
void CgenNode::make_vtable_type(CgenEnvironment *env)
{
assert(vtable_type == nullptr);
vtable_type = StructType::create(this->ctx, std::string{"_"} + name->get_string() + "_vtable");
if (cgen_debug)
std::cerr << "Creating vtable type\n";
std::vector<Type*> vtable_elems{
i32, i32,
ptr
};
for (auto [_, t] : methods)
vtable_elems.emplace_back(t->getPointerTo());
vtable_type->setBody(vtable_elems);
assert(vtable_type != nullptr);
}
void CgenNode::make_type_forrealz(CgenEnvironment *env)
{
assert(type != nullptr);
assert(vtable_type != nullptr);
std::vector<Type *> type_elems{vtable_type->getPointerTo()};
type_elems.reserve(attributes.size() + 1);
if (cgen_debug)
std::cerr << "Creating type\n";
for (auto [_, i] : attributes) {
type_elems.emplace_back(env->ptr); }
type->setBody(type_elems);
}
void CgenNode::make_vtable_prototype(CgenEnvironment *env)
{
assert(vtable_type != nullptr);
assert(vtable == nullptr);
if (cgen_debug)
std::cerr << "Emitting vtable " << get_vtable_name() << "\n";
using me = std::pair<method_class*, FunctionType*>;
auto methods = map<me, Constant*>(this->methods,
[this](me fn) -> Constant* {
auto f = this->class_table->the_module.getFunction(fn.first->qualified_name);
assertm(f, ("Couldn't find " + fn.first->qualified_name).c_str());
return f;
});
auto* str = env->builder.CreateGlobalStringPtr(get_type_name(), name->get_string() + "_str", 0, &env->the_module);
assert(type->isSized());
std::vector consts{ConstantInt::get(i32, tag), ConstantInt::get(i32,
env->data_layout.getTypeAllocSize(type)),
str,
};
consts.insert(consts.end(), methods.begin(), methods.end());
auto* cstrct = ConstantStruct::get(vtable_type, {consts});
vtable = new GlobalVariable(env->the_module, this->vtable_type, true, GlobalValue::ExternalLinkage,
cstrct, get_vtable_name());
assert(vtable != nullptr);
}
void CgenNode::make_debug_type(CgenEnvironment* env)
{
auto scope = class_table->di_cu;
auto name = get_type_name();
auto file = class_table->di_file;
auto line_num = this->name->get_index();
auto size_in_bits = env->data_layout.getTypeSizeInBits(type);
auto align_in_bits = env->data_layout.getABITypeAlign(type).value();
auto offset_in_bits = 0;
auto flags = DINode::FlagZero;
DIType* derived_from = nullptr;
if (parentnd && parentnd->get_type_name() != "_no_class")
derived_from = parentnd->dtype;
auto elements = di_builder.getOrCreateArray(dfeats);
this->dtype = di_builder.createClassType(scope, name, file, line_num,
size_in_bits, align_in_bits, offset_in_bits, flags, derived_from,
elements);
}
void CgenNode::premake_debug_type()
{
auto scope = class_table->di_cu;
auto name = get_type_name();
auto file = class_table->di_file;
auto line_num = this->name->get_index();
auto size_in_bits = 0;
auto align_in_bits = 0;
auto offset_in_bits = 0;
auto flags = DINode::FlagZero;
DIType* derived_from = nullptr;
auto elements = di_builder.getOrCreateArray(dfeats);
this->dtype = di_builder.createClassType(scope, name, file, line_num,
size_in_bits, align_in_bits, offset_in_bits, flags, derived_from,
elements);
}
#pragma endregion
#pragma region "CgenEvironment"
CgenNode* CgenEnvironment::type_to_class(Symbol t) const
{
return t == SELF_TYPE
? get_class()
: get_class()->get_classtable()->find_in_scopes(t);
}
BasicBlock* CgenEnvironment::get_or_insert_abort_block(Function* f)
{
for (auto &bb: *f) {
if (bb.getName() == "abort") {
return &bb;
}
}
auto* abort_bb = BasicBlock::Create(this->context, "abort", f);
Type* void_ = Type::getVoidTy(this->context);
IRBuilder<> builder(abort_bb);
FunctionCallee abort = this->the_module.getOrInsertFunction("abort", void_);
builder.CreateCall(abort, {});
builder.CreateUnreachable();
return abort_bb;
}
std::optional<Value*> CgenEnvironment::find_if_exists(Symbol name) const
{
if (auto* f = vars.find_in_scopes(name)) {
return std::make_optional(f);
}
return std::nullopt;
}
std::pair<Type*, Value*> CgenEnvironment::find_in_scopes(Symbol name) const
{
auto val = find_if_exists(name);
assertm(val, ("Variable " + name->get_string() + " not found").c_str());
return resolve_opaque(*val);
}
AllocaInst* CgenEnvironment::insert_alloca_at_head(Type* ty)
{
BasicBlock &entry_bb = builder.GetInsertBlock()->getParent()->
getEntryBlock();
if (entry_bb.empty()) {
return new AllocaInst(ty, 0, "", &entry_bb);
} else {
return new AllocaInst(ty, 0, "", &entry_bb.front());
}
}
AllocaInst* CgenEnvironment::insert_alloca_at_head(Type* ty, Twine const &msg)
{
assert(builder.GetInsertBlock());
BasicBlock &entry_bb = builder.GetInsertBlock()->getParent()->
getEntryBlock();
if (entry_bb.empty()) {
return new AllocaInst(ty, 0, msg, &entry_bb);
} else {
return new AllocaInst(ty, 0, msg, &entry_bb.front());
}
}
Type* CgenEnvironment::as_type(Symbol const s) const
{
auto const _s = as_string(s);
if (_s == "Int" || _s == "int" ) return i32;
if (_s == "Bool" || _s == "bool" ) return i1;
if (_s == "sbyte*" ) return ptr;
return this->type_to_class(s)->type;
}
Type* CgenEnvironment::as_mostly_boxed_type(Symbol const s) const
{
auto const _s = as_string(s);
if (_s == "Int" || _s == "int" ) return i32;
if (_s == "Bool" || _s == "bool" ) return i1;
return ptr;
}
DIType* CgenEnvironment::as_boxed_dtype(Symbol s) const
{
auto const _s = as_string(s);
return class_table.dptr;
}
Value* CgenEnvironment::default_value(Type* ty) const
{
if (ty->isIntegerTy())
switch (ty->getIntegerBitWidth()) {
case 1: return builder.getFalse();
case 32: return builder.getInt32(0);
default: llvm_unreachable(
"Unhandled integer bit with");
}
if (ty->isStructTy() && ty->getStructName() == "String")
return builder.CreateGlobalString("");
return ConstantPointerNull::get(ptr);
}
Value* CgenEnvironment::conform(Value* src, Type* dest_type)
{
Type* src_type = src->getType();
if (src_type == dest_type)
return src;
if (src_type->isPointerTy() && dest_type->isPointerTy())
return src;
if (src_type->isIntegerTy() && dest_type->isIntegerTy()) {
return builder.CreateZExtOrTrunc(src, dest_type);
}
if (src_type->isIntegerTy() && dest_type->isPointerTy()) {
switch (src_type->getIntegerBitWidth()) {
case 1: {
auto* bool_new = the_module.getFunction("Bool_new");
assert(bool_new);
auto* bool_init = the_module.getFunction("Bool_init");
assert(bool_init);
auto* r = insert_alloca_at_head(ptr, "box.i1");
auto* b = builder.CreateCall(bool_new->getFunctionType(), bool_new, {});
builder.CreateStore(b, r);
auto* c = builder.CreateZExt(src, i8);
auto* bptr1 = builder.CreateLoad(ptr, r);
builder.CreateCall(bool_init->getFunctionType(), bool_init, {bptr1, c});
return builder.CreateLoad(ptr, r, "boxed.i1");
}
case 32: {
auto* int_new = the_module.getFunction("Int_new");
assert(int_new);
auto* int_init = the_module.getFunction("Int_init");
assert(int_init);
auto* r = insert_alloca_at_head(ptr, "box.i32");
auto* b = builder.CreateCall(int_new->getFunctionType(), int_new, {});
builder.CreateStore(b, r);
auto* iptr1 = builder.CreateLoad(ptr, r);
builder.CreateCall(int_init->getFunctionType(), int_init, {iptr1, src});
return builder.CreateLoad(ptr, r, "boxed.i32");
}
default: llvm_unreachable("Unsupported integer width to conform to");
}
}
if (src_type->isPointerTy() && dest_type->isIntegerTy()) {
auto* ptr = builder.CreateStructGEP(type_to_class(Int)->type, src, 1, "unboxedptr");
return builder.CreateLoad(dest_type, ptr, "unboxed");
}
errs() << "Source ty: ", src_type->print(errs(), true), errs() << "\n";
errs() << "Dest ty: ", dest_type->print(errs(), true), errs() << "\n";
llvm_unreachable("Couldn't conform types");
}
#pragma endregion
void program_class::cgen(const std::optional<std::string> &outfile)
{
initialize_constants();
class_table = new CgenClassTable(classes);
if (outfile) {
std::error_code err;
raw_fd_ostream s(*outfile, err, sys::fs::FA_Write);
if (err) {
std::cerr << "Cannot open output file " << *outfile << std::endl;
exit(1);
}
s << class_table->the_module;
} else {
outs() << class_table->the_module;
}
}
Value* method_class::code(CgenEnvironment* env)
{
if (env->get_class()->get_type_name() != split(qualified_name, '_').first)
return nullptr;
if (cgen_debug) {
std::cerr << "\t\tmethod" << std::endl;
}
env->open_scope();
auto* bb = BasicBlock::Create(env->context, "entry", fn);
env->builder.SetInsertPoint(bb);
assert(fn->arg_size() == formals->len() + 1);
for (auto* arg = fn->arg_begin(); arg != fn->arg_end(); ++arg) {
int idx = arg->getArgNo();
auto* arg_ptr = env->insert_alloca_at_head(arg->getType());
env->builder.CreateStore(arg, arg_ptr);
if (0 == idx) {
arg->setName("self");
env->add_binding(self, arg_ptr);
} else {
auto* name = formals->nth(idx - 1)->get_name();
arg->setName(name->get_string());
env->add_binding(name, arg_ptr);
}
}
env->open_scope(); Value* val = expr->code(env);
env->builder.CreateRet(env->conform(val, fn->getFunctionType()->getReturnType()));
env->close_scope();
env->close_scope();
return fn;
}
Value* assign_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tassign" << std::endl;
Value* r = expr->code(env);
if (auto ptr = env->find_if_exists(name)) {
auto [ty, val] = resolve_opaque(*ptr);
env->builder.CreateStore(env->conform(r, ty), val, "a.local");
return r;
}
assert(env->get_class()->type->getNumElements() > 1);
auto attrs = env->get_class()->attributes;
for (int i = 0; i < attrs.size(); ++i)
if (attrs.at(i).first->get_name() == name) {
auto [ty, val] = env->find_in_scopes(self);
auto* self = env->builder.CreateLoad(ty, val, "a.self");
auto v = env->builder.CreateStructGEP(env->get_class()->type, self, 1 + i, "a.attrptr");
auto x = env->builder.CreateStore(env->conform(r, env->ptr), v, "a.attr");
return r;
}
llvm_unreachable(("Couldn't assign to " + name->get_string() + ", reference not found").c_str());
}
Value* cond_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tcond" << std::endl;
auto* res = env->insert_alloca_at_head(env->as_mostly_boxed_type(type), "cond");
BasicBlock* startbb = env->builder.GetInsertBlock();
Function* fn = startbb->getParent();
auto* truebb = BasicBlock::Create(env->context, "true", fn);
auto* falsebb = BasicBlock::Create(env->context, "false", fn);
auto* mergebb = BasicBlock::Create(env->context, "merge", fn);
env->builder.SetInsertPoint(startbb);
Value* cond = env->conform(pred->code(env), env->i1);
env->builder.CreateCondBr(cond, truebb, falsebb);
env->builder.SetInsertPoint(truebb);
env->builder.CreateStore(then_exp->code(env), res);
env->builder.CreateBr(mergebb);
env->builder.SetInsertPoint(falsebb);
env->builder.CreateStore(else_exp->code(env), res);
env->builder.CreateBr(mergebb);
env->builder.SetInsertPoint(mergebb);
return env->builder.CreateLoad(res->getAllocatedType(), res);
}
Value* loop_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tloop" << std::endl;
BasicBlock* startbb = env->builder.GetInsertBlock();
Function* fn = startbb->getParent();
auto* condbb = BasicBlock::Create(env->context, "conditional", fn);
auto* loopbb = BasicBlock::Create(env->context, "loop", fn);
auto* endbb = BasicBlock::Create(env->context, "end", fn);
env->builder.SetInsertPoint(startbb);
env->builder.CreateBr(condbb);
env->builder.SetInsertPoint(condbb);
Value* cond = env->conform(pred->code(env), env->i1);
env->builder.CreateCondBr(cond, loopbb, endbb);
env->builder.SetInsertPoint(loopbb);
body->code(env);
env->builder.CreateBr(condbb);
env->builder.SetInsertPoint(endbb);
return ConstantPointerNull::get(env->ptr);
}
Value* block_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tblock" << std::endl;
return map<Expression, Value *>(unfuck(body),
[env](Expression const &e) -> Value* {
return e->code(env);
}).back();
}
Value* let_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\tlet" << std::endl;
auto* ty = env->as_mostly_boxed_type(type_decl);
auto* var_ptr = env->insert_alloca_at_head(ty, "let");
Value* initial_val = init->code(env);
if (!ConstantPointerNull::classof(initial_val))
env->builder.CreateStore(initial_val, var_ptr);
else env->builder.CreateStore(env->default_value(ty), var_ptr);
env->open_scope();
env->add_binding(identifier, var_ptr);
Value* r = body->code(env);
env->close_scope();
return r;
}
Value* plus_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tplus" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateAdd(r1, r2, "add");
}
Value* sub_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tsub" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateSub(r1, r2, "sub");
}
Value* mul_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tmul" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateMul(r1, r2, "mul");
}
Value* divide_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tdiv" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
auto* curbb = env->builder.GetInsertBlock();
auto* div = BasicBlock::Create(env->context, "div", curbb->getParent());
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
env->builder.SetInsertPoint(curbb);
Value* is_zero = env->builder.CreateICmpEQ(env->builder.getInt32(0), r2);
env->builder.CreateCondBr(is_zero, abort, div);
env->builder.SetInsertPoint(div);
return env->builder.CreateSDiv(r1, r2, "div");
}
Value* neg_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tneg" << std::endl;
Value* r = env->conform(e1->code(env), env->i32);
return env->builder.CreateNeg(r, "neg");
}
Value* lt_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tlt" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateICmpSLT(r1, r2, "cmpl");
}
Value* eq_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\teq" << std::endl;
Value* r1 = e1->code(env);
Value* r2 = e2->code(env);
if (env->as_type(e1->get_type())->isIntegerTy() || env->as_type(e2->get_type())->isIntegerTy())
return env->builder.CreateICmpEQ(env->conform(r1, env->i32), env->conform(r2, env->i32));
return env->builder.CreateICmpEQ(r1, r2, "eq");
}
Value* leq_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tleq" << std::endl;
Value* r1 = env->conform(e1->code(env), env->i32);
Value* r2 = env->conform(e2->code(env), env->i32);
return env->builder.CreateICmpSLE(r1, r2, "leq");
}
Value* comp_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tcomplement" << std::endl;
Value* r = env->conform(e1->code(env), env->i1); return env->builder.CreateNot(r, "comp");
}
Value* int_const_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tint_const" << std::endl;
return env->builder.getInt32((uint32_t) std::stol(token->get_string()));
}
Value* bool_const_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tbool_const" << std::endl;
return env->builder.getInt1(this->val);
}
Value* object_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tobject" << std::endl;
if (auto f = env->find_if_exists(name)) {
auto [ty, val] = resolve_opaque(*f);
return env->builder.CreateLoad(ty, val, "o.local_" + name->get_string());
}
assert(env->get_class()->type->getNumElements() > 1);
auto attrs = env->get_class()->attributes;
for (int i = 0; i < attrs.size(); ++i)
if (attrs.at(i).first->get_name() == name) {
auto [ty, val] = env->find_in_scopes(self);
auto* self = env->builder.CreateLoad(ty, val, "o.self");
auto v = env->builder.CreateStructGEP(env->get_class()->type, self, 1 + i, "o.attrptr_" + name->get_string());
auto r = env->builder.CreateLoad(env->ptr, v, "o.attr_" + name->get_string());
return r;
}
llvm_unreachable(("Couldn't resolve a reference to " + name->get_string()).c_str());
}
Value* no_expr_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tno expr" << std::endl;
return ConstantPointerNull::get(env->ptr);
}
Value* static_dispatch_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tstatic dispatch" << std::endl;
auto args = map<Expression, Value*>(unfuck(actual), [env](Expression const& e) -> Value* {
return e->code(env);
});
auto* caller_class = env->type_to_class(type_name);
auto* caller = expr->code(env);
if (caller->getType()->isIntegerTy()) {
auto* orig = caller;
caller = env->conform(orig, env->ptr);
}
assert(caller->getType()->isPointerTy());
if (cgen_debug)
errs() << "\t\t\tLooking for " << as_string(name) << "\n";
auto get_method_idx = [](CgenNode* cls, Symbol name) -> int {
auto methods = cls->methods;
for (int i = methods.size() - 1; i > 0; --i) {
if (methods.at(i).first->get_name() == name) {
return i;
}
}
llvm_unreachable(("Couldn't find " + as_string(name) + " in " + as_string(cls->get_name())).c_str());
};
int method_idx = get_method_idx(caller_class, name);
auto n = as_string(name);
auto* curbb = env->builder.GetInsertBlock();
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
auto* validbb = BasicBlock::Create(env->context, "sdispatch_" + n, curbb->getParent());
env->builder.SetInsertPoint(curbb);
Value* is_nullptr = env->builder.CreateICmpEQ(caller, ConstantPointerNull::get(env->ptr));
env->builder.CreateCondBr(is_nullptr, abort, validbb);
env->builder.SetInsertPoint(validbb);
auto* method_ty = caller_class->methods.at(method_idx).second;
Value* method_ptr = env->builder.CreateStructGEP(caller_class->vtable_type,
caller_class->vtable, method_idx + 3, "sd.mptr"); auto* method = env->builder.CreateLoad(method_ty->getPointerTo(), method_ptr, "sd." + n);
std::vector real_args{caller};
real_args.reserve(1 + args.size());
for (int i = 0; i < args.size(); ++i) { real_args.emplace_back(env->conform(args.at(i), method_ty->getParamType(i + 1)));
}
return env->builder.CreateCall(method_ty, method, real_args);
}
Value* string_const_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tstring_const" << std::endl;
auto* e = stringtable.lookup_string(as_string(token));
auto* global = reinterpret_cast<StringEntry*>(e)->ptr;
return global;
}
Value* dispatch_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tdispatch\n" << std::endl;
auto args = map<Expression, Value*>(unfuck(actual), [env](Expression const& e) -> Value* {
return e->code(env);
});
auto* caller_class = env->type_to_class(expr->get_type());
Value* caller = expr->code(env);
if (caller->getType()->isIntegerTy()) {
auto* orig = caller;
caller = env->conform(orig, env->ptr);
}
assert(caller->getType()->isPointerTy());
if (cgen_debug)
errs() << "\t\t\tLooking for " << as_string(name) << "\n";
auto get_method_idx = [](CgenNode* cls, Symbol name) -> int {
auto methods = cls->methods;
for (int i = methods.size() - 1; i >= 0; --i) {
if (methods.at(i).first->get_name() == name) {
return i;
}
}
llvm_unreachable(("Couldn't find " + as_string(name) + " in " + as_string(cls->get_name())).c_str());
};
int method_idx = get_method_idx(caller_class, name);
auto n = as_string(name);
auto* curbb = env->builder.GetInsertBlock();
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
auto* validbb = BasicBlock::Create(env->context, "dispatch_" + n, curbb->getParent());
env->builder.SetInsertPoint(curbb);
Value* is_nullptr = env->builder.CreateICmpEQ(caller, ConstantPointerNull::get(env->ptr));
env->builder.CreateCondBr(is_nullptr, abort, validbb);
env->builder.SetInsertPoint(validbb);
auto* vtable_ptr = env->builder.CreateStructGEP(caller_class->type, caller, 0, "d.vtblptr");
auto* vtable = env->builder.CreateLoad(env->ptr, vtable_ptr, "d.vtbl");
auto* method_ty = caller_class->methods.at(method_idx).second;
Value* method_ptr = env->builder.CreateStructGEP(caller_class->vtable_type,
vtable, method_idx + 3, "d.mptr"); auto* method = env->builder.CreateLoad(method_ty->getPointerTo(), method_ptr, "d." + n);
std::vector real_args{caller};
real_args.reserve(1 + args.size());
for (int i = 0; i < args.size(); ++i) { real_args.emplace_back(env->conform(args.at(i), method_ty->getParamType(i + 1)));
assert(real_args.at(i + 1)->getType() == method_ty->getParamType(i + 1));
}
assert(real_args.size() == method_ty->getNumParams());
if (cgen_debug)
errs() << "\t\tend dispatch\n";
return env->builder.CreateCall(method_ty, method, real_args);
}
Value* typcase_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\ttype case" << std::endl;
auto e_class = env->type_to_class(expr->get_type());
auto sumty = env->type_to_class(type);
Value* e = expr->code(env);
if (e->getType()->isIntegerTy()) {
auto* orig = e;
e = env->conform(orig, env->ptr);
}
assert(e->getType()->isPointerTy());
auto* curbb = env->builder.GetInsertBlock();
auto* abort = env->get_or_insert_abort_block(curbb->getParent());
auto* goodbb = BasicBlock::Create(env->context, "typcase.good", curbb->getParent());
auto* matchbb = BasicBlock::Create(env->context, "typcase.match", curbb->getParent());
auto* resbb = BasicBlock::Create(env->context, "typcase.result", curbb->getParent());
env->builder.SetInsertPoint(curbb);
auto* test = env->builder.CreateICmpEQ(e, ConstantPointerNull::get(env->ptr), "typcase.isvoid");
env->builder.CreateCondBr(test, abort, goodbb);
env->builder.SetInsertPoint(goodbb);
auto* vtable_ptr = env->builder.CreateStructGEP(e_class->type, e, 0, "typcase.vtblptr");
auto* vtable = env->builder.CreateLoad(env->ptr, vtable_ptr, "typcase.vtbl");
auto* tag_ptr = env->builder.CreateStructGEP(e_class->vtable_type, vtable, 0, "typcase.tagptr");
auto* tag = env->builder.CreateLoad(env->i32, tag_ptr, "typcase.tag");
auto* res = env->insert_alloca_at_head(env->ptr);
env->builder.CreateStore(ConstantPointerNull::get(env->ptr), res);
std::vector<Case> branches;
branches.reserve(cases->len());
for (auto c: cases) {
branches.emplace_back(c);
}
std::sort(branches.begin(), branches.end(), [env](Case a, Case b) {
return env->type_to_class(a->get_type_decl())->get_tag() > env->type_to_class(b->get_type_decl())->get_tag();
});
std::for_each(branches.begin(), branches.end(), [env, e, tag, res, matchbb](Case c) {
c->code(e, tag, res, matchbb, env);
});
env->builder.CreateBr(abort);
env->builder.SetInsertPoint(matchbb);
auto* r = env->builder.CreateLoad(env->ptr, res, "typcase.res");
auto* test_res = env->builder.CreateICmpEQ(r, ConstantPointerNull::get(env->ptr), "typcase.res.isvoid");
env->builder.CreateCondBr(test_res, abort, resbb);
env->builder.SetInsertPoint(resbb);
return r;
}
Value* new__class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tnew" << std::endl;
auto init = env->type_to_class(type_name)->get_init_function_name();
auto* initfn = env->the_module.getFunction(init);
assert(initfn);
return env->builder.CreateCall(initfn->getFunctionType(), initfn, {});
}
Value* isvoid_class::code(CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tisvoid" << std::endl;
Value* e = e1->code(env);
if (e->getType()->isIntegerTy())
return env->builder.getTrue();
assert(e->getType()->isPointerTy());
auto* ret = env->insert_alloca_at_head(env->i1);
auto* curbb = env->builder.GetInsertBlock();
auto* truebb = BasicBlock::Create(env->context, "isvoid.true", curbb->getParent());
auto* falsebb = BasicBlock::Create(env->context, "isvoid.false", curbb->getParent());
auto* mergebb = BasicBlock::Create(env->context, "isvoid.result", curbb->getParent());
env->builder.SetInsertPoint(curbb);
auto* test = env->builder.CreateICmpEQ(e, ConstantPointerNull::get(env->ptr), "isvoid");
env->builder.CreateCondBr(test, truebb, falsebb);
env->builder.SetInsertPoint(truebb);
env->builder.CreateStore(env->builder.getTrue(), ret);
env->builder.CreateBr(mergebb);
env->builder.SetInsertPoint(falsebb);
env->builder.CreateStore(env->builder.getFalse(), ret);
env->builder.CreateBr(mergebb);
env->builder.SetInsertPoint(mergebb);
return env->builder.CreateLoad(env->i1, ret);
}
void method_class::layout_feature(CgenNode* cls)
{
auto* env = new CgenEnvironment(cls);
assert(qualified_name.empty());
qualified_name = cls->get_type_name() + "_" + this->get_name()->get_string();
std::vector<Type*> real_args;
real_args.reserve(formals->len() + 1);
real_args.emplace_back(env->ptr); auto _formals = unfuck(formals);
auto args = map<Formal, Type *>(_formals,
[env](Formal const &f) -> Type* {
return env->as_mostly_boxed_type(f->get_type_decl());
});
real_args.insert(real_args.end(), args.begin(), args.end());
auto* ty = CgenNode::create_functionty(env->as_mostly_boxed_type(return_type), real_args);
fn = cls->create_function(as_string(get_name()), ty);
#ifdef EMIT_DBG
if (!cls->basic()) {
std::vector<Metadata*> dtys;
dtys.emplace_back(env->as_boxed_dtype(return_type));
for (auto f: _formals)
dtys.emplace_back(env->as_boxed_dtype(f->get_type_decl()));
auto dty = cls->di_builder.createSubroutineType(cls->di_builder.getOrCreateTypeArray(dtys));
auto dfn = cls->di_builder.createFunction(env->class_table.di_cu, this->get_name()->get_string(), cls->get_type_name() + "_" + this->get_name()->get_string(), env->class_table.di_file, this->get_name()->get_index(), dty,this->get_name()->get_index(), DINode::FlagPrototyped, DISubprogram::SPFlagDefinition);
fn->setSubprogram(dfn);
cls->dfeats.emplace_back(dfn);
}
#endif
cls->methods.emplace_back(this, ty);
delete env;
}
void branch_class::code(Value* expr_val, Value* tag, Value* mem, BasicBlock* sbb, CgenEnvironment* env)
{
if (cgen_debug)
std::cerr << "\t\tbranch\n";
auto cls = env->type_to_class(type_decl);
int start_tag = cls->get_tag();
int end_tag = cls->get_max_child();
auto* curbb = env->builder.GetInsertBlock();
auto* maxbb = BasicBlock::Create(env->context, "typcase.br.match.max." + name->get_string(), curbb->getParent());
auto* minbb = BasicBlock::Create(env->context, "typcase.br.match.min." + name->get_string(), curbb->getParent());
auto* endbb = BasicBlock::Create(env->context, "typcase.br.nomatch." + name->get_string(), curbb->getParent());
env->builder.SetInsertPoint(curbb);
auto* mintest = env->builder.CreateICmpSGE(tag, ConstantInt::get(env->i32, start_tag, true), "typcase.br.min." + name->get_string());
env->builder.CreateCondBr(mintest, minbb, endbb);
env->builder.SetInsertPoint(minbb);
auto* maxtest = env->builder.CreateICmpSLE(tag, ConstantInt::get(env->i32, end_tag, true), "typcase.br.max." + name->get_string());
env->builder.CreateCondBr(maxtest, maxbb, endbb);
env->builder.SetInsertPoint(maxbb);
auto* branchptr = env->insert_alloca_at_head(env->ptr);
env->builder.CreateStore(expr_val, branchptr);
env->open_scope(); env->add_binding(name, branchptr);
auto* res = expr->code(env);
env->close_scope();
env->builder.CreateStore(res, mem);
env->builder.CreateBr(sbb);
env->builder.SetInsertPoint(endbb);
}
void attr_class::layout_feature(CgenNode* cls)
{
auto* env = new CgenEnvironment(cls);
auto ty = env->as_mostly_boxed_type(type_decl);
cls->attributes.emplace_back(this, ty);
#ifdef EMIT_DBG
cls->dfeats.emplace_back(env->as_boxed_dtype(type_decl));
#endif
delete env;
}
Value* attr_class::code(CgenEnvironment* env)
{
val = init->code(env);
return val;
}
#pragma region "utils"
namespace
{
std::string as_string(Symbol const s)
{
return s->get_string();
}
std::vector<Expression> unfuck(Expressions const fuck_this)
{
std::vector<Expression> r{};
r.reserve(fuck_this->len());
for (int i = fuck_this->first(); fuck_this->more(i); i = fuck_this->next(i))
r.push_back(fuck_this->nth(i));
return r;
}
std::vector<Formal> unfuck(Formals const fuck_this)
{
std::vector<Formal> r{};
r.reserve(fuck_this->len());
for (int i = fuck_this->first(); fuck_this->more(i); i = fuck_this->next(i))
r.push_back(fuck_this->nth(i));
return r;
}
std::vector<Feature> unfuck(Features const fuck_this)
{
std::vector<Feature> r{};
r.reserve(fuck_this->len());
for (int i = fuck_this->first(); fuck_this->more(i); i = fuck_this->next(i))
r.push_back(fuck_this->nth(i));
return r;
}
std::pair<Type*, Value*> resolve_opaque(Value* val)
{
if (auto* a = dyn_cast<AllocaInst>(val))
return {a->getAllocatedType(), val};
if (auto* g = dyn_cast<GlobalVariable>(val))
return {g->getValueType(), val};
if (auto* s = dyn_cast<GetElementPtrInst>(val))
return {s->getSourceElementType(), val};
errs() << "Unresolved opaque value: ", val->print(errs(), true), errs() << "\n";
llvm_unreachable("couldn't get original type for value");
}
template<class T, class R>
std::vector<R> map(std::vector<T> src, std::function<R(T const &)> mapper)
{
std::vector<R> r{};
r.reserve(src.size());
for (auto i: src)
r.emplace_back(mapper(i));
return r;
}
std::pair<std::string, std::string> split(const std::string& s, char const c)
{
size_t pos = s.find(c);
if (pos == std::string::npos)
return {s, ""};
return {s.substr(0, pos), s.substr(pos + 1)};
}
}
#pragma endregion