From 53bebf9c7326ed466be27785842d743b20186755 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 29 Apr 2019 00:13:34 -0500 Subject: [PATCH 01/15] Add initial progress to add LLVM to module refactor --- Cargo.lock | 8 +- lib/llvm-backend/Cargo.toml | 2 +- lib/llvm-backend/src/code.rs | 2248 +++++++++++++++++++++++++ lib/llvm-backend/src/lib.rs | 8 + lib/spectests/examples/simple/main.rs | 4 +- 5 files changed, 2260 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03a29e4ee75..7995d9aa60a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2300,7 +2300,7 @@ dependencies = [ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.3.0", - "wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2433,11 +2433,6 @@ name = "wasmparser" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "wasmparser" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "wasmparser" version = "0.29.2" @@ -2832,7 +2827,6 @@ dependencies = [ "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" -"checksum wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40f426b1929bd26517fb10702e2a8e520d1845c49567aa4d244f426f10b206c1" "checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 944db6d4124..c1a1cbbdc93 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" } inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm7-0" } -wasmparser = "0.28.0" +wasmparser = "0.29.2" hashbrown = "0.1.8" smallvec = "0.6.8" goblin = "0.0.20" diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 05cde06949c..bc13bf28194 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8,7 +8,10 @@ use inkwell::{ AddressSpace, FloatPredicate, IntPredicate, }; use smallvec::SmallVec; +use std::{any::Any, collections::HashMap, sync::Arc}; use wasmer_runtime_core::{ + backend::Backend, + codegen::*, memory::MemoryType, module::ModuleInfo, structures::{Map, SliceMap, TypedIndex}, @@ -19,12 +22,14 @@ use wasmer_runtime_core::{ }; use wasmparser::{ BinaryReaderError, CodeSectionReader, LocalsReader, MemoryImmediate, Operator, OperatorsReader, + Type as WpType, }; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::type_to_type; use crate::state::{ControlFrame, IfElseState, State}; use crate::trampolines::generate_trampolines; +use crate::backend::LLVMBackend; 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)); @@ -2460,3 +2465,2246 @@ fn resolve_memory_ptr( builder.build_int_add(mem_base_int, effective_offset, &state.var_name()); Ok(builder.build_int_to_ptr(effective_address_int, ptr_ty, &state.var_name())) } + +#[derive(Debug)] +pub struct CodegenError { + pub message: &'static str, +} + +pub struct LLVMModuleCodeGenerator { + context: Context, + builder: &'static Builder, + functions: Vec, + functions_llvm: &'static SliceMap, +// signatures: Option>>, + signatures: &'static SliceMap, + function_signatures: Option>>, + // function_labels: Option)>>, + // assembler: Option, + func_import_count: usize, + intrinsics: &'static Intrinsics, +// ctx: CtxType, +} + +// pub struct LLVMExecutionContext { +// // #[allow(dead_code)] +// // code: ExecutableBuffer, +// // #[allow(dead_code)] +// // functions: Vec, +// // function_pointers: Vec, +// // signatures: Arc>, +// // _br_table_data: Vec>, +// // breakpoints: Arc>>, +// // func_import_count: usize, +// } + +pub struct LLVMFunctionCodeGenerator { + state: State, + builder: &'static Builder, + context: &'static Context, + function: FunctionValue, + func_sig: &'static FuncSig, + intrinsics: &'static Intrinsics, + signatures: &'static SliceMap, + // signatures: Arc>, + + // function_signatures: Arc>, + + // assembler: Option, + // function_labels: Option)>>, + // br_table_data: Option>>, + // breakpoints: Option>>, + // returns: SmallVec<[WpType; 1]>, + locals: Vec, + // num_params: usize, + // num_locals: usize, + // value_stack: Vec<(Location, LocalOrTemp)>, + // control_stack: Vec, + // machine: Machine, + // unreachable_depth: usize, +} + +impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { + fn feed_return(&mut self, ty: WpType) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { + unimplemented!() + } + + fn begin_body(&mut self) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { + +// let sig_index = info.func_assoc[func_index.convert_up(info)]; +// let func_sig = &info.signatures[sig_index]; +// +// let function = self.functions[func_index]; +// 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(); +// +// state.push_block(return_block, phis); +// builder.position_at_end(&entry_block); +// +// let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity +// +// locals.extend( +// function +// .get_param_iter() +// .skip(1) +// .enumerate() +// .map(|(index, param)| { +// let ty = param.get_type(); +// +// let alloca = builder.build_alloca(ty, &format!("local{}", index)); +// builder.build_store(alloca, param); +// alloca +// }), +// ); +// +// let param_len = locals.len(); +// +// let mut local_idx = 0; +// for local in locals_reader.into_iter() { +// let (count, ty) = local?; +// let wasmer_ty = type_to_type(ty)?; +// let ty = type_to_llvm(intrinsics, wasmer_ty); +// +// let default_value = match wasmer_ty { +// Type::I32 => intrinsics.i32_zero.as_basic_value_enum(), +// Type::I64 => intrinsics.i64_zero.as_basic_value_enum(), +// Type::F32 => intrinsics.f32_zero.as_basic_value_enum(), +// Type::F64 => intrinsics.f64_zero.as_basic_value_enum(), +// }; +// +// for _ in 0..count { +// let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); +// +// builder.build_store(alloca, default_value); +// +// locals.push(alloca); +// local_idx += 1; +// } +// } +// +// let start_of_code_block = context.append_basic_block(&function, "start_of_code"); +// let entry_end_inst = builder.build_unconditional_branch(&start_of_code_block); +// builder.position_at_end(&start_of_code_block); +// +// let cache_builder = context.create_builder(); +// cache_builder.position_before(&entry_end_inst); + + + let mut state = &mut self.state; + let builder = self.builder; + let context = self.context; + let function = self.function; + let intrinsics = self.intrinsics; + let locals = &self.locals; + let info = module_info; + let signatures = self.signatures; + + + // TODO this should be done only once per function I believe + // just adding here to get compilation + let cache_builder = context.create_builder(); +// cache_builder.position_before(&entry_end_inst); + let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); +// self.ctx; + + + let op = match event { + Event::Wasm(x) => x, + Event::Internal(x) => { + unimplemented!() + } + }; + + let mut unreachable_depth = 0; + if !state.reachable { + match *op { + Operator::Block { ty: _ } | Operator::Loop { ty: _ } | Operator::If { ty: _ } => { + unreachable_depth += 1; +// continue; + return Ok(()); + } + Operator::Else => { + if unreachable_depth != 0 { + // continue; + return Ok(()); + } + } + Operator::End => { + if unreachable_depth != 0 { + unreachable_depth -= 1; + // continue; + return Ok(()); + } + } + _ => { + // continue; + return Ok(()); + } + } + } + + match *op { + /*************************** + * Control Flow instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#control-flow-instructions + ***************************/ + Operator::Block { ty } => { + let current_block = builder.get_insert_block().ok_or(BinaryReaderError { + message: "not currently in a block", + offset: -1isize as usize, + })?; + + 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) { + 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() + }; + + state.push_block(end_block, phis); + 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"); + + 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)?; + + let current_block = builder.get_insert_block().ok_or(BinaryReaderError { + message: "not currently in a block", + offset: -1isize as usize, + })?; + + 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 + // the corresponding phi. + for (phi, value) in frame.phis().iter().zip(values.iter()) { + phi.add_incoming(&[(value, ¤t_block)]); + } + + builder.build_unconditional_branch(frame.br_dest()); + + state.popn(value_len)?; + state.reachable = false; + } + Operator::BrIf { relative_depth } => { + let cond = state.pop1()?; + let frame = state.frame_at_depth(relative_depth)?; + + let current_block = builder.get_insert_block().ok_or(BinaryReaderError { + message: "not currently in a block", + offset: -1isize as usize, + })?; + + 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 else_block = context.append_basic_block(&function, "else"); + + 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, 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 { + message: "not currently in a block", + offset: -1isize as usize, + })?; + + let (label_depths, default_depth) = table.read_table()?; + + let index = state.pop1()?; + + let default_frame = state.frame_at_depth(default_depth)?; + + let args = if default_frame.is_loop() { + &[] + } else { + let res_len = default_frame.phis().len(); + state.peekn(res_len)? + }; + + for (phi, value) in default_frame.phis().iter().zip(args.iter()) { + phi.add_incoming(&[(value, ¤t_block)]); + } + + let cases: Vec<_> = label_depths + .iter() + .enumerate() + .map(|(case_index, &depth)| { + let frame_result: Result<&ControlFrame, BinaryReaderError> = state.frame_at_depth(depth); + let frame = match frame_result { + Ok(v) => v, + Err(e) => return Err(e), + }; + let case_index_literal = + context.i32_type().const_int(case_index as u64, false); + + for (phi, value) in frame.phis().iter().zip(args.iter()) { + phi.add_incoming(&[(value, ¤t_block)]); + } + + Ok((case_index_literal, frame.br_dest())) + }) + .collect::>()?; + + builder.build_switch(index.into_int_value(), default_frame.br_dest(), &cases[..]); + + state.popn(args.len())?; + state.reachable = false; + } + 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, + 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() { + if phi.count_incoming() != 0 { + state.push1(phi.as_basic_value()); + } else { + let basic_ty = phi.as_basic_value().get_type(); + let placeholder_value = match basic_ty { + BasicTypeEnum::IntType(int_ty) => { + int_ty.const_int(0, false).as_basic_value_enum() + } + BasicTypeEnum::FloatType(float_ty) => { + float_ty.const_float(0.0).as_basic_value_enum() + } + _ => unimplemented!(), + }; + state.push1(placeholder_value); + phi.as_instruction().erase_from_basic_block(); + } + } + } + Operator::Return => { + let frame = state.outermost_frame()?; + let current_block = builder.get_insert_block().ok_or(BinaryReaderError { + message: "not currently in a block", + offset: -1isize as usize, + })?; + + builder.build_unconditional_branch(frame.br_dest()); + + let phis = frame.phis().to_vec(); + + for phi in phis.iter() { + let arg = state.pop1()?; + phi.add_incoming(&[(&arg, ¤t_block)]); + } + + state.reachable = false; + } + + Operator::Unreachable => { + // Emit an unreachable instruction. + // If llvm cannot prove that this is never touched, + // it will emit a `ud2` instruction on x86_64 arches. + + builder.build_call( + intrinsics.throw_trap, + &[intrinsics.trap_unreachable], + "throw", + ); + builder.build_unreachable(); + + state.reachable = false; + } + + /*************************** + * Basic instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#basic-instructions + ***************************/ + Operator::Nop => { + // Do nothing. + } + Operator::Drop => { + state.pop1()?; + } + + // Generate const values. + Operator::I32Const { value } => { + let i = intrinsics.i32_ty.const_int(value as u64, false); + state.push1(i); + } + Operator::I64Const { value } => { + let i = intrinsics.i64_ty.const_int(value as u64, false); + state.push1(i); + } + Operator::F32Const { value } => { + let bits = intrinsics.i32_ty.const_int(value.bits() as u64, false); + let space = + builder.build_alloca(intrinsics.f32_ty.as_basic_type_enum(), "const_space"); + let i32_space = + builder.build_pointer_cast(space, intrinsics.i32_ptr_ty, "i32_space"); + builder.build_store(i32_space, bits); + let f = builder.build_load(space, "f"); + state.push1(f); + } + Operator::F64Const { value } => { + let bits = intrinsics.i64_ty.const_int(value.bits(), false); + let space = + builder.build_alloca(intrinsics.f64_ty.as_basic_type_enum(), "const_space"); + let i64_space = + builder.build_pointer_cast(space, intrinsics.i64_ptr_ty, "i32_space"); + builder.build_store(i64_space, bits); + let f = builder.build_load(space, "f"); + state.push1(f); + } + + // Operate on locals. + Operator::GetLocal { local_index } => { + let pointer_value = locals[local_index as usize]; + let v = builder.build_load(pointer_value, &state.var_name()); + state.push1(v); + } + Operator::SetLocal { local_index } => { + let pointer_value = locals[local_index as usize]; + let v = state.pop1()?; + builder.build_store(pointer_value, v); + } + Operator::TeeLocal { local_index } => { + let pointer_value = locals[local_index as usize]; + let v = state.peek1()?; + builder.build_store(pointer_value, v); + } + + Operator::GetGlobal { global_index } => { + let index = GlobalIndex::new(global_index as usize); + let global_cache = ctx.global_cache(index); + match global_cache { + GlobalCache::Const { value } => { + state.push1(value); + } + GlobalCache::Mut { ptr_to_value } => { + let value = builder.build_load(ptr_to_value, "global_value"); + state.push1(value); + } + } + } + Operator::SetGlobal { global_index } => { + let value = state.pop1()?; + let index = GlobalIndex::new(global_index as usize); + let global_cache = ctx.global_cache(index); + match global_cache { + GlobalCache::Mut { ptr_to_value } => { + builder.build_store(ptr_to_value, value); + } + GlobalCache::Const { value: _ } => { + unreachable!("cannot set non-mutable globals") + } + } + } + + Operator::Select => { + let (v1, v2, cond) = state.pop3()?; + let cond_value = builder.build_int_compare( + IntPredicate::NE, + cond.into_int_value(), + intrinsics.i32_zero, + &state.var_name(), + ); + let res = builder.build_select(cond_value, v1, v2, &state.var_name()); + state.push1(res); + } + Operator::Call { function_index } => { + let func_index = FuncIndex::new(function_index as usize); + let sigindex = info.func_assoc[func_index]; + let llvm_sig = signatures[sigindex]; + let func_sig = &info.signatures[sigindex]; + + let call_site = match func_index.local_or_import(info) { + LocalOrImport::Local(local_func_index) => { + let params: Vec<_> = [ctx.basic()] + .iter() + .chain(state.peekn(func_sig.params().len())?.iter()) + .map(|v| *v) + .collect(); + + let func_ptr = ctx.local_func(local_func_index, llvm_sig); + + builder.build_call(func_ptr, ¶ms, &state.var_name()) + } + LocalOrImport::Import(import_func_index) => { + let (func_ptr_untyped, ctx_ptr) = ctx.imported_func(import_func_index); + let params: Vec<_> = [ctx_ptr.as_basic_value_enum()] + .iter() + .chain(state.peekn(func_sig.params().len())?.iter()) + .map(|v| *v) + .collect(); + + let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic); + + let func_ptr = builder.build_pointer_cast( + func_ptr_untyped, + func_ptr_ty, + "typed_func_ptr", + ); + + builder.build_call(func_ptr, ¶ms, &state.var_name()) + } + }; + + state.popn(func_sig.params().len())?; + + if let Some(basic_value) = call_site.try_as_basic_value().left() { + match func_sig.returns().len() { + 1 => state.push1(basic_value), + count @ _ => { + // This is a multi-value return. + let struct_value = basic_value.into_struct_value(); + for i in 0..(count as u32) { + let value = builder + .build_extract_value(struct_value, i, &state.var_name()) + .unwrap(); + state.push1(value); + } + } + } + } + } + Operator::CallIndirect { index, table_index } => { + let sig_index = SigIndex::new(index as usize); + let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index); + let (table_base, table_bound) = ctx.table(TableIndex::new(table_index as usize)); + let func_index = state.pop1()?.into_int_value(); + + // We assume the table has the `anyfunc` element type. + let casted_table_base = builder.build_pointer_cast( + table_base, + intrinsics.anyfunc_ty.ptr_type(AddressSpace::Generic), + "casted_table_base", + ); + + let anyfunc_struct_ptr = unsafe { + builder.build_in_bounds_gep( + casted_table_base, + &[func_index], + "anyfunc_struct_ptr", + ) + }; + + // Load things from the anyfunc data structure. + let (func_ptr, ctx_ptr, found_dynamic_sigindex) = unsafe { + ( + builder + .build_load( + builder.build_struct_gep(anyfunc_struct_ptr, 0, "func_ptr_ptr"), + "func_ptr", + ) + .into_pointer_value(), + builder.build_load( + builder.build_struct_gep(anyfunc_struct_ptr, 1, "ctx_ptr_ptr"), + "ctx_ptr", + ), + builder + .build_load( + builder.build_struct_gep(anyfunc_struct_ptr, 2, "sigindex_ptr"), + "sigindex", + ) + .into_int_value(), + ) + }; + + let truncated_table_bounds = builder.build_int_truncate( + table_bound, + intrinsics.i32_ty, + "truncated_table_bounds", + ); + + // First, check if the index is outside of the table bounds. + let index_in_bounds = builder.build_int_compare( + IntPredicate::ULT, + func_index, + truncated_table_bounds, + "index_in_bounds", + ); + + let index_in_bounds = builder + .build_call( + intrinsics.expect_i1, + &[ + index_in_bounds.as_basic_value_enum(), + intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), + ], + "index_in_bounds_expect", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + + let in_bounds_continue_block = + context.append_basic_block(&function, "in_bounds_continue_block"); + let not_in_bounds_block = + context.append_basic_block(&function, "not_in_bounds_block"); + builder.build_conditional_branch( + index_in_bounds, + &in_bounds_continue_block, + ¬_in_bounds_block, + ); + builder.position_at_end(¬_in_bounds_block); + builder.build_call( + intrinsics.throw_trap, + &[intrinsics.trap_call_indirect_oob], + "throw", + ); + builder.build_unreachable(); + builder.position_at_end(&in_bounds_continue_block); + + // Next, check if the signature id is correct. + + let sigindices_equal = builder.build_int_compare( + IntPredicate::EQ, + expected_dynamic_sigindex, + found_dynamic_sigindex, + "sigindices_equal", + ); + + // Tell llvm that `expected_dynamic_sigindex` should equal `found_dynamic_sigindex`. + let sigindices_equal = builder + .build_call( + intrinsics.expect_i1, + &[ + sigindices_equal.as_basic_value_enum(), + intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), + ], + "sigindices_equal_expect", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + + let continue_block = context.append_basic_block(&function, "continue_block"); + let sigindices_notequal_block = + context.append_basic_block(&function, "sigindices_notequal_block"); + builder.build_conditional_branch( + sigindices_equal, + &continue_block, + &sigindices_notequal_block, + ); + + builder.position_at_end(&sigindices_notequal_block); + builder.build_call( + intrinsics.throw_trap, + &[intrinsics.trap_call_indirect_sig], + "throw", + ); + builder.build_unreachable(); + builder.position_at_end(&continue_block); + + let wasmer_fn_sig = &info.signatures[sig_index]; + let fn_ty = signatures[sig_index]; + + let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?; + + let args: Vec<_> = std::iter::once(ctx_ptr) + .chain(pushed_args.into_iter()) + .collect(); + + let typed_func_ptr = builder.build_pointer_cast( + func_ptr, + fn_ty.ptr_type(AddressSpace::Generic), + "typed_func_ptr", + ); + + let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); + + match wasmer_fn_sig.returns() { + [] => {} + [_] => { + let value = call_site.try_as_basic_value().left().unwrap(); + state.push1(value); + } + _ => unimplemented!("multi-value returns"), + } + } + + /*************************** + * Integer Arithmetic instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-arithmetic-instructions + ***************************/ + Operator::I32Add | Operator::I64Add => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_int_add(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32Sub | Operator::I64Sub => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_int_sub(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32Mul | Operator::I64Mul => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_int_mul(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32DivS | Operator::I64DivS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + + trap_if_zero_or_overflow(builder, intrinsics, context, &function, v1, v2); + + let res = builder.build_int_signed_div(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32DivU | Operator::I64DivU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + + trap_if_zero(builder, intrinsics, context, &function, v2); + + let res = builder.build_int_unsigned_div(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32RemS | Operator::I64RemS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + + trap_if_zero(builder, intrinsics, context, &function, v2); + + let res = builder.build_int_signed_rem(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32RemU | Operator::I64RemU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + + trap_if_zero(builder, intrinsics, context, &function, v2); + + let res = builder.build_int_unsigned_rem(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32And | Operator::I64And => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_and(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32Or | Operator::I64Or => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_or(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32Xor | Operator::I64Xor => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_xor(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32Shl | Operator::I64Shl => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_left_shift(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::I32ShrS | Operator::I64ShrS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_right_shift(v1, v2, true, &state.var_name()); + state.push1(res); + } + Operator::I32ShrU | Operator::I64ShrU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let res = builder.build_right_shift(v1, v2, false, &state.var_name()); + state.push1(res); + } + Operator::I32Rotl => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let lhs = builder.build_left_shift(v1, v2, &state.var_name()); + let rhs = { + let int_width = intrinsics.i32_ty.const_int(32 as u64, false); + let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); + builder.build_right_shift(v1, rhs, false, &state.var_name()) + }; + let res = builder.build_or(lhs, rhs, &state.var_name()); + state.push1(res); + } + Operator::I64Rotl => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let lhs = builder.build_left_shift(v1, v2, &state.var_name()); + let rhs = { + let int_width = intrinsics.i64_ty.const_int(64 as u64, false); + let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); + builder.build_right_shift(v1, rhs, false, &state.var_name()) + }; + let res = builder.build_or(lhs, rhs, &state.var_name()); + state.push1(res); + } + Operator::I32Rotr => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let lhs = builder.build_right_shift(v1, v2, false, &state.var_name()); + let rhs = { + let int_width = intrinsics.i32_ty.const_int(32 as u64, false); + let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); + builder.build_left_shift(v1, rhs, &state.var_name()) + }; + let res = builder.build_or(lhs, rhs, &state.var_name()); + state.push1(res); + } + Operator::I64Rotr => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let lhs = builder.build_right_shift(v1, v2, false, &state.var_name()); + let rhs = { + let int_width = intrinsics.i64_ty.const_int(64 as u64, false); + let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); + builder.build_left_shift(v1, rhs, &state.var_name()) + }; + let res = builder.build_or(lhs, rhs, &state.var_name()); + state.push1(res); + } + Operator::I32Clz => { + let input = state.pop1()?; + let ensure_defined_zero = intrinsics + .i1_ty + .const_int(1 as u64, false) + .as_basic_value_enum(); + let res = builder + .build_call( + intrinsics.ctlz_i32, + &[input, ensure_defined_zero], + &state.var_name(), + ) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::I64Clz => { + let input = state.pop1()?; + let ensure_defined_zero = intrinsics + .i1_ty + .const_int(1 as u64, false) + .as_basic_value_enum(); + let res = builder + .build_call( + intrinsics.ctlz_i64, + &[input, ensure_defined_zero], + &state.var_name(), + ) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::I32Ctz => { + let input = state.pop1()?; + let ensure_defined_zero = intrinsics + .i1_ty + .const_int(1 as u64, false) + .as_basic_value_enum(); + let res = builder + .build_call( + intrinsics.cttz_i32, + &[input, ensure_defined_zero], + &state.var_name(), + ) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::I64Ctz => { + let input = state.pop1()?; + let ensure_defined_zero = intrinsics + .i1_ty + .const_int(1 as u64, false) + .as_basic_value_enum(); + let res = builder + .build_call( + intrinsics.cttz_i64, + &[input, ensure_defined_zero], + &state.var_name(), + ) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::I32Popcnt => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.ctpop_i32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::I64Popcnt => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.ctpop_i64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::I32Eqz => { + let input = state.pop1()?.into_int_value(); + let cond = builder.build_int_compare( + IntPredicate::EQ, + input, + intrinsics.i32_zero, + &state.var_name(), + ); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I64Eqz => { + let input = state.pop1()?.into_int_value(); + let cond = builder.build_int_compare( + IntPredicate::EQ, + input, + intrinsics.i64_zero, + &state.var_name(), + ); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + + /*************************** + * Floating-Point Arithmetic instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions + ***************************/ + Operator::F32Add | Operator::F64Add => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_add(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::F32Sub | Operator::F64Sub => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_sub(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::F32Mul | Operator::F64Mul => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_mul(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::F32Div | Operator::F64Div => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_div(v1, v2, &state.var_name()); + state.push1(res); + } + Operator::F32Sqrt => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.sqrt_f32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Sqrt => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.sqrt_f64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Min => { + let (v1, v2) = state.pop2()?; + let res = builder + .build_call(intrinsics.minimum_f32, &[v1, v2], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Min => { + let (v1, v2) = state.pop2()?; + let res = builder + .build_call(intrinsics.minimum_f64, &[v1, v2], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Max => { + let (v1, v2) = state.pop2()?; + let res = builder + .build_call(intrinsics.maximum_f32, &[v1, v2], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Max => { + let (v1, v2) = state.pop2()?; + let res = builder + .build_call(intrinsics.maximum_f64, &[v1, v2], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Ceil => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.ceil_f32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Ceil => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.ceil_f64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Floor => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.floor_f32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Floor => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.floor_f64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Trunc => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.trunc_f32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Trunc => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.trunc_f64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Nearest => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.nearbyint_f32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Nearest => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.nearbyint_f64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Abs => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.fabs_f32, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Abs => { + let input = state.pop1()?; + let res = builder + .build_call(intrinsics.fabs_f64, &[input], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F32Neg | Operator::F64Neg => { + let input = state.pop1()?.into_float_value(); + let res = builder.build_float_neg(input, &state.var_name()); + state.push1(res); + } + Operator::F32Copysign => { + let (mag, sgn) = state.pop2()?; + let res = builder + .build_call(intrinsics.copysign_f32, &[mag, sgn], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + Operator::F64Copysign => { + let (msg, sgn) = state.pop2()?; + let res = builder + .build_call(intrinsics.copysign_f64, &[msg, sgn], &state.var_name()) + .try_as_basic_value() + .left() + .unwrap(); + state.push1(res); + } + + /*************************** + * Integer Comparison instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-comparison-instructions + ***************************/ + Operator::I32Eq | Operator::I64Eq => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::EQ, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32Ne | Operator::I64Ne => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::NE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32LtS | Operator::I64LtS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::SLT, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32LtU | Operator::I64LtU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::ULT, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32LeS | Operator::I64LeS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::SLE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32LeU | Operator::I64LeU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::ULE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32GtS | Operator::I64GtS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::SGT, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32GtU | Operator::I64GtU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::UGT, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32GeS | Operator::I64GeS => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::SGE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32GeU | Operator::I64GeU => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = builder.build_int_compare(IntPredicate::UGE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + + /*************************** + * Floating-Point Comparison instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-comparison-instructions + ***************************/ + Operator::F32Eq | Operator::F64Eq => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let cond = + builder.build_float_compare(FloatPredicate::OEQ, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::F32Ne | Operator::F64Ne => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let cond = + builder.build_float_compare(FloatPredicate::UNE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::F32Lt | Operator::F64Lt => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let cond = + builder.build_float_compare(FloatPredicate::OLT, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::F32Le | Operator::F64Le => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let cond = + builder.build_float_compare(FloatPredicate::OLE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::F32Gt | Operator::F64Gt => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let cond = + builder.build_float_compare(FloatPredicate::OGT, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::F32Ge | Operator::F64Ge => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let cond = + builder.build_float_compare(FloatPredicate::OGE, v1, v2, &state.var_name()); + let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + + /*************************** + * Conversion instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#conversion-instructions + ***************************/ + Operator::I32WrapI64 => { + let v1 = state.pop1()?.into_int_value(); + let res = builder.build_int_truncate(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I64ExtendSI32 => { + let v1 = state.pop1()?.into_int_value(); + let res = builder.build_int_s_extend(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I64ExtendUI32 => { + let v1 = state.pop1()?.into_int_value(); + let res = builder.build_int_z_extend(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I32TruncSF32 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -2147483904.0, + 2147483648.0, + v1, + ); + let res = + builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32TruncSF64 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -2147483649.0, + 2147483648.0, + v1, + ); + let res = + builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32TruncSSatF32 | Operator::I32TruncSSatF64 => { + let v1 = state.pop1()?.into_float_value(); + let res = + builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I64TruncSF32 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -9223373136366403584.0, + 9223372036854775808.0, + v1, + ); + let res = + builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I64TruncSF64 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -9223372036854777856.0, + 9223372036854775808.0, + v1, + ); + let res = + builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I64TruncSSatF32 | Operator::I64TruncSSatF64 => { + let v1 = state.pop1()?.into_float_value(); + let res = + builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I32TruncUF32 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -1.0, + 4294967296.0, + v1, + ); + let res = + builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32TruncUF64 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -1.0, + 4294967296.0, + v1, + ); + let res = + builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I32TruncUSatF32 | Operator::I32TruncUSatF64 => { + let v1 = state.pop1()?.into_float_value(); + let res = + builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name()); + state.push1(res); + } + Operator::I64TruncUF32 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -1.0, + 18446744073709551616.0, + v1, + ); + let res = + builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I64TruncUF64 => { + let v1 = state.pop1()?.into_float_value(); + trap_if_not_representatable_as_int( + builder, + intrinsics, + context, + &function, + -1.0, + 18446744073709551616.0, + v1, + ); + let res = + builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::I64TruncUSatF32 | Operator::I64TruncUSatF64 => { + let v1 = state.pop1()?.into_float_value(); + let res = + builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name()); + state.push1(res); + } + Operator::F32DemoteF64 => { + let v1 = state.pop1()?.into_float_value(); + let res = builder.build_float_trunc(v1, intrinsics.f32_ty, &state.var_name()); + state.push1(res); + } + Operator::F64PromoteF32 => { + let v1 = state.pop1()?.into_float_value(); + let res = builder.build_float_ext(v1, intrinsics.f64_ty, &state.var_name()); + state.push1(res); + } + Operator::F32ConvertSI32 | Operator::F32ConvertSI64 => { + let v1 = state.pop1()?.into_int_value(); + let res = + builder.build_signed_int_to_float(v1, intrinsics.f32_ty, &state.var_name()); + state.push1(res); + } + Operator::F64ConvertSI32 | Operator::F64ConvertSI64 => { + let v1 = state.pop1()?.into_int_value(); + let res = + builder.build_signed_int_to_float(v1, intrinsics.f64_ty, &state.var_name()); + state.push1(res); + } + Operator::F32ConvertUI32 | Operator::F32ConvertUI64 => { + let v1 = state.pop1()?.into_int_value(); + let res = + builder.build_unsigned_int_to_float(v1, intrinsics.f32_ty, &state.var_name()); + state.push1(res); + } + Operator::F64ConvertUI32 | Operator::F64ConvertUI64 => { + let v1 = state.pop1()?.into_int_value(); + let res = + builder.build_unsigned_int_to_float(v1, intrinsics.f64_ty, &state.var_name()); + state.push1(res); + } + Operator::I32ReinterpretF32 => { + let v = state.pop1()?; + let space = + builder.build_alloca(intrinsics.i32_ty.as_basic_type_enum(), &state.var_name()); + let f32_space = + builder.build_pointer_cast(space, intrinsics.f32_ptr_ty, &state.var_name()); + builder.build_store(f32_space, v); + let int = builder.build_load(space, &state.var_name()); + state.push1(int); + } + Operator::I64ReinterpretF64 => { + let v = state.pop1()?; + let space = + builder.build_alloca(intrinsics.i64_ty.as_basic_type_enum(), &state.var_name()); + let f64_space = + builder.build_pointer_cast(space, intrinsics.f64_ptr_ty, &state.var_name()); + builder.build_store(f64_space, v); + let int = builder.build_load(space, &state.var_name()); + state.push1(int); + } + Operator::F32ReinterpretI32 => { + let v = state.pop1()?; + let space = + builder.build_alloca(intrinsics.f32_ty.as_basic_type_enum(), &state.var_name()); + let i32_space = + builder.build_pointer_cast(space, intrinsics.i32_ptr_ty, &state.var_name()); + builder.build_store(i32_space, v); + let f = builder.build_load(space, &state.var_name()); + state.push1(f); + } + Operator::F64ReinterpretI64 => { + let v = state.pop1()?; + let space = + builder.build_alloca(intrinsics.f64_ty.as_basic_type_enum(), &state.var_name()); + let i64_space = + builder.build_pointer_cast(space, intrinsics.i64_ptr_ty, &state.var_name()); + builder.build_store(i64_space, v); + let f = builder.build_load(space, &state.var_name()); + state.push1(f); + } + + /*************************** + * Sign-extension operators. + * https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md + ***************************/ + Operator::I32Extend8S => { + let value = state.pop1()?.into_int_value(); + let narrow_value = + builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); + let extended_value = + builder.build_int_s_extend(narrow_value, intrinsics.i32_ty, &state.var_name()); + state.push1(extended_value); + } + Operator::I32Extend16S => { + let value = state.pop1()?.into_int_value(); + let narrow_value = + builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); + let extended_value = + builder.build_int_s_extend(narrow_value, intrinsics.i32_ty, &state.var_name()); + state.push1(extended_value); + } + Operator::I64Extend8S => { + let value = state.pop1()?.into_int_value(); + let narrow_value = + builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); + let extended_value = + builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name()); + state.push1(extended_value); + } + Operator::I64Extend16S => { + let value = state.pop1()?.into_int_value(); + let narrow_value = + builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); + let extended_value = + builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name()); + state.push1(extended_value); + } + Operator::I64Extend32S => { + let value = state.pop1()?.into_int_value(); + let narrow_value = + builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); + let extended_value = + builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name()); + state.push1(extended_value); + } + + /*************************** + * Load and Store instructions. + * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#load-and-store-instructions + ***************************/ + Operator::I32Load { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i32_ptr_ty, + )?; + let result = builder.build_load(effective_address, &state.var_name()); + state.push1(result); + } + Operator::I64Load { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i64_ptr_ty, + )?; + let result = builder.build_load(effective_address, &state.var_name()); + state.push1(result); + } + Operator::F32Load { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.f32_ptr_ty, + )?; + let result = builder.build_load(effective_address, &state.var_name()); + state.push1(result); + } + Operator::F64Load { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.f64_ptr_ty, + )?; + let result = builder.build_load(effective_address, &state.var_name()); + state.push1(result); + } + + Operator::I32Store { memarg } => { + let value = state.pop1()?; + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i32_ptr_ty, + )?; + builder.build_store(effective_address, value); + } + Operator::I64Store { memarg } => { + let value = state.pop1()?; + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i64_ptr_ty, + )?; + builder.build_store(effective_address, value); + } + Operator::F32Store { memarg } => { + let value = state.pop1()?; + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.f32_ptr_ty, + )?; + builder.build_store(effective_address, value); + } + Operator::F64Store { memarg } => { + let value = state.pop1()?; + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.f64_ptr_ty, + )?; + builder.build_store(effective_address, value); + } + + Operator::I32Load8S { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i8_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + state.push1(result); + } + Operator::I32Load16S { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i16_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + state.push1(result); + } + Operator::I64Load8S { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i8_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + state.push1(result); + } + Operator::I64Load16S { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i16_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + state.push1(result); + } + Operator::I64Load32S { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i32_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + state.push1(result); + } + + Operator::I32Load8U { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i8_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + state.push1(result); + } + Operator::I32Load16U { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i16_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + state.push1(result); + } + Operator::I64Load8U { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i8_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + state.push1(result); + } + Operator::I64Load16U { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i16_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + state.push1(result); + } + Operator::I64Load32U { memarg } => { + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i32_ptr_ty, + )?; + let narrow_result = builder + .build_load(effective_address, &state.var_name()) + .into_int_value(); + let result = + builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + state.push1(result); + } + + Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => { + let value = state.pop1()?.into_int_value(); + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i8_ptr_ty, + )?; + let narrow_value = + builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); + builder.build_store(effective_address, narrow_value); + } + Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => { + let value = state.pop1()?.into_int_value(); + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i16_ptr_ty, + )?; + let narrow_value = + builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); + builder.build_store(effective_address, narrow_value); + } + Operator::I64Store32 { memarg } => { + let value = state.pop1()?.into_int_value(); + let effective_address = resolve_memory_ptr( + builder, + intrinsics, + context, + &function, + &mut state, + &mut ctx, + memarg, + intrinsics.i32_ptr_ty, + )?; + let narrow_value = + builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); + builder.build_store(effective_address, narrow_value); + } + + Operator::MemoryGrow { reserved } => { + let memory_index = MemoryIndex::new(reserved as usize); + let func_value = 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 => intrinsics.memory_grow_dynamic_local, + MemoryType::Static => intrinsics.memory_grow_static_local, + MemoryType::SharedStatic => intrinsics.memory_grow_shared_local, + } + } + LocalOrImport::Import(import_mem_index) => { + let mem_desc = &info.imported_memories[import_mem_index].1; + match mem_desc.memory_type() { + MemoryType::Dynamic => intrinsics.memory_grow_dynamic_import, + MemoryType::Static => intrinsics.memory_grow_static_import, + MemoryType::SharedStatic => intrinsics.memory_grow_shared_import, + } + } + }; + + let memory_index_const = intrinsics + .i32_ty + .const_int(reserved as u64, false) + .as_basic_value_enum(); + let delta = state.pop1()?; + + let result = builder.build_call( + func_value, + &[ctx.basic(), memory_index_const, delta], + &state.var_name(), + ); + state.push1(result.try_as_basic_value().left().unwrap()); + } + Operator::MemorySize { reserved } => { + let memory_index = MemoryIndex::new(reserved as usize); + let func_value = 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 => intrinsics.memory_size_dynamic_local, + MemoryType::Static => intrinsics.memory_size_static_local, + MemoryType::SharedStatic => intrinsics.memory_size_shared_local, + } + } + LocalOrImport::Import(import_mem_index) => { + let mem_desc = &info.imported_memories[import_mem_index].1; + match mem_desc.memory_type() { + MemoryType::Dynamic => intrinsics.memory_size_dynamic_import, + MemoryType::Static => intrinsics.memory_size_static_import, + MemoryType::SharedStatic => intrinsics.memory_size_shared_import, + } + } + }; + + let memory_index_const = intrinsics + .i32_ty + .const_int(reserved as u64, false) + .as_basic_value_enum(); + let result = builder.build_call( + func_value, + &[ctx.basic(), memory_index_const], + &state.var_name(), + ); + state.push1(result.try_as_basic_value().left().unwrap()); + } + op @ _ => { + unimplemented!("{:?}", op); + } + } + + unimplemented!() + + } + + fn finalize(&mut self) -> Result<(), CodegenError> { + unimplemented!() + } +} + +impl From for CodegenError { + fn from(other: BinaryReaderError) -> CodegenError { + unimplemented!() + //CodegenError + } +} + +impl ModuleCodeGenerator + for LLVMModuleCodeGenerator +{ + fn new() -> LLVMModuleCodeGenerator { + let context = Context::create(); + let module = context.create_module("module"); + let builder = context.create_builder(); + + let intrinsics = Intrinsics::declare(&module, &context); + + let personality_func = module.add_function( + "__gxx_personality_v0", + intrinsics.i32_ty.fn_type(&[], false), + Some(Linkage::External), + ); + + + // TODO signatures and functions +// let signatures: Map = info +// .signatures +// .iter() +// .map(|(_, sig)| func_sig_to_llvm(&context, &intrinsics, sig)) +// .collect(); + let signatures = Map::new(); +// let functions: Map = info +// .func_assoc +// .iter() +// .skip(info.imported_functions.len()) +// .map(|(func_index, &sig_index)| { +// let func = module.add_function( +// &format!("fn{}", func_index.index()), +// signatures[sig_index], +// Some(Linkage::External), +// ); +// func.set_personality_function(personality_func); +// func +// }) +// .collect(); + let functions = Map::new(); + +// let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); + + LLVMModuleCodeGenerator { + context: context, + builder: &builder, + functions: vec![], + functions_llvm: &functions, + signatures: &signatures, + function_signatures: None, + // function_labels: Some(HashMap::new()), + // assembler: Some(Assembler::new().unwrap()), + func_import_count: 0, + intrinsics: &intrinsics, +// ctx: ctx, + } + } + + fn backend_id() -> Backend { + Backend::LLVM + } + + fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError> { + Ok(()) + } + + fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { + // Creates a new function and returns the function-scope code generator for it. + + use std::mem; + + let func_sig_dummy: FuncSig = unsafe { mem::uninitialized() }; + let function_dummy: FunctionValue = unsafe { mem::uninitialized() }; + let intrinsics_dummy: &Intrinsics = unsafe { mem::uninitialized() }; + let context_dummy: &Context = unsafe { mem::uninitialized() }; + + let code = LLVMFunctionCodeGenerator { + state: State::new(), + builder: self.builder, + context: context_dummy, //&self.context, + function: function_dummy, + func_sig: &func_sig_dummy, + locals: vec![], + signatures: &Map::new(), +// context: self.fu + +// signatures: self.signatures.as_ref().unwrap().clone(), +// function_signatures: self.function_signatures.as_ref().unwrap().clone(), +// +// assembler: Some(assembler), +// function_labels: Some(function_labels), +// br_table_data: Some(br_table_data), +// breakpoints: Some(breakpoints), +// returns: smallvec![], +// locals: vec![], +// num_params: 0, +// num_locals: 0, +// value_stack: vec![], +// control_stack: vec![], +// machine: Machine::new(), +// unreachable_depth: 0, + intrinsics: intrinsics_dummy, + }; + self.functions.push(code); + Ok(self.functions.last_mut().unwrap()) + } + + fn finalize(self, module_info: &ModuleInfo) -> Result { + unimplemented!() + } + + fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { +// self.signatures = Some(Arc::new(signatures)); + Ok(()) + } + + fn feed_function_signatures(&mut self, assoc: Map) -> Result<(), CodegenError> { + self.function_signatures = Some(Arc::new(assoc)); + Ok(()) + } + + fn feed_import_function(&mut self) -> Result<(), CodegenError> { + // TODO + Ok(()) + } +} \ No newline at end of file diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 6ce8139c327..ee5d4d2ef0f 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -26,6 +26,14 @@ impl LLVMCompiler { } } +use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen; +pub type LLVMStreamingCompiler = SimpleStreamingCompilerGen< + code::LLVMModuleCodeGenerator, + code::LLVMFunctionCodeGenerator, + backend::LLVMBackend, + code::CodegenError, +>; + impl Compiler for LLVMCompiler { fn compile( &self, diff --git a/lib/spectests/examples/simple/main.rs b/lib/spectests/examples/simple/main.rs index 357adb5f70d..8ac05dedb32 100644 --- a/lib/spectests/examples/simple/main.rs +++ b/lib/spectests/examples/simple/main.rs @@ -18,8 +18,8 @@ fn get_compiler() -> impl Compiler { #[cfg(feature = "llvm")] fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() + use wasmer_llvm_backend::LLVMStreamingCompiler; + LLVMStreamingCompiler::new() } #[cfg(feature = "singlepass")] From 21dd01c3aa1b6b7f21598e9bbf267428611d96eb Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 30 Apr 2019 15:52:43 +0800 Subject: [PATCH 02/15] Fix LLVM backend compilation and segfaults. --- lib/llvm-backend/src/code.rs | 159 +++++++++++++++++++---------------- lib/llvm-backend/src/lib.rs | 8 +- 2 files changed, 91 insertions(+), 76 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index bc13bf28194..42474a79b4a 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1733,7 +1733,7 @@ fn parse_function( * Load and Store instructions. * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#load-and-store-instructions ***************************/ - Operator::I32Load { memarg } => { + Operator::I32Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1747,7 +1747,7 @@ fn parse_function( let result = builder.build_load(effective_address, &state.var_name()); state.push1(result); } - Operator::I64Load { memarg } => { + Operator::I64Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1761,7 +1761,7 @@ fn parse_function( let result = builder.build_load(effective_address, &state.var_name()); state.push1(result); } - Operator::F32Load { memarg } => { + Operator::F32Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1775,7 +1775,7 @@ fn parse_function( let result = builder.build_load(effective_address, &state.var_name()); state.push1(result); } - Operator::F64Load { memarg } => { + Operator::F64Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1790,7 +1790,7 @@ fn parse_function( state.push1(result); } - Operator::I32Store { memarg } => { + Operator::I32Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -1804,7 +1804,7 @@ fn parse_function( )?; builder.build_store(effective_address, value); } - Operator::I64Store { memarg } => { + Operator::I64Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -1818,7 +1818,7 @@ fn parse_function( )?; builder.build_store(effective_address, value); } - Operator::F32Store { memarg } => { + Operator::F32Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -1832,7 +1832,7 @@ fn parse_function( )?; builder.build_store(effective_address, value); } - Operator::F64Store { memarg } => { + Operator::F64Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -1847,7 +1847,7 @@ fn parse_function( builder.build_store(effective_address, value); } - Operator::I32Load8S { memarg } => { + Operator::I32Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1865,7 +1865,7 @@ fn parse_function( builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I32Load16S { memarg } => { + Operator::I32Load16S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1883,7 +1883,7 @@ fn parse_function( builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I64Load8S { memarg } => { + Operator::I64Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1901,7 +1901,7 @@ fn parse_function( builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load16S { memarg } => { + Operator::I64Load16S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1919,7 +1919,7 @@ fn parse_function( builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load32S { memarg } => { + Operator::I64Load32S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1938,7 +1938,7 @@ fn parse_function( state.push1(result); } - Operator::I32Load8U { memarg } => { + Operator::I32Load8U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1956,7 +1956,7 @@ fn parse_function( builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I32Load16U { memarg } => { + Operator::I32Load16U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1974,7 +1974,7 @@ fn parse_function( builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I64Load8U { memarg } => { + Operator::I64Load8U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -1992,7 +1992,7 @@ fn parse_function( builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load16U { memarg } => { + Operator::I64Load16U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -2010,7 +2010,7 @@ fn parse_function( builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load32U { memarg } => { + Operator::I64Load32U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -2029,7 +2029,7 @@ fn parse_function( state.push1(result); } - Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => { + Operator::I32Store8 { ref memarg } | Operator::I64Store8 { ref memarg } => { let value = state.pop1()?.into_int_value(); let effective_address = resolve_memory_ptr( builder, @@ -2045,7 +2045,7 @@ fn parse_function( builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); builder.build_store(effective_address, narrow_value); } - Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => { + Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { let value = state.pop1()?.into_int_value(); let effective_address = resolve_memory_ptr( builder, @@ -2061,7 +2061,7 @@ fn parse_function( builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); builder.build_store(effective_address, narrow_value); } - Operator::I64Store32 { memarg } => { + Operator::I64Store32 { ref memarg } => { let value = state.pop1()?.into_int_value(); let effective_address = resolve_memory_ptr( builder, @@ -2392,7 +2392,7 @@ fn resolve_memory_ptr( function: &FunctionValue, state: &mut State, ctx: &mut CtxType, - memarg: MemoryImmediate, + memarg: &MemoryImmediate, ptr_ty: PointerType, ) -> Result { // Ignore alignment hint for the time being. @@ -2468,21 +2468,24 @@ fn resolve_memory_ptr( #[derive(Debug)] pub struct CodegenError { - pub message: &'static str, + pub message: String, } pub struct LLVMModuleCodeGenerator { context: Context, - builder: &'static Builder, + builder: Builder, functions: Vec, - functions_llvm: &'static SliceMap, + functions_llvm: Map, // signatures: Option>>, - signatures: &'static SliceMap, + signatures: Map, + signatures_raw: Map, function_signatures: Option>>, // function_labels: Option)>>, // assembler: Option, func_import_count: usize, - intrinsics: &'static Intrinsics, + intrinsics: Intrinsics, + personality_func: FunctionValue, + module: Module, // ctx: CtxType, } @@ -2503,9 +2506,9 @@ pub struct LLVMFunctionCodeGenerator { builder: &'static Builder, context: &'static Context, function: FunctionValue, - func_sig: &'static FuncSig, + func_sig: FuncSig, intrinsics: &'static Intrinsics, - signatures: &'static SliceMap, + signatures: Map, // signatures: Arc>, // function_signatures: Arc>, @@ -2538,7 +2541,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn begin_body(&mut self) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { @@ -2619,7 +2622,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let intrinsics = self.intrinsics; let locals = &self.locals; let info = module_info; - let signatures = self.signatures; + let signatures = &self.signatures; // TODO this should be done only once per function I believe @@ -2633,7 +2636,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let op = match event { Event::Wasm(x) => x, Event::Internal(x) => { - unimplemented!() + return Ok(()); + //unimplemented!() } }; @@ -4151,7 +4155,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * Load and Store instructions. * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#load-and-store-instructions ***************************/ - Operator::I32Load { memarg } => { + Operator::I32Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4165,7 +4169,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let result = builder.build_load(effective_address, &state.var_name()); state.push1(result); } - Operator::I64Load { memarg } => { + Operator::I64Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4179,7 +4183,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let result = builder.build_load(effective_address, &state.var_name()); state.push1(result); } - Operator::F32Load { memarg } => { + Operator::F32Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4193,7 +4197,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let result = builder.build_load(effective_address, &state.var_name()); state.push1(result); } - Operator::F64Load { memarg } => { + Operator::F64Load { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4208,7 +4212,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(result); } - Operator::I32Store { memarg } => { + Operator::I32Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -4222,7 +4226,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; builder.build_store(effective_address, value); } - Operator::I64Store { memarg } => { + Operator::I64Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -4236,7 +4240,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; builder.build_store(effective_address, value); } - Operator::F32Store { memarg } => { + Operator::F32Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -4250,7 +4254,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; builder.build_store(effective_address, value); } - Operator::F64Store { memarg } => { + Operator::F64Store { ref memarg } => { let value = state.pop1()?; let effective_address = resolve_memory_ptr( builder, @@ -4265,7 +4269,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_store(effective_address, value); } - Operator::I32Load8S { memarg } => { + Operator::I32Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4283,7 +4287,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I32Load16S { memarg } => { + Operator::I32Load16S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4301,7 +4305,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I64Load8S { memarg } => { + Operator::I64Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4319,7 +4323,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load16S { memarg } => { + Operator::I64Load16S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4337,7 +4341,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load32S { memarg } => { + Operator::I64Load32S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4356,7 +4360,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(result); } - Operator::I32Load8U { memarg } => { + Operator::I32Load8U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4374,7 +4378,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I32Load16U { memarg } => { + Operator::I32Load16U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4392,7 +4396,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); } - Operator::I64Load8U { memarg } => { + Operator::I64Load8U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4410,7 +4414,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load16U { memarg } => { + Operator::I64Load16U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4428,7 +4432,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); } - Operator::I64Load32U { memarg } => { + Operator::I64Load32U { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4447,7 +4451,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(result); } - Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => { + Operator::I32Store8 { ref memarg } | Operator::I64Store8 { ref memarg } => { let value = state.pop1()?.into_int_value(); let effective_address = resolve_memory_ptr( builder, @@ -4463,7 +4467,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); builder.build_store(effective_address, narrow_value); } - Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => { + Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { let value = state.pop1()?.into_int_value(); let effective_address = resolve_memory_ptr( builder, @@ -4479,7 +4483,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); builder.build_store(effective_address, narrow_value); } - Operator::I64Store32 { memarg } => { + Operator::I64Store32 { ref memarg } => { let value = state.pop1()?.into_int_value(); let effective_address = resolve_memory_ptr( builder, @@ -4562,7 +4566,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ); state.push1(result.try_as_basic_value().left().unwrap()); } - op @ _ => { + _ => { unimplemented!("{:?}", op); } } @@ -4578,8 +4582,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { impl From for CodegenError { fn from(other: BinaryReaderError) -> CodegenError { - unimplemented!() - //CodegenError + CodegenError { message: format!("{:?}", other) } } } @@ -4627,15 +4630,18 @@ impl ModuleCodeGenerator LLVMModuleCodeGenerator { context: context, - builder: &builder, + builder: builder, + module: module, functions: vec![], - functions_llvm: &functions, - signatures: &signatures, + functions_llvm: functions, + signatures: signatures, + signatures_raw: Map::new(), function_signatures: None, // function_labels: Some(HashMap::new()), // assembler: Some(Assembler::new().unwrap()), func_import_count: 0, - intrinsics: &intrinsics, + intrinsics: intrinsics, + personality_func: personality_func, // ctx: ctx, } } @@ -4653,19 +4659,24 @@ impl ModuleCodeGenerator use std::mem; - let func_sig_dummy: FuncSig = unsafe { mem::uninitialized() }; - let function_dummy: FunctionValue = unsafe { mem::uninitialized() }; - let intrinsics_dummy: &Intrinsics = unsafe { mem::uninitialized() }; - let context_dummy: &Context = unsafe { mem::uninitialized() }; + let sig_id = self.function_signatures.as_ref().unwrap()[FuncIndex::new(self.func_import_count + self.functions.len())]; + let func_sig = self.signatures_raw[sig_id].clone(); + + let func = self.module.add_function( + &format!("fn{}", self.func_import_count + self.functions.len()), + self.signatures[sig_id], + Some(Linkage::External), + ); + func.set_personality_function(self.personality_func); let code = LLVMFunctionCodeGenerator { state: State::new(), - builder: self.builder, - context: context_dummy, //&self.context, - function: function_dummy, - func_sig: &func_sig_dummy, + builder: unsafe { ::std::mem::transmute::<&Builder, &'static Builder>(&self.builder) }, + context: unsafe { ::std::mem::transmute::<&Context, &'static Context>(&self.context) }, + function: func, + func_sig: func_sig, locals: vec![], - signatures: &Map::new(), + signatures: self.signatures.clone(), // context: self.fu // signatures: self.signatures.as_ref().unwrap().clone(), @@ -4683,7 +4694,7 @@ impl ModuleCodeGenerator // control_stack: vec![], // machine: Machine::new(), // unreachable_depth: 0, - intrinsics: intrinsics_dummy, + intrinsics: unsafe { ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) }, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -4694,7 +4705,11 @@ impl ModuleCodeGenerator } fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { -// self.signatures = Some(Arc::new(signatures)); + self.signatures = signatures + .iter() + .map(|(_, sig)| func_sig_to_llvm(&self.context, &self.intrinsics, sig)) + .collect(); + self.signatures_raw = signatures.clone(); Ok(()) } @@ -4704,7 +4719,7 @@ impl ModuleCodeGenerator } fn feed_import_function(&mut self) -> Result<(), CodegenError> { - // TODO + self.func_import_count += 1; Ok(()) } } \ No newline at end of file diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index ee5d4d2ef0f..53ba7cd983b 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -16,25 +16,25 @@ mod read_info; mod state; mod trampolines; -pub struct LLVMCompiler { +pub struct LLVMOldCompiler { _private: (), } -impl LLVMCompiler { +impl LLVMOldCompiler { pub fn new() -> Self { Self { _private: () } } } use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen; -pub type LLVMStreamingCompiler = SimpleStreamingCompilerGen< +pub type LLVMCompiler = SimpleStreamingCompilerGen< code::LLVMModuleCodeGenerator, code::LLVMFunctionCodeGenerator, backend::LLVMBackend, code::CodegenError, >; -impl Compiler for LLVMCompiler { +impl Compiler for LLVMOldCompiler { fn compile( &self, wasm: &[u8], From ec253c73ab6530902b4040235ea29d5fa00f29a5 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 30 Apr 2019 20:11:44 -0500 Subject: [PATCH 03/15] Implement feed_local --- lib/llvm-backend/src/code.rs | 328 +++++++++++++++----------- lib/spectests/examples/simple/main.rs | 4 +- 2 files changed, 188 insertions(+), 144 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 42474a79b4a..f5b5e9c2e42 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -25,11 +25,11 @@ use wasmparser::{ Type as WpType, }; +use crate::backend::LLVMBackend; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::type_to_type; use crate::state::{ControlFrame, IfElseState, State}; use crate::trampolines::generate_trampolines; -use crate::backend::LLVMBackend; 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)); @@ -2476,7 +2476,7 @@ pub struct LLVMModuleCodeGenerator { builder: Builder, functions: Vec, functions_llvm: Map, -// signatures: Option>>, + // signatures: Option>>, signatures: Map, signatures_raw: Map, function_signatures: Option>>, @@ -2486,7 +2486,7 @@ pub struct LLVMModuleCodeGenerator { intrinsics: Intrinsics, personality_func: FunctionValue, module: Module, -// ctx: CtxType, + // ctx: CtxType, } // pub struct LLVMExecutionContext { @@ -2518,8 +2518,8 @@ pub struct LLVMFunctionCodeGenerator { // br_table_data: Option>>, // breakpoints: Option>>, // returns: SmallVec<[WpType; 1]>, - locals: Vec, - // num_params: usize, + locals: Vec, // Contains params and locals + num_params: usize, // num_locals: usize, // value_stack: Vec<(Location, LocalOrTemp)>, // control_stack: Vec, @@ -2529,15 +2529,40 @@ pub struct LLVMFunctionCodeGenerator { impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { fn feed_return(&mut self, ty: WpType) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { - unimplemented!() + let param_len = self.num_params; + + let mut local_idx = 0; + // let (count, ty) = local?; + let count = n; + let wasmer_ty = type_to_type(ty)?; + let ty = type_to_llvm(self.intrinsics, wasmer_ty); + + let default_value = match wasmer_ty { + Type::I32 => self.intrinsics.i32_zero.as_basic_value_enum(), + Type::I64 => self.intrinsics.i64_zero.as_basic_value_enum(), + Type::F32 => self.intrinsics.f32_zero.as_basic_value_enum(), + Type::F64 => self.intrinsics.f64_zero.as_basic_value_enum(), + }; + + for _ in 0..count { + let alloca = self + .builder + .build_alloca(ty, &format!("local{}", param_len + local_idx)); + + self.builder.build_store(alloca, default_value); + + self.locals.push(alloca); + local_idx += 1; + } + Ok(()) } fn begin_body(&mut self) -> Result<(), CodegenError> { @@ -2545,75 +2570,73 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { - -// let sig_index = info.func_assoc[func_index.convert_up(info)]; -// let func_sig = &info.signatures[sig_index]; -// -// let function = self.functions[func_index]; -// 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(); -// -// state.push_block(return_block, phis); -// builder.position_at_end(&entry_block); -// -// let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity -// -// locals.extend( -// function -// .get_param_iter() -// .skip(1) -// .enumerate() -// .map(|(index, param)| { -// let ty = param.get_type(); -// -// let alloca = builder.build_alloca(ty, &format!("local{}", index)); -// builder.build_store(alloca, param); -// alloca -// }), -// ); -// -// let param_len = locals.len(); -// -// let mut local_idx = 0; -// for local in locals_reader.into_iter() { -// let (count, ty) = local?; -// let wasmer_ty = type_to_type(ty)?; -// let ty = type_to_llvm(intrinsics, wasmer_ty); -// -// let default_value = match wasmer_ty { -// Type::I32 => intrinsics.i32_zero.as_basic_value_enum(), -// Type::I64 => intrinsics.i64_zero.as_basic_value_enum(), -// Type::F32 => intrinsics.f32_zero.as_basic_value_enum(), -// Type::F64 => intrinsics.f64_zero.as_basic_value_enum(), -// }; -// -// for _ in 0..count { -// let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); -// -// builder.build_store(alloca, default_value); -// -// locals.push(alloca); -// local_idx += 1; -// } -// } -// -// let start_of_code_block = context.append_basic_block(&function, "start_of_code"); -// let entry_end_inst = builder.build_unconditional_branch(&start_of_code_block); -// builder.position_at_end(&start_of_code_block); -// -// let cache_builder = context.create_builder(); -// cache_builder.position_before(&entry_end_inst); - + // let sig_index = info.func_assoc[func_index.convert_up(info)]; + // let func_sig = &info.signatures[sig_index]; + // + // let function = self.functions[func_index]; + // 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(); + // + // state.push_block(return_block, phis); + // builder.position_at_end(&entry_block); + // + // let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity + // + // locals.extend( + // function + // .get_param_iter() + // .skip(1) + // .enumerate() + // .map(|(index, param)| { + // let ty = param.get_type(); + // + // let alloca = builder.build_alloca(ty, &format!("local{}", index)); + // builder.build_store(alloca, param); + // alloca + // }), + // ); + // + // let param_len = locals.len(); + // + // let mut local_idx = 0; + // for local in locals_reader.into_iter() { + // let (count, ty) = local?; + // let wasmer_ty = type_to_type(ty)?; + // let ty = type_to_llvm(intrinsics, wasmer_ty); + // + // let default_value = match wasmer_ty { + // Type::I32 => intrinsics.i32_zero.as_basic_value_enum(), + // Type::I64 => intrinsics.i64_zero.as_basic_value_enum(), + // Type::F32 => intrinsics.f32_zero.as_basic_value_enum(), + // Type::F64 => intrinsics.f64_zero.as_basic_value_enum(), + // }; + // + // for _ in 0..count { + // let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); + // + // builder.build_store(alloca, default_value); + // + // locals.push(alloca); + // local_idx += 1; + // } + // } + // + // let start_of_code_block = context.append_basic_block(&function, "start_of_code"); + // let entry_end_inst = builder.build_unconditional_branch(&start_of_code_block); + // builder.position_at_end(&start_of_code_block); + // + // let cache_builder = context.create_builder(); + // cache_builder.position_before(&entry_end_inst); let mut state = &mut self.state; let builder = self.builder; @@ -2624,14 +2647,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let info = module_info; let signatures = &self.signatures; - // TODO this should be done only once per function I believe // just adding here to get compilation let cache_builder = context.create_builder(); -// cache_builder.position_before(&entry_end_inst); + // cache_builder.position_before(&entry_end_inst); let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); -// self.ctx; - + // self.ctx; let op = match event { Event::Wasm(x) => x, @@ -2646,7 +2667,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { match *op { Operator::Block { ty: _ } | Operator::Loop { ty: _ } | Operator::If { ty: _ } => { unreachable_depth += 1; -// continue; + // continue; return Ok(()); } Operator::Else => { @@ -2803,7 +2824,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .iter() .enumerate() .map(|(case_index, &depth)| { - let frame_result: Result<&ControlFrame, BinaryReaderError> = state.frame_at_depth(depth); + let frame_result: Result<&ControlFrame, BinaryReaderError> = + state.frame_at_depth(depth); let frame = match frame_result { Ok(v) => v, Err(e) => return Err(e), @@ -4572,7 +4594,6 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } unimplemented!() - } fn finalize(&mut self) -> Result<(), CodegenError> { @@ -4582,7 +4603,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { impl From for CodegenError { fn from(other: BinaryReaderError) -> CodegenError { - CodegenError { message: format!("{:?}", other) } + CodegenError { + message: format!("{:?}", other), + } } } @@ -4590,43 +4613,42 @@ impl ModuleCodeGenerator for LLVMModuleCodeGenerator { fn new() -> LLVMModuleCodeGenerator { - let context = Context::create(); - let module = context.create_module("module"); - let builder = context.create_builder(); + let context = Context::create(); + let module = context.create_module("module"); + let builder = context.create_builder(); - let intrinsics = Intrinsics::declare(&module, &context); - - let personality_func = module.add_function( - "__gxx_personality_v0", - intrinsics.i32_ty.fn_type(&[], false), - Some(Linkage::External), - ); + let intrinsics = Intrinsics::declare(&module, &context); + let personality_func = module.add_function( + "__gxx_personality_v0", + intrinsics.i32_ty.fn_type(&[], false), + Some(Linkage::External), + ); // TODO signatures and functions -// let signatures: Map = info -// .signatures -// .iter() -// .map(|(_, sig)| func_sig_to_llvm(&context, &intrinsics, sig)) -// .collect(); - let signatures = Map::new(); -// let functions: Map = info -// .func_assoc -// .iter() -// .skip(info.imported_functions.len()) -// .map(|(func_index, &sig_index)| { -// let func = module.add_function( -// &format!("fn{}", func_index.index()), -// signatures[sig_index], -// Some(Linkage::External), -// ); -// func.set_personality_function(personality_func); -// func -// }) -// .collect(); + // let signatures: Map = info + // .signatures + // .iter() + // .map(|(_, sig)| func_sig_to_llvm(&context, &intrinsics, sig)) + // .collect(); + let signatures = Map::new(); + // let functions: Map = info + // .func_assoc + // .iter() + // .skip(info.imported_functions.len()) + // .map(|(func_index, &sig_index)| { + // let func = module.add_function( + // &format!("fn{}", func_index.index()), + // signatures[sig_index], + // Some(Linkage::External), + // ); + // func.set_personality_function(personality_func); + // func + // }) + // .collect(); let functions = Map::new(); -// let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); + // let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); LLVMModuleCodeGenerator { context: context, @@ -4642,7 +4664,7 @@ impl ModuleCodeGenerator func_import_count: 0, intrinsics: intrinsics, personality_func: personality_func, -// ctx: ctx, + // ctx: ctx, } } @@ -4659,42 +4681,61 @@ impl ModuleCodeGenerator use std::mem; - let sig_id = self.function_signatures.as_ref().unwrap()[FuncIndex::new(self.func_import_count + self.functions.len())]; + let sig_id = self.function_signatures.as_ref().unwrap() + [FuncIndex::new(self.func_import_count + self.functions.len())]; let func_sig = self.signatures_raw[sig_id].clone(); - let func = self.module.add_function( + let function = self.module.add_function( &format!("fn{}", self.func_import_count + self.functions.len()), self.signatures[sig_id], Some(Linkage::External), ); - func.set_personality_function(self.personality_func); + function.set_personality_function(self.personality_func); + + let mut locals = Vec::new(); + locals.extend( + function + .get_param_iter() + .skip(1) + .enumerate() + .map(|(index, param)| { + let ty = param.get_type(); + + let alloca = self.builder.build_alloca(ty, &format!("local{}", index)); + self.builder.build_store(alloca, param); + alloca + }), + ); + let num_params = locals.len(); let code = LLVMFunctionCodeGenerator { state: State::new(), builder: unsafe { ::std::mem::transmute::<&Builder, &'static Builder>(&self.builder) }, context: unsafe { ::std::mem::transmute::<&Context, &'static Context>(&self.context) }, - function: func, + function, func_sig: func_sig, - locals: vec![], + locals, signatures: self.signatures.clone(), -// context: self.fu - -// signatures: self.signatures.as_ref().unwrap().clone(), -// function_signatures: self.function_signatures.as_ref().unwrap().clone(), -// -// assembler: Some(assembler), -// function_labels: Some(function_labels), -// br_table_data: Some(br_table_data), -// breakpoints: Some(breakpoints), -// returns: smallvec![], -// locals: vec![], -// num_params: 0, -// num_locals: 0, -// value_stack: vec![], -// control_stack: vec![], -// machine: Machine::new(), -// unreachable_depth: 0, - intrinsics: unsafe { ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) }, + // context: self.fu + + // signatures: self.signatures.as_ref().unwrap().clone(), + // function_signatures: self.function_signatures.as_ref().unwrap().clone(), + // + // assembler: Some(assembler), + // function_labels: Some(function_labels), + // br_table_data: Some(br_table_data), + // breakpoints: Some(breakpoints), + // returns: smallvec![], + // locals: vec![], + num_params, + // num_locals: 0, + // value_stack: vec![], + // control_stack: vec![], + // machine: Machine::new(), + // unreachable_depth: 0, + intrinsics: unsafe { + ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) + }, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -4713,7 +4754,10 @@ impl ModuleCodeGenerator Ok(()) } - fn feed_function_signatures(&mut self, assoc: Map) -> Result<(), CodegenError> { + fn feed_function_signatures( + &mut self, + assoc: Map, + ) -> Result<(), CodegenError> { self.function_signatures = Some(Arc::new(assoc)); Ok(()) } @@ -4722,4 +4766,4 @@ impl ModuleCodeGenerator self.func_import_count += 1; Ok(()) } -} \ No newline at end of file +} diff --git a/lib/spectests/examples/simple/main.rs b/lib/spectests/examples/simple/main.rs index 8ac05dedb32..357adb5f70d 100644 --- a/lib/spectests/examples/simple/main.rs +++ b/lib/spectests/examples/simple/main.rs @@ -18,8 +18,8 @@ fn get_compiler() -> impl Compiler { #[cfg(feature = "llvm")] fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMStreamingCompiler; - LLVMStreamingCompiler::new() + use wasmer_llvm_backend::LLVMCompiler; + LLVMCompiler::new() } #[cfg(feature = "singlepass")] From 0ee2ba0ee6fc0828ac29a29848dc7f64fa1031f5 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 30 Apr 2019 23:22:41 -0500 Subject: [PATCH 04/15] Implement more of next_function and finalize --- lib/llvm-backend/src/code.rs | 52 +++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index f5b5e9c2e42..1a309dcfec1 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -4593,11 +4593,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } } - unimplemented!() + Ok(()) } fn finalize(&mut self) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } } @@ -4692,6 +4692,22 @@ impl ModuleCodeGenerator ); function.set_personality_function(self.personality_func); + let mut state = State::new(); + let entry_block = self.context.append_basic_block(&function, "entry"); + + let return_block = self.context.append_basic_block(&function, "return"); + self.builder.position_at_end(&return_block); + + let phis: SmallVec<[PhiValue; 1]> = func_sig + .returns() + .iter() + .map(|&wasmer_ty| type_to_llvm(&self.intrinsics, wasmer_ty)) + .map(|ty| self.builder.build_phi(ty, &state.var_name())) + .collect(); + + state.push_block(return_block, phis); + self.builder.position_at_end(&entry_block); + let mut locals = Vec::new(); locals.extend( function @@ -4709,7 +4725,7 @@ impl ModuleCodeGenerator let num_params = locals.len(); let code = LLVMFunctionCodeGenerator { - state: State::new(), + state, builder: unsafe { ::std::mem::transmute::<&Builder, &'static Builder>(&self.builder) }, context: unsafe { ::std::mem::transmute::<&Context, &'static Context>(&self.context) }, function, @@ -4742,7 +4758,35 @@ impl ModuleCodeGenerator } fn finalize(self, module_info: &ModuleInfo) -> Result { - unimplemented!() +// self.module.print_to_stderr(); + + generate_trampolines( + module_info, + &self.signatures, + &self.module, + &self.context, + &self.builder, + &self.intrinsics, + ); + + let pass_manager = PassManager::create_for_module(); + // pass_manager.add_verifier_pass(); + pass_manager.add_function_inlining_pass(); + pass_manager.add_promote_memory_to_register_pass(); + pass_manager.add_cfg_simplification_pass(); + // pass_manager.add_instruction_combining_pass(); + pass_manager.add_aggressive_inst_combiner_pass(); + pass_manager.add_merged_load_store_motion_pass(); + // pass_manager.add_sccp_pass(); + // pass_manager.add_gvn_pass(); + pass_manager.add_new_gvn_pass(); + pass_manager.add_aggressive_dce_pass(); + pass_manager.run_on_module(&self.module); + + // self.module.print_to_stderr(); + + let (backend, _cache_gen) = LLVMBackend::new(self.module, self.intrinsics); + Ok(backend) } fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { From b016ec6b344e63bf18d3f90b3926c531288e2071 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 30 Apr 2019 23:44:34 -0500 Subject: [PATCH 05/15] Add start_of_code_block to function --- lib/llvm-backend/src/code.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 1a309dcfec1..f9bfba26b17 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -4724,6 +4724,12 @@ impl ModuleCodeGenerator ); let num_params = locals.len(); + let start_of_code_block = self.context.append_basic_block(&function, "start_of_code"); + let entry_end_inst = self + .builder + .build_unconditional_branch(&start_of_code_block); + self.builder.position_at_end(&start_of_code_block); + let code = LLVMFunctionCodeGenerator { state, builder: unsafe { ::std::mem::transmute::<&Builder, &'static Builder>(&self.builder) }, From c5caf9b6dbff43947a0c3e8219627be210e48c9f Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Fri, 3 May 2019 00:14:25 -0500 Subject: [PATCH 06/15] Update LLVM FCG begin_body --- lib/llvm-backend/src/code.rs | 54 +++++++++++++---------- lib/runtime-core/src/codegen.rs | 17 ++++++- lib/runtime-core/src/parse.rs | 2 +- lib/singlepass-backend/src/codegen_x64.rs | 2 +- 4 files changed, 49 insertions(+), 26 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index f9bfba26b17..8745f7e3895 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2520,6 +2520,7 @@ pub struct LLVMFunctionCodeGenerator { // returns: SmallVec<[WpType; 1]>, locals: Vec, // Contains params and locals num_params: usize, + ctx: Option>, // num_locals: usize, // value_stack: Vec<(Location, LocalOrTemp)>, // control_stack: Vec, @@ -2565,7 +2566,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Ok(()) } - fn begin_body(&mut self) -> Result<(), CodegenError> { + fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError> { + let start_of_code_block = self + .context + .append_basic_block(&self.function, "start_of_code"); + let entry_end_inst = self + .builder + .build_unconditional_branch(&start_of_code_block); + self.builder.position_at_end(&start_of_code_block); + + let cache_builder = self.context.create_builder(); + cache_builder.position_before(&entry_end_inst); + let module_info = + unsafe { ::std::mem::transmute::<&ModuleInfo, &'static ModuleInfo>(module_info) }; + let function = unsafe { + ::std::mem::transmute::<&FunctionValue, &'static FunctionValue>(&self.function) + }; + let mut ctx = self + .intrinsics + .ctx(module_info, self.builder, function, cache_builder); + + self.ctx = Some(ctx); Ok(()) } @@ -2637,6 +2658,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // // let cache_builder = context.create_builder(); // cache_builder.position_before(&entry_end_inst); + let op = match event { + Event::Wasm(x) => x, + Event::Internal(x) => { + return Ok(()); + } + }; let mut state = &mut self.state; let builder = self.builder; @@ -2646,21 +2673,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let locals = &self.locals; let info = module_info; let signatures = &self.signatures; - - // TODO this should be done only once per function I believe - // just adding here to get compilation - let cache_builder = context.create_builder(); - // cache_builder.position_before(&entry_end_inst); - let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); - // self.ctx; - - let op = match event { - Event::Wasm(x) => x, - Event::Internal(x) => { - return Ok(()); - //unimplemented!() - } - }; + let mut ctx = self.ctx.as_mut().unwrap(); let mut unreachable_depth = 0; if !state.reachable { @@ -4724,12 +4737,6 @@ impl ModuleCodeGenerator ); let num_params = locals.len(); - let start_of_code_block = self.context.append_basic_block(&function, "start_of_code"); - let entry_end_inst = self - .builder - .build_unconditional_branch(&start_of_code_block); - self.builder.position_at_end(&start_of_code_block); - let code = LLVMFunctionCodeGenerator { state, builder: unsafe { ::std::mem::transmute::<&Builder, &'static Builder>(&self.builder) }, @@ -4758,13 +4765,14 @@ impl ModuleCodeGenerator intrinsics: unsafe { ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) }, + ctx: None, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) } fn finalize(self, module_info: &ModuleInfo) -> Result { -// self.module.print_to_stderr(); + // self.module.print_to_stderr(); generate_trampolines( module_info, diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 210a105bede..6694fbb8610 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -12,7 +12,9 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::marker::PhantomData; use wasmparser::{Operator, Type as WpType}; +use std::fmt; +#[derive(Debug)] pub enum Event<'a, 'b> { Internal(InternalEvent), Wasm(&'b Operator<'a>), @@ -26,6 +28,19 @@ pub enum InternalEvent { GetInternal(u32), } +impl fmt::Debug for InternalEvent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + InternalEvent::FunctionBegin(_) => write!(f, "FunctionBegin"), + InternalEvent::FunctionEnd => write!(f, "FunctionEnd"), + InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"), + InternalEvent::SetInternal(_) => write!(f, "SetInternal"), + InternalEvent::GetInternal(_) => write!(f, "GetInternal"), + _ => panic!("unknown event") + } + } +} + pub struct BkptInfo {} pub trait ModuleCodeGenerator, RM: RunnableModule, E: Debug> { @@ -246,7 +261,7 @@ pub trait FunctionCodeGenerator { fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), E>; /// Called before the first call to `feed_opcode`. - fn begin_body(&mut self) -> Result<(), E>; + fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), E>; /// Called for each operator. fn feed_event(&mut self, op: Event, module_info: &ModuleInfo) -> Result<(), E>; diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index e8fabf1947c..e7e80fc2971 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -244,7 +244,7 @@ pub fn read_module< ParserState::CodeOperator(ref op) => { if !body_begun { body_begun = true; - fcg.begin_body() + fcg.begin_body(&info) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } middlewares diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 783ca13af1e..86bcde07e54 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1387,7 +1387,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Ok(()) } - fn begin_body(&mut self) -> Result<(), CodegenError> { + fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError> { let a = self.assembler.as_mut().unwrap(); a.emit_push(Size::S64, Location::GPR(GPR::RBP)); a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP)); From 60c0504bdf727b6643fbd5eecff14f01cf08c64e Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 4 May 2019 12:07:21 -0500 Subject: [PATCH 07/15] Implement llvm returns in function code generator finalize --- lib/llvm-backend/src/code.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8745f7e3895..a65cb25d14f 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -4610,6 +4610,21 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn finalize(&mut self) -> Result<(), CodegenError> { + let results = self.state.popn_save(self.func_sig.returns().len())?; + + match results.as_slice() { + [] => { + self.builder.build_return(None); + } + [one_value] => { + self.builder.build_return(Some(one_value)); + } + _ => { + // 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") + } + } Ok(()) } } From 31acf817623aefeda471342074e471907df406d1 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 5 May 2019 13:37:36 -0500 Subject: [PATCH 08/15] cargo fmt --- lib/runtime-core/src/codegen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 6694fbb8610..6cb0021bd3e 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -9,10 +9,10 @@ use crate::{ types::{FuncIndex, FuncSig, SigIndex}, }; use smallvec::SmallVec; +use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; use wasmparser::{Operator, Type as WpType}; -use std::fmt; #[derive(Debug)] pub enum Event<'a, 'b> { @@ -36,7 +36,7 @@ impl fmt::Debug for InternalEvent { InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"), InternalEvent::SetInternal(_) => write!(f, "SetInternal"), InternalEvent::GetInternal(_) => write!(f, "GetInternal"), - _ => panic!("unknown event") + _ => panic!("unknown event"), } } } From e1138a553bb118952235acc6413657c10fc04c28 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 5 May 2019 13:56:02 -0500 Subject: [PATCH 09/15] Fix LLVM refactor unreachable depth --- lib/llvm-backend/src/code.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 0de1c2ade25..7c85040ab1e 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2525,7 +2525,7 @@ pub struct LLVMFunctionCodeGenerator { // value_stack: Vec<(Location, LocalOrTemp)>, // control_stack: Vec, // machine: Machine, - // unreachable_depth: usize, + unreachable_depth: usize, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -2675,29 +2675,24 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let signatures = &self.signatures; let mut ctx = self.ctx.as_mut().unwrap(); - let mut unreachable_depth = 0; if !state.reachable { match *op { Operator::Block { ty: _ } | Operator::Loop { ty: _ } | Operator::If { ty: _ } => { - unreachable_depth += 1; - // continue; + self.unreachable_depth += 1; return Ok(()); } Operator::Else => { - if unreachable_depth != 0 { - // continue; + if self.unreachable_depth != 0 { return Ok(()); } } Operator::End => { - if unreachable_depth != 0 { - unreachable_depth -= 1; - // continue; + if self.unreachable_depth != 0 { + self.unreachable_depth -= 1; return Ok(()); } } _ => { - // continue; return Ok(()); } } @@ -4781,6 +4776,7 @@ impl ModuleCodeGenerator ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) }, ctx: None, + unreachable_depth: 0, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) From 4770277b15959c1d669e7ab6be8d1a6c3906c727 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 5 May 2019 14:28:40 -0500 Subject: [PATCH 10/15] Remove parser refactor commented out code, unused imports and fields --- lib/llvm-backend/src/code.rs | 166 +++-------------------------------- 1 file changed, 12 insertions(+), 154 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 7c85040ab1e..302db536757 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8,7 +8,7 @@ use inkwell::{ AddressSpace, FloatPredicate, IntPredicate, }; use smallvec::SmallVec; -use std::{any::Any, collections::HashMap, sync::Arc}; +use std::sync::Arc; use wasmer_runtime_core::{ backend::Backend, codegen::*, @@ -2475,32 +2475,15 @@ pub struct LLVMModuleCodeGenerator { context: Context, builder: Builder, functions: Vec, - functions_llvm: Map, - // signatures: Option>>, signatures: Map, signatures_raw: Map, function_signatures: Option>>, - // function_labels: Option)>>, - // assembler: Option, func_import_count: usize, intrinsics: Intrinsics, personality_func: FunctionValue, module: Module, - // ctx: CtxType, } -// pub struct LLVMExecutionContext { -// // #[allow(dead_code)] -// // code: ExecutableBuffer, -// // #[allow(dead_code)] -// // functions: Vec, -// // function_pointers: Vec, -// // signatures: Arc>, -// // _br_table_data: Vec>, -// // breakpoints: Arc>>, -// // func_import_count: usize, -// } - pub struct LLVMFunctionCodeGenerator { state: State, builder: &'static Builder, @@ -2509,31 +2492,18 @@ pub struct LLVMFunctionCodeGenerator { func_sig: FuncSig, intrinsics: &'static Intrinsics, signatures: Map, - // signatures: Arc>, - - // function_signatures: Arc>, - - // assembler: Option, - // function_labels: Option)>>, - // br_table_data: Option>>, - // breakpoints: Option>>, - // returns: SmallVec<[WpType; 1]>, locals: Vec, // Contains params and locals num_params: usize, ctx: Option>, - // num_locals: usize, - // value_stack: Vec<(Location, LocalOrTemp)>, - // control_stack: Vec, - // machine: Machine, unreachable_depth: usize, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { - fn feed_return(&mut self, ty: WpType) -> Result<(), CodegenError> { + fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> { Ok(()) } - fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> { + fn feed_param(&mut self, _ty: WpType) -> Result<(), CodegenError> { Ok(()) } @@ -2582,7 +2552,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let function = unsafe { ::std::mem::transmute::<&FunctionValue, &'static FunctionValue>(&self.function) }; - let mut ctx = self + let ctx = self .intrinsics .ctx(module_info, self.builder, function, cache_builder); @@ -2591,76 +2561,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { - // let sig_index = info.func_assoc[func_index.convert_up(info)]; - // let func_sig = &info.signatures[sig_index]; - // - // let function = self.functions[func_index]; - // 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(); - // - // state.push_block(return_block, phis); - // builder.position_at_end(&entry_block); - // - // let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity - // - // locals.extend( - // function - // .get_param_iter() - // .skip(1) - // .enumerate() - // .map(|(index, param)| { - // let ty = param.get_type(); - // - // let alloca = builder.build_alloca(ty, &format!("local{}", index)); - // builder.build_store(alloca, param); - // alloca - // }), - // ); - // - // let param_len = locals.len(); - // - // let mut local_idx = 0; - // for local in locals_reader.into_iter() { - // let (count, ty) = local?; - // let wasmer_ty = type_to_type(ty)?; - // let ty = type_to_llvm(intrinsics, wasmer_ty); - // - // let default_value = match wasmer_ty { - // Type::I32 => intrinsics.i32_zero.as_basic_value_enum(), - // Type::I64 => intrinsics.i64_zero.as_basic_value_enum(), - // Type::F32 => intrinsics.f32_zero.as_basic_value_enum(), - // Type::F64 => intrinsics.f64_zero.as_basic_value_enum(), - // }; - // - // for _ in 0..count { - // let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); - // - // builder.build_store(alloca, default_value); - // - // locals.push(alloca); - // local_idx += 1; - // } - // } - // - // let start_of_code_block = context.append_basic_block(&function, "start_of_code"); - // let entry_end_inst = builder.build_unconditional_branch(&start_of_code_block); - // builder.position_at_end(&start_of_code_block); - // - // let cache_builder = context.create_builder(); - // cache_builder.position_before(&entry_end_inst); let op = match event { Event::Wasm(x) => x, - Event::Internal(x) => { + Event::Internal(_x) => { return Ok(()); } }; @@ -4648,46 +4551,19 @@ impl ModuleCodeGenerator Some(Linkage::External), ); - // TODO signatures and functions - // let signatures: Map = info - // .signatures - // .iter() - // .map(|(_, sig)| func_sig_to_llvm(&context, &intrinsics, sig)) - // .collect(); let signatures = Map::new(); - // let functions: Map = info - // .func_assoc - // .iter() - // .skip(info.imported_functions.len()) - // .map(|(func_index, &sig_index)| { - // let func = module.add_function( - // &format!("fn{}", func_index.index()), - // signatures[sig_index], - // Some(Linkage::External), - // ); - // func.set_personality_function(personality_func); - // func - // }) - // .collect(); - let functions = Map::new(); - - // let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); LLVMModuleCodeGenerator { - context: context, - builder: builder, - module: module, + context, + builder, + module, functions: vec![], - functions_llvm: functions, - signatures: signatures, + signatures, signatures_raw: Map::new(), function_signatures: None, - // function_labels: Some(HashMap::new()), - // assembler: Some(Assembler::new().unwrap()), func_import_count: 0, - intrinsics: intrinsics, - personality_func: personality_func, - // ctx: ctx, + intrinsics, + personality_func, } } @@ -4695,15 +4571,13 @@ impl ModuleCodeGenerator Backend::LLVM } - fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError> { + fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { Ok(()) } fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { // Creates a new function and returns the function-scope code generator for it. - use std::mem; - let sig_id = self.function_signatures.as_ref().unwrap() [FuncIndex::new(self.func_import_count + self.functions.len())]; let func_sig = self.signatures_raw[sig_id].clone(); @@ -4755,23 +4629,7 @@ impl ModuleCodeGenerator func_sig: func_sig, locals, signatures: self.signatures.clone(), - // context: self.fu - - // signatures: self.signatures.as_ref().unwrap().clone(), - // function_signatures: self.function_signatures.as_ref().unwrap().clone(), - // - // assembler: Some(assembler), - // function_labels: Some(function_labels), - // br_table_data: Some(br_table_data), - // breakpoints: Some(breakpoints), - // returns: smallvec![], - // locals: vec![], num_params, - // num_locals: 0, - // value_stack: vec![], - // control_stack: vec![], - // machine: Machine::new(), - // unreachable_depth: 0, intrinsics: unsafe { ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) }, From 0926a5020e74ae64cf608317b2b6adaf29d4ca54 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 5 May 2019 20:11:47 -0500 Subject: [PATCH 11/15] Implement caching for parser refactor --- lib/llvm-backend/src/code.rs | 29 +++++++++++--- lib/runtime-core/src/codegen.rs | 37 ++++++++---------- lib/singlepass-backend/src/codegen_x64.rs | 46 +++++++++++++++++------ 3 files changed, 73 insertions(+), 39 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 302db536757..2a607a076d5 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -10,10 +10,11 @@ use inkwell::{ use smallvec::SmallVec; use std::sync::Arc; use wasmer_runtime_core::{ - backend::Backend, + backend::{Backend, CacheGen, Token}, + cache::{Artifact, Error as CacheError}, codegen::*, memory::MemoryType, - module::ModuleInfo, + module::{ModuleInfo, ModuleInner}, structures::{Map, SliceMap, TypedIndex}, types::{ FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, @@ -25,7 +26,7 @@ use wasmparser::{ Type as WpType, }; -use crate::backend::LLVMBackend; +use crate::backend::{LLVMBackend, LLVMCache}; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::type_to_type; use crate::state::{ControlFrame, IfElseState, State}; @@ -4640,7 +4641,10 @@ impl ModuleCodeGenerator Ok(self.functions.last_mut().unwrap()) } - fn finalize(self, module_info: &ModuleInfo) -> Result { + fn finalize( + self, + module_info: &ModuleInfo, + ) -> Result<(LLVMBackend, Box), CodegenError> { // self.module.print_to_stderr(); generate_trampolines( @@ -4668,8 +4672,8 @@ impl ModuleCodeGenerator // self.module.print_to_stderr(); - let (backend, _cache_gen) = LLVMBackend::new(self.module, self.intrinsics); - Ok(backend) + let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics); + Ok((backend, Box::new(cache_gen))) } fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { @@ -4693,4 +4697,17 @@ impl ModuleCodeGenerator self.func_import_count += 1; Ok(()) } + + unsafe fn from_cache(artifact: Artifact, _: Token) -> Result { + let (info, _, memory) = artifact.consume(); + let (backend, cache_gen) = + LLVMBackend::from_buffer(memory).map_err(CacheError::DeserializeError)?; + + Ok(ModuleInner { + runnable_module: Box::new(backend), + cache_gen: Box::new(cache_gen), + + info, + }) + } } diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 6cb0021bd3e..07cc7d94abe 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -50,7 +50,7 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, /// Creates a new function and returns the function-scope code generator for it. fn next_function(&mut self) -> Result<&mut FCG, E>; - fn finalize(self, module_info: &ModuleInfo) -> Result; + fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box), E>; fn feed_signatures(&mut self, signatures: Map) -> Result<(), E>; /// Sets function signatures. @@ -58,6 +58,8 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, /// Adds an import function. fn feed_import_function(&mut self) -> Result<(), E>; + + unsafe fn from_cache(cache: Artifact, _: Token) -> Result; } pub struct StreamingCompiler< @@ -131,15 +133,6 @@ impl< compiler_config: CompilerConfig, _: Token, ) -> CompileResult { - struct Placeholder; - impl CacheGen for Placeholder { - fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { - Err(CacheError::Unknown( - "the streaming compiler API doesn't support caching yet".to_string(), - )) - } - } - let mut mcg = MCG::new(); let mut chain = (self.middleware_chain_generator)(); let info = crate::parse::read_module( @@ -149,22 +142,24 @@ impl< &mut chain, &compiler_config, )?; - let exec_context = mcg - .finalize(&info) - .map_err(|x| CompileError::InternalError { - msg: format!("{:?}", x), - })?; + let (exec_context, cache_gen) = + mcg.finalize(&info) + .map_err(|x| CompileError::InternalError { + msg: format!("{:?}", x), + })?; Ok(ModuleInner { - cache_gen: Box::new(Placeholder), + cache_gen, runnable_module: Box::new(exec_context), - info: info, + info, }) } - unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result { - Err(CacheError::Unknown( - "the streaming compiler API doesn't support caching yet".to_string(), - )) + unsafe fn from_cache( + &self, + artifact: Artifact, + token: Token, + ) -> Result { + MCG::from_cache(artifact, token) } } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 86bcde07e54..22687cd9fc6 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -10,10 +10,11 @@ use smallvec::SmallVec; use std::ptr::NonNull; use std::{any::Any, collections::HashMap, sync::Arc}; use wasmer_runtime_core::{ - backend::{Backend, RunnableModule}, + backend::{sys::Memory, Backend, CacheGen, RunnableModule, Token}, + cache::{Artifact, Error as CacheError}, codegen::*, memory::MemoryType, - module::ModuleInfo, + module::{ModuleInfo, ModuleInner}, structures::{Map, TypedIndex}, typed_func::Wasm, types::{ @@ -349,7 +350,10 @@ impl ModuleCodeGenerator Ok(self.functions.last_mut().unwrap()) } - fn finalize(mut self, _: &ModuleInfo) -> Result { + fn finalize( + mut self, + _: &ModuleInfo, + ) -> Result<(X64ExecutionContext, Box), CodegenError> { let (assembler, mut br_table_data, breakpoints) = match self.functions.last_mut() { Some(x) => ( x.assembler.take().unwrap(), @@ -404,15 +408,27 @@ impl ModuleCodeGenerator .collect(), ); - Ok(X64ExecutionContext { - code: output, - functions: self.functions, - signatures: self.signatures.as_ref().unwrap().clone(), - _br_table_data: br_table_data, - breakpoints: breakpoints, - func_import_count: self.func_import_count, - function_pointers: out_labels, - }) + struct Placeholder; + impl CacheGen for Placeholder { + fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { + Err(CacheError::Unknown( + "the singlepass backend doesn't support caching yet".to_string(), + )) + } + } + + Ok(( + X64ExecutionContext { + code: output, + functions: self.functions, + signatures: self.signatures.as_ref().unwrap().clone(), + _br_table_data: br_table_data, + breakpoints: breakpoints, + func_import_count: self.func_import_count, + function_pointers: out_labels, + }, + Box::new(Placeholder), + )) } fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { @@ -461,6 +477,12 @@ impl ModuleCodeGenerator Ok(()) } + + unsafe fn from_cache(artifact: Artifact, _: Token) -> Result { + Err(CacheError::Unknown( + "the singlepass compiler API doesn't support caching yet".to_string(), + )) + } } impl X64FunctionCode { From 9c0cbc9775027b75bcd25db89cf7b1ea8313d2c5 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 6 May 2019 23:41:31 -0500 Subject: [PATCH 12/15] Remove previous LLVM parser code --- lib/llvm-backend/src/code.rs | 2121 +---------------------------- lib/llvm-backend/src/lib.rs | 118 +- lib/llvm-backend/src/read_info.rs | 331 +---- 3 files changed, 9 insertions(+), 2561 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 2a607a076d5..8c3d89d7448 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -15,18 +15,14 @@ use wasmer_runtime_core::{ codegen::*, memory::MemoryType, module::{ModuleInfo, ModuleInner}, - structures::{Map, SliceMap, TypedIndex}, + structures::{Map, TypedIndex}, types::{ - FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, - TableIndex, Type, + FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, }, }; -use wasmparser::{ - BinaryReaderError, CodeSectionReader, LocalsReader, MemoryImmediate, Operator, OperatorsReader, - Type as WpType, -}; +use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; -use crate::backend::{LLVMBackend, LLVMCache}; +use crate::backend::LLVMBackend; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::type_to_type; use crate::state::{ControlFrame, IfElseState, State}; @@ -64,2112 +60,6 @@ fn type_to_llvm(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { } } -pub fn parse_function_bodies( - info: &ModuleInfo, - code_reader: CodeSectionReader, -) -> Result<(Module, Intrinsics), BinaryReaderError> { - let context = Context::create(); - let module = context.create_module("module"); - let builder = context.create_builder(); - - let intrinsics = Intrinsics::declare(&module, &context); - - let personality_func = module.add_function( - "__gxx_personality_v0", - intrinsics.i32_ty.fn_type(&[], false), - Some(Linkage::External), - ); - - let signatures: Map = info - .signatures - .iter() - .map(|(_, sig)| func_sig_to_llvm(&context, &intrinsics, sig)) - .collect(); - let functions: Map = info - .func_assoc - .iter() - .skip(info.imported_functions.len()) - .map(|(func_index, &sig_index)| { - let func = module.add_function( - &format!("fn{}", func_index.index()), - signatures[sig_index], - Some(Linkage::External), - ); - func.set_personality_function(personality_func); - func - }) - .collect(); - - for (local_func_index, body) in code_reader.into_iter().enumerate() { - let body = body?; - - let locals_reader = body.get_locals_reader()?; - let op_reader = body.get_operators_reader()?; - - parse_function( - &context, - &builder, - &intrinsics, - info, - &signatures, - &functions, - LocalFuncIndex::new(local_func_index), - locals_reader, - op_reader, - ) - .map_err(|e| BinaryReaderError { - message: e.message, - offset: local_func_index, - })?; - } - - // module.print_to_stderr(); - - generate_trampolines(info, &signatures, &module, &context, &builder, &intrinsics); - - let pass_manager = PassManager::create_for_module(); - // pass_manager.add_verifier_pass(); - pass_manager.add_function_inlining_pass(); - pass_manager.add_promote_memory_to_register_pass(); - pass_manager.add_cfg_simplification_pass(); - // pass_manager.add_instruction_combining_pass(); - pass_manager.add_aggressive_inst_combiner_pass(); - pass_manager.add_merged_load_store_motion_pass(); - // pass_manager.add_sccp_pass(); - // pass_manager.add_gvn_pass(); - pass_manager.add_new_gvn_pass(); - pass_manager.add_aggressive_dce_pass(); - pass_manager.run_on_module(&module); - - // module.print_to_stderr(); - - Ok((module, intrinsics)) -} - -fn parse_function( - context: &Context, - builder: &Builder, - intrinsics: &Intrinsics, - info: &ModuleInfo, - signatures: &SliceMap, - functions: &SliceMap, - func_index: LocalFuncIndex, - locals_reader: LocalsReader, - op_reader: OperatorsReader, -) -> Result<(), BinaryReaderError> { - let sig_index = info.func_assoc[func_index.convert_up(info)]; - let func_sig = &info.signatures[sig_index]; - - let function = functions[func_index]; - 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(); - - state.push_block(return_block, phis); - builder.position_at_end(&entry_block); - - let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity - - locals.extend( - function - .get_param_iter() - .skip(1) - .enumerate() - .map(|(index, param)| { - let ty = param.get_type(); - - let alloca = builder.build_alloca(ty, &format!("local{}", index)); - builder.build_store(alloca, param); - alloca - }), - ); - - let param_len = locals.len(); - - let mut local_idx = 0; - for local in locals_reader.into_iter() { - let (count, ty) = local?; - let wasmer_ty = type_to_type(ty)?; - let ty = type_to_llvm(intrinsics, wasmer_ty); - - let default_value = match wasmer_ty { - Type::I32 => intrinsics.i32_zero.as_basic_value_enum(), - Type::I64 => intrinsics.i64_zero.as_basic_value_enum(), - Type::F32 => intrinsics.f32_zero.as_basic_value_enum(), - Type::F64 => intrinsics.f64_zero.as_basic_value_enum(), - }; - - for _ in 0..count { - let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); - - builder.build_store(alloca, default_value); - - locals.push(alloca); - local_idx += 1; - } - } - - let start_of_code_block = context.append_basic_block(&function, "start_of_code"); - let entry_end_inst = builder.build_unconditional_branch(&start_of_code_block); - builder.position_at_end(&start_of_code_block); - - let cache_builder = context.create_builder(); - cache_builder.position_before(&entry_end_inst); - let mut ctx = intrinsics.ctx(info, builder, &function, cache_builder); - let mut unreachable_depth = 0; - - for op in op_reader { - let op = op?; - if !state.reachable { - match op { - Operator::Block { ty: _ } | Operator::Loop { ty: _ } | Operator::If { ty: _ } => { - unreachable_depth += 1; - continue; - } - Operator::Else => { - if unreachable_depth != 0 { - continue; - } - } - Operator::End => { - if unreachable_depth != 0 { - unreachable_depth -= 1; - continue; - } - } - _ => { - continue; - } - } - } - - match op { - /*************************** - * Control Flow instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#control-flow-instructions - ***************************/ - Operator::Block { ty } => { - let current_block = builder.get_insert_block().ok_or(BinaryReaderError { - message: "not currently in a block", - offset: -1isize as usize, - })?; - - 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) { - 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() - }; - - state.push_block(end_block, phis); - 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"); - - 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)?; - - let current_block = builder.get_insert_block().ok_or(BinaryReaderError { - message: "not currently in a block", - offset: -1isize as usize, - })?; - - 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 - // the corresponding phi. - for (phi, value) in frame.phis().iter().zip(values.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); - } - - builder.build_unconditional_branch(frame.br_dest()); - - state.popn(value_len)?; - state.reachable = false; - } - Operator::BrIf { relative_depth } => { - let cond = state.pop1()?; - let frame = state.frame_at_depth(relative_depth)?; - - let current_block = builder.get_insert_block().ok_or(BinaryReaderError { - message: "not currently in a block", - offset: -1isize as usize, - })?; - - 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 else_block = context.append_basic_block(&function, "else"); - - 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, 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 { - message: "not currently in a block", - offset: -1isize as usize, - })?; - - let (label_depths, default_depth) = table.read_table()?; - - let index = state.pop1()?; - - let default_frame = state.frame_at_depth(default_depth)?; - - let args = if default_frame.is_loop() { - &[] - } else { - let res_len = default_frame.phis().len(); - state.peekn(res_len)? - }; - - for (phi, value) in default_frame.phis().iter().zip(args.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); - } - - let cases: Vec<_> = label_depths - .iter() - .enumerate() - .map(|(case_index, &depth)| { - let frame = state.frame_at_depth(depth)?; - let case_index_literal = - context.i32_type().const_int(case_index as u64, false); - - for (phi, value) in frame.phis().iter().zip(args.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); - } - - Ok((case_index_literal, frame.br_dest())) - }) - .collect::>()?; - - builder.build_switch(index.into_int_value(), default_frame.br_dest(), &cases[..]); - - state.popn(args.len())?; - state.reachable = false; - } - 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, - 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() { - if phi.count_incoming() != 0 { - state.push1(phi.as_basic_value()); - } else { - let basic_ty = phi.as_basic_value().get_type(); - let placeholder_value = match basic_ty { - BasicTypeEnum::IntType(int_ty) => { - int_ty.const_int(0, false).as_basic_value_enum() - } - BasicTypeEnum::FloatType(float_ty) => { - float_ty.const_float(0.0).as_basic_value_enum() - } - _ => unimplemented!(), - }; - state.push1(placeholder_value); - phi.as_instruction().erase_from_basic_block(); - } - } - } - Operator::Return => { - let frame = state.outermost_frame()?; - let current_block = builder.get_insert_block().ok_or(BinaryReaderError { - message: "not currently in a block", - offset: -1isize as usize, - })?; - - builder.build_unconditional_branch(frame.br_dest()); - - let phis = frame.phis().to_vec(); - - for phi in phis.iter() { - let arg = state.pop1()?; - phi.add_incoming(&[(&arg, ¤t_block)]); - } - - state.reachable = false; - } - - Operator::Unreachable => { - // Emit an unreachable instruction. - // If llvm cannot prove that this is never touched, - // it will emit a `ud2` instruction on x86_64 arches. - - builder.build_call( - intrinsics.throw_trap, - &[intrinsics.trap_unreachable], - "throw", - ); - builder.build_unreachable(); - - state.reachable = false; - } - - /*************************** - * Basic instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#basic-instructions - ***************************/ - Operator::Nop => { - // Do nothing. - } - Operator::Drop => { - state.pop1()?; - } - - // Generate const values. - Operator::I32Const { value } => { - let i = intrinsics.i32_ty.const_int(value as u64, false); - state.push1(i); - } - Operator::I64Const { value } => { - let i = intrinsics.i64_ty.const_int(value as u64, false); - state.push1(i); - } - Operator::F32Const { value } => { - let bits = intrinsics.i32_ty.const_int(value.bits() as u64, false); - let space = - builder.build_alloca(intrinsics.f32_ty.as_basic_type_enum(), "const_space"); - let i32_space = - builder.build_pointer_cast(space, intrinsics.i32_ptr_ty, "i32_space"); - builder.build_store(i32_space, bits); - let f = builder.build_load(space, "f"); - state.push1(f); - } - Operator::F64Const { value } => { - let bits = intrinsics.i64_ty.const_int(value.bits(), false); - let space = - builder.build_alloca(intrinsics.f64_ty.as_basic_type_enum(), "const_space"); - let i64_space = - builder.build_pointer_cast(space, intrinsics.i64_ptr_ty, "i32_space"); - builder.build_store(i64_space, bits); - let f = builder.build_load(space, "f"); - state.push1(f); - } - - // Operate on locals. - Operator::GetLocal { local_index } => { - let pointer_value = locals[local_index as usize]; - let v = builder.build_load(pointer_value, &state.var_name()); - state.push1(v); - } - Operator::SetLocal { local_index } => { - let pointer_value = locals[local_index as usize]; - let v = state.pop1()?; - builder.build_store(pointer_value, v); - } - Operator::TeeLocal { local_index } => { - let pointer_value = locals[local_index as usize]; - let v = state.peek1()?; - builder.build_store(pointer_value, v); - } - - Operator::GetGlobal { global_index } => { - let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index); - match global_cache { - GlobalCache::Const { value } => { - state.push1(value); - } - GlobalCache::Mut { ptr_to_value } => { - let value = builder.build_load(ptr_to_value, "global_value"); - state.push1(value); - } - } - } - Operator::SetGlobal { global_index } => { - let value = state.pop1()?; - let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index); - match global_cache { - GlobalCache::Mut { ptr_to_value } => { - builder.build_store(ptr_to_value, value); - } - GlobalCache::Const { value: _ } => { - unreachable!("cannot set non-mutable globals") - } - } - } - - Operator::Select => { - let (v1, v2, cond) = state.pop3()?; - let cond_value = builder.build_int_compare( - IntPredicate::NE, - cond.into_int_value(), - intrinsics.i32_zero, - &state.var_name(), - ); - let res = builder.build_select(cond_value, v1, v2, &state.var_name()); - state.push1(res); - } - Operator::Call { function_index } => { - let func_index = FuncIndex::new(function_index as usize); - let sigindex = info.func_assoc[func_index]; - let llvm_sig = signatures[sigindex]; - let func_sig = &info.signatures[sigindex]; - - let call_site = match func_index.local_or_import(info) { - LocalOrImport::Local(local_func_index) => { - let params: Vec<_> = [ctx.basic()] - .iter() - .chain(state.peekn(func_sig.params().len())?.iter()) - .map(|v| *v) - .collect(); - - let func_ptr = ctx.local_func(local_func_index, llvm_sig); - - builder.build_call(func_ptr, ¶ms, &state.var_name()) - } - LocalOrImport::Import(import_func_index) => { - let (func_ptr_untyped, ctx_ptr) = ctx.imported_func(import_func_index); - let params: Vec<_> = [ctx_ptr.as_basic_value_enum()] - .iter() - .chain(state.peekn(func_sig.params().len())?.iter()) - .map(|v| *v) - .collect(); - - let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic); - - let func_ptr = builder.build_pointer_cast( - func_ptr_untyped, - func_ptr_ty, - "typed_func_ptr", - ); - - builder.build_call(func_ptr, ¶ms, &state.var_name()) - } - }; - - state.popn(func_sig.params().len())?; - - if let Some(basic_value) = call_site.try_as_basic_value().left() { - match func_sig.returns().len() { - 1 => state.push1(basic_value), - count @ _ => { - // This is a multi-value return. - let struct_value = basic_value.into_struct_value(); - for i in 0..(count as u32) { - let value = builder - .build_extract_value(struct_value, i, &state.var_name()) - .unwrap(); - state.push1(value); - } - } - } - } - } - Operator::CallIndirect { index, table_index } => { - let sig_index = SigIndex::new(index as usize); - let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index); - let (table_base, table_bound) = ctx.table(TableIndex::new(table_index as usize)); - let func_index = state.pop1()?.into_int_value(); - - // We assume the table has the `anyfunc` element type. - let casted_table_base = builder.build_pointer_cast( - table_base, - intrinsics.anyfunc_ty.ptr_type(AddressSpace::Generic), - "casted_table_base", - ); - - let anyfunc_struct_ptr = unsafe { - builder.build_in_bounds_gep( - casted_table_base, - &[func_index], - "anyfunc_struct_ptr", - ) - }; - - // Load things from the anyfunc data structure. - let (func_ptr, ctx_ptr, found_dynamic_sigindex) = unsafe { - ( - builder - .build_load( - builder.build_struct_gep(anyfunc_struct_ptr, 0, "func_ptr_ptr"), - "func_ptr", - ) - .into_pointer_value(), - builder.build_load( - builder.build_struct_gep(anyfunc_struct_ptr, 1, "ctx_ptr_ptr"), - "ctx_ptr", - ), - builder - .build_load( - builder.build_struct_gep(anyfunc_struct_ptr, 2, "sigindex_ptr"), - "sigindex", - ) - .into_int_value(), - ) - }; - - let truncated_table_bounds = builder.build_int_truncate( - table_bound, - intrinsics.i32_ty, - "truncated_table_bounds", - ); - - // First, check if the index is outside of the table bounds. - let index_in_bounds = builder.build_int_compare( - IntPredicate::ULT, - func_index, - truncated_table_bounds, - "index_in_bounds", - ); - - let index_in_bounds = builder - .build_call( - intrinsics.expect_i1, - &[ - index_in_bounds.as_basic_value_enum(), - intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), - ], - "index_in_bounds_expect", - ) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - - let in_bounds_continue_block = - context.append_basic_block(&function, "in_bounds_continue_block"); - let not_in_bounds_block = - context.append_basic_block(&function, "not_in_bounds_block"); - builder.build_conditional_branch( - index_in_bounds, - &in_bounds_continue_block, - ¬_in_bounds_block, - ); - builder.position_at_end(¬_in_bounds_block); - builder.build_call( - intrinsics.throw_trap, - &[intrinsics.trap_call_indirect_oob], - "throw", - ); - builder.build_unreachable(); - builder.position_at_end(&in_bounds_continue_block); - - // Next, check if the signature id is correct. - - let sigindices_equal = builder.build_int_compare( - IntPredicate::EQ, - expected_dynamic_sigindex, - found_dynamic_sigindex, - "sigindices_equal", - ); - - // Tell llvm that `expected_dynamic_sigindex` should equal `found_dynamic_sigindex`. - let sigindices_equal = builder - .build_call( - intrinsics.expect_i1, - &[ - sigindices_equal.as_basic_value_enum(), - intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), - ], - "sigindices_equal_expect", - ) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - - let continue_block = context.append_basic_block(&function, "continue_block"); - let sigindices_notequal_block = - context.append_basic_block(&function, "sigindices_notequal_block"); - builder.build_conditional_branch( - sigindices_equal, - &continue_block, - &sigindices_notequal_block, - ); - - builder.position_at_end(&sigindices_notequal_block); - builder.build_call( - intrinsics.throw_trap, - &[intrinsics.trap_call_indirect_sig], - "throw", - ); - builder.build_unreachable(); - builder.position_at_end(&continue_block); - - let wasmer_fn_sig = &info.signatures[sig_index]; - let fn_ty = signatures[sig_index]; - - let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?; - - let args: Vec<_> = std::iter::once(ctx_ptr) - .chain(pushed_args.into_iter()) - .collect(); - - let typed_func_ptr = builder.build_pointer_cast( - func_ptr, - fn_ty.ptr_type(AddressSpace::Generic), - "typed_func_ptr", - ); - - let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); - - match wasmer_fn_sig.returns() { - [] => {} - [_] => { - let value = call_site.try_as_basic_value().left().unwrap(); - state.push1(value); - } - _ => unimplemented!("multi-value returns"), - } - } - - /*************************** - * Integer Arithmetic instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-arithmetic-instructions - ***************************/ - Operator::I32Add | Operator::I64Add => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_int_add(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32Sub | Operator::I64Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_int_sub(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32Mul | Operator::I64Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_int_mul(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32DivS | Operator::I64DivS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - - trap_if_zero_or_overflow(builder, intrinsics, context, &function, v1, v2); - - let res = builder.build_int_signed_div(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32DivU | Operator::I64DivU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - - trap_if_zero(builder, intrinsics, context, &function, v2); - - let res = builder.build_int_unsigned_div(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32RemS | Operator::I64RemS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - - trap_if_zero(builder, intrinsics, context, &function, v2); - - let res = builder.build_int_signed_rem(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32RemU | Operator::I64RemU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - - trap_if_zero(builder, intrinsics, context, &function, v2); - - let res = builder.build_int_unsigned_rem(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32And | Operator::I64And => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_and(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32Or | Operator::I64Or => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_or(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32Xor | Operator::I64Xor => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_xor(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32Shl | Operator::I64Shl => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_left_shift(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::I32ShrS | Operator::I64ShrS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_right_shift(v1, v2, true, &state.var_name()); - state.push1(res); - } - Operator::I32ShrU | Operator::I64ShrU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = builder.build_right_shift(v1, v2, false, &state.var_name()); - state.push1(res); - } - Operator::I32Rotl => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let lhs = builder.build_left_shift(v1, v2, &state.var_name()); - let rhs = { - let int_width = intrinsics.i32_ty.const_int(32 as u64, false); - let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); - builder.build_right_shift(v1, rhs, false, &state.var_name()) - }; - let res = builder.build_or(lhs, rhs, &state.var_name()); - state.push1(res); - } - Operator::I64Rotl => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let lhs = builder.build_left_shift(v1, v2, &state.var_name()); - let rhs = { - let int_width = intrinsics.i64_ty.const_int(64 as u64, false); - let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); - builder.build_right_shift(v1, rhs, false, &state.var_name()) - }; - let res = builder.build_or(lhs, rhs, &state.var_name()); - state.push1(res); - } - Operator::I32Rotr => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let lhs = builder.build_right_shift(v1, v2, false, &state.var_name()); - let rhs = { - let int_width = intrinsics.i32_ty.const_int(32 as u64, false); - let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); - builder.build_left_shift(v1, rhs, &state.var_name()) - }; - let res = builder.build_or(lhs, rhs, &state.var_name()); - state.push1(res); - } - Operator::I64Rotr => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let lhs = builder.build_right_shift(v1, v2, false, &state.var_name()); - let rhs = { - let int_width = intrinsics.i64_ty.const_int(64 as u64, false); - let rhs = builder.build_int_sub(int_width, v2, &state.var_name()); - builder.build_left_shift(v1, rhs, &state.var_name()) - }; - let res = builder.build_or(lhs, rhs, &state.var_name()); - state.push1(res); - } - Operator::I32Clz => { - let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); - let res = builder - .build_call( - intrinsics.ctlz_i32, - &[input, ensure_defined_zero], - &state.var_name(), - ) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::I64Clz => { - let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); - let res = builder - .build_call( - intrinsics.ctlz_i64, - &[input, ensure_defined_zero], - &state.var_name(), - ) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::I32Ctz => { - let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); - let res = builder - .build_call( - intrinsics.cttz_i32, - &[input, ensure_defined_zero], - &state.var_name(), - ) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::I64Ctz => { - let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); - let res = builder - .build_call( - intrinsics.cttz_i64, - &[input, ensure_defined_zero], - &state.var_name(), - ) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::I32Popcnt => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.ctpop_i32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::I64Popcnt => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.ctpop_i64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::I32Eqz => { - let input = state.pop1()?.into_int_value(); - let cond = builder.build_int_compare( - IntPredicate::EQ, - input, - intrinsics.i32_zero, - &state.var_name(), - ); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I64Eqz => { - let input = state.pop1()?.into_int_value(); - let cond = builder.build_int_compare( - IntPredicate::EQ, - input, - intrinsics.i64_zero, - &state.var_name(), - ); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - - /*************************** - * Floating-Point Arithmetic instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions - ***************************/ - Operator::F32Add | Operator::F64Add => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::F32Sub | Operator::F64Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::F32Mul | Operator::F64Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::F32Div | Operator::F64Div => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = builder.build_float_div(v1, v2, &state.var_name()); - state.push1(res); - } - Operator::F32Sqrt => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.sqrt_f32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Sqrt => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.sqrt_f64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Min => { - let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Min => { - let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Max => { - let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Max => { - let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Ceil => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.ceil_f32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Ceil => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.ceil_f64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Floor => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.floor_f32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Floor => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.floor_f64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Trunc => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.trunc_f32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Trunc => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.trunc_f64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Nearest => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.nearbyint_f32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Nearest => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.nearbyint_f64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Abs => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.fabs_f32, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Abs => { - let input = state.pop1()?; - let res = builder - .build_call(intrinsics.fabs_f64, &[input], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F32Neg | Operator::F64Neg => { - let input = state.pop1()?.into_float_value(); - let res = builder.build_float_neg(input, &state.var_name()); - state.push1(res); - } - Operator::F32Copysign => { - let (mag, sgn) = state.pop2()?; - let res = builder - .build_call(intrinsics.copysign_f32, &[mag, sgn], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - Operator::F64Copysign => { - let (msg, sgn) = state.pop2()?; - let res = builder - .build_call(intrinsics.copysign_f64, &[msg, sgn], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); - state.push1(res); - } - - /*************************** - * Integer Comparison instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-comparison-instructions - ***************************/ - Operator::I32Eq | Operator::I64Eq => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::EQ, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32Ne | Operator::I64Ne => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::NE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32LtS | Operator::I64LtS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::SLT, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32LtU | Operator::I64LtU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::ULT, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32LeS | Operator::I64LeS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::SLE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32LeU | Operator::I64LeU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::ULE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32GtS | Operator::I64GtS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::SGT, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32GtU | Operator::I64GtU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::UGT, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32GeS | Operator::I64GeS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::SGE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32GeU | Operator::I64GeU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = builder.build_int_compare(IntPredicate::UGE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - - /*************************** - * Floating-Point Comparison instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-comparison-instructions - ***************************/ - Operator::F32Eq | Operator::F64Eq => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = - builder.build_float_compare(FloatPredicate::OEQ, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::F32Ne | Operator::F64Ne => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = - builder.build_float_compare(FloatPredicate::UNE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::F32Lt | Operator::F64Lt => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = - builder.build_float_compare(FloatPredicate::OLT, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::F32Le | Operator::F64Le => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = - builder.build_float_compare(FloatPredicate::OLE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::F32Gt | Operator::F64Gt => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = - builder.build_float_compare(FloatPredicate::OGT, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::F32Ge | Operator::F64Ge => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = - builder.build_float_compare(FloatPredicate::OGE, v1, v2, &state.var_name()); - let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - - /*************************** - * Conversion instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#conversion-instructions - ***************************/ - Operator::I32WrapI64 => { - let v1 = state.pop1()?.into_int_value(); - let res = builder.build_int_truncate(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I64ExtendSI32 => { - let v1 = state.pop1()?.into_int_value(); - let res = builder.build_int_s_extend(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I64ExtendUI32 => { - let v1 = state.pop1()?.into_int_value(); - let res = builder.build_int_z_extend(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I32TruncSF32 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -2147483904.0, - 2_147_483_648.0, - v1, - ); - let res = - builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32TruncSF64 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -2_147_483_649.0, - 2_147_483_648.0, - v1, - ); - let res = - builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32TruncSSatF32 | Operator::I32TruncSSatF64 => { - let v1 = state.pop1()?.into_float_value(); - let res = - builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I64TruncSF32 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -9_223_373_136_366_403_584.0, - 9_223_372_036_854_775_808.0, - v1, - ); - let res = - builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I64TruncSF64 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -9223372036854777856.0, - 9223372036854775808.0, - v1, - ); - let res = - builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I64TruncSSatF32 | Operator::I64TruncSSatF64 => { - let v1 = state.pop1()?.into_float_value(); - let res = - builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I32TruncUF32 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -1.0, - 4294967296.0, - v1, - ); - let res = - builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32TruncUF64 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -1.0, - 4294967296.0, - v1, - ); - let res = - builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I32TruncUSatF32 | Operator::I32TruncUSatF64 => { - let v1 = state.pop1()?.into_float_value(); - let res = - builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name()); - state.push1(res); - } - Operator::I64TruncUF32 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -1.0, - 18446744073709551616.0, - v1, - ); - let res = - builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I64TruncUF64 => { - let v1 = state.pop1()?.into_float_value(); - trap_if_not_representatable_as_int( - builder, - intrinsics, - context, - &function, - -1.0, - 18446744073709551616.0, - v1, - ); - let res = - builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::I64TruncUSatF32 | Operator::I64TruncUSatF64 => { - let v1 = state.pop1()?.into_float_value(); - let res = - builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); - } - Operator::F32DemoteF64 => { - let v1 = state.pop1()?.into_float_value(); - let res = builder.build_float_trunc(v1, intrinsics.f32_ty, &state.var_name()); - state.push1(res); - } - Operator::F64PromoteF32 => { - let v1 = state.pop1()?.into_float_value(); - let res = builder.build_float_ext(v1, intrinsics.f64_ty, &state.var_name()); - state.push1(res); - } - Operator::F32ConvertSI32 | Operator::F32ConvertSI64 => { - let v1 = state.pop1()?.into_int_value(); - let res = - builder.build_signed_int_to_float(v1, intrinsics.f32_ty, &state.var_name()); - state.push1(res); - } - Operator::F64ConvertSI32 | Operator::F64ConvertSI64 => { - let v1 = state.pop1()?.into_int_value(); - let res = - builder.build_signed_int_to_float(v1, intrinsics.f64_ty, &state.var_name()); - state.push1(res); - } - Operator::F32ConvertUI32 | Operator::F32ConvertUI64 => { - let v1 = state.pop1()?.into_int_value(); - let res = - builder.build_unsigned_int_to_float(v1, intrinsics.f32_ty, &state.var_name()); - state.push1(res); - } - Operator::F64ConvertUI32 | Operator::F64ConvertUI64 => { - let v1 = state.pop1()?.into_int_value(); - let res = - builder.build_unsigned_int_to_float(v1, intrinsics.f64_ty, &state.var_name()); - state.push1(res); - } - Operator::I32ReinterpretF32 => { - let v = state.pop1()?; - let space = - builder.build_alloca(intrinsics.i32_ty.as_basic_type_enum(), &state.var_name()); - let f32_space = - builder.build_pointer_cast(space, intrinsics.f32_ptr_ty, &state.var_name()); - builder.build_store(f32_space, v); - let int = builder.build_load(space, &state.var_name()); - state.push1(int); - } - Operator::I64ReinterpretF64 => { - let v = state.pop1()?; - let space = - builder.build_alloca(intrinsics.i64_ty.as_basic_type_enum(), &state.var_name()); - let f64_space = - builder.build_pointer_cast(space, intrinsics.f64_ptr_ty, &state.var_name()); - builder.build_store(f64_space, v); - let int = builder.build_load(space, &state.var_name()); - state.push1(int); - } - Operator::F32ReinterpretI32 => { - let v = state.pop1()?; - let space = - builder.build_alloca(intrinsics.f32_ty.as_basic_type_enum(), &state.var_name()); - let i32_space = - builder.build_pointer_cast(space, intrinsics.i32_ptr_ty, &state.var_name()); - builder.build_store(i32_space, v); - let f = builder.build_load(space, &state.var_name()); - state.push1(f); - } - Operator::F64ReinterpretI64 => { - let v = state.pop1()?; - let space = - builder.build_alloca(intrinsics.f64_ty.as_basic_type_enum(), &state.var_name()); - let i64_space = - builder.build_pointer_cast(space, intrinsics.i64_ptr_ty, &state.var_name()); - builder.build_store(i64_space, v); - let f = builder.build_load(space, &state.var_name()); - state.push1(f); - } - - /*************************** - * Sign-extension operators. - * https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md - ***************************/ - Operator::I32Extend8S => { - let value = state.pop1()?.into_int_value(); - let narrow_value = - builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); - let extended_value = - builder.build_int_s_extend(narrow_value, intrinsics.i32_ty, &state.var_name()); - state.push1(extended_value); - } - Operator::I32Extend16S => { - let value = state.pop1()?.into_int_value(); - let narrow_value = - builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); - let extended_value = - builder.build_int_s_extend(narrow_value, intrinsics.i32_ty, &state.var_name()); - state.push1(extended_value); - } - Operator::I64Extend8S => { - let value = state.pop1()?.into_int_value(); - let narrow_value = - builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); - let extended_value = - builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name()); - state.push1(extended_value); - } - Operator::I64Extend16S => { - let value = state.pop1()?.into_int_value(); - let narrow_value = - builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); - let extended_value = - builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name()); - state.push1(extended_value); - } - Operator::I64Extend32S => { - let value = state.pop1()?.into_int_value(); - let narrow_value = - builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); - let extended_value = - builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name()); - state.push1(extended_value); - } - - /*************************** - * Load and Store instructions. - * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#load-and-store-instructions - ***************************/ - Operator::I32Load { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i32_ptr_ty, - )?; - let result = builder.build_load(effective_address, &state.var_name()); - state.push1(result); - } - Operator::I64Load { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i64_ptr_ty, - )?; - let result = builder.build_load(effective_address, &state.var_name()); - state.push1(result); - } - Operator::F32Load { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.f32_ptr_ty, - )?; - let result = builder.build_load(effective_address, &state.var_name()); - state.push1(result); - } - Operator::F64Load { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.f64_ptr_ty, - )?; - let result = builder.build_load(effective_address, &state.var_name()); - state.push1(result); - } - - Operator::I32Store { ref memarg } => { - let value = state.pop1()?; - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i32_ptr_ty, - )?; - builder.build_store(effective_address, value); - } - Operator::I64Store { ref memarg } => { - let value = state.pop1()?; - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i64_ptr_ty, - )?; - builder.build_store(effective_address, value); - } - Operator::F32Store { ref memarg } => { - let value = state.pop1()?; - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.f32_ptr_ty, - )?; - builder.build_store(effective_address, value); - } - Operator::F64Store { ref memarg } => { - let value = state.pop1()?; - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.f64_ptr_ty, - )?; - builder.build_store(effective_address, value); - } - - Operator::I32Load8S { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i8_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - state.push1(result); - } - Operator::I32Load16S { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i16_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - state.push1(result); - } - Operator::I64Load8S { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i8_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - state.push1(result); - } - Operator::I64Load16S { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i16_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - state.push1(result); - } - Operator::I64Load32S { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i32_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - state.push1(result); - } - - Operator::I32Load8U { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i8_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - state.push1(result); - } - Operator::I32Load16U { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i16_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - state.push1(result); - } - Operator::I64Load8U { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i8_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - state.push1(result); - } - Operator::I64Load16U { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i16_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - state.push1(result); - } - Operator::I64Load32U { ref memarg } => { - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i32_ptr_ty, - )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - state.push1(result); - } - - Operator::I32Store8 { ref memarg } | Operator::I64Store8 { ref memarg } => { - let value = state.pop1()?.into_int_value(); - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i8_ptr_ty, - )?; - let narrow_value = - builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); - } - Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { - let value = state.pop1()?.into_int_value(); - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i16_ptr_ty, - )?; - let narrow_value = - builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); - } - Operator::I64Store32 { ref memarg } => { - let value = state.pop1()?.into_int_value(); - let effective_address = resolve_memory_ptr( - builder, - intrinsics, - context, - &function, - &mut state, - &mut ctx, - memarg, - intrinsics.i32_ptr_ty, - )?; - let narrow_value = - builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); - } - - Operator::MemoryGrow { reserved } => { - let memory_index = MemoryIndex::new(reserved as usize); - let func_value = 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 => intrinsics.memory_grow_dynamic_local, - MemoryType::Static => intrinsics.memory_grow_static_local, - MemoryType::SharedStatic => intrinsics.memory_grow_shared_local, - } - } - LocalOrImport::Import(import_mem_index) => { - let mem_desc = &info.imported_memories[import_mem_index].1; - match mem_desc.memory_type() { - MemoryType::Dynamic => intrinsics.memory_grow_dynamic_import, - MemoryType::Static => intrinsics.memory_grow_static_import, - MemoryType::SharedStatic => intrinsics.memory_grow_shared_import, - } - } - }; - - let memory_index_const = intrinsics - .i32_ty - .const_int(reserved as u64, false) - .as_basic_value_enum(); - let delta = state.pop1()?; - - let result = builder.build_call( - func_value, - &[ctx.basic(), memory_index_const, delta], - &state.var_name(), - ); - state.push1(result.try_as_basic_value().left().unwrap()); - } - Operator::MemorySize { reserved } => { - let memory_index = MemoryIndex::new(reserved as usize); - let func_value = 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 => intrinsics.memory_size_dynamic_local, - MemoryType::Static => intrinsics.memory_size_static_local, - MemoryType::SharedStatic => intrinsics.memory_size_shared_local, - } - } - LocalOrImport::Import(import_mem_index) => { - let mem_desc = &info.imported_memories[import_mem_index].1; - match mem_desc.memory_type() { - MemoryType::Dynamic => intrinsics.memory_size_dynamic_import, - MemoryType::Static => intrinsics.memory_size_static_import, - MemoryType::SharedStatic => intrinsics.memory_size_shared_import, - } - } - }; - - let memory_index_const = intrinsics - .i32_ty - .const_int(reserved as u64, false) - .as_basic_value_enum(); - let result = builder.build_call( - func_value, - &[ctx.basic(), memory_index_const], - &state.var_name(), - ); - state.push1(result.try_as_basic_value().left().unwrap()); - } - op @ _ => { - unimplemented!("{:?}", op); - } - } - } - - let results = state.popn_save(func_sig.returns().len())?; - - match results.as_slice() { - [] => { - builder.build_return(None); - } - [one_value] => { - builder.build_return(Some(one_value)); - } - _ => { - // 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") - } - } - - Ok(()) -} - fn trap_if_not_representatable_as_int( builder: &Builder, intrinsics: &Intrinsics, @@ -2755,7 +645,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_switch(index.into_int_value(), default_frame.br_dest(), &cases[..]); - state.popn(args.len())?; + let args_len = args.len(); + state.popn(args_len)?; state.reachable = false; } Operator::If { ty } => { diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 53ba7cd983b..1d9a030e6ce 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -1,13 +1,5 @@ #![cfg_attr(nightly, feature(unwind_attributes))] -use wasmer_runtime_core::{ - backend::{Compiler, CompilerConfig, Token}, - cache::{Artifact, Error as CacheError}, - error::CompileError, - module::ModuleInner, -}; -use wasmparser::{self, WasmDecoder}; - mod backend; mod code; mod intrinsics; @@ -16,119 +8,11 @@ mod read_info; mod state; mod trampolines; -pub struct LLVMOldCompiler { - _private: (), -} - -impl LLVMOldCompiler { - pub fn new() -> Self { - Self { _private: () } - } -} - use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen; + pub type LLVMCompiler = SimpleStreamingCompilerGen< code::LLVMModuleCodeGenerator, code::LLVMFunctionCodeGenerator, backend::LLVMBackend, code::CodegenError, >; - -impl Compiler for LLVMOldCompiler { - fn compile( - &self, - wasm: &[u8], - compiler_config: CompilerConfig, - _: Token, - ) -> Result { - validate(wasm)?; - - let (info, code_reader) = read_info::read_module(wasm, compiler_config).unwrap(); - let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap(); - - let (backend, cache_gen) = backend::LLVMBackend::new(module, intrinsics); - - Ok(ModuleInner { - runnable_module: Box::new(backend), - cache_gen: Box::new(cache_gen), - - info, - }) - } - - unsafe fn from_cache(&self, artifact: Artifact, _: Token) -> Result { - let (info, _, memory) = artifact.consume(); - let (backend, cache_gen) = - backend::LLVMBackend::from_buffer(memory).map_err(CacheError::DeserializeError)?; - - Ok(ModuleInner { - runnable_module: Box::new(backend), - cache_gen: Box::new(cache_gen), - - info, - }) - } -} - -fn validate(bytes: &[u8]) -> Result<(), CompileError> { - let mut parser = wasmparser::ValidatingParser::new( - bytes, - Some(wasmparser::ValidatingParserConfig { - operator_config: wasmparser::OperatorValidatorConfig { - enable_threads: false, - enable_reference_types: false, - enable_simd: false, - enable_bulk_memory: false, - }, - mutable_global_imports: false, - }), - ); - - loop { - let state = parser.read(); - match *state { - wasmparser::ParserState::EndWasm => break Ok(()), - wasmparser::ParserState::Error(err) => Err(CompileError::ValidationError { - msg: err.message.to_string(), - })?, - _ => {} - } - } -} - -#[test] -fn test_read_module() { - use std::mem::transmute; - use wabt::wat2wasm; - use wasmer_runtime_core::{ - backend::RunnableModule, structures::TypedIndex, types::LocalFuncIndex, vm, - }; - // let wasm = include_bytes!("../../spectests/examples/simple/simple.wasm") as &[u8]; - let wat = r#" - (module - (type $t0 (func (param i32) (result i32))) - (type $t1 (func (result i32))) - (memory 1) - (global $g0 (mut i32) (i32.const 0)) - (func $foo (type $t0) (param i32) (result i32) - get_local 0 - )) - "#; - let wasm = wat2wasm(wat).unwrap(); - - let (info, code_reader) = read_info::read_module(&wasm, Default::default()).unwrap(); - - let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap(); - - let (backend, _) = backend::LLVMBackend::new(module, intrinsics); - - let func_ptr = backend.get_func(&info, LocalFuncIndex::new(0)).unwrap(); - - println!("func_ptr: {:p}", func_ptr.as_ptr()); - - unsafe { - let func: unsafe extern "C" fn(*mut vm::Ctx, i32) -> i32 = transmute(func_ptr); - let result = func(0 as _, 42); - println!("result: {}", result); - } -} diff --git a/lib/llvm-backend/src/read_info.rs b/lib/llvm-backend/src/read_info.rs index 5ebfa5868f4..572469ce2b2 100644 --- a/lib/llvm-backend/src/read_info.rs +++ b/lib/llvm-backend/src/read_info.rs @@ -1,289 +1,5 @@ -use wasmer_runtime_core::{ - backend::{Backend, CompilerConfig}, - module::{ - DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder, - TableInitializer, - }, - structures::{Map, TypedIndex}, - types::{ - ElementType, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, - ImportedGlobalIndex, Initializer, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, - TableIndex, Type, Value, - }, - units::Pages, -}; -use wasmparser::{ - BinaryReaderError, CodeSectionReader, Data, DataKind, Element, ElementKind, Export, - ExternalKind, FuncType, Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator, - SectionCode, Type as WpType, -}; - -use hashbrown::HashMap; - -pub fn read_module( - wasm: &[u8], - compiler_config: CompilerConfig, -) -> Result<(ModuleInfo, CodeSectionReader), BinaryReaderError> { - let mut info = ModuleInfo { - memories: Map::new(), - globals: Map::new(), - tables: Map::new(), - - imported_functions: Map::new(), - imported_memories: Map::new(), - imported_tables: Map::new(), - imported_globals: Map::new(), - - exports: Default::default(), - - data_initializers: Vec::new(), - elem_initializers: Vec::new(), - - start_func: None, - - func_assoc: Map::new(), - signatures: Map::new(), - backend: Backend::LLVM, - - namespace_table: StringTable::new(), - name_table: StringTable::new(), - - em_symbol_map: compiler_config.symbol_map.clone(), - - custom_sections: HashMap::new(), - }; - - let mut reader = ModuleReader::new(wasm)?; - let mut code_reader = None; - - loop { - if reader.eof() { - return Ok((info, code_reader.unwrap())); - } - - let section = reader.read()?; - - match section.code { - SectionCode::Type => { - let type_reader = section.get_type_section_reader()?; - - for ty in type_reader { - let ty = ty?; - info.signatures.push(func_type_to_func_sig(ty)?); - } - } - SectionCode::Import => { - let import_reader = section.get_import_section_reader()?; - let mut namespace_builder = StringTableBuilder::new(); - let mut name_builder = StringTableBuilder::new(); - - for import in import_reader { - let Import { module, field, ty } = import?; - - let namespace_index = namespace_builder.register(module); - let name_index = name_builder.register(field); - let import_name = ImportName { - namespace_index, - name_index, - }; - - match ty { - ImportSectionEntryType::Function(sigindex) => { - let sigindex = SigIndex::new(sigindex as usize); - info.imported_functions.push(import_name); - info.func_assoc.push(sigindex); - } - ImportSectionEntryType::Table(table_ty) => { - assert_eq!(table_ty.element_type, WpType::AnyFunc); - let table_desc = TableDescriptor { - element: ElementType::Anyfunc, - minimum: table_ty.limits.initial, - maximum: table_ty.limits.maximum, - }; - - info.imported_tables.push((import_name, table_desc)); - } - ImportSectionEntryType::Memory(memory_ty) => { - let mem_desc = MemoryDescriptor { - minimum: Pages(memory_ty.limits.initial), - maximum: memory_ty.limits.maximum.map(|max| Pages(max)), - shared: memory_ty.shared, - }; - info.imported_memories.push((import_name, mem_desc)); - } - ImportSectionEntryType::Global(global_ty) => { - let global_desc = GlobalDescriptor { - mutable: global_ty.mutable, - ty: type_to_type(global_ty.content_type)?, - }; - info.imported_globals.push((import_name, global_desc)); - } - } - } - - info.namespace_table = namespace_builder.finish(); - info.name_table = name_builder.finish(); - } - SectionCode::Function => { - let func_decl_reader = section.get_function_section_reader()?; - - for sigindex in func_decl_reader { - let sigindex = sigindex?; - - let sigindex = SigIndex::new(sigindex as usize); - info.func_assoc.push(sigindex); - } - } - SectionCode::Table => { - let table_decl_reader = section.get_table_section_reader()?; - - for table_ty in table_decl_reader { - let table_ty = table_ty?; - - let table_desc = TableDescriptor { - element: ElementType::Anyfunc, - minimum: table_ty.limits.initial, - maximum: table_ty.limits.maximum, - }; - - info.tables.push(table_desc); - } - } - SectionCode::Memory => { - let mem_decl_reader = section.get_memory_section_reader()?; - - for memory_ty in mem_decl_reader { - let memory_ty = memory_ty?; - - let mem_desc = MemoryDescriptor { - minimum: Pages(memory_ty.limits.initial), - maximum: memory_ty.limits.maximum.map(|max| Pages(max)), - shared: memory_ty.shared, - }; - - info.memories.push(mem_desc); - } - } - SectionCode::Global => { - let global_decl_reader = section.get_global_section_reader()?; - - for global in global_decl_reader { - let global = global?; - - let desc = GlobalDescriptor { - mutable: global.ty.mutable, - ty: type_to_type(global.ty.content_type)?, - }; - - let global_init = GlobalInit { - desc, - init: eval_init_expr(&global.init_expr)?, - }; - - info.globals.push(global_init); - } - } - SectionCode::Export => { - let export_reader = section.get_export_section_reader()?; - - for export in export_reader { - let Export { field, kind, index } = export?; - - let export_index = match kind { - ExternalKind::Function => ExportIndex::Func(FuncIndex::new(index as usize)), - ExternalKind::Table => ExportIndex::Table(TableIndex::new(index as usize)), - ExternalKind::Memory => { - ExportIndex::Memory(MemoryIndex::new(index as usize)) - } - ExternalKind::Global => { - ExportIndex::Global(GlobalIndex::new(index as usize)) - } - }; - - info.exports.insert(field.to_string(), export_index); - } - } - SectionCode::Start => { - let start_index = section.get_start_section_content()?; - - info.start_func = Some(FuncIndex::new(start_index as usize)); - } - SectionCode::Element => { - let element_reader = section.get_element_section_reader()?; - - for element in element_reader { - let Element { kind, items } = element?; - - match kind { - ElementKind::Active { - table_index, - init_expr, - } => { - let table_index = TableIndex::new(table_index as usize); - let base = eval_init_expr(&init_expr)?; - let items_reader = items.get_items_reader()?; - - let elements: Vec<_> = items_reader - .into_iter() - .map(|res| res.map(|index| FuncIndex::new(index as usize))) - .collect::>()?; - - let table_init = TableInitializer { - table_index, - base, - elements, - }; - - info.elem_initializers.push(table_init); - } - ElementKind::Passive(_ty) => { - return Err(BinaryReaderError { - message: "passive tables are not yet supported", - offset: -1isize as usize, - }); - } - } - } - } - SectionCode::Code => { - code_reader = Some(section.get_code_section_reader()?); - } - SectionCode::Data => { - let data_reader = section.get_data_section_reader()?; - - for data in data_reader { - let Data { kind, data } = data?; - - match kind { - DataKind::Active { - memory_index, - init_expr, - } => { - let memory_index = MemoryIndex::new(memory_index as usize); - let base = eval_init_expr(&init_expr)?; - - let data_init = DataInitializer { - memory_index, - base, - data: data.to_vec(), - }; - - info.data_initializers.push(data_init); - } - DataKind::Passive => { - return Err(BinaryReaderError { - message: "passive memories are not yet supported", - offset: -1isize as usize, - }); - } - } - } - } - SectionCode::DataCount => {} - SectionCode::Custom { .. } => {} - } - } -} +use wasmer_runtime_core::types::Type; +use wasmparser::{BinaryReaderError, Type as WpType}; pub fn type_to_type(ty: WpType) -> Result { Ok(match ty { @@ -305,46 +21,3 @@ pub fn type_to_type(ty: WpType) -> Result { } }) } - -fn func_type_to_func_sig(func_ty: FuncType) -> Result { - assert_eq!(func_ty.form, WpType::Func); - - Ok(FuncSig::new( - func_ty - .params - .iter() - .cloned() - .map(type_to_type) - .collect::, _>>()?, - func_ty - .returns - .iter() - .cloned() - .map(type_to_type) - .collect::, _>>()?, - )) -} - -fn eval_init_expr(expr: &InitExpr) -> Result { - let mut reader = expr.get_operators_reader(); - let (op, offset) = reader.read_with_offset()?; - Ok(match op { - Operator::GetGlobal { global_index } => { - Initializer::GetGlobal(ImportedGlobalIndex::new(global_index as usize)) - } - Operator::I32Const { value } => Initializer::Const(Value::I32(value)), - Operator::I64Const { value } => Initializer::Const(Value::I64(value)), - Operator::F32Const { value } => { - Initializer::Const(Value::F32(f32::from_bits(value.bits()))) - } - Operator::F64Const { value } => { - Initializer::Const(Value::F64(f64::from_bits(value.bits()))) - } - _ => { - return Err(BinaryReaderError { - message: "init expr evaluation failed: unsupported opcode", - offset, - }); - } - }) -} From e53d5a91ca1d5ea6e2f7b9db2b122d55f0ac49bf Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 7 May 2019 19:20:18 +0800 Subject: [PATCH 13/15] Remove transmutes. --- lib/llvm-backend/src/code.rs | 150 ++++++++++++++++++----------- lib/llvm-backend/src/intrinsics.rs | 112 +++++++++++---------- 2 files changed, 150 insertions(+), 112 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8c3d89d7448..4981fd0add1 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8,6 +8,7 @@ use inkwell::{ AddressSpace, FloatPredicate, IntPredicate, }; use smallvec::SmallVec; +use std::ops::{Deref, DerefMut}; use std::sync::Arc; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, @@ -292,7 +293,7 @@ fn resolve_memory_ptr( let var_offset = builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name()); let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name()); - let memory_cache = ctx.memory(MemoryIndex::new(0)); + let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); let mem_base_int = match memory_cache { MemoryCache::Dynamic { @@ -363,25 +364,25 @@ pub struct CodegenError { } pub struct LLVMModuleCodeGenerator { - context: Context, - builder: Builder, + context: Option, + builder: Option, + intrinsics: Option, functions: Vec, signatures: Map, signatures_raw: Map, function_signatures: Option>>, func_import_count: usize, - intrinsics: Intrinsics, personality_func: FunctionValue, module: Module, } pub struct LLVMFunctionCodeGenerator { + context: Option, + builder: Option, + intrinsics: Option, state: State, - builder: &'static Builder, - context: &'static Context, function: FunctionValue, func_sig: FuncSig, - intrinsics: &'static Intrinsics, signatures: Map, locals: Vec, // Contains params and locals num_params: usize, @@ -405,21 +406,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // let (count, ty) = local?; let count = n; let wasmer_ty = type_to_type(ty)?; - let ty = type_to_llvm(self.intrinsics, wasmer_ty); + + let intrinsics = self.intrinsics.as_ref().unwrap(); + let ty = type_to_llvm(intrinsics, wasmer_ty); let default_value = match wasmer_ty { - Type::I32 => self.intrinsics.i32_zero.as_basic_value_enum(), - Type::I64 => self.intrinsics.i64_zero.as_basic_value_enum(), - Type::F32 => self.intrinsics.f32_zero.as_basic_value_enum(), - Type::F64 => self.intrinsics.f64_zero.as_basic_value_enum(), + Type::I32 => intrinsics.i32_zero.as_basic_value_enum(), + Type::I64 => intrinsics.i64_zero.as_basic_value_enum(), + Type::F32 => intrinsics.f32_zero.as_basic_value_enum(), + Type::F64 => intrinsics.f64_zero.as_basic_value_enum(), }; + let builder = self.builder.as_ref().unwrap(); + for _ in 0..count { - let alloca = self - .builder - .build_alloca(ty, &format!("local{}", param_len + local_idx)); + let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); - self.builder.build_store(alloca, default_value); + builder.build_store(alloca, default_value); self.locals.push(alloca); local_idx += 1; @@ -430,22 +433,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError> { let start_of_code_block = self .context + .as_ref() + .unwrap() .append_basic_block(&self.function, "start_of_code"); let entry_end_inst = self .builder + .as_ref() + .unwrap() .build_unconditional_branch(&start_of_code_block); - self.builder.position_at_end(&start_of_code_block); + self.builder + .as_ref() + .unwrap() + .position_at_end(&start_of_code_block); - let cache_builder = self.context.create_builder(); + let cache_builder = self.context.as_ref().unwrap().create_builder(); cache_builder.position_before(&entry_end_inst); let module_info = unsafe { ::std::mem::transmute::<&ModuleInfo, &'static ModuleInfo>(module_info) }; let function = unsafe { ::std::mem::transmute::<&FunctionValue, &'static FunctionValue>(&self.function) }; - let ctx = self - .intrinsics - .ctx(module_info, self.builder, function, cache_builder); + let ctx = CtxType::new(module_info, function, cache_builder); self.ctx = Some(ctx); Ok(()) @@ -460,10 +468,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; let mut state = &mut self.state; - let builder = self.builder; - let context = self.context; + let builder = self.builder.as_ref().unwrap(); + let context = self.context.as_ref().unwrap(); let function = self.function; - let intrinsics = self.intrinsics; + let intrinsics = self.intrinsics.as_ref().unwrap(); let locals = &self.locals; let info = module_info; let signatures = &self.signatures; @@ -868,7 +876,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::GetGlobal { global_index } => { let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index); + let global_cache = ctx.global_cache(index, intrinsics); match global_cache { GlobalCache::Const { value } => { state.push1(value); @@ -882,7 +890,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::SetGlobal { global_index } => { let value = state.pop1()?; let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index); + let global_cache = ctx.global_cache(index, intrinsics); match global_cache { GlobalCache::Mut { ptr_to_value } => { builder.build_store(ptr_to_value, value); @@ -918,12 +926,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .map(|v| *v) .collect(); - let func_ptr = ctx.local_func(local_func_index, llvm_sig); + let func_ptr = + ctx.local_func(local_func_index, llvm_sig, intrinsics, builder); builder.build_call(func_ptr, ¶ms, &state.var_name()) } LocalOrImport::Import(import_func_index) => { - let (func_ptr_untyped, ctx_ptr) = ctx.imported_func(import_func_index); + let (func_ptr_untyped, ctx_ptr) = + ctx.imported_func(import_func_index, intrinsics); let params: Vec<_> = [ctx_ptr.as_basic_value_enum()] .iter() .chain(state.peekn(func_sig.params().len())?.iter()) @@ -962,8 +972,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::CallIndirect { index, table_index } => { let sig_index = SigIndex::new(index as usize); - let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index); - let (table_base, table_bound) = ctx.table(TableIndex::new(table_index as usize)); + let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index, intrinsics); + let (table_base, table_bound) = + ctx.table(TableIndex::new(table_index as usize), intrinsics, builder); let func_index = state.pop1()?.into_int_value(); // We assume the table has the `anyfunc` element type. @@ -2404,10 +2415,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { match results.as_slice() { [] => { - self.builder.build_return(None); + self.builder.as_ref().unwrap().build_return(None); } [one_value] => { - self.builder.build_return(Some(one_value)); + self.builder.as_ref().unwrap().build_return(Some(one_value)); } _ => { // let struct_ty = llvm_sig.get_return_type().as_struct_type(); @@ -2446,15 +2457,15 @@ impl ModuleCodeGenerator let signatures = Map::new(); LLVMModuleCodeGenerator { - context, - builder, + context: Some(context), + builder: Some(builder), + intrinsics: Some(intrinsics), module, functions: vec![], signatures, signatures_raw: Map::new(), function_signatures: None, func_import_count: 0, - intrinsics, personality_func, } } @@ -2469,6 +2480,18 @@ impl ModuleCodeGenerator fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { // Creates a new function and returns the function-scope code generator for it. + let (context, builder, intrinsics) = match self.functions.last_mut() { + Some(x) => ( + x.context.take().unwrap(), + x.builder.take().unwrap(), + x.intrinsics.take().unwrap(), + ), + None => ( + self.context.take().unwrap(), + self.builder.take().unwrap(), + self.intrinsics.take().unwrap(), + ), + }; let sig_id = self.function_signatures.as_ref().unwrap() [FuncIndex::new(self.func_import_count + self.functions.len())]; @@ -2482,20 +2505,20 @@ impl ModuleCodeGenerator function.set_personality_function(self.personality_func); let mut state = State::new(); - let entry_block = self.context.append_basic_block(&function, "entry"); + let entry_block = context.append_basic_block(&function, "entry"); - let return_block = self.context.append_basic_block(&function, "return"); - self.builder.position_at_end(&return_block); + 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(&self.intrinsics, wasmer_ty)) - .map(|ty| self.builder.build_phi(ty, &state.var_name())) + .map(|&wasmer_ty| type_to_llvm(&intrinsics, wasmer_ty)) + .map(|ty| builder.build_phi(ty, &state.var_name())) .collect(); state.push_block(return_block, phis); - self.builder.position_at_end(&entry_block); + builder.position_at_end(&entry_block); let mut locals = Vec::new(); locals.extend( @@ -2506,8 +2529,8 @@ impl ModuleCodeGenerator .map(|(index, param)| { let ty = param.get_type(); - let alloca = self.builder.build_alloca(ty, &format!("local{}", index)); - self.builder.build_store(alloca, param); + let alloca = builder.build_alloca(ty, &format!("local{}", index)); + builder.build_store(alloca, param); alloca }), ); @@ -2515,16 +2538,14 @@ impl ModuleCodeGenerator let code = LLVMFunctionCodeGenerator { state, - builder: unsafe { ::std::mem::transmute::<&Builder, &'static Builder>(&self.builder) }, - context: unsafe { ::std::mem::transmute::<&Context, &'static Context>(&self.context) }, + context: Some(context), + builder: Some(builder), + intrinsics: Some(intrinsics), function, func_sig: func_sig, locals, signatures: self.signatures.clone(), num_params, - intrinsics: unsafe { - ::std::mem::transmute::<&Intrinsics, &'static Intrinsics>(&self.intrinsics) - }, ctx: None, unreachable_depth: 0, }; @@ -2533,18 +2554,33 @@ impl ModuleCodeGenerator } fn finalize( - self, + mut self, module_info: &ModuleInfo, ) -> Result<(LLVMBackend, Box), CodegenError> { // self.module.print_to_stderr(); + let (context, builder, intrinsics) = match self.functions.last_mut() { + Some(x) => ( + x.context.take().unwrap(), + x.builder.take().unwrap(), + x.intrinsics.take().unwrap(), + ), + None => ( + self.context.take().unwrap(), + self.builder.take().unwrap(), + self.intrinsics.take().unwrap(), + ), + }; + self.context = Some(context); + self.builder = Some(builder); + self.intrinsics = Some(intrinsics); generate_trampolines( module_info, &self.signatures, &self.module, - &self.context, - &self.builder, - &self.intrinsics, + self.context.as_ref().unwrap(), + self.builder.as_ref().unwrap(), + self.intrinsics.as_ref().unwrap(), ); let pass_manager = PassManager::create_for_module(); @@ -2563,14 +2599,20 @@ impl ModuleCodeGenerator // self.module.print_to_stderr(); - let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics); + let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap()); Ok((backend, Box::new(cache_gen))) } fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { self.signatures = signatures .iter() - .map(|(_, sig)| func_sig_to_llvm(&self.context, &self.intrinsics, sig)) + .map(|(_, sig)| { + func_sig_to_llvm( + self.context.as_ref().unwrap(), + self.intrinsics.as_ref().unwrap(), + sig, + ) + }) .collect(); self.signatures_raw = signatures.clone(); Ok(()) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 1b367f5d4f8..6250fd4fd44 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -369,31 +369,6 @@ impl Intrinsics { ctx_ptr_ty, } } - - pub fn ctx<'a>( - &'a self, - info: &'a ModuleInfo, - builder: &'a Builder, - func_value: &'a FunctionValue, - cache_builder: Builder, - ) -> CtxType<'a> { - CtxType { - ctx_ptr_value: func_value.get_nth_param(0).unwrap().into_pointer_value(), - - builder, - intrinsics: self, - info, - cache_builder, - - cached_memories: HashMap::new(), - cached_tables: HashMap::new(), - cached_sigindices: HashMap::new(), - cached_globals: HashMap::new(), - cached_imported_functions: HashMap::new(), - - _phantom: PhantomData, - } - } } #[derive(Clone, Copy)] @@ -429,8 +404,6 @@ struct ImportedFuncCache { pub struct CtxType<'a> { ctx_ptr_value: PointerValue, - builder: &'a Builder, - intrinsics: &'a Intrinsics, info: &'a ModuleInfo, cache_builder: Builder, @@ -444,16 +417,36 @@ pub struct CtxType<'a> { } impl<'a> CtxType<'a> { + pub fn new( + info: &'a ModuleInfo, + func_value: &'a FunctionValue, + cache_builder: Builder, + ) -> CtxType<'a> { + CtxType { + ctx_ptr_value: func_value.get_nth_param(0).unwrap().into_pointer_value(), + + info, + cache_builder, + + cached_memories: HashMap::new(), + cached_tables: HashMap::new(), + cached_sigindices: HashMap::new(), + cached_globals: HashMap::new(), + cached_imported_functions: HashMap::new(), + + _phantom: PhantomData, + } + } + pub fn basic(&self) -> BasicValueEnum { self.ctx_ptr_value.as_basic_value_enum() } - pub fn memory(&mut self, index: MemoryIndex) -> MemoryCache { - let (cached_memories, info, ctx_ptr_value, intrinsics, cache_builder) = ( + pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache { + let (cached_memories, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_memories, self.info, self.ctx_ptr_value, - self.intrinsics, &self.cache_builder, ); @@ -514,13 +507,16 @@ impl<'a> CtxType<'a> { }) } - pub fn table(&mut self, index: TableIndex) -> (PointerValue, IntValue) { - let (cached_tables, builder, info, ctx_ptr_value, intrinsics, cache_builder) = ( + pub fn table( + &mut self, + index: TableIndex, + intrinsics: &Intrinsics, + builder: &Builder, + ) -> (PointerValue, IntValue) { + let (cached_tables, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_tables, - self.builder, self.info, self.ctx_ptr_value, - self.intrinsics, &self.cache_builder, ); @@ -575,41 +571,39 @@ impl<'a> CtxType<'a> { ) } - pub fn local_func(&mut self, index: LocalFuncIndex, fn_ty: FunctionType) -> PointerValue { - let local_func_array_ptr_ptr = unsafe { - self.builder - .build_struct_gep(self.ctx_ptr_value, 8, "local_func_array_ptr_ptr") - }; - let local_func_array_ptr = self - .builder + pub fn local_func( + &mut self, + index: LocalFuncIndex, + fn_ty: FunctionType, + intrinsics: &Intrinsics, + builder: &Builder, + ) -> PointerValue { + let local_func_array_ptr_ptr = + unsafe { builder.build_struct_gep(self.ctx_ptr_value, 8, "local_func_array_ptr_ptr") }; + let local_func_array_ptr = builder .build_load(local_func_array_ptr_ptr, "local_func_array_ptr") .into_pointer_value(); let local_func_ptr_ptr = unsafe { - self.builder.build_in_bounds_gep( + builder.build_in_bounds_gep( local_func_array_ptr, - &[self - .intrinsics - .i32_ty - .const_int(index.index() as u64, false)], + &[intrinsics.i32_ty.const_int(index.index() as u64, false)], "local_func_ptr_ptr", ) }; - let local_func_ptr = self - .builder + let local_func_ptr = builder .build_load(local_func_ptr_ptr, "local_func_ptr") .into_pointer_value(); - self.builder.build_pointer_cast( + builder.build_pointer_cast( local_func_ptr, fn_ty.ptr_type(AddressSpace::Generic), "local_func_ptr", ) } - pub fn dynamic_sigindex(&mut self, index: SigIndex) -> IntValue { - let (cached_sigindices, ctx_ptr_value, intrinsics, cache_builder) = ( + pub fn dynamic_sigindex(&mut self, index: SigIndex, intrinsics: &Intrinsics) -> IntValue { + let (cached_sigindices, ctx_ptr_value, cache_builder) = ( &mut self.cached_sigindices, self.ctx_ptr_value, - self.intrinsics, &self.cache_builder, ); @@ -636,12 +630,11 @@ impl<'a> CtxType<'a> { }) } - pub fn global_cache(&mut self, index: GlobalIndex) -> GlobalCache { - let (cached_globals, ctx_ptr_value, info, intrinsics, cache_builder) = ( + pub fn global_cache(&mut self, index: GlobalIndex, intrinsics: &Intrinsics) -> GlobalCache { + let (cached_globals, ctx_ptr_value, info, cache_builder) = ( &mut self.cached_globals, self.ctx_ptr_value, self.info, - self.intrinsics, &self.cache_builder, ); @@ -712,11 +705,14 @@ impl<'a> CtxType<'a> { }) } - pub fn imported_func(&mut self, index: ImportedFuncIndex) -> (PointerValue, PointerValue) { - let (cached_imported_functions, ctx_ptr_value, intrinsics, cache_builder) = ( + pub fn imported_func( + &mut self, + index: ImportedFuncIndex, + intrinsics: &Intrinsics, + ) -> (PointerValue, PointerValue) { + let (cached_imported_functions, ctx_ptr_value, cache_builder) = ( &mut self.cached_imported_functions, self.ctx_ptr_value, - self.intrinsics, &self.cache_builder, ); From 43bf83cd09d3cea8237dd0e5c24d37acf83d5909 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 7 May 2019 22:46:04 -0500 Subject: [PATCH 14/15] Add LLVM backend parser update entry to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a367e344d..b3f8313136f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits + ## 0.4.1 - 2018-05-06 - [#426](https://github.com/wasmerio/wasmer/pull/426) Update wapm-cli submodule, bump version to 0.4.1 From 54095fcd678c302d53f897ce1a0d787dbfd4ec82 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 7 May 2019 22:53:48 -0500 Subject: [PATCH 15/15] Clean up commented out code in LLVM codegen --- lib/llvm-backend/src/code.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 4981fd0add1..028207a8c4f 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8,7 +8,6 @@ use inkwell::{ AddressSpace, FloatPredicate, IntPredicate, }; use smallvec::SmallVec; -use std::ops::{Deref, DerefMut}; use std::sync::Arc; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, @@ -2420,11 +2419,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { [one_value] => { self.builder.as_ref().unwrap().build_return(Some(one_value)); } - _ => { - // 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") - } + _ => unimplemented!("multi-value returns not yet implemented"), } Ok(()) } @@ -2557,7 +2552,6 @@ impl ModuleCodeGenerator mut self, module_info: &ModuleInfo, ) -> Result<(LLVMBackend, Box), CodegenError> { - // self.module.print_to_stderr(); let (context, builder, intrinsics) = match self.functions.last_mut() { Some(x) => ( x.context.take().unwrap(), @@ -2584,15 +2578,14 @@ impl ModuleCodeGenerator ); let pass_manager = PassManager::create_for_module(); - // pass_manager.add_verifier_pass(); + if cfg!(test) { + pass_manager.add_verifier_pass(); + } pass_manager.add_function_inlining_pass(); pass_manager.add_promote_memory_to_register_pass(); pass_manager.add_cfg_simplification_pass(); - // pass_manager.add_instruction_combining_pass(); pass_manager.add_aggressive_inst_combiner_pass(); pass_manager.add_merged_load_store_motion_pass(); - // pass_manager.add_sccp_pass(); - // pass_manager.add_gvn_pass(); pass_manager.add_new_gvn_pass(); pass_manager.add_aggressive_dce_pass(); pass_manager.run_on_module(&self.module);