From ef1e46d8ef74b7082c3d0f33f4cc66fbcf51cec1 Mon Sep 17 00:00:00 2001 From: T0b1 Date: Fri, 28 Apr 2023 01:10:49 +0200 Subject: [PATCH] first try handly cycles/chains (doesnt work) --- src/ion/fast_alloc.rs | 164 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 5 deletions(-) diff --git a/src/ion/fast_alloc.rs b/src/ion/fast_alloc.rs index 8eb7ea0..b081443 100644 --- a/src/ion/fast_alloc.rs +++ b/src/ion/fast_alloc.rs @@ -908,6 +908,155 @@ fn handle_out_block_params<'a, F: Function>( let in_params = state.func.block_params(succ); let out_params = state.func.branch_blockparams(block, last_inst, 0); debug_assert_eq!(in_params.len(), out_params.len()); + assert!(in_params.len() < 254); + + if in_params.is_empty() { + trace!("No params. Skipping"); + return Ok(()); + } + + // TODO: this is a really dumb way to handle cycles/chains + // need a better algo + let mut depend_count: SmallVec<[u8; 8]> = SmallVec::new(); + let mut params_left: SmallVec<[u8; 8]> = SmallVec::new(); + //let mut remap: SmallVec<[Option; 8]> = SmallVec::new(); + + depend_count.resize(out_params.len(), 0); + //remap.resize(out_params.len(), None); + for i in 0..in_params.len() { + params_left.push(i as u8); + } + + for i in 0..out_params.len() { + let out_slot = state.vregs[out_params[i].vreg()].slot_idx.unwrap(); + for j in 0..in_params.len() { + let in_slot = state.vregs[in_params[j].vreg()].slot_idx.unwrap(); + if i == j { + continue; + } + + if out_slot == in_slot { + depend_count[j] += 1; + } + } + } + + while !params_left.is_empty() { + let count = params_left.len(); + + let mut i = 0; + while i < params_left.len() { + let idx = params_left[i] as usize; + if depend_count[idx] != 0 { + i += 1; + continue; + } + + params_left.swap_remove(i); + let out_slot = state.vregs[out_params[idx].vreg()].slot_idx.unwrap(); + // check if any other value depends on this + for j in 0..params_left.len() { + let idx = params_left[j] as usize; + let in_slot = state.vregs[in_params[idx].vreg()].slot_idx.unwrap(); + if in_slot == out_slot { + depend_count[idx] -= 1; + } + } + + let in_vreg = in_params[idx]; + let out_vreg = out_params[idx]; + + debug_assert!(state.vregs[in_vreg.vreg()].slot_idx.is_some()); + debug_assert!(state.vregs[out_vreg.vreg()].slot_idx.is_some()); + + let tmp_reg = if out_vreg.class() == RegClass::Int { + tmp_reg_int + } else { + tmp_reg_float + }; + /*let out_slot = match remap[idx] { + Some(idx) => idx, + None => state.vregs[out_vreg.vreg()].slot_idx.unwrap(), + };*/ + let out_slot = state.vregs[out_vreg.vreg()].slot_idx.unwrap(); + let in_slot = state.vregs[in_vreg.vreg()].slot_idx.unwrap(); + + trace!( + "Move {} from slot {} to slot {} for {}", + out_vreg, + out_slot, + in_slot, + in_vreg + ); + if out_slot == in_slot { + continue; + } + state.edits.push(( + ProgPoint::before(last_inst), + Edit::Move { + from: Allocation::stack(SpillSlot::new(out_slot as usize)), + to: Allocation::reg(tmp_reg), + }, + )); + state.edits.push(( + ProgPoint::before(last_inst), + Edit::Move { + from: Allocation::reg(tmp_reg), + to: Allocation::stack(SpillSlot::new(in_slot as usize)), + }, + )); + } + + if params_left.len() == count { + // everything left belongs to a cycle + if cfg!(debug_assertions) { + for i in 0..params_left.len() { + assert_eq!(depend_count[params_left[i] as usize], 1); + } + } + + // just move the first element to a tmp pos and search which reg depends on it + // TODO: we should sanity check that all regs in the cycle die after the block + + let idx = params_left[0] as usize; + let tmp_reg = if out_params[idx].class() == RegClass::Int { + tmp_reg_int + } else { + tmp_reg_float + }; + let out_slot = state.vregs[out_params[idx].vreg()].slot_idx.take().unwrap(); + state.edits.push(( + ProgPoint::before(last_inst), + Edit::Move { + from: Allocation::stack(SpillSlot::new(out_slot as usize)), + to: Allocation::reg(tmp_reg), + }, + )); + // TODO: mark out_slot as free + let new_slot = state.alloc_stack_slot(out_params[idx]); + trace!( + "Cycle detected. Breaking by allocating new slot {} for {}", + new_slot, + out_params[idx] + ); + state.edits.push(( + ProgPoint::before(last_inst), + Edit::Move { + from: Allocation::reg(tmp_reg), + to: Allocation::stack(SpillSlot::new(new_slot as usize)), + }, + )); + + for j in 0..params_left.len() { + let in_slot = state.vregs[in_params[params_left[j] as usize].vreg()] + .slot_idx + .unwrap(); + if in_slot == out_slot { + depend_count[params_left[j] as usize] -= 1; + } + } + } + } // TODO: need to break cycles // e.g. @@ -915,13 +1064,18 @@ fn handle_out_block_params<'a, F: Function>( // Move v145 from slot 6 to slot 3 for v136 // Move v146 from slot 3 to slot 4 for v137 // or - // 6->3 - // 3->5 - // 5->6 + // 0: 6->4 + // 1: 6->3 + // 2: 3->5 + // 3: 5->6 + // depends: [3, 3, 1, 2] // or // 3->6 // 6->3 - for i in 0..in_params.len() { + // 2->1 + // 1->4 + // depends: [1, 0, 0xFF, 2] + /*for i in 0..in_params.len() { let in_vreg = in_params[i]; let out_vreg = out_params[i]; @@ -960,7 +1114,7 @@ fn handle_out_block_params<'a, F: Function>( to: Allocation::stack(SpillSlot::new(in_slot as usize)), }, )); - } + }*/ } else { trace!("Successors not allocated. Creating allocation");