Skip to content

Commit

Permalink
dwarf init
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-q committed Jul 26, 2024
1 parent c5e7add commit adbf8ac
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 62 deletions.
81 changes: 37 additions & 44 deletions src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@ use hugr::{
HugrView, Node,
};
use inkwell::{
builder::Builder,
context::Context,
module::{Linkage, Module},
types::{AnyType, BasicType, BasicTypeEnum, FunctionType},
values::{BasicValueEnum, CallSiteValue, FunctionValue, GlobalValue},
builder::Builder, context::Context, debug_info::{AsDIScope, DICompileUnit, DIScope, DebugInfoBuilder}, module::{Linkage, Module}, types::{AnyType, BasicType, BasicTypeEnum, FunctionType}, values::{BasicValueEnum, CallSiteValue, FunctionValue, GlobalValue}
};
use std::{collections::HashSet, rc::Rc};
use std::{collections::{HashMap, HashSet}, rc::Rc};

use crate::types::{HugrFuncType, HugrSumType, HugrType, TypingSession};

Expand All @@ -32,6 +28,8 @@ pub use func::{EmitFuncContext, RowPromise};
pub use namer::Namer;
pub use ops::emit_value;

type DI<'c> = (Rc<DebugInfoBuilder<'c>>, DICompileUnit<'c>);

/// A trait used to abstract over emission.
///
/// In particular a `Box<dyn EmitOp>` is returned by
Expand Down Expand Up @@ -74,7 +72,7 @@ impl<'c, H> EmitModuleContext<'c, H> {
/// Convert a [HugrFuncType] into an LLVM [FunctionType].
pub fn llvm_func_type(&self, [self.extensions()], hugr_type: &HugrFuncType) -> Result<FunctionType<'c>>;
/// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType].
pub fn llvm_sum_type(&self, [self.extensions()], sum_ty: HugrSumType) -> Result<LLVMSumType<'c>>;
pub fn llvm_sum_type(&self, [self.extensions()], sum_ty: &HugrSumType) -> Result<LLVMSumType<'c>>;
}

to self.namer {
Expand Down Expand Up @@ -242,7 +240,7 @@ impl<'c, H> EmitModuleContext<'c, H> {
}
}

type EmissionSet<'c, H> = HashSet<FatNode<'c, FuncDefn, H>>;
type EmissionSet<'c, H> = HashMap<FatNode<'c, FuncDefn, H>, DIScope<'c>>;

/// Emits [HugrView]s into an LLVM [Module].
pub struct EmitHugr<'c, H> {
Expand Down Expand Up @@ -294,14 +292,20 @@ impl<'c, H: HugrView> EmitHugr<'c, H> {
///
/// If any LLVM IR declaration which is to be emitted already exists in the
/// [Module] and it differs from what would be emitted, then we fail.
pub fn emit_func(mut self, node: FatNode<'c, FuncDefn, H>) -> Result<Self> {
let mut worklist: EmissionSet<'c, H> = [node].into_iter().collect();
pub fn emit_func(mut self, node: FatNode<'c, FuncDefn, H>, di: DI<'c>) -> Result<Self> {
let mut worklist: EmissionSet<'c, H> = [(node, di.1.clone().as_debug_info_scope())].into_iter().collect();
let pop =
|wl: &mut EmissionSet<'c, H>| wl.iter().next().cloned().map(|x| wl.take(&x).unwrap());
|wl: &mut EmissionSet<'c, H>| {
let &k = wl.keys().next()?;
wl.remove_entry(&k)
};

while let Some(x) = pop(&mut worklist) {
let (new_self, new_tasks) = self.emit_func_impl(x)?;
self = new_self;
while let Some((node, scope)) = pop(&mut worklist) {
if self.emitted.insert(node, scope.clone()).is_some() {
continue;
}
let (new_self, new_tasks) = func::emit_func(self.module_context, node, di.0.clone(), scope)?;
self.module_context = new_self;
worklist.extend(new_tasks.into_iter());
}
Ok(self)
Expand All @@ -314,11 +318,29 @@ impl<'c, H: HugrView> EmitHugr<'c, H> {
/// emission of ops with static edges from them. So [FuncDefn] are the only
/// interesting children.
pub fn emit_module(mut self, node: FatNode<'c, hugr::ops::Module, H>) -> Result<Self> {
let (di_builder, di_compile_unit) = self.module().create_debug_info_builder(
true, // allow_unresolved
inkwell::debug_info::DWARFSourceLanguage::C, // language
"filename", // filename
"directory", // directory
"producer", // produer
false, // is_optimised
"", //flags
0, // runtime_ver
"", //split_name
inkwell::debug_info::DWARFEmissionKind::Full,
0, // dwo_id
false, // split_debug_inlining
false, //debug_info_for_profiling
"", // sysroot
""); // sdk
let di_builder = Rc::new(di_builder);
for c in node.children() {
match c.as_ref() {
OpType::FuncDefn(ref fd) => {
let fat_ot = c.into_ot(fd);
self = self.emit_func(fat_ot)?;

self = self.emit_func(fat_ot, (di_builder.clone(), di_compile_unit))?;
}
// FuncDecls are allowed, but we don't need to do anything here.
OpType::FuncDecl(_) => (),
Expand All @@ -330,35 +352,6 @@ impl<'c, H: HugrView> EmitHugr<'c, H> {
Ok(self)
}

fn emit_func_impl(
mut self,
node: FatNode<'c, FuncDefn, H>,
) -> Result<(Self, EmissionSet<'c, H>)> {
if !self.emitted.insert(node) {
return Ok((self, EmissionSet::default()));
}
let func = self.module_context.get_func_defn(node)?;
let mut func_ctx = EmitFuncContext::new(self.module_context, func)?;
let ret_rmb = func_ctx.new_row_mail_box(node.signature.body().output.iter(), "ret")?;
ops::emit_dataflow_parent(
&mut func_ctx,
EmitOpArgs {
node,
inputs: func.get_params(),
outputs: ret_rmb.promise(),
},
)?;
let builder = func_ctx.builder();
match &ret_rmb.read::<Vec<_>>(builder, [])?[..] {
[] => builder.build_return(None)?,
[x] => builder.build_return(Some(x))?,
xs => builder.build_aggregate_return(xs)?,
};
let (mctx, todos) = func_ctx.finish()?;
self.module_context = mctx;
Ok((self, todos))
}

/// Consumes the `EmitHugr` and returns the internal [Module].
pub fn finish(self) -> Module<'c> {
self.module_context.finish()
Expand Down
70 changes: 62 additions & 8 deletions src/emit/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ use hugr::{
HugrView, NodeIndex, PortIndex, Wire,
};
use inkwell::{
basic_block::BasicBlock,
builder::Builder,
context::Context,
types::{BasicType, BasicTypeEnum, FunctionType},
values::{FunctionValue, GlobalValue},
basic_block::BasicBlock, builder::Builder, context::Context, debug_info::{AsDIScope, DICompileUnit, DIScope, DebugInfoBuilder}, types::{BasicType, BasicTypeEnum, FunctionType}, values::{FunctionValue, GlobalValue}
};
use itertools::zip_eq;

Expand All @@ -21,7 +17,7 @@ use delegate::delegate;

use self::mailbox::ValueMailBox;

use super::{EmissionSet, EmitModuleContext};
use super::{EmissionSet, EmitModuleContext, EmitOpArgs};

mod mailbox;
pub use mailbox::{RowMailBox, RowPromise};
Expand Down Expand Up @@ -51,6 +47,9 @@ pub struct EmitFuncContext<'c, H> {
builder: Builder<'c>,
prologue_bb: BasicBlock<'c>,
launch_bb: BasicBlock<'c>,
scope: DIScope<'c>,
di_builder: Rc<DebugInfoBuilder<'c>>,

}

impl<'c, H: HugrView> EmitFuncContext<'c, H> {
Expand All @@ -67,7 +66,7 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
/// Convert a [HugrFuncType] into an LLVM [FunctionType].
pub fn llvm_func_type(&self, hugr_type: &HugrFuncType) -> Result<FunctionType<'c> >;
/// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType].
pub fn llvm_sum_type(&self, sum_ty: HugrSumType) -> Result<LLVMSumType<'c>>;
pub fn llvm_sum_type(&self, sum_ty: &HugrSumType) -> Result<LLVMSumType<'c>>;
/// Adds or gets the [FunctionValue] in the [inkwell::module::Module] corresponding to the given [FuncDefn].
///
/// The name of the result may have been mangled.
Expand Down Expand Up @@ -99,10 +98,15 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
}
}

pub fn set_debug_location(&self, line: u32, col: u32, scope: Option<DIScope<'c>>) {
let location = self.di_builder.create_debug_location(self.iw_context(), line, col, scope.unwrap_or(self.scope), None);
self.builder().set_current_debug_location(location);
}

/// Used when emitters encounter a scoped definition. `node` will be
/// returned from [EmitFuncContext::finish].
pub fn push_todo_func(&mut self, node: FatNode<'c, FuncDefn, H>) {
self.todo.insert(node);
self.todo.insert(node, self.scope);
}

// TODO likely we don't need this
Expand Down Expand Up @@ -148,13 +152,16 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
pub fn new(
emit_context: EmitModuleContext<'c, H>,
func: FunctionValue<'c>,
di_builder: Rc<DebugInfoBuilder<'c>>,
scope: DIScope<'c>,
) -> Result<EmitFuncContext<'c, H>> {
if func.get_first_basic_block().is_some() {
Err(anyhow!(
"EmitContext::new: Function already has a basic block: {:?}",
func.get_name()
))?;
}

let prologue_bb = emit_context
.iw_context()
.append_basic_block(func, "alloca_block");
Expand All @@ -171,6 +178,8 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
builder,
prologue_bb,
launch_bb,
scope,
di_builder
})
}

Expand Down Expand Up @@ -286,6 +295,51 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
pub fn finish(self) -> Result<(EmitModuleContext<'c, H>, EmissionSet<'c, H>)> {
self.builder.position_at_end(self.prologue_bb);
self.builder.build_unconditional_branch(self.launch_bb)?;
self.di_builder.finalize();
Ok((self.emit_context, self.todo))
}
}

pub fn emit_func<'c,H: HugrView>(
emit_context: EmitModuleContext<'c, H>,
node: FatNode<'c, FuncDefn, H>,
di_builder: Rc<DebugInfoBuilder<'c>>,
scope: DIScope<'c>,
) -> Result<(EmitModuleContext<'c, H>, EmissionSet<'c, H>)> {
let func = emit_context.get_func_defn(node)?;
let di_file =
di_builder.create_file("fn", "dir");
let di_subroutine_type = di_builder.create_subroutine_type(di_file, None, &[], 0);
let di_subprogram = di_builder.create_function(
scope,
&node.name,
None,
di_file,
0,
di_subroutine_type,
true,
false,
0,
0, // DIFLAGS
false);

func.set_subprogram(di_subprogram);

let mut func_ctx = EmitFuncContext::new(emit_context, func, di_builder, di_subprogram.as_debug_info_scope())?;
let ret_rmb = func_ctx.new_row_mail_box(node.signature.body().output.iter(), "ret")?;
super::ops::emit_dataflow_parent(
&mut func_ctx,
EmitOpArgs {
node,
inputs: func.get_params(),
outputs: ret_rmb.promise(),
},
)?;
let builder = func_ctx.builder();
match &ret_rmb.read::<Vec<_>>(builder, [])?[..] {
[] => builder.build_return(None)?,
[x] => builder.build_return(Some(x))?,
xs => builder.build_aggregate_return(xs)?,
};
func_ctx.finish()
}
9 changes: 6 additions & 3 deletions src/emit/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl<'c, 'd, H: HugrView> SumOpEmitter<'c, 'd, H> {
context: &'d mut EmitFuncContext<'c, H>,
ts: impl IntoIterator<Item = Type>,
) -> Result<Self> {
let llvm_sum_type = context.llvm_sum_type(get_exactly_one_sum_type(ts)?)?;
let llvm_sum_type = context.llvm_sum_type(&get_exactly_one_sum_type(ts)?)?;
Ok(Self::new(context, llvm_sum_type))
}
}
Expand Down Expand Up @@ -130,6 +130,9 @@ where
let inputs_rmb = self.context.node_ins_rmb(node)?;
let inputs = inputs_rmb.read(self.builder(), [])?;
let outputs = self.context.node_outs_rmb(node)?.promise();

self.context.set_debug_location(0,0,None);

self.emit(EmitOpArgs {
node,
inputs,
Expand Down Expand Up @@ -211,7 +214,7 @@ impl<'c, H: HugrView> EmitOp<'c, Conditional, H> for ConditionalEmitter<'c, '_,
.collect::<Result<Vec<_>>>()?;

let sum_type = get_exactly_one_sum_type(node.in_value_types().next().map(|x| x.1))?;
let llvm_sum_type = context.llvm_sum_type(sum_type)?;
let llvm_sum_type = context.llvm_sum_type(&sum_type)?;
debug_assert!(inputs[0].get_type() == llvm_sum_type.as_basic_type_enum());

let sum_input = inputs[0].into_struct_value();
Expand Down Expand Up @@ -260,7 +263,7 @@ pub fn emit_value<'c, H: HugrView>(
values,
sum_type,
}) => {
let llvm_st = LLVMSumType::try_new(&context.typing_session(), sum_type.clone())?;
let llvm_st = LLVMSumType::try_new(&context.typing_session(), sum_type)?;
let vs = values
.iter()
.map(|x| emit_value(context, x))
Expand Down
2 changes: 1 addition & 1 deletion src/emit/ops/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl<'c, H: HugrView> EmitOp<'c, DataflowBlock, H> for CfgEmitter<'c, '_, H> {
// code here at the expense of messier generated code. We expect the
// simplify-cfg pass to clean this up without issue.
let branch_sum_type = SumType::new(node.sum_rows.clone());
let llvm_sum_type = context.llvm_sum_type(branch_sum_type)?;
let llvm_sum_type = context.llvm_sum_type(&branch_sum_type)?;
let tag_bbs = successor_data
.into_iter()
.enumerate()
Expand Down
12 changes: 6 additions & 6 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl<'c, H> TypingSession<'c, H> {
use hugr::types::TypeEnum;
match hugr_type.as_type_enum() {
TypeEnum::Extension(ref custom_type) => self.extensions.llvm_type(self, custom_type),
TypeEnum::Sum(sum) => self.llvm_sum_type(sum.clone()).map(Into::into),
TypeEnum::Sum(sum) => self.llvm_sum_type(sum).map(Into::into),
TypeEnum::Function(func_ty) => {
let func_ty: Signature = func_ty.as_ref().clone().try_into()?;
Ok(self
Expand Down Expand Up @@ -102,7 +102,7 @@ impl<'c, H> TypingSession<'c, H> {
}

/// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType].
pub fn llvm_sum_type(&self, sum_type: HugrSumType) -> Result<LLVMSumType<'c>> {
pub fn llvm_sum_type(&self, sum_type: &HugrSumType) -> Result<LLVMSumType<'c>> {
LLVMSumType::try_new(self, sum_type)
}
}
Expand Down Expand Up @@ -145,7 +145,7 @@ impl<'c> TypeConverter<'c> {
pub fn llvm_sum_type<H>(
self: Rc<Self>,
extensions: Rc<CodegenExtsMap<'c, H>>,
sum_type: HugrSumType,
sum_type: &HugrSumType,
) -> Result<LLVMSumType<'c>> {
self.session(extensions).llvm_sum_type(sum_type)
}
Expand All @@ -162,7 +162,7 @@ pub struct LLVMSumType<'c>(StructType<'c>, SumType);

impl<'c> LLVMSumType<'c> {
/// Attempt to create a new `LLVMSumType` from a [HugrSumType].
pub fn try_new<H>(session: &TypingSession<'c, H>, sum_type: SumType) -> Result<Self> {
pub fn try_new<H>(session: &TypingSession<'c, H>, sum_type: &SumType) -> Result<Self> {
assert!(sum_type.num_variants() < u32::MAX as usize);
let variants = (0..sum_type.num_variants())
.map(|i| {
Expand All @@ -184,7 +184,7 @@ impl<'c> LLVMSumType<'c> {
.collect_vec();
Ok(Self(
session.iw_context().struct_type(&types, false),
sum_type,
sum_type.clone(),
))
}

Expand Down Expand Up @@ -384,7 +384,7 @@ pub mod test {
"sum_type_to_llvm",
llvm_ctx
.get_typing_session()
.llvm_sum_type(st.clone())
.llvm_sum_type(&st)
.unwrap(),
&st.to_string()
)
Expand Down

0 comments on commit adbf8ac

Please sign in to comment.