Skip to content

Commit 4bd6fad

Browse files
committed
wip: Async state machine compilation with SSA value tracking
- Fix grammar fold_binary to properly capture operators for expressions - Track SSA parameter value IDs (distinct from declaration IDs) for captures - Skip copying Parameter values to async wrapper (loaded from state machine) - Fix call_async to look up {name}_new and {name}_poll functions - Add async_test.zyn grammar for testing async/await functionality - Add comprehensive async runtime tests Note: Current implementation uses _new/_poll naming convention which needs refactoring to return Promise objects directly from async functions.
1 parent 8c656e1 commit 4bd6fad

11 files changed

Lines changed: 2847 additions & 179 deletions

File tree

crates/compiler/src/async_support.rs

Lines changed: 406 additions & 87 deletions
Large diffs are not rendered by default.

crates/compiler/src/cranelift_backend.rs

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,10 @@ impl CraneliftBackend {
287287
self.function_map.insert(id, func_id);
288288
} else {
289289
// Regular functions use Export linkage with unique name
290-
let unique_name = format!("{}__{:?}", function.name.to_string(), id);
290+
// Use resolve_global to get the actual function name
291+
let base_name = function.name.resolve_global()
292+
.unwrap_or_else(|| format!("{:?}", function.name));
293+
let unique_name = format!("{}__{:?}", base_name, id);
291294
let func_id = self.module.declare_function(
292295
&unique_name,
293296
Linkage::Export,
@@ -454,6 +457,8 @@ impl CraneliftBackend {
454457
}
455458

456459
// Build function body
460+
eprintln!("[Cranelift] Building function body with signature:");
461+
eprintln!("[Cranelift] sig.returns = {:?}", sig.returns);
457462
self.codegen_context.func = cranelift_codegen::ir::Function::with_name_signature(
458463
UserFuncName::user(0, func_id.as_u32()),
459464
sig.clone(),
@@ -466,11 +471,21 @@ impl CraneliftBackend {
466471

467472
// Phase 1: Analyze function structure
468473
let block_order = self.compute_block_order(function);
469-
log::debug!("[Cranelift] Block order: {:?} blocks", block_order.len());
470-
log::debug!("[Cranelift] Entry block: {:?}", function.entry_block);
471-
log::debug!("[Cranelift] Total blocks in function: {:?}", function.blocks.len());
474+
eprintln!("[Cranelift] Compiling function: {:?}", function.name);
475+
eprintln!("[Cranelift] Block order: {:?} blocks", block_order.len());
476+
eprintln!("[Cranelift] Entry block: {:?}", function.entry_block);
477+
eprintln!("[Cranelift] Total blocks in function: {:?}", function.blocks.len());
478+
eprintln!("[Cranelift] Values count: {:?}", function.values.len());
472479
for (i, block_id) in block_order.iter().enumerate() {
473-
log::debug!("[Cranelift] [{}] {:?}", i, block_id);
480+
if let Some(block) = function.blocks.get(block_id) {
481+
eprintln!("[Cranelift] [{}] {:?} - {} instructions, terminator: {:?}",
482+
i, block_id, block.instructions.len(), block.terminator);
483+
for (j, inst) in block.instructions.iter().enumerate() {
484+
eprintln!("[Cranelift] inst[{}]: {:?}", j, inst);
485+
}
486+
} else {
487+
eprintln!("[Cranelift] [{}] {:?} - MISSING!", i, block_id);
488+
}
474489
}
475490
let predecessor_map = self.build_predecessor_map(function);
476491

@@ -542,7 +557,9 @@ impl CraneliftBackend {
542557
}
543558

544559
// Map all constant values (needs active block for instruction creation)
560+
eprintln!("[Cranelift] Processing {} values", function.values.len());
545561
for value in function.values.values() {
562+
eprintln!("[Cranelift] Value {:?} kind={:?}", value.id, value.kind);
546563
if let HirValueKind::Constant(constant) = &value.kind {
547564
let cranelift_val = match constant {
548565
// For narrow integer types, Cranelift expects zero-extended values, not sign-extended
@@ -1598,6 +1615,30 @@ impl CraneliftBackend {
15981615
}
15991616
}
16001617

1618+
HirInstruction::Cast { result, ty, op, operand } => {
1619+
// Cast instruction: convert between types
1620+
let val = self.value_map.get(operand).copied()
1621+
.unwrap_or_else(|| panic!("Cast operand {:?} not in value_map", operand));
1622+
// Use type_cache directly - types should be pre-cached
1623+
let target_ty = type_cache.get(ty).copied().unwrap_or(types::I64);
1624+
1625+
let cast_val = match op {
1626+
crate::hir::CastOp::Bitcast => val,
1627+
crate::hir::CastOp::ZExt => builder.ins().uextend(target_ty, val),
1628+
crate::hir::CastOp::SExt => builder.ins().sextend(target_ty, val),
1629+
crate::hir::CastOp::Trunc => builder.ins().ireduce(target_ty, val),
1630+
crate::hir::CastOp::FpToSi => builder.ins().fcvt_to_sint(target_ty, val),
1631+
crate::hir::CastOp::FpToUi => builder.ins().fcvt_to_uint(target_ty, val),
1632+
crate::hir::CastOp::SiToFp => builder.ins().fcvt_from_sint(target_ty, val),
1633+
crate::hir::CastOp::UiToFp => builder.ins().fcvt_from_uint(target_ty, val),
1634+
crate::hir::CastOp::FpExt => builder.ins().fpromote(target_ty, val),
1635+
crate::hir::CastOp::FpTrunc => builder.ins().fdemote(target_ty, val),
1636+
_ => val, // PtrToInt, IntToPtr handled as bitcasts for now
1637+
};
1638+
1639+
self.value_map.insert(*result, cast_val);
1640+
}
1641+
16011642
_ => {
16021643
// Other instructions not yet implemented
16031644
// This will cause values to be unmapped, leading to verifier errors
@@ -1609,9 +1650,17 @@ impl CraneliftBackend {
16091650
// Process terminator (inline to avoid borrow checker)
16101651
match &hir_block.terminator {
16111652
HirTerminator::Return { values } => {
1653+
eprintln!("[Cranelift] Return terminator with values: {:?}", values);
16121654
let cranelift_vals: Vec<_> = values.iter()
1613-
.filter_map(|v| self.value_map.get(v).copied())
1655+
.filter_map(|v| {
1656+
let result = self.value_map.get(v).copied();
1657+
if result.is_none() {
1658+
eprintln!("[Cranelift ERROR] Return value {:?} not in value_map", v);
1659+
}
1660+
result
1661+
})
16141662
.collect();
1663+
eprintln!("[Cranelift] Returning {} values", cranelift_vals.len());
16151664
builder.ins().return_(&cranelift_vals);
16161665
}
16171666

@@ -1705,6 +1754,7 @@ impl CraneliftBackend {
17051754
let target_block = self.block_map[target];
17061755

17071756
// Create constant value for comparison
1757+
// Handle both signed and unsigned integer types
17081758
let const_val = match constant {
17091759
HirConstant::I8(v) => {
17101760
let extended = (*v as u8) as i64;
@@ -1719,6 +1769,17 @@ impl CraneliftBackend {
17191769
builder.ins().iconst(types::I32, extended)
17201770
}
17211771
HirConstant::I64(v) => builder.ins().iconst(types::I64, *v),
1772+
// Unsigned integer types
1773+
HirConstant::U8(v) => {
1774+
builder.ins().iconst(types::I8, *v as i64)
1775+
}
1776+
HirConstant::U16(v) => {
1777+
builder.ins().iconst(types::I16, *v as i64)
1778+
}
1779+
HirConstant::U32(v) => {
1780+
builder.ins().iconst(types::I32, *v as i64)
1781+
}
1782+
HirConstant::U64(v) => builder.ins().iconst(types::I64, *v as i64),
17221783
_ => continue, // Skip non-integer constants
17231784
};
17241785

@@ -1895,12 +1956,13 @@ impl CraneliftBackend {
18951956
}
18961957

18971958
// Debug: Print IR after finalize
1898-
log::debug!("[Cranelift] IR after finalize (inside compile_function_body):\n{}", self.codegen_context.func);
1959+
eprintln!("[Cranelift] IR after finalize (inside compile_function_body):\n{}", self.codegen_context.func);
18991960

19001961
// Debug: Uncomment to dump IR for all functions
19011962
// self.dump_cranelift_ir(&function.name.to_string());
19021963

19031964
// Compile the function
1965+
eprintln!("[Cranelift] About to call define_function for {:?}", function.name);
19041966
let code = self.module.define_function(
19051967
func_id,
19061968
&mut self.codegen_context,
@@ -2012,6 +2074,10 @@ impl CraneliftBackend {
20122074

20132075
/// Translate function signature
20142076
pub fn translate_signature(&self, function: &HirFunction) -> CompilerResult<Signature> {
2077+
eprintln!("[Cranelift] translate_signature for function {:?}", function.name);
2078+
eprintln!("[Cranelift] params: {:?}", function.signature.params.len());
2079+
eprintln!("[Cranelift] returns: {:?}", function.signature.returns);
2080+
20152081
let mut cranelift_sig = self.module.make_signature();
20162082

20172083
// Set calling convention
@@ -3180,9 +3246,12 @@ impl CraneliftBackend {
31803246
}
31813247

31823248
HirInstruction::Cast { result, ty, op, operand } => {
3183-
let val = self.value_map[operand];
3249+
eprintln!("[Cranelift Cast] operand={:?}, op={:?}, target_ty={:?}", operand, op, ty);
3250+
let val = self.value_map.get(operand).copied()
3251+
.unwrap_or_else(|| panic!("Cast operand {:?} not in value_map", operand));
31843252
let target_ty = self.translate_type(ty)?;
3185-
3253+
eprintln!("[Cranelift Cast] val={:?}, target_ty={:?}", val, target_ty);
3254+
31863255
let cast_val = match op {
31873256
crate::hir::CastOp::Bitcast => {
31883257
// Bitcast - just return the value for now
@@ -3192,7 +3261,10 @@ impl CraneliftBackend {
31923261
builder.ins().uextend(target_ty, val)
31933262
}
31943263
crate::hir::CastOp::SExt => {
3195-
builder.ins().sextend(target_ty, val)
3264+
eprintln!("[Cranelift Cast] Doing sextend from val={:?} to target_ty={:?}", val, target_ty);
3265+
let result = builder.ins().sextend(target_ty, val);
3266+
eprintln!("[Cranelift Cast] sextend result={:?}", result);
3267+
result
31963268
}
31973269
crate::hir::CastOp::Trunc => {
31983270
builder.ins().ireduce(target_ty, val)

crates/compiler/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ pub fn compile_to_hir(
230230
let wrapper_func = async_compiler.generate_async_wrapper_with_arena(
231231
&state_machine,
232232
&mut *lowering_ctx.arena.lock().unwrap(),
233+
&original_func,
233234
)?;
234235

235236
// Replace the original async function with the state machine wrapper

crates/compiler/src/lowering.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,23 @@ impl LoweringContext {
639639
let mut typed_cfg_builder = crate::typed_cfg::TypedCfgBuilder::new();
640640
let typed_cfg = typed_cfg_builder.build_from_block(body, hir_func.entry_block)?;
641641

642+
// Debug: check TypedCFG
643+
eprintln!("[LOWERING DEBUG] TypedCFG for function {:?} (is_async={}):", func.name, func.is_async);
644+
eprintln!("[LOWERING DEBUG] Entry block: {:?}", hir_func.entry_block);
645+
eprintln!("[LOWERING DEBUG] CFG nodes: {}", typed_cfg.graph.node_count());
646+
eprintln!("[LOWERING DEBUG] CFG edges: {}", typed_cfg.graph.edge_count());
647+
for node in typed_cfg.graph.node_indices() {
648+
let block = &typed_cfg.graph[node];
649+
let pred_count = typed_cfg.graph.edges_directed(node, petgraph::Direction::Incoming).count();
650+
eprintln!("[LOWERING DEBUG] CFG Block {:?}: {} statements, {} predecessors", block.id, block.statements.len(), pred_count);
651+
}
652+
if func.is_async {
653+
eprintln!("[LOWERING DEBUG] Body statements: {:?}", body.statements.len());
654+
for stmt in &body.statements {
655+
eprintln!("[LOWERING DEBUG] Statement: {:?}", stmt);
656+
}
657+
}
658+
642659
// Convert to SSA form, processing TypedStatements to emit HIR instructions
643660
let ssa_builder = SsaBuilder::new(
644661
hir_func,
@@ -648,6 +665,15 @@ impl LoweringContext {
648665
).with_return_type(func.return_type.clone());
649666
let ssa = ssa_builder.build_from_typed_cfg(&typed_cfg)?;
650667

668+
// Debug: check SSA result
669+
if func.is_async {
670+
eprintln!("[LOWERING DEBUG] After SSA build for async function {:?}:", func.name);
671+
eprintln!("[LOWERING DEBUG] SSA blocks: {}", ssa.function.blocks.len());
672+
for (bid, block) in &ssa.function.blocks {
673+
eprintln!("[LOWERING DEBUG] SSA Block {:?}: {} instructions", bid, block.instructions.len());
674+
}
675+
}
676+
651677
// Verify SSA properties
652678
ssa.verify()?;
653679

@@ -682,6 +708,20 @@ impl LoweringContext {
682708

683709
// Gap 6 Phase 2: Transform async functions to state machines
684710
if func.is_async {
711+
eprintln!("[LOWERING DEBUG] Before transform_async_function:");
712+
eprintln!("[LOWERING DEBUG] Function: {:?}", hir_func.name);
713+
eprintln!("[LOWERING DEBUG] Values: {} entries", hir_func.values.len());
714+
for (vid, val) in &hir_func.values {
715+
eprintln!("[LOWERING DEBUG] {:?} -> {:?}", vid, val.kind);
716+
}
717+
eprintln!("[LOWERING DEBUG] Blocks: {}", hir_func.blocks.len());
718+
for (bid, block) in &hir_func.blocks {
719+
eprintln!("[LOWERING DEBUG] Block {:?}: {} instructions, terminator = {:?}",
720+
bid, block.instructions.len(), block.terminator);
721+
for (i, inst) in block.instructions.iter().enumerate() {
722+
eprintln!("[LOWERING DEBUG] inst[{}]: {:?}", i, inst);
723+
}
724+
}
685725
hir_func = self.transform_async_function(hir_func)?;
686726
}
687727

@@ -722,7 +762,8 @@ impl LoweringContext {
722762
// 2. Generate the poll() wrapper that implements Future::poll
723763
let poll_wrapper = async_compiler.generate_async_wrapper_with_arena(
724764
&state_machine,
725-
&mut *arena
765+
&mut *arena,
766+
&original_func,
726767
)?;
727768

728769
// 3. Generate the constructor function

0 commit comments

Comments
 (0)