Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/thorin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ if(LLVM_FOUND)
be/llvm/runtime.cpp
be/llvm/runtime.h
be/llvm/vectorize.cpp
be/llvm/debug.cpp
)
endif()

Expand Down
4 changes: 2 additions & 2 deletions src/thorin/be/c/c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1451,8 +1451,8 @@ std::string CCodeGen::emit_fun_decl(Continuation* cont) {
}

Stream& CCodeGen::emit_debug_info(Stream& s, const Def* def) {
if (debug_ && !def->loc().file.empty())
return s.fmt("#line {} \"{}\"\n", def->loc().begin.row, def->loc().file);
if (debug_ && def->loc())
return s.fmt("#line {} \"{}\"\n", def->loc()->begin.row, def->loc()->file);
return s;
}

Expand Down
1 change: 0 additions & 1 deletion src/thorin/be/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class CodeGen {
//@{
Thorin& thorin() const { return thorin_; }
World& world() const { return thorin().world(); }
bool debug() const { return debug_; }
//@}

private:
Expand Down
128 changes: 128 additions & 0 deletions src/thorin/be/llvm/debug.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include "llvm.h"

#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/DIBuilder.h>
#include <llvm/DebugInfo/DWARF/DWARFTypeUnit.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/Host.h>

namespace thorin::llvm {

CodeGen::Debug::Debug(thorin::llvm::CodeGen& cg) : cg_(cg), dibuilder_(cg.module()) {}

void CodeGen::Debug::emit_module() {
cg_.module().addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
// Darwin only supports dwarf2
if (llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin())
cg_.module().addModuleFlag(llvm::Module::Warning, "Dwarf Version", 2);
dicompile_unit_ = dibuilder_.createCompileUnit(llvm::dwarf::DW_LANG_C, dibuilder_.createFile(cg_.world().name(), llvm::StringRef()), "Impala", cg_.opt() > 0, llvm::StringRef(), 0);
}

void CodeGen::Debug::prepare(const thorin::Scope& scope, llvm::Function* fct) {
if (auto loc = scope.entry()->debug().loc) {
auto difile = get_difile(loc->file);
auto disub_program = dibuilder_.createFunction(
discope_, fct->getName(), fct->getName(), difile, loc->begin.row,
dibuilder_.createSubroutineType(dibuilder_.getOrCreateTypeArray(llvm::ArrayRef<llvm::Metadata*>())),
loc->begin.row,
llvm::DINode::FlagPrototyped,
llvm::DISubprogram::SPFlagDefinition | (cg_.opt() > 0 ? llvm::DISubprogram::SPFlagOptimized : llvm::DISubprogram::SPFlagZero));
fct->setSubprogram(disub_program);
discope_ = disub_program;
} else {
discope_ = dicompile_unit_;
}
}

void CodeGen::Debug::prepare(llvm::IRBuilder<>& irbuilder, const thorin::Continuation* cont) {
if (auto loc = cont->debug().loc)
irbuilder.SetCurrentDebugLocation(llvm::DILocation::get(discope_->getContext(), loc->begin.row, loc->begin.col, discope_));
}

void CodeGen::Debug::prepare(llvm::IRBuilder<>& irbuilder, const thorin::Def* def) {
if (auto loc = def->debug().loc)
irbuilder.SetCurrentDebugLocation(llvm::DILocation::get(discope_->getContext(), loc->begin.row, loc->begin.col, discope_));
}

void CodeGen::Debug::finalize(const thorin::Def* def, llvm::Value* val) {
val->setName(def->unique_name());
}

void CodeGen::Debug::register_param(const Param* param, int index, llvm::Value* val) {
if (!param->type()->isa<PrimType>())
return;
if (auto loc = param->debug().loc; loc) {
llvm::DIFile* file = get_difile(loc->file);
auto local_var = dibuilder_.createParameterVariable(discope_, param->name(), index, file, loc->begin.row, get_ditype(param->type(), *loc));
dibuilder_.insertDbgValueIntrinsic(val, local_var, llvm::DIExpression::get(cg_.context(), {}), get_dilocation(*loc, discope_), cg_.cont2bb(param->continuation()));
}
}

llvm::DIFile* CodeGen::Debug::get_difile(const std::string& file) {
auto src_file = llvm::sys::path::filename(file);
auto src_dir = llvm::sys::path::parent_path(file);
return dibuilder_.createFile(src_file, src_dir);
}

llvm::DILocation* CodeGen::Debug::get_dilocation(const thorin::Loc& loc, llvm::DIScope* discope) {
return llvm::DILocation::get(cg_.context(), loc.begin.row, loc.begin.col, discope);
}

llvm::DIType* CodeGen::Debug::get_ditype(const thorin::Type* t, Loc loc) {
if (auto found = types_.lookup(t))
return *found;

// If the type comes with its own debug info, let's use that instead!
if (t->debug().loc)
loc = *t->debug().loc;

using namespace llvm::dwarf;

if (auto prim_type = t->isa<PrimType>()) {
switch (prim_type->primtype_tag()) {
case PrimType_bool: return types_[t] = dibuilder_.createBasicType("bool", 1, DW_ATE_boolean);
case PrimType_ps8: case PrimType_qs8: case PrimType_pu8: case PrimType_qu8: return types_[t] = dibuilder_.createBasicType("bool", 8, is_type_s(prim_type) ? DW_ATE_signed_char : DW_ATE_unsigned_char);
case PrimType_ps16: case PrimType_qs16: case PrimType_pu16: case PrimType_qu16: return types_[t] = dibuilder_.createBasicType("bool", 16, is_type_s(prim_type) ? DW_ATE_signed : DW_ATE_unsigned);
case PrimType_ps32: case PrimType_qs32: case PrimType_pu32: case PrimType_qu32: return types_[t] = dibuilder_.createBasicType("bool", 32, is_type_s(prim_type) ? DW_ATE_signed : DW_ATE_unsigned);
case PrimType_ps64: case PrimType_qs64: case PrimType_pu64: case PrimType_qu64: return types_[t] = dibuilder_.createBasicType("bool", 64, is_type_s(prim_type) ? DW_ATE_signed : DW_ATE_unsigned);
case PrimType_pf16: case PrimType_qf16: return types_[t] = dibuilder_.createBasicType("bool", 16, DW_ATE_float);
case PrimType_pf32: case PrimType_qf32: return types_[t] = dibuilder_.createBasicType("bool", 32, DW_ATE_float);
case PrimType_pf64: case PrimType_qf64: return types_[t] = dibuilder_.createBasicType("bool", 64, DW_ATE_float);
}
} else if (auto ptr_t = t->isa<PtrType>()) {
return types_[t] = dibuilder_.createPointerType(get_ditype(ptr_t->pointee(), loc), cg_.machine_->getPointerSize(static_cast<unsigned int>(ptr_t->addr_space())));
} else if (auto fun_t = t->isa<FnType>()) {

} else if (auto agg_t = t->isa<StructType>()) {
types_[t] = dibuilder_.createForwardDecl(DW_TAG_structure_type, agg_t->name().str(), dicompile_unit_, get_difile(loc.file), loc.begin.row);
auto data_layout = cg_.module().getDataLayout();
auto layout_t = data_layout.getStructLayout(llvm::cast<llvm::StructType>(cg_.convert(t)));
std::vector<llvm::Metadata*> members;
size_t i = 0;
for (auto member_t : agg_t->types()) {
auto member_di = get_ditype(member_t, loc);
auto member_llvm_t = cg_.convert(member_t);
auto derived = dibuilder_.createMemberType(dicompile_unit_, agg_t->op_name(i).str(), get_difile(loc.file), loc.begin.row,
data_layout.getTypeSizeInBits(member_llvm_t),
data_layout.getABITypeAlign(member_llvm_t).value(),
layout_t->getElementOffsetInBits(i),
llvm::DINode::DIFlags::FlagZero,
member_di);
i++;
}
return types_[t] = dibuilder_.createStructType(dicompile_unit_, agg_t->name().str(), get_difile(loc.file), loc.begin.row,
layout_t->getSizeInBits(),
layout_t->getAlignment().value(),
llvm::DINode::DIFlags::FlagZero,
nullptr,
dibuilder_.getOrCreateArray(members));
}

assert(false);
}

void CodeGen::Debug::finalize() {
dibuilder_.finalize();
}

}
58 changes: 23 additions & 35 deletions src/thorin/be/llvm/llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <llvm/IR/Verifier.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Transforms/Scalar.h>
Expand Down Expand Up @@ -51,7 +50,7 @@ CodeGen::CodeGen(
, context_(std::make_unique<llvm::LLVMContext>())
, module_(std::make_unique<llvm::Module>(world().name(), context()))
, opt_(opt)
, dibuilder_(module())
, debug_(debug ? std::make_optional<Debug>(*this) : std::nullopt)
, function_calling_convention_(function_calling_convention)
, device_calling_convention_(device_calling_convention)
, kernel_calling_convention_(kernel_calling_convention)
Expand Down Expand Up @@ -295,13 +294,7 @@ void CodeGen::emit_stream(std::ostream& stream) {

std::pair<std::unique_ptr<llvm::LLVMContext>, std::unique_ptr<llvm::Module>>
CodeGen::emit_module() {
if (debug()) {
module().addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION);
// Darwin only supports dwarf2
if (llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin())
module().addModuleFlag(llvm::Module::Warning, "Dwarf Version", 2);
dicompile_unit_ = dibuilder_.createCompileUnit(llvm::dwarf::DW_LANG_C, dibuilder_.createFile(world().name(), llvm::StringRef()), "Impala", opt() > 0, llvm::StringRef(), 0);
}
if (debug_) debug_->emit_module();

for (auto&& [_, def] : world().externals()) {
if (auto global = def->isa<Global>()) {
Expand All @@ -319,7 +312,7 @@ CodeGen::emit_module() {
emit_scope(scope, forest);
});

if (debug()) dibuilder_.finalize();
if (debug_) debug_->finalize();

#if THORIN_ENABLE_RV
for (auto [width, fct, call] : vec_todo_)
Expand Down Expand Up @@ -380,21 +373,7 @@ llvm::Function* CodeGen::emit_fun_decl(Continuation* continuation) {
llvm::Function* CodeGen::prepare(const Scope& scope) {
auto fct = llvm::cast<llvm::Function>(emit(scope.entry()));

discope_ = dicompile_unit_;
if (debug()) {
auto file = entry_->loc().file;
auto src_file = llvm::sys::path::filename(file);
auto src_dir = llvm::sys::path::parent_path(file);
auto difile = dibuilder_.createFile(src_file, src_dir);
auto disub_program = dibuilder_.createFunction(
discope_, fct->getName(), fct->getName(), difile, entry_->loc().begin.row,
dibuilder_.createSubroutineType(dibuilder_.getOrCreateTypeArray(llvm::ArrayRef<llvm::Metadata*>())),
entry_->loc().begin.row,
llvm::DINode::FlagPrototyped,
llvm::DISubprogram::SPFlagDefinition | (opt() > 0 ? llvm::DISubprogram::SPFlagOptimized : llvm::DISubprogram::SPFlagZero));
fct->setSubprogram(disub_program);
discope_ = disub_program;
}
if (debug_) debug_->prepare(scope, fct);

return fct;
}
Expand All @@ -407,11 +386,11 @@ void CodeGen::prepare(Continuation* cont, llvm::Function* fct) {
auto& irbuilder = *i->second.second;
irbuilder.SetInsertPoint(bb);

if (debug())
irbuilder.SetCurrentDebugLocation(llvm::DILocation::get(discope_->getContext(), cont->loc().begin.row, cont->loc().begin.col, discope_));
if (debug_) debug_->prepare(irbuilder, cont);

if (entry_ == cont) {
auto arg = fct->arg_begin();
size_t arg_id = 0;
for (auto param : entry_->params()) {
if (is_mem(param) || is_unit(param)) {
defs_[param] = nullptr;
Expand All @@ -420,21 +399,29 @@ void CodeGen::prepare(Continuation* cont, llvm::Function* fct) {
auto value = map_param(fct, argv, param);
if (value == argv) {
arg->setName(param->unique_name()); // use param
defs_[param] = &*arg++;
defs_[param] = argv;
arg++;
} else {
defs_[param] = value; // use provided value
}

if (debug_) debug_->register_param(param, arg_id, defs_[param]);
}
arg_id++;
}
} else {
size_t arg_id = 0;
for (auto param : cont->params()) {
if (is_mem(param) || is_unit(param)) {
defs_[param] = nullptr;
} else {
// do not bother reserving anything (the 0 below) - it's a tiny optimization nobody cares about
auto phi = irbuilder.CreatePHI(convert(param->type()), 0, param->name().c_str());
defs_[param] = phi;

// if (debug_) debug_->register_param(param, arg_id, defs_[param]);
}
arg_id++;
}
}
}
Expand Down Expand Up @@ -614,19 +601,19 @@ void CodeGen::emit_epilogue(Continuation* continuation) {
llvm::Value* CodeGen::emit_constant(const Def* def) {
auto irbuilder = llvm::IRBuilder(context());
auto val = emit_builder(irbuilder, def);
if (debug_ && val) debug_->finalize(def, val);
return val;
}

llvm::Value* CodeGen::emit_bb(BB& bb, const Def* def) {
auto& irbuilder = *bb.second;
auto val = emit_builder(irbuilder, def);
if (debug_ && val) debug_->finalize(def, val);
return val;
}

llvm::Value* CodeGen::emit_builder(llvm::IRBuilder<>& irbuilder, const Def* def) {
// TODO
//if (debug())
//irbuilder.SetCurrentDebugLocation(llvm::DILocation::get(discope_->getContext(), def->loc().begin.row, def->loc().begin.col, discope_));
if (debug_) debug_->prepare(irbuilder, def);

if (false) {}
else if (auto load = def->isa<Load>()) return emit_load(irbuilder, load);
Expand Down Expand Up @@ -990,7 +977,7 @@ llvm::Value* CodeGen::emit_builder(llvm::IRBuilder<>& irbuilder, const Def* def)
} else if (auto vector = def->isa<Vector>()) {
llvm::Value* vec = llvm::UndefValue::get(convert(vector->type()));
for (size_t i = 0, e = vector->num_ops(); i != e; ++i)
vec = irbuilder.CreateInsertElement(vec, emit(vector->op(i)), emit(world().literal_pu32(i, vector->loc())));
vec = irbuilder.CreateInsertElement(vec, emit(vector->op(i)), emit(world().literal_pu32(i, vector->debug())));

return vec;
} else if (auto global = def->isa<Global>()) {
Expand Down Expand Up @@ -1035,10 +1022,11 @@ llvm::AllocaInst* CodeGen::emit_alloca(llvm::IRBuilder<>& irbuilder, llvm::Type*
auto entry = &irbuilder.GetInsertBlock()->getParent()->getEntryBlock();
auto layout = module().getDataLayout();
llvm::AllocaInst* alloca;
if (entry->empty())
alloca = new llvm::AllocaInst(type, layout.getAllocaAddrSpace(), nullptr, name, entry);
llvm::Instruction* insert_before = entry->empty() ? nullptr : entry->getFirstNonPHIOrDbg();
if (insert_before)
alloca = new llvm::AllocaInst(type, layout.getAllocaAddrSpace(), nullptr, name, insert_before);
else
alloca = new llvm::AllocaInst(type, layout.getAllocaAddrSpace(), nullptr, name, entry->getFirstNonPHIOrDbg());
alloca = new llvm::AllocaInst(type, layout.getAllocaAddrSpace(), nullptr, name, entry);
alloca->setAlignment(layout.getABITypeAlign(type));
return alloca;
}
Expand Down
32 changes: 29 additions & 3 deletions src/thorin/be/llvm/llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,43 @@ class CodeGen : public thorin::CodeGen, public thorin::Emitter<llvm::Value*, llv

protected:
std::unique_ptr<llvm::TargetMachine> machine_;
llvm::DIBuilder dibuilder_;
llvm::DICompileUnit* dicompile_unit_;
llvm::CallingConv::ID function_calling_convention_;
llvm::CallingConv::ID device_calling_convention_;
llvm::CallingConv::ID kernel_calling_convention_;
llvm::DIScope* discope_ = nullptr;
std::unique_ptr<Runtime> runtime_;
#if THORIN_ENABLE_RV
std::vector<std::tuple<u32, llvm::Function*, llvm::CallInst*>> vec_todo_;
#endif

struct Debug {
Debug(CodeGen&);

void emit_module();
void finalize();

void prepare(const Scope&, llvm::Function*);
void prepare(llvm::IRBuilder<>& irbuilder, const Continuation*);

void prepare(llvm::IRBuilder<>& irbuilder, const Def*);
void finalize(const Def*, llvm::Value*);

void register_param(const Param* param, int index, llvm::Value*);

llvm::DIFile* get_difile(const std::string&);
llvm::DILocation* get_dilocation(const Loc&, llvm::DIScope*);
llvm::DIType* get_ditype(const Type*, Loc);

private:
CodeGen& cg_;

llvm::DIBuilder dibuilder_;
llvm::DICompileUnit* dicompile_unit_;
llvm::DIScope* discope_ = nullptr;

DefMap<llvm::DIType*> types_;
};
std::optional<Debug> debug_;

friend class Runtime;
};

Expand Down
Loading