mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +00:00
Get control flow working (fingers crossed)
This commit is contained in:
parent
5ee19e55a5
commit
2572a0259b
@ -2,21 +2,22 @@ use inkwell::{
|
||||
builder::Builder,
|
||||
context::Context,
|
||||
module::Module,
|
||||
passes::PassManager,
|
||||
types::{BasicType, BasicTypeEnum, FunctionType},
|
||||
values::{BasicValue, FunctionValue},
|
||||
values::{BasicValue, FunctionValue, PhiValue},
|
||||
FloatPredicate, IntPredicate,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use wasmer_runtime_core::{
|
||||
module::ModuleInfo,
|
||||
structures::{Map, SliceMap, TypedIndex},
|
||||
types::{FuncIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type},
|
||||
types::{FuncIndex, MemoryIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type, MemoryType},
|
||||
};
|
||||
use wasmparser::{BinaryReaderError, CodeSectionReader, LocalsReader, Operator, OperatorsReader};
|
||||
|
||||
use crate::intrinsics::Intrinsics;
|
||||
use crate::read_info::type_to_type;
|
||||
use crate::state::State;
|
||||
use crate::state::{ControlFrame, IfElseState, State};
|
||||
|
||||
fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig) -> FunctionType {
|
||||
let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
|
||||
@ -116,10 +117,37 @@ fn parse_function(
|
||||
let llvm_sig = &signatures[sig_index];
|
||||
|
||||
let function = functions[func_index];
|
||||
let entry_block = context.append_basic_block(&function, "entry");
|
||||
builder.position_at_end(&entry_block);
|
||||
|
||||
let mut state = State::new();
|
||||
let entry_block = context.append_basic_block(&function, "entry");
|
||||
|
||||
let return_block = context.append_basic_block(&function, "return");
|
||||
builder.position_at_end(&return_block);
|
||||
|
||||
let phis: SmallVec<[PhiValue; 1]> = func_sig
|
||||
.returns()
|
||||
.iter()
|
||||
.map(|&wasmer_ty| type_to_llvm(intrinsics, wasmer_ty))
|
||||
.map(|ty| builder.build_phi(ty, &state.var_name()))
|
||||
.collect();
|
||||
|
||||
match phis.as_slice() {
|
||||
// No returns.
|
||||
&[] => {
|
||||
builder.build_return(None);
|
||||
}
|
||||
&[one_value] => {
|
||||
let value = one_value.as_basic_value();
|
||||
builder.build_return(Some(&value));
|
||||
}
|
||||
returns @ _ => {
|
||||
// let struct_ty = llvm_sig.get_return_type().as_struct_type();
|
||||
// let ret_struct = struct_ty.const_zero();
|
||||
unimplemented!("multi-value returns not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
state.push_block(return_block, phis);
|
||||
builder.position_at_end(&entry_block);
|
||||
|
||||
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
|
||||
locals.extend(function.get_param_iter().enumerate().map(|(index, param)| {
|
||||
@ -163,7 +191,7 @@ fn parse_function(
|
||||
offset: -1isize as usize,
|
||||
})?;
|
||||
|
||||
let end_block = context.append_basic_block(&function, &state.block_name());
|
||||
let end_block = context.append_basic_block(&function, "end");
|
||||
builder.position_at_end(&end_block);
|
||||
|
||||
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
||||
@ -180,12 +208,24 @@ fn parse_function(
|
||||
builder.position_at_end(¤t_block);
|
||||
}
|
||||
Operator::Loop { ty } => {
|
||||
let loop_body = context.append_basic_block(&function, "loop_body");
|
||||
let loop_next = context.append_basic_block(&function, "loop_outer");
|
||||
|
||||
// let loop_body = context.append_basic_block(&function, &state.block_name());
|
||||
// let next = context.append_basic_block(&function, &state.block_name());
|
||||
// builder.build_unconditional_branch(&body);
|
||||
// let num_return_values = if ty == wasmparser::Type::EmptyBlockType { 0 } else { 1 };
|
||||
// state.push_loop(loop_body, next, num_return_values);
|
||||
builder.build_unconditional_branch(&loop_body);
|
||||
|
||||
builder.position_at_end(&loop_next);
|
||||
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
||||
let llvm_ty = type_to_llvm(intrinsics, wasmer_ty);
|
||||
[llvm_ty]
|
||||
.iter()
|
||||
.map(|&ty| builder.build_phi(ty, &state.var_name()))
|
||||
.collect()
|
||||
} else {
|
||||
SmallVec::new()
|
||||
};
|
||||
|
||||
builder.position_at_end(&loop_body);
|
||||
state.push_loop(loop_body, loop_next, phis);
|
||||
}
|
||||
Operator::Br { relative_depth } => {
|
||||
let frame = state.frame_at_depth(relative_depth)?;
|
||||
@ -195,7 +235,13 @@ fn parse_function(
|
||||
offset: -1isize as usize,
|
||||
})?;
|
||||
|
||||
let values = state.peekn(frame.phis().len())?;
|
||||
let value_len = if frame.is_loop() {
|
||||
0
|
||||
} else {
|
||||
frame.phis().len()
|
||||
};
|
||||
|
||||
let values = state.peekn(value_len)?;
|
||||
|
||||
// For each result of the block we're branching to,
|
||||
// pop a value off the value stack and load it into
|
||||
@ -204,11 +250,10 @@ fn parse_function(
|
||||
phi.add_incoming(&[(value, ¤t_block)]);
|
||||
}
|
||||
|
||||
builder.build_unconditional_branch(frame.dest());
|
||||
builder.build_unconditional_branch(frame.br_dest());
|
||||
|
||||
state.popn(frame.phis().len())?;
|
||||
|
||||
builder.build_unreachable();
|
||||
state.popn(value_len)?;
|
||||
state.reachable = false;
|
||||
}
|
||||
Operator::BrIf { relative_depth } => {
|
||||
let cond = state.pop1()?;
|
||||
@ -219,13 +264,19 @@ fn parse_function(
|
||||
offset: -1isize as usize,
|
||||
})?;
|
||||
|
||||
let param_stack = state.peekn(frame.phis().len())?;
|
||||
let value_len = if frame.is_loop() {
|
||||
0
|
||||
} else {
|
||||
frame.phis().len()
|
||||
};
|
||||
|
||||
let param_stack = state.peekn(value_len)?;
|
||||
|
||||
for (phi, value) in frame.phis().iter().zip(param_stack.iter()) {
|
||||
phi.add_incoming(&[(value, ¤t_block)]);
|
||||
}
|
||||
|
||||
let false_block = context.append_basic_block(&function, &state.block_name());
|
||||
let else_block = context.append_basic_block(&function, "else");
|
||||
|
||||
let cond_value = builder.build_int_compare(
|
||||
IntPredicate::NE,
|
||||
@ -233,8 +284,8 @@ fn parse_function(
|
||||
intrinsics.i32_zero,
|
||||
&state.var_name(),
|
||||
);
|
||||
builder.build_conditional_branch(cond_value, frame.dest(), &false_block);
|
||||
builder.position_at_end(&false_block);
|
||||
builder.build_conditional_branch(cond_value, frame.br_dest(), &else_block);
|
||||
builder.position_at_end(&else_block);
|
||||
}
|
||||
Operator::BrTable { ref table } => {
|
||||
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||
@ -268,25 +319,131 @@ fn parse_function(
|
||||
phi.add_incoming(&[(value, ¤t_block)]);
|
||||
}
|
||||
|
||||
Ok((case_index_literal, frame.dest()))
|
||||
Ok((case_index_literal, frame.br_dest()))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
builder.build_switch(index.into_int_value(), default_frame.dest(), &cases[..]);
|
||||
builder.build_switch(index.into_int_value(), default_frame.br_dest(), &cases[..]);
|
||||
|
||||
state.popn(res_len)?;
|
||||
builder.build_unreachable();
|
||||
}
|
||||
Operator::If { ty } => {
|
||||
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||
message: "not currently in a block",
|
||||
offset: -1isize as usize,
|
||||
})?;
|
||||
let if_then_block = context.append_basic_block(&function, "if_then");
|
||||
let if_else_block = context.append_basic_block(&function, "if_else");
|
||||
let end_block = context.append_basic_block(&function, "if_end");
|
||||
|
||||
let end_phis = {
|
||||
builder.position_at_end(&end_block);
|
||||
|
||||
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
||||
let llvm_ty = type_to_llvm(intrinsics, wasmer_ty);
|
||||
[llvm_ty]
|
||||
.iter()
|
||||
.map(|&ty| builder.build_phi(ty, &state.var_name()))
|
||||
.collect()
|
||||
} else {
|
||||
SmallVec::new()
|
||||
};
|
||||
|
||||
builder.position_at_end(¤t_block);
|
||||
phis
|
||||
};
|
||||
|
||||
let cond = state.pop1()?;
|
||||
|
||||
let cond_value = builder.build_int_compare(
|
||||
IntPredicate::NE,
|
||||
cond.into_int_value(),
|
||||
intrinsics.i32_zero,
|
||||
&state.var_name(),
|
||||
);
|
||||
|
||||
builder.build_conditional_branch(cond_value, &if_then_block, &if_else_block);
|
||||
builder.position_at_end(&if_then_block);
|
||||
state.push_if(if_then_block, if_else_block, end_block, end_phis);
|
||||
}
|
||||
Operator::Else => {
|
||||
if state.reachable {
|
||||
let frame = state.frame_at_depth(0)?;
|
||||
builder.build_unconditional_branch(frame.code_after());
|
||||
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||
message: "not currently in a block",
|
||||
offset: -1isize as usize,
|
||||
})?;
|
||||
|
||||
for phi in frame.phis().to_vec().iter().rev() {
|
||||
let value = state.pop1()?;
|
||||
phi.add_incoming(&[(&value, ¤t_block)])
|
||||
}
|
||||
}
|
||||
|
||||
let (if_else_block, if_else_state) = if let ControlFrame::IfElse {
|
||||
if_else,
|
||||
if_else_state,
|
||||
..
|
||||
} = state.frame_at_depth_mut(0)?
|
||||
{
|
||||
(if_else, if_else_state)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
*if_else_state = IfElseState::Else;
|
||||
|
||||
builder.position_at_end(if_else_block);
|
||||
state.reachable = true;
|
||||
}
|
||||
|
||||
Operator::End => {
|
||||
let frame = state.pop_frame()?;
|
||||
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||
message: "not currently in a block",
|
||||
offset: -1isize as usize,
|
||||
})?;
|
||||
|
||||
if state.reachable {
|
||||
builder.build_unconditional_branch(frame.code_after());
|
||||
|
||||
for phi in frame.phis().iter().rev() {
|
||||
let value = state.pop1()?;
|
||||
phi.add_incoming(&[(&value, ¤t_block)])
|
||||
}
|
||||
}
|
||||
|
||||
if let ControlFrame::IfElse {
|
||||
if_else,
|
||||
next,
|
||||
phis,
|
||||
if_else_state,
|
||||
..
|
||||
} = &frame
|
||||
{
|
||||
if let IfElseState::If = if_else_state {
|
||||
builder.position_at_end(if_else);
|
||||
builder.build_unconditional_branch(next);
|
||||
}
|
||||
}
|
||||
|
||||
builder.position_at_end(frame.code_after());
|
||||
state.reset_stack(&frame);
|
||||
|
||||
state.reachable = true;
|
||||
|
||||
// Push each phi value to the value stack.
|
||||
for phi in frame.phis() {
|
||||
state.push1(phi.as_basic_value());
|
||||
}
|
||||
}
|
||||
Operator::Return => {
|
||||
let frame = state.outermost_frame()?;
|
||||
|
||||
state.reset_stack(&frame);
|
||||
builder.build_unconditional_branch(frame.br_dest());
|
||||
state.reachable = false;
|
||||
}
|
||||
|
||||
Operator::Unreachable => {
|
||||
@ -294,6 +451,7 @@ fn parse_function(
|
||||
// If llvm cannot prove that this is never touched,
|
||||
// it will emit a `ud2` instruction on x86_64 arches.
|
||||
builder.build_unreachable();
|
||||
state.reachable = false;
|
||||
}
|
||||
|
||||
/***************************
|
||||
@ -1021,6 +1179,26 @@ fn parse_function(
|
||||
unimplemented!("waiting on better bitcasting support in inkwell")
|
||||
}
|
||||
|
||||
Operator::MemoryGrow { reserved } => {
|
||||
|
||||
let memory_grow_const = intrinsics.i32_ty.const_int(reserved as u64, false);
|
||||
|
||||
let memory_index = MemoryIndex::new(reserved);
|
||||
match memory_index.local_or_import(info) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let mem_desc = &info.memories[local_mem_index];
|
||||
match mem_desc.memory_type() {
|
||||
MemoryType::Dynamic => {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
LocalOrImport::Import(import_mem_index) => {
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
op @ _ => {
|
||||
println!("{}", module.print_to_string().to_string());
|
||||
unimplemented!("{:?}", op);
|
||||
@ -1028,5 +1206,12 @@ fn parse_function(
|
||||
}
|
||||
}
|
||||
|
||||
let pass_manager = PassManager::create_for_module();
|
||||
pass_manager.add_promote_memory_to_register_pass();
|
||||
pass_manager.add_cfg_simplification_pass();
|
||||
pass_manager.run_on_module(module);
|
||||
|
||||
println!("{}", module.print_to_string().to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -54,6 +54,22 @@ pub struct Intrinsics {
|
||||
pub i64_zero: IntValue,
|
||||
pub f32_zero: FloatValue,
|
||||
pub f64_zero: FloatValue,
|
||||
|
||||
// VM intrinsics.
|
||||
pub memory_grow_dynamic_local: FunctionValue,
|
||||
pub memory_grow_static_local: FunctionValue,
|
||||
pub memory_grow_shared_local: FunctionValue,
|
||||
pub memory_grow_dynamic_import: FunctionValue,
|
||||
pub memory_grow_static_import: FunctionValue,
|
||||
pub memory_grow_shared_import: FunctionValue,
|
||||
|
||||
pub memory_size_dynamic_local: FunctionValue,
|
||||
pub memory_size_static_local: FunctionValue,
|
||||
pub memory_size_shared_local: FunctionValue,
|
||||
pub memory_size_dynamic_import: FunctionValue,
|
||||
pub memory_size_static_import: FunctionValue,
|
||||
pub memory_size_shared_import: FunctionValue,
|
||||
// pub ctx_ty: StructType,
|
||||
}
|
||||
|
||||
impl Intrinsics {
|
||||
@ -64,6 +80,7 @@ impl Intrinsics {
|
||||
let i64_ty = context.i64_type();
|
||||
let f32_ty = context.f32_type();
|
||||
let f64_ty = context.f64_type();
|
||||
// let ctx_ty = context.struct_type(&[], false);
|
||||
|
||||
let i1_zero = i1_ty.const_int(0, false);
|
||||
let i32_zero = i32_ty.const_int(0, false);
|
||||
@ -89,6 +106,9 @@ impl Intrinsics {
|
||||
let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false);
|
||||
let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false);
|
||||
|
||||
let ret_i32_take_i64_i32_i32 = i32_ty.fn_type(&[i64_ty, i32_ty, i32_ty], false);
|
||||
let ret_i32_take_i64_i32 = i32_ty.fn_type(&[i64_ty, i32_ty], false);
|
||||
|
||||
Self {
|
||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
||||
@ -138,6 +158,25 @@ impl Intrinsics {
|
||||
i64_zero,
|
||||
f32_zero,
|
||||
f64_zero,
|
||||
|
||||
// VM intrinsics.
|
||||
memory_grow_dynamic_local: module.add_function("vm.memory.grow.dynamic.local", ret_i32_take_i64_i32_i32, None),
|
||||
memory_grow_static_local: module.add_function("vm.memory.grow.static.local", ret_i32_take_i64_i32_i32, None),
|
||||
memory_grow_shared_local: module.add_function("vm.memory.grow.shared.local", ret_i32_take_i64_i32_i32, None),
|
||||
memory_grow_dynamic_import: module.add_function("vm.memory.grow.dynamic.import", ret_i32_take_i64_i32_i32, None),
|
||||
memory_grow_static_import: module.add_function("vm.memory.grow.static.import", ret_i32_take_i64_i32_i32, None),
|
||||
memory_grow_shared_import: module.add_function("vm.memory.grow.shared.import", ret_i32_take_i64_i32_i32, None),
|
||||
|
||||
memory_size_dynamic_local: module.add_function("vm.memory.size.dynamic.local", ret_i32_take_i64_i32, None),
|
||||
memory_size_static_local: module.add_function("vm.memory.size.static.local", ret_i32_take_i64_i32, None),
|
||||
memory_size_shared_local: module.add_function("vm.memory.size.shared.local", ret_i32_take_i64_i32, None),
|
||||
memory_size_dynamic_import: module.add_function("vm.memory.size.dynamic.import", ret_i32_take_i64_i32, None),
|
||||
memory_size_static_import: module.add_function("vm.memory.size.static.import", ret_i32_take_i64_i32, None),
|
||||
memory_size_shared_import: module.add_function("vm.memory.size.shared.import", ret_i32_take_i64_i32, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub struct CtxType {
|
||||
// ctx_ty: StructType,
|
||||
// }
|
||||
|
@ -30,21 +30,26 @@ impl Compiler for LLVMCompiler {
|
||||
#[test]
|
||||
fn test_read_module() {
|
||||
use wabt::wat2wasm;
|
||||
let WAT: &'static str = r#"
|
||||
let wat = r#"
|
||||
(module
|
||||
(type $t0 (func (param i32) (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
(import "env" "table" (table 10 anyfunc))
|
||||
(import "env" "global" (global i32))
|
||||
(import "env" "print_i32" (func $print_i32 (type $t0)))
|
||||
(func $identity (type $t0) (param $p0 i32) (result i32)
|
||||
get_local $p0)
|
||||
(func $print_num (export "print_num") (type $t0) (param $p0 i32) (result i32)
|
||||
get_global 0
|
||||
call $identity
|
||||
call $print_i32))
|
||||
(type $t1 (func (result i32)))
|
||||
(func $foo (type $t0) (param i32) (result i32)
|
||||
get_local 0
|
||||
(if
|
||||
(then
|
||||
i32.const 42
|
||||
set_local 0
|
||||
)
|
||||
(else
|
||||
i32.const 24
|
||||
set_local 0
|
||||
)
|
||||
)
|
||||
get_local 0
|
||||
))
|
||||
"#;
|
||||
let wasm = wat2wasm(WAT).unwrap();
|
||||
let wasm = wat2wasm(wat).unwrap();
|
||||
|
||||
let (info, code_reader) = read_info::read_module(&wasm).unwrap();
|
||||
|
||||
|
@ -285,7 +285,12 @@ pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
_ => panic!("broken invariant, invalid type"),
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "that type is not supported as a wasmer type",
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -6,33 +6,73 @@ use smallvec::SmallVec;
|
||||
use std::cell::Cell;
|
||||
use wasmparser::BinaryReaderError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ControlFrame {
|
||||
Block {
|
||||
end_label: BasicBlock,
|
||||
next: BasicBlock,
|
||||
phis: SmallVec<[PhiValue; 1]>,
|
||||
stack_size_snapshot: usize,
|
||||
},
|
||||
Loop {
|
||||
body: BasicBlock,
|
||||
next: BasicBlock,
|
||||
phis: SmallVec<[PhiValue; 1]>,
|
||||
stack_size_snapshot: usize,
|
||||
},
|
||||
IfElse {
|
||||
if_then: BasicBlock,
|
||||
if_else: BasicBlock,
|
||||
next: BasicBlock,
|
||||
phis: SmallVec<[PhiValue; 1]>,
|
||||
stack_size_snapshot: usize,
|
||||
if_else_state: IfElseState,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IfElseState {
|
||||
If,
|
||||
Else,
|
||||
}
|
||||
|
||||
impl ControlFrame {
|
||||
pub fn dest(&self) -> &BasicBlock {
|
||||
pub fn code_after(&self) -> &BasicBlock {
|
||||
match self {
|
||||
ControlFrame::Block { ref end_label, .. } => end_label,
|
||||
ControlFrame::Block { ref next, .. }
|
||||
| ControlFrame::Loop { ref next, .. }
|
||||
| ControlFrame::IfElse { ref next, .. } => next,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn br_dest(&self) -> &BasicBlock {
|
||||
match self {
|
||||
ControlFrame::Block { ref next, .. } | ControlFrame::IfElse { ref next, .. } => next,
|
||||
ControlFrame::Loop { ref body, .. } => body,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn phis(&self) -> &[PhiValue] {
|
||||
match self {
|
||||
ControlFrame::Block { ref phis, .. } => phis.as_slice(),
|
||||
ControlFrame::Block { ref phis, .. }
|
||||
| ControlFrame::Loop { ref phis, .. }
|
||||
| ControlFrame::IfElse { ref phis, .. } => phis.as_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_loop(&self) -> bool {
|
||||
match self {
|
||||
ControlFrame::Loop { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct State {
|
||||
stack: Vec<BasicValueEnum>,
|
||||
control_stack: Vec<ControlFrame>,
|
||||
value_counter: Cell<usize>,
|
||||
block_counter: Cell<usize>,
|
||||
pub reachable: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@ -41,7 +81,7 @@ impl State {
|
||||
stack: vec![],
|
||||
control_stack: vec![],
|
||||
value_counter: Cell::new(0),
|
||||
block_counter: Cell::new(0),
|
||||
reachable: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,11 +90,26 @@ impl State {
|
||||
ControlFrame::Block {
|
||||
stack_size_snapshot,
|
||||
..
|
||||
}
|
||||
| ControlFrame::Loop {
|
||||
stack_size_snapshot,
|
||||
..
|
||||
}
|
||||
| ControlFrame::IfElse {
|
||||
stack_size_snapshot,
|
||||
..
|
||||
} => *stack_size_snapshot,
|
||||
};
|
||||
self.stack.truncate(stack_size_snapshot);
|
||||
}
|
||||
|
||||
pub fn outermost_frame(&self) -> Result<&ControlFrame, BinaryReaderError> {
|
||||
self.control_stack.get(0).ok_or(BinaryReaderError {
|
||||
message: "invalid control stack depth",
|
||||
offset: -1isize as usize,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame, BinaryReaderError> {
|
||||
let index = self.control_stack.len() - 1 - (depth as usize);
|
||||
self.control_stack.get(index).ok_or(BinaryReaderError {
|
||||
@ -63,6 +118,17 @@ impl State {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn frame_at_depth_mut(
|
||||
&mut self,
|
||||
depth: u32,
|
||||
) -> Result<&mut ControlFrame, BinaryReaderError> {
|
||||
let index = self.control_stack.len() - 1 - (depth as usize);
|
||||
self.control_stack.get_mut(index).ok_or(BinaryReaderError {
|
||||
message: "invalid control stack depth",
|
||||
offset: -1isize as usize,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pop_frame(&mut self) -> Result<ControlFrame, BinaryReaderError> {
|
||||
self.control_stack.pop().ok_or(BinaryReaderError {
|
||||
message: "cannot pop from control stack",
|
||||
@ -70,13 +136,6 @@ impl State {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn block_name(&self) -> String {
|
||||
let counter = self.block_counter.get();
|
||||
let s = format!("block{}", counter);
|
||||
self.block_counter.set(counter + 1);
|
||||
s
|
||||
}
|
||||
|
||||
pub fn var_name(&self) -> String {
|
||||
let counter = self.value_counter.get();
|
||||
let s = format!("s{}", counter);
|
||||
@ -129,6 +188,12 @@ impl State {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn popn_save(&mut self, n: usize) -> Result<Vec<BasicValueEnum>, BinaryReaderError> {
|
||||
let v = self.peekn(n)?.to_vec();
|
||||
self.popn(n)?;
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub fn popn(&mut self, n: usize) -> Result<(), BinaryReaderError> {
|
||||
if self.stack.len() < n {
|
||||
return Err(BinaryReaderError {
|
||||
@ -142,11 +207,37 @@ impl State {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_block(&mut self, end_label: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
|
||||
pub fn push_block(&mut self, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
|
||||
self.control_stack.push(ControlFrame::Block {
|
||||
end_label,
|
||||
next,
|
||||
phis,
|
||||
stack_size_snapshot: self.stack.len(),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push_loop(&mut self, body: BasicBlock, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
|
||||
self.control_stack.push(ControlFrame::Loop {
|
||||
body,
|
||||
next,
|
||||
phis,
|
||||
stack_size_snapshot: self.stack.len(),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push_if(
|
||||
&mut self,
|
||||
if_then: BasicBlock,
|
||||
if_else: BasicBlock,
|
||||
next: BasicBlock,
|
||||
phis: SmallVec<[PhiValue; 1]>,
|
||||
) {
|
||||
self.control_stack.push(ControlFrame::IfElse {
|
||||
if_then,
|
||||
if_else,
|
||||
next,
|
||||
phis,
|
||||
stack_size_snapshot: self.stack.len(),
|
||||
if_else_state: IfElseState::If,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user