Move SSA value caches to the entry block.

The supporting framework around LLVM will make sure to only compute values once if they
are known to never change. Previously, these values were attempted to be reused from places where
the users may not dominate the creation of the value. To avoid that, they are always created
in the entry block now.
This commit is contained in:
Lachlan Sneff
2019-03-03 21:13:37 -08:00
parent c07298e58e
commit 51cf9dde05
3 changed files with 99 additions and 49 deletions

View File

@ -159,18 +159,14 @@ extern "C" {
) throw() { ) throw() {
try { try {
trampoline(ctx, func, params, results); trampoline(ctx, func, params, results);
std::cout << "Success" << std::endl;
return true; return true;
} catch(const WasmTrap& e) { } catch(const WasmTrap& e) {
std::cout << e.description() << std::endl;
*trap_out = e.type; *trap_out = e.type;
return false; return false;
} catch(const WasmException& e) { } catch(const WasmException& e) {
std::cout << e.description() << std::endl;
*trap_out = WasmTrap::Type::Unknown; *trap_out = WasmTrap::Type::Unknown;
return false; return false;
} catch (...) { } catch (...) {
std::cout << "unknown" << std::endl;
*trap_out = WasmTrap::Type::Unknown; *trap_out = WasmTrap::Type::Unknown;
return false; return false;
} }

View File

@ -118,6 +118,8 @@ pub fn parse_function_bodies(
})?; })?;
} }
// module.print_to_stderr();
generate_trampolines(info, &signatures, &module, &context, &builder, &intrinsics); generate_trampolines(info, &signatures, &module, &context, &builder, &intrinsics);
let pass_manager = PassManager::create_for_module(); let pass_manager = PassManager::create_for_module();
@ -170,8 +172,6 @@ fn parse_function(
state.push_block(return_block, phis); state.push_block(return_block, phis);
builder.position_at_end(&entry_block); builder.position_at_end(&entry_block);
let mut ctx = intrinsics.ctx(info, builder, &function);
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity let mut locals = Vec::with_capacity(locals_reader.get_count() as usize); // TODO fix capacity
locals.extend( locals.extend(
@ -213,6 +213,13 @@ fn parse_function(
} }
} }
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; let mut unreachable_depth = 0;
for op in op_reader { for op in op_reader {

View File

@ -4,7 +4,10 @@ use inkwell::{
context::Context, context::Context,
module::Module, module::Module,
types::{BasicType, FloatType, IntType, PointerType, StructType, VoidType}, types::{BasicType, FloatType, IntType, PointerType, StructType, VoidType},
values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue}, values::{
BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue,
PointerValue,
},
AddressSpace, AddressSpace,
}; };
use std::marker::PhantomData; use std::marker::PhantomData;
@ -369,6 +372,7 @@ impl Intrinsics {
info: &'a ModuleInfo, info: &'a ModuleInfo,
builder: &'a Builder, builder: &'a Builder,
func_value: &'a FunctionValue, func_value: &'a FunctionValue,
cache_builder: Builder,
) -> CtxType<'a> { ) -> CtxType<'a> {
CtxType { CtxType {
ctx_ty: self.ctx_ty, ctx_ty: self.ctx_ty,
@ -379,6 +383,7 @@ impl Intrinsics {
builder, builder,
intrinsics: self, intrinsics: self,
info, info,
cache_builder,
cached_memories: HashMap::new(), cached_memories: HashMap::new(),
cached_tables: HashMap::new(), cached_tables: HashMap::new(),
@ -429,6 +434,7 @@ pub struct CtxType<'a> {
builder: &'a Builder, builder: &'a Builder,
intrinsics: &'a Intrinsics, intrinsics: &'a Intrinsics,
info: &'a ModuleInfo, info: &'a ModuleInfo,
cache_builder: Builder,
cached_memories: HashMap<MemoryIndex, MemoryCache>, cached_memories: HashMap<MemoryIndex, MemoryCache>,
cached_tables: HashMap<TableIndex, TableCache>, cached_tables: HashMap<TableIndex, TableCache>,
@ -445,43 +451,52 @@ impl<'a> CtxType<'a> {
} }
pub fn memory(&mut self, index: MemoryIndex) -> (PointerValue, IntValue) { pub fn memory(&mut self, index: MemoryIndex) -> (PointerValue, IntValue) {
let (cached_memories, builder, info, ctx_ptr_value, intrinsics) = ( let (cached_memories, builder, info, ctx_ptr_value, intrinsics, cache_builder) = (
&mut self.cached_memories, &mut self.cached_memories,
self.builder, self.builder,
self.info, self.info,
self.ctx_ptr_value, self.ctx_ptr_value,
self.intrinsics, self.intrinsics,
&self.cache_builder,
); );
let memory_cache = cached_memories.entry(index).or_insert_with(|| { let memory_cache = cached_memories.entry(index).or_insert_with(|| {
let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) { let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) {
LocalOrImport::Local(local_mem_index) => ( LocalOrImport::Local(local_mem_index) => (
unsafe { builder.build_struct_gep(ctx_ptr_value, 0, "memory_array_ptr_ptr") }, unsafe {
cache_builder.build_struct_gep(ctx_ptr_value, 0, "memory_array_ptr_ptr")
},
local_mem_index.index() as u64, local_mem_index.index() as u64,
info.memories[local_mem_index].memory_type(), info.memories[local_mem_index].memory_type(),
), ),
LocalOrImport::Import(import_mem_index) => ( LocalOrImport::Import(import_mem_index) => (
unsafe { builder.build_struct_gep(ctx_ptr_value, 3, "memory_array_ptr_ptr") }, unsafe {
cache_builder.build_struct_gep(ctx_ptr_value, 3, "memory_array_ptr_ptr")
},
import_mem_index.index() as u64, import_mem_index.index() as u64,
info.imported_memories[import_mem_index].1.memory_type(), info.imported_memories[import_mem_index].1.memory_type(),
), ),
}; };
let memory_array_ptr = builder let memory_array_ptr = cache_builder
.build_load(memory_array_ptr_ptr, "memory_array_ptr") .build_load(memory_array_ptr_ptr, "memory_array_ptr")
.into_pointer_value(); .into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index, false); let const_index = intrinsics.i32_ty.const_int(index, false);
let memory_ptr_ptr = unsafe { let memory_ptr_ptr = unsafe {
builder.build_in_bounds_gep(memory_array_ptr, &[const_index], "memory_ptr_ptr") cache_builder.build_in_bounds_gep(
memory_array_ptr,
&[const_index],
"memory_ptr_ptr",
)
}; };
let memory_ptr = builder let memory_ptr = cache_builder
.build_load(memory_ptr_ptr, "memory_ptr") .build_load(memory_ptr_ptr, "memory_ptr")
.into_pointer_value(); .into_pointer_value();
let (ptr_to_base_ptr, ptr_to_bounds) = unsafe { let (ptr_to_base_ptr, ptr_to_bounds) = unsafe {
( (
builder.build_struct_gep(memory_ptr, 0, "base_ptr"), cache_builder.build_struct_gep(memory_ptr, 0, "base_ptr"),
builder.build_struct_gep(memory_ptr, 1, "bounds_ptr"), cache_builder.build_struct_gep(memory_ptr, 1, "bounds_ptr"),
) )
}; };
@ -491,10 +506,12 @@ impl<'a> CtxType<'a> {
ptr_to_bounds, ptr_to_bounds,
}, },
MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static { MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static {
base_ptr: builder base_ptr: cache_builder
.build_load(ptr_to_base_ptr, "base") .build_load(ptr_to_base_ptr, "base")
.into_pointer_value(), .into_pointer_value(),
bounds: builder.build_load(ptr_to_bounds, "bounds").into_int_value(), bounds: cache_builder
.build_load(ptr_to_bounds, "bounds")
.into_int_value(),
}, },
} }
}); });
@ -518,12 +535,13 @@ impl<'a> CtxType<'a> {
} }
pub fn table(&mut self, index: TableIndex) -> (PointerValue, IntValue) { pub fn table(&mut self, index: TableIndex) -> (PointerValue, IntValue) {
let (cached_tables, builder, info, ctx_ptr_value, intrinsics) = ( let (cached_tables, builder, info, ctx_ptr_value, intrinsics, cache_builder) = (
&mut self.cached_tables, &mut self.cached_tables,
self.builder, self.builder,
self.info, self.info,
self.ctx_ptr_value, self.ctx_ptr_value,
self.intrinsics, self.intrinsics,
&self.cache_builder,
); );
let TableCache { let TableCache {
@ -532,30 +550,34 @@ impl<'a> CtxType<'a> {
} = *cached_tables.entry(index).or_insert_with(|| { } = *cached_tables.entry(index).or_insert_with(|| {
let (table_array_ptr_ptr, index) = match index.local_or_import(info) { let (table_array_ptr_ptr, index) = match index.local_or_import(info) {
LocalOrImport::Local(local_table_index) => ( LocalOrImport::Local(local_table_index) => (
unsafe { builder.build_struct_gep(ctx_ptr_value, 1, "table_array_ptr_ptr") }, unsafe {
cache_builder.build_struct_gep(ctx_ptr_value, 1, "table_array_ptr_ptr")
},
local_table_index.index() as u64, local_table_index.index() as u64,
), ),
LocalOrImport::Import(import_table_index) => ( LocalOrImport::Import(import_table_index) => (
unsafe { builder.build_struct_gep(ctx_ptr_value, 4, "table_array_ptr_ptr") }, unsafe {
cache_builder.build_struct_gep(ctx_ptr_value, 4, "table_array_ptr_ptr")
},
import_table_index.index() as u64, import_table_index.index() as u64,
), ),
}; };
let table_array_ptr = builder let table_array_ptr = cache_builder
.build_load(table_array_ptr_ptr, "table_array_ptr") .build_load(table_array_ptr_ptr, "table_array_ptr")
.into_pointer_value(); .into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index, false); let const_index = intrinsics.i32_ty.const_int(index, false);
let table_ptr_ptr = unsafe { let table_ptr_ptr = unsafe {
builder.build_in_bounds_gep(table_array_ptr, &[const_index], "table_ptr_ptr") cache_builder.build_in_bounds_gep(table_array_ptr, &[const_index], "table_ptr_ptr")
}; };
let table_ptr = builder let table_ptr = cache_builder
.build_load(table_ptr_ptr, "table_ptr") .build_load(table_ptr_ptr, "table_ptr")
.into_pointer_value(); .into_pointer_value();
let (ptr_to_base_ptr, ptr_to_bounds) = unsafe { let (ptr_to_base_ptr, ptr_to_bounds) = unsafe {
( (
builder.build_struct_gep(table_ptr, 0, "base_ptr"), cache_builder.build_struct_gep(table_ptr, 0, "base_ptr"),
builder.build_struct_gep(table_ptr, 1, "bounds_ptr"), cache_builder.build_struct_gep(table_ptr, 1, "bounds_ptr"),
) )
}; };
@ -574,39 +596,46 @@ impl<'a> CtxType<'a> {
} }
pub fn dynamic_sigindex(&mut self, index: SigIndex) -> IntValue { pub fn dynamic_sigindex(&mut self, index: SigIndex) -> IntValue {
let (cached_sigindices, builder, info, ctx_ptr_value, intrinsics) = ( let (cached_sigindices, builder, info, ctx_ptr_value, intrinsics, cache_builder) = (
&mut self.cached_sigindices, &mut self.cached_sigindices,
self.builder, self.builder,
self.info, self.info,
self.ctx_ptr_value, self.ctx_ptr_value,
self.intrinsics, self.intrinsics,
&self.cache_builder,
); );
*cached_sigindices.entry(index).or_insert_with(|| { *cached_sigindices.entry(index).or_insert_with(|| {
let sigindex_array_ptr_ptr = let sigindex_array_ptr_ptr = unsafe {
unsafe { builder.build_struct_gep(ctx_ptr_value, 7, "sigindex_array_ptr_ptr") }; cache_builder.build_struct_gep(ctx_ptr_value, 7, "sigindex_array_ptr_ptr")
let sigindex_array_ptr = builder };
let sigindex_array_ptr = cache_builder
.build_load(sigindex_array_ptr_ptr, "sigindex_array_ptr") .build_load(sigindex_array_ptr_ptr, "sigindex_array_ptr")
.into_pointer_value(); .into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false); let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false);
let sigindex_ptr = unsafe { let sigindex_ptr = unsafe {
builder.build_in_bounds_gep(sigindex_array_ptr, &[const_index], "sigindex_ptr") cache_builder.build_in_bounds_gep(
sigindex_array_ptr,
&[const_index],
"sigindex_ptr",
)
}; };
builder cache_builder
.build_load(sigindex_ptr, "sigindex") .build_load(sigindex_ptr, "sigindex")
.into_int_value() .into_int_value()
}) })
} }
pub fn global_cache(&mut self, index: GlobalIndex) -> GlobalCache { pub fn global_cache(&mut self, index: GlobalIndex) -> GlobalCache {
let (cached_globals, builder, ctx_ptr_value, info, intrinsics) = ( let (cached_globals, builder, ctx_ptr_value, info, intrinsics, cache_builder) = (
&mut self.cached_globals, &mut self.cached_globals,
self.builder, self.builder,
self.ctx_ptr_value, self.ctx_ptr_value,
self.info, self.info,
self.intrinsics, self.intrinsics,
&self.cache_builder,
); );
*cached_globals.entry(index).or_insert_with(|| { *cached_globals.entry(index).or_insert_with(|| {
@ -616,7 +645,11 @@ impl<'a> CtxType<'a> {
let desc = info.globals[local_global_index].desc; let desc = info.globals[local_global_index].desc;
( (
unsafe { unsafe {
builder.build_struct_gep(ctx_ptr_value, 2, "globals_array_ptr_ptr") cache_builder.build_struct_gep(
ctx_ptr_value,
2,
"globals_array_ptr_ptr",
)
}, },
local_global_index.index() as u64, local_global_index.index() as u64,
desc.mutable, desc.mutable,
@ -627,7 +660,11 @@ impl<'a> CtxType<'a> {
let desc = info.imported_globals[import_global_index].1; let desc = info.imported_globals[import_global_index].1;
( (
unsafe { unsafe {
builder.build_struct_gep(ctx_ptr_value, 5, "globals_array_ptr_ptr") cache_builder.build_struct_gep(
ctx_ptr_value,
5,
"globals_array_ptr_ptr",
)
}, },
import_global_index.index() as u64, import_global_index.index() as u64,
desc.mutable, desc.mutable,
@ -638,20 +675,25 @@ impl<'a> CtxType<'a> {
let llvm_ptr_ty = type_to_llvm_ptr(intrinsics, wasmer_ty); let llvm_ptr_ty = type_to_llvm_ptr(intrinsics, wasmer_ty);
let global_array_ptr = builder let global_array_ptr = cache_builder
.build_load(globals_array_ptr_ptr, "global_array_ptr") .build_load(globals_array_ptr_ptr, "global_array_ptr")
.into_pointer_value(); .into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index, false); let const_index = intrinsics.i32_ty.const_int(index, false);
let global_ptr_ptr = unsafe { let global_ptr_ptr = unsafe {
builder.build_in_bounds_gep(global_array_ptr, &[const_index], "global_ptr_ptr") cache_builder.build_in_bounds_gep(
global_array_ptr,
&[const_index],
"global_ptr_ptr",
)
}; };
let global_ptr = builder let global_ptr = cache_builder
.build_load(global_ptr_ptr, "global_ptr") .build_load(global_ptr_ptr, "global_ptr")
.into_pointer_value(); .into_pointer_value();
let global_ptr_typed = { let global_ptr_typed = {
let int = builder.build_ptr_to_int(global_ptr, intrinsics.i64_ty, "global_ptr_int"); let int =
builder.build_int_to_ptr(int, llvm_ptr_ty, "global_ptr_typed") cache_builder.build_ptr_to_int(global_ptr, intrinsics.i64_ty, "global_ptr_int");
cache_builder.build_int_to_ptr(int, llvm_ptr_ty, "global_ptr_typed")
}; };
if mutable { if mutable {
@ -660,7 +702,7 @@ impl<'a> CtxType<'a> {
} }
} else { } else {
GlobalCache::Const { GlobalCache::Const {
value: builder value: cache_builder
.build_load(global_ptr_typed, "global_value") .build_load(global_ptr_typed, "global_value")
.into_int_value(), .into_int_value(),
} }
@ -669,38 +711,43 @@ impl<'a> CtxType<'a> {
} }
pub fn imported_func(&mut self, index: ImportedFuncIndex) -> (PointerValue, PointerValue) { pub fn imported_func(&mut self, index: ImportedFuncIndex) -> (PointerValue, PointerValue) {
let (cached_imported_functions, builder, ctx_ptr_value, intrinsics) = ( let (cached_imported_functions, builder, ctx_ptr_value, intrinsics, cache_builder) = (
&mut self.cached_imported_functions, &mut self.cached_imported_functions,
self.builder, self.builder,
self.ctx_ptr_value, self.ctx_ptr_value,
self.intrinsics, self.intrinsics,
&self.cache_builder,
); );
let imported_func_cache = cached_imported_functions.entry(index).or_insert_with(|| { let imported_func_cache = cached_imported_functions.entry(index).or_insert_with(|| {
let func_array_ptr_ptr = unsafe { let func_array_ptr_ptr = unsafe {
builder.build_struct_gep(ctx_ptr_value, 6, "imported_func_array_ptr_ptr") cache_builder.build_struct_gep(ctx_ptr_value, 6, "imported_func_array_ptr_ptr")
}; };
let func_array_ptr = builder let func_array_ptr = cache_builder
.build_load(func_array_ptr_ptr, "func_array_ptr") .build_load(func_array_ptr_ptr, "func_array_ptr")
.into_pointer_value(); .into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false); let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false);
let imported_func_ptr_ptr = unsafe { let imported_func_ptr_ptr = unsafe {
builder.build_in_bounds_gep(func_array_ptr, &[const_index], "imported_func_ptr_ptr") cache_builder.build_in_bounds_gep(
func_array_ptr,
&[const_index],
"imported_func_ptr_ptr",
)
}; };
let imported_func_ptr = builder let imported_func_ptr = cache_builder
.build_load(imported_func_ptr_ptr, "imported_func_ptr") .build_load(imported_func_ptr_ptr, "imported_func_ptr")
.into_pointer_value(); .into_pointer_value();
let (func_ptr_ptr, ctx_ptr_ptr) = unsafe { let (func_ptr_ptr, ctx_ptr_ptr) = unsafe {
( (
builder.build_struct_gep(imported_func_ptr, 0, "func_ptr_ptr"), cache_builder.build_struct_gep(imported_func_ptr, 0, "func_ptr_ptr"),
builder.build_struct_gep(imported_func_ptr, 1, "ctx_ptr_ptr"), cache_builder.build_struct_gep(imported_func_ptr, 1, "ctx_ptr_ptr"),
) )
}; };
let func_ptr = builder let func_ptr = cache_builder
.build_load(func_ptr_ptr, "func_ptr") .build_load(func_ptr_ptr, "func_ptr")
.into_pointer_value(); .into_pointer_value();
let ctx_ptr = builder let ctx_ptr = cache_builder
.build_load(ctx_ptr_ptr, "ctx_ptr") .build_load(ctx_ptr_ptr, "ctx_ptr")
.into_pointer_value(); .into_pointer_value();