Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit adbf8ac

Browse files
committed
dwarf init
1 parent c5e7add commit adbf8ac

File tree

5 files changed

+112
-62
lines changed

5 files changed

+112
-62
lines changed

src/emit.rs

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,9 @@ use hugr::{
66
HugrView, Node,
77
};
88
use inkwell::{
9-
builder::Builder,
10-
context::Context,
11-
module::{Linkage, Module},
12-
types::{AnyType, BasicType, BasicTypeEnum, FunctionType},
13-
values::{BasicValueEnum, CallSiteValue, FunctionValue, GlobalValue},
9+
builder::Builder, context::Context, debug_info::{AsDIScope, DICompileUnit, DIScope, DebugInfoBuilder}, module::{Linkage, Module}, types::{AnyType, BasicType, BasicTypeEnum, FunctionType}, values::{BasicValueEnum, CallSiteValue, FunctionValue, GlobalValue}
1410
};
15-
use std::{collections::HashSet, rc::Rc};
11+
use std::{collections::{HashMap, HashSet}, rc::Rc};
1612

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

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

31+
type DI<'c> = (Rc<DebugInfoBuilder<'c>>, DICompileUnit<'c>);
32+
3533
/// A trait used to abstract over emission.
3634
///
3735
/// In particular a `Box<dyn EmitOp>` is returned by
@@ -74,7 +72,7 @@ impl<'c, H> EmitModuleContext<'c, H> {
7472
/// Convert a [HugrFuncType] into an LLVM [FunctionType].
7573
pub fn llvm_func_type(&self, [self.extensions()], hugr_type: &HugrFuncType) -> Result<FunctionType<'c>>;
7674
/// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType].
77-
pub fn llvm_sum_type(&self, [self.extensions()], sum_ty: HugrSumType) -> Result<LLVMSumType<'c>>;
75+
pub fn llvm_sum_type(&self, [self.extensions()], sum_ty: &HugrSumType) -> Result<LLVMSumType<'c>>;
7876
}
7977

8078
to self.namer {
@@ -242,7 +240,7 @@ impl<'c, H> EmitModuleContext<'c, H> {
242240
}
243241
}
244242

245-
type EmissionSet<'c, H> = HashSet<FatNode<'c, FuncDefn, H>>;
243+
type EmissionSet<'c, H> = HashMap<FatNode<'c, FuncDefn, H>, DIScope<'c>>;
246244

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

302-
while let Some(x) = pop(&mut worklist) {
303-
let (new_self, new_tasks) = self.emit_func_impl(x)?;
304-
self = new_self;
303+
while let Some((node, scope)) = pop(&mut worklist) {
304+
if self.emitted.insert(node, scope.clone()).is_some() {
305+
continue;
306+
}
307+
let (new_self, new_tasks) = func::emit_func(self.module_context, node, di.0.clone(), scope)?;
308+
self.module_context = new_self;
305309
worklist.extend(new_tasks.into_iter());
306310
}
307311
Ok(self)
@@ -314,11 +318,29 @@ impl<'c, H: HugrView> EmitHugr<'c, H> {
314318
/// emission of ops with static edges from them. So [FuncDefn] are the only
315319
/// interesting children.
316320
pub fn emit_module(mut self, node: FatNode<'c, hugr::ops::Module, H>) -> Result<Self> {
321+
let (di_builder, di_compile_unit) = self.module().create_debug_info_builder(
322+
true, // allow_unresolved
323+
inkwell::debug_info::DWARFSourceLanguage::C, // language
324+
"filename", // filename
325+
"directory", // directory
326+
"producer", // produer
327+
false, // is_optimised
328+
"", //flags
329+
0, // runtime_ver
330+
"", //split_name
331+
inkwell::debug_info::DWARFEmissionKind::Full,
332+
0, // dwo_id
333+
false, // split_debug_inlining
334+
false, //debug_info_for_profiling
335+
"", // sysroot
336+
""); // sdk
337+
let di_builder = Rc::new(di_builder);
317338
for c in node.children() {
318339
match c.as_ref() {
319340
OpType::FuncDefn(ref fd) => {
320341
let fat_ot = c.into_ot(fd);
321-
self = self.emit_func(fat_ot)?;
342+
343+
self = self.emit_func(fat_ot, (di_builder.clone(), di_compile_unit))?;
322344
}
323345
// FuncDecls are allowed, but we don't need to do anything here.
324346
OpType::FuncDecl(_) => (),
@@ -330,35 +352,6 @@ impl<'c, H: HugrView> EmitHugr<'c, H> {
330352
Ok(self)
331353
}
332354

333-
fn emit_func_impl(
334-
mut self,
335-
node: FatNode<'c, FuncDefn, H>,
336-
) -> Result<(Self, EmissionSet<'c, H>)> {
337-
if !self.emitted.insert(node) {
338-
return Ok((self, EmissionSet::default()));
339-
}
340-
let func = self.module_context.get_func_defn(node)?;
341-
let mut func_ctx = EmitFuncContext::new(self.module_context, func)?;
342-
let ret_rmb = func_ctx.new_row_mail_box(node.signature.body().output.iter(), "ret")?;
343-
ops::emit_dataflow_parent(
344-
&mut func_ctx,
345-
EmitOpArgs {
346-
node,
347-
inputs: func.get_params(),
348-
outputs: ret_rmb.promise(),
349-
},
350-
)?;
351-
let builder = func_ctx.builder();
352-
match &ret_rmb.read::<Vec<_>>(builder, [])?[..] {
353-
[] => builder.build_return(None)?,
354-
[x] => builder.build_return(Some(x))?,
355-
xs => builder.build_aggregate_return(xs)?,
356-
};
357-
let (mctx, todos) = func_ctx.finish()?;
358-
self.module_context = mctx;
359-
Ok((self, todos))
360-
}
361-
362355
/// Consumes the `EmitHugr` and returns the internal [Module].
363356
pub fn finish(self) -> Module<'c> {
364357
self.module_context.finish()

src/emit/func.rs

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ use hugr::{
77
HugrView, NodeIndex, PortIndex, Wire,
88
};
99
use inkwell::{
10-
basic_block::BasicBlock,
11-
builder::Builder,
12-
context::Context,
13-
types::{BasicType, BasicTypeEnum, FunctionType},
14-
values::{FunctionValue, GlobalValue},
10+
basic_block::BasicBlock, builder::Builder, context::Context, debug_info::{AsDIScope, DICompileUnit, DIScope, DebugInfoBuilder}, types::{BasicType, BasicTypeEnum, FunctionType}, values::{FunctionValue, GlobalValue}
1511
};
1612
use itertools::zip_eq;
1713

@@ -21,7 +17,7 @@ use delegate::delegate;
2117

2218
use self::mailbox::ValueMailBox;
2319

24-
use super::{EmissionSet, EmitModuleContext};
20+
use super::{EmissionSet, EmitModuleContext, EmitOpArgs};
2521

2622
mod mailbox;
2723
pub use mailbox::{RowMailBox, RowPromise};
@@ -51,6 +47,9 @@ pub struct EmitFuncContext<'c, H> {
5147
builder: Builder<'c>,
5248
prologue_bb: BasicBlock<'c>,
5349
launch_bb: BasicBlock<'c>,
50+
scope: DIScope<'c>,
51+
di_builder: Rc<DebugInfoBuilder<'c>>,
52+
5453
}
5554

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

101+
pub fn set_debug_location(&self, line: u32, col: u32, scope: Option<DIScope<'c>>) {
102+
let location = self.di_builder.create_debug_location(self.iw_context(), line, col, scope.unwrap_or(self.scope), None);
103+
self.builder().set_current_debug_location(location);
104+
}
105+
102106
/// Used when emitters encounter a scoped definition. `node` will be
103107
/// returned from [EmitFuncContext::finish].
104108
pub fn push_todo_func(&mut self, node: FatNode<'c, FuncDefn, H>) {
105-
self.todo.insert(node);
109+
self.todo.insert(node, self.scope);
106110
}
107111

108112
// TODO likely we don't need this
@@ -148,13 +152,16 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
148152
pub fn new(
149153
emit_context: EmitModuleContext<'c, H>,
150154
func: FunctionValue<'c>,
155+
di_builder: Rc<DebugInfoBuilder<'c>>,
156+
scope: DIScope<'c>,
151157
) -> Result<EmitFuncContext<'c, H>> {
152158
if func.get_first_basic_block().is_some() {
153159
Err(anyhow!(
154160
"EmitContext::new: Function already has a basic block: {:?}",
155161
func.get_name()
156162
))?;
157163
}
164+
158165
let prologue_bb = emit_context
159166
.iw_context()
160167
.append_basic_block(func, "alloca_block");
@@ -171,6 +178,8 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
171178
builder,
172179
prologue_bb,
173180
launch_bb,
181+
scope,
182+
di_builder
174183
})
175184
}
176185

@@ -286,6 +295,51 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> {
286295
pub fn finish(self) -> Result<(EmitModuleContext<'c, H>, EmissionSet<'c, H>)> {
287296
self.builder.position_at_end(self.prologue_bb);
288297
self.builder.build_unconditional_branch(self.launch_bb)?;
298+
self.di_builder.finalize();
289299
Ok((self.emit_context, self.todo))
290300
}
291301
}
302+
303+
pub fn emit_func<'c,H: HugrView>(
304+
emit_context: EmitModuleContext<'c, H>,
305+
node: FatNode<'c, FuncDefn, H>,
306+
di_builder: Rc<DebugInfoBuilder<'c>>,
307+
scope: DIScope<'c>,
308+
) -> Result<(EmitModuleContext<'c, H>, EmissionSet<'c, H>)> {
309+
let func = emit_context.get_func_defn(node)?;
310+
let di_file =
311+
di_builder.create_file("fn", "dir");
312+
let di_subroutine_type = di_builder.create_subroutine_type(di_file, None, &[], 0);
313+
let di_subprogram = di_builder.create_function(
314+
scope,
315+
&node.name,
316+
None,
317+
di_file,
318+
0,
319+
di_subroutine_type,
320+
true,
321+
false,
322+
0,
323+
0, // DIFLAGS
324+
false);
325+
326+
func.set_subprogram(di_subprogram);
327+
328+
let mut func_ctx = EmitFuncContext::new(emit_context, func, di_builder, di_subprogram.as_debug_info_scope())?;
329+
let ret_rmb = func_ctx.new_row_mail_box(node.signature.body().output.iter(), "ret")?;
330+
super::ops::emit_dataflow_parent(
331+
&mut func_ctx,
332+
EmitOpArgs {
333+
node,
334+
inputs: func.get_params(),
335+
outputs: ret_rmb.promise(),
336+
},
337+
)?;
338+
let builder = func_ctx.builder();
339+
match &ret_rmb.read::<Vec<_>>(builder, [])?[..] {
340+
[] => builder.build_return(None)?,
341+
[x] => builder.build_return(Some(x))?,
342+
xs => builder.build_aggregate_return(xs)?,
343+
};
344+
func_ctx.finish()
345+
}

src/emit/ops.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl<'c, 'd, H: HugrView> SumOpEmitter<'c, 'd, H> {
3333
context: &'d mut EmitFuncContext<'c, H>,
3434
ts: impl IntoIterator<Item = Type>,
3535
) -> Result<Self> {
36-
let llvm_sum_type = context.llvm_sum_type(get_exactly_one_sum_type(ts)?)?;
36+
let llvm_sum_type = context.llvm_sum_type(&get_exactly_one_sum_type(ts)?)?;
3737
Ok(Self::new(context, llvm_sum_type))
3838
}
3939
}
@@ -130,6 +130,9 @@ where
130130
let inputs_rmb = self.context.node_ins_rmb(node)?;
131131
let inputs = inputs_rmb.read(self.builder(), [])?;
132132
let outputs = self.context.node_outs_rmb(node)?.promise();
133+
134+
self.context.set_debug_location(0,0,None);
135+
133136
self.emit(EmitOpArgs {
134137
node,
135138
inputs,
@@ -211,7 +214,7 @@ impl<'c, H: HugrView> EmitOp<'c, Conditional, H> for ConditionalEmitter<'c, '_,
211214
.collect::<Result<Vec<_>>>()?;
212215

213216
let sum_type = get_exactly_one_sum_type(node.in_value_types().next().map(|x| x.1))?;
214-
let llvm_sum_type = context.llvm_sum_type(sum_type)?;
217+
let llvm_sum_type = context.llvm_sum_type(&sum_type)?;
215218
debug_assert!(inputs[0].get_type() == llvm_sum_type.as_basic_type_enum());
216219

217220
let sum_input = inputs[0].into_struct_value();
@@ -260,7 +263,7 @@ pub fn emit_value<'c, H: HugrView>(
260263
values,
261264
sum_type,
262265
}) => {
263-
let llvm_st = LLVMSumType::try_new(&context.typing_session(), sum_type.clone())?;
266+
let llvm_st = LLVMSumType::try_new(&context.typing_session(), sum_type)?;
264267
let vs = values
265268
.iter()
266269
.map(|x| emit_value(context, x))

src/emit/ops/cfg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl<'c, H: HugrView> EmitOp<'c, DataflowBlock, H> for CfgEmitter<'c, '_, H> {
183183
// code here at the expense of messier generated code. We expect the
184184
// simplify-cfg pass to clean this up without issue.
185185
let branch_sum_type = SumType::new(node.sum_rows.clone());
186-
let llvm_sum_type = context.llvm_sum_type(branch_sum_type)?;
186+
let llvm_sum_type = context.llvm_sum_type(&branch_sum_type)?;
187187
let tag_bbs = successor_data
188188
.into_iter()
189189
.enumerate()

src/types.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<'c, H> TypingSession<'c, H> {
6262
use hugr::types::TypeEnum;
6363
match hugr_type.as_type_enum() {
6464
TypeEnum::Extension(ref custom_type) => self.extensions.llvm_type(self, custom_type),
65-
TypeEnum::Sum(sum) => self.llvm_sum_type(sum.clone()).map(Into::into),
65+
TypeEnum::Sum(sum) => self.llvm_sum_type(sum).map(Into::into),
6666
TypeEnum::Function(func_ty) => {
6767
let func_ty: Signature = func_ty.as_ref().clone().try_into()?;
6868
Ok(self
@@ -102,7 +102,7 @@ impl<'c, H> TypingSession<'c, H> {
102102
}
103103

104104
/// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType].
105-
pub fn llvm_sum_type(&self, sum_type: HugrSumType) -> Result<LLVMSumType<'c>> {
105+
pub fn llvm_sum_type(&self, sum_type: &HugrSumType) -> Result<LLVMSumType<'c>> {
106106
LLVMSumType::try_new(self, sum_type)
107107
}
108108
}
@@ -145,7 +145,7 @@ impl<'c> TypeConverter<'c> {
145145
pub fn llvm_sum_type<H>(
146146
self: Rc<Self>,
147147
extensions: Rc<CodegenExtsMap<'c, H>>,
148-
sum_type: HugrSumType,
148+
sum_type: &HugrSumType,
149149
) -> Result<LLVMSumType<'c>> {
150150
self.session(extensions).llvm_sum_type(sum_type)
151151
}
@@ -162,7 +162,7 @@ pub struct LLVMSumType<'c>(StructType<'c>, SumType);
162162

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

@@ -384,7 +384,7 @@ pub mod test {
384384
"sum_type_to_llvm",
385385
llvm_ctx
386386
.get_typing_session()
387-
.llvm_sum_type(st.clone())
387+
.llvm_sum_type(&st)
388388
.unwrap(),
389389
&st.to_string()
390390
)

0 commit comments

Comments
 (0)