Make abi a trait.

This commit is contained in:
Nick Lewycky
2020-10-20 12:53:09 -07:00
parent b04b4b03c7
commit fa8e423404
4 changed files with 838 additions and 757 deletions

View File

@@ -1,9 +1,6 @@
use crate::config::{CompiledKind, LLVM};
use crate::object_file::{load_object_file, CompiledFunction};
use crate::translator::abi::{
func_type_to_llvm, get_vmctx_ptr_param, is_sret, pack_values_for_register_return,
rets_from_call,
};
use crate::translator::abi::{Abi, X86_64SystemV};
use crate::translator::intrinsics::{type_to_llvm, type_to_llvm_ptr, Intrinsics};
use inkwell::{
attributes::{Attribute, AttributeLoc},
@@ -23,6 +20,7 @@ use wasmer_types::{FunctionType, LocalFunctionIndex};
pub struct FuncTrampoline {
ctx: Context,
target_machine: TargetMachine,
abi: Box<dyn Abi>,
}
const FUNCTION_SECTION: &str = "__TEXT,wasmer_trmpl"; // Needs to be between 1 and 16 chars
@@ -32,6 +30,7 @@ impl FuncTrampoline {
Self {
ctx: Context::create(),
target_machine,
abi: Box::new(X86_64SystemV {}),
}
}
@@ -50,7 +49,7 @@ impl FuncTrampoline {
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
let intrinsics = Intrinsics::declare(&module, &self.ctx);
let (callee_ty, callee_attrs) = func_type_to_llvm(&self.ctx, &intrinsics, ty)?;
let (callee_ty, callee_attrs) = self.abi.func_type_to_llvm(&self.ctx, &intrinsics, ty)?;
let trampoline_ty = intrinsics.void_ty.fn_type(
&[
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // vmctx ptr
@@ -72,7 +71,7 @@ impl FuncTrampoline {
trampoline_func
.as_global_value()
.set_dll_storage_class(DLLStorageClass::Export);
generate_trampoline(trampoline_func, ty, &callee_attrs, &self.ctx, &intrinsics)?;
self.generate_trampoline(trampoline_func, ty, &callee_attrs, &self.ctx, &intrinsics)?;
if let Some(ref callbacks) = config.callbacks {
callbacks.preopt_ir(&function, &module);
@@ -180,7 +179,8 @@ impl FuncTrampoline {
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
let intrinsics = Intrinsics::declare(&module, &self.ctx);
let (trampoline_ty, trampoline_attrs) = func_type_to_llvm(&self.ctx, &intrinsics, ty)?;
let (trampoline_ty, trampoline_attrs) =
self.abi.func_type_to_llvm(&self.ctx, &intrinsics, ty)?;
let trampoline_func = module.add_function(name, trampoline_ty, Some(Linkage::External));
for (attr, attr_loc) in trampoline_attrs {
trampoline_func.add_attribute(attr_loc, attr);
@@ -194,7 +194,7 @@ impl FuncTrampoline {
trampoline_func
.as_global_value()
.set_dll_storage_class(DLLStorageClass::Export);
generate_dynamic_trampoline(trampoline_func, ty, &self.ctx, &intrinsics)?;
self.generate_dynamic_trampoline(trampoline_func, ty, &self.ctx, &intrinsics)?;
if let Some(ref callbacks) = config.callbacks {
callbacks.preopt_ir(&function, &module);
@@ -286,225 +286,231 @@ impl FuncTrampoline {
unwind_info: compiled_function.body.unwind_info,
})
}
}
fn generate_trampoline<'ctx>(
trampoline_func: FunctionValue,
func_sig: &FunctionType,
func_attrs: &[(Attribute, AttributeLoc)],
context: &'ctx Context,
intrinsics: &Intrinsics<'ctx>,
) -> Result<(), CompileError> {
let entry_block = context.append_basic_block(trampoline_func, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_block);
fn generate_trampoline<'ctx>(
&self,
trampoline_func: FunctionValue,
func_sig: &FunctionType,
func_attrs: &[(Attribute, AttributeLoc)],
context: &'ctx Context,
intrinsics: &Intrinsics<'ctx>,
) -> Result<(), CompileError> {
let entry_block = context.append_basic_block(trampoline_func, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_block);
/*
// TODO: remove debugging
builder.build_call(
intrinsics.debug_trap,
&[],
"");
*/
/*
// TODO: remove debugging
builder.build_call(
intrinsics.debug_trap,
&[],
"");
*/
let (callee_vmctx_ptr, func_ptr, args_rets_ptr) = match *trampoline_func.get_params().as_slice()
{
[callee_vmctx_ptr, func_ptr, args_rets_ptr] => (
callee_vmctx_ptr,
func_ptr.into_pointer_value(),
args_rets_ptr.into_pointer_value(),
),
_ => {
return Err(CompileError::Codegen(
"trampoline function unimplemented".to_string(),
))
let (callee_vmctx_ptr, func_ptr, args_rets_ptr) =
match *trampoline_func.get_params().as_slice() {
[callee_vmctx_ptr, func_ptr, args_rets_ptr] => (
callee_vmctx_ptr,
func_ptr.into_pointer_value(),
args_rets_ptr.into_pointer_value(),
),
_ => {
return Err(CompileError::Codegen(
"trampoline function unimplemented".to_string(),
))
}
};
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
if self.abi.is_sret(func_sig)? {
let basic_types: Vec<_> = func_sig
.results()
.iter()
.map(|&ty| type_to_llvm(intrinsics, ty))
.collect::<Result<_, _>>()?;
let sret_ty = context.struct_type(&basic_types, false);
args_vec.push(builder.build_alloca(sret_ty, "sret").into());
}
};
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
args_vec.push(callee_vmctx_ptr);
if is_sret(func_sig)? {
let basic_types: Vec<_> = func_sig
.results()
.iter()
.map(|&ty| type_to_llvm(intrinsics, ty))
.collect::<Result<_, _>>()?;
for (i, param_ty) in func_sig.params().iter().enumerate() {
let index = intrinsics.i32_ty.const_int(i as _, false);
let item_pointer =
unsafe { builder.build_in_bounds_gep(args_rets_ptr, &[index], "arg_ptr") };
let sret_ty = context.struct_type(&basic_types, false);
args_vec.push(builder.build_alloca(sret_ty, "sret").into());
}
let casted_pointer_type = type_to_llvm_ptr(intrinsics, *param_ty)?;
args_vec.push(callee_vmctx_ptr);
let typed_item_pointer =
builder.build_pointer_cast(item_pointer, casted_pointer_type, "typed_arg_pointer");
for (i, param_ty) in func_sig.params().iter().enumerate() {
let index = intrinsics.i32_ty.const_int(i as _, false);
let item_pointer =
unsafe { builder.build_in_bounds_gep(args_rets_ptr, &[index], "arg_ptr") };
let casted_pointer_type = type_to_llvm_ptr(intrinsics, *param_ty)?;
let typed_item_pointer =
builder.build_pointer_cast(item_pointer, casted_pointer_type, "typed_arg_pointer");
let arg = builder.build_load(typed_item_pointer, "arg");
args_vec.push(arg);
}
let call_site = builder.build_call(func_ptr, &args_vec, "call");
for (attr, attr_loc) in func_attrs {
call_site.add_attribute(*attr_loc, *attr);
}
let rets = rets_from_call(&builder, intrinsics, call_site, func_sig);
let mut idx = 0;
rets.iter().for_each(|v| {
let ptr = unsafe {
builder.build_gep(
args_rets_ptr,
&[intrinsics.i32_ty.const_int(idx, false)],
"",
)
};
let ptr = builder.build_pointer_cast(ptr, v.get_type().ptr_type(AddressSpace::Generic), "");
builder.build_store(ptr, *v);
if v.get_type() == intrinsics.i128_ty.as_basic_type_enum() {
idx += 1;
let arg = builder.build_load(typed_item_pointer, "arg");
args_vec.push(arg);
}
idx += 1;
});
builder.build_return(None);
Ok(())
}
let call_site = builder.build_call(func_ptr, &args_vec, "call");
for (attr, attr_loc) in func_attrs {
call_site.add_attribute(*attr_loc, *attr);
}
fn generate_dynamic_trampoline<'ctx>(
trampoline_func: FunctionValue,
func_sig: &FunctionType,
context: &'ctx Context,
intrinsics: &Intrinsics<'ctx>,
) -> Result<(), CompileError> {
let entry_block = context.append_basic_block(trampoline_func, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_block);
// Allocate stack space for the params and results.
let values = builder.build_alloca(
intrinsics.i128_ty.array_type(cmp::max(
func_sig.params().len().try_into().unwrap(),
func_sig.results().len().try_into().unwrap(),
)),
"",
);
// Copy params to 'values'.
let first_user_param = if is_sret(func_sig)? { 2 } else { 1 };
for i in 0..func_sig.params().len() {
let ptr = unsafe {
builder.build_in_bounds_gep(
values,
&[
intrinsics.i32_zero,
intrinsics.i32_ty.const_int(i.try_into().unwrap(), false),
],
"",
)
};
let ptr = builder
.build_bitcast(ptr, type_to_llvm_ptr(intrinsics, func_sig.params()[i])?, "")
.into_pointer_value();
builder.build_store(
ptr,
trampoline_func
.get_nth_param(i as u32 + first_user_param)
.unwrap(),
);
}
let callee_ty = intrinsics
.void_ty
.fn_type(
&[
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // vmctx ptr
intrinsics.i128_ptr_ty.as_basic_type_enum(), // in/out values ptr
],
false,
)
.ptr_type(AddressSpace::Generic);
let vmctx = get_vmctx_ptr_param(&trampoline_func);
let callee = builder
.build_load(
builder
.build_bitcast(vmctx, callee_ty.ptr_type(AddressSpace::Generic), "")
.into_pointer_value(),
"",
)
.into_pointer_value();
let values_ptr = builder.build_pointer_cast(values, intrinsics.i128_ptr_ty, "");
builder.build_call(
callee,
&[
vmctx.as_basic_value_enum(),
values_ptr.as_basic_value_enum(),
],
"",
);
if func_sig.results().is_empty() {
builder.build_return(None);
} else {
let results = func_sig
.results()
.iter()
.enumerate()
.map(|(idx, ty)| {
let ptr = unsafe {
builder.build_gep(
values,
&[
intrinsics.i32_ty.const_zero(),
intrinsics.i32_ty.const_int(idx.try_into().unwrap(), false),
],
"",
)
};
let ptr = builder.build_pointer_cast(ptr, type_to_llvm_ptr(intrinsics, *ty)?, "");
Ok(builder.build_load(ptr, ""))
})
.collect::<Result<Vec<_>, CompileError>>()?;
if is_sret(func_sig)? {
let sret = trampoline_func
.get_first_param()
.unwrap()
.into_pointer_value();
let mut struct_value = sret
.get_type()
.get_element_type()
.into_struct_type()
.get_undef();
for (idx, value) in results.iter().enumerate() {
let value = builder.build_bitcast(
*value,
type_to_llvm(&intrinsics, func_sig.results()[idx])?,
let rets = self
.abi
.rets_from_call(&builder, intrinsics, call_site, func_sig);
let mut idx = 0;
rets.iter().for_each(|v| {
let ptr = unsafe {
builder.build_gep(
args_rets_ptr,
&[intrinsics.i32_ty.const_int(idx, false)],
"",
);
struct_value = builder
.build_insert_value(struct_value, value, idx as u32, "")
.unwrap()
.into_struct_value();
)
};
let ptr =
builder.build_pointer_cast(ptr, v.get_type().ptr_type(AddressSpace::Generic), "");
builder.build_store(ptr, *v);
if v.get_type() == intrinsics.i128_ty.as_basic_type_enum() {
idx += 1;
}
builder.build_store(sret, struct_value);
idx += 1;
});
builder.build_return(None);
Ok(())
}
fn generate_dynamic_trampoline<'ctx>(
&self,
trampoline_func: FunctionValue,
func_sig: &FunctionType,
context: &'ctx Context,
intrinsics: &Intrinsics<'ctx>,
) -> Result<(), CompileError> {
let entry_block = context.append_basic_block(trampoline_func, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_block);
// Allocate stack space for the params and results.
let values = builder.build_alloca(
intrinsics.i128_ty.array_type(cmp::max(
func_sig.params().len().try_into().unwrap(),
func_sig.results().len().try_into().unwrap(),
)),
"",
);
// Copy params to 'values'.
let first_user_param = if self.abi.is_sret(func_sig)? { 2 } else { 1 };
for i in 0..func_sig.params().len() {
let ptr = unsafe {
builder.build_in_bounds_gep(
values,
&[
intrinsics.i32_zero,
intrinsics.i32_ty.const_int(i.try_into().unwrap(), false),
],
"",
)
};
let ptr = builder
.build_bitcast(ptr, type_to_llvm_ptr(intrinsics, func_sig.params()[i])?, "")
.into_pointer_value();
builder.build_store(
ptr,
trampoline_func
.get_nth_param(i as u32 + first_user_param)
.unwrap(),
);
}
let callee_ty = intrinsics
.void_ty
.fn_type(
&[
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // vmctx ptr
intrinsics.i128_ptr_ty.as_basic_type_enum(), // in/out values ptr
],
false,
)
.ptr_type(AddressSpace::Generic);
let vmctx = self.abi.get_vmctx_ptr_param(&trampoline_func);
let callee = builder
.build_load(
builder
.build_bitcast(vmctx, callee_ty.ptr_type(AddressSpace::Generic), "")
.into_pointer_value(),
"",
)
.into_pointer_value();
let values_ptr = builder.build_pointer_cast(values, intrinsics.i128_ptr_ty, "");
builder.build_call(
callee,
&[
vmctx.as_basic_value_enum(),
values_ptr.as_basic_value_enum(),
],
"",
);
if func_sig.results().is_empty() {
builder.build_return(None);
} else {
builder.build_return(Some(&pack_values_for_register_return(
&intrinsics,
&builder,
&results.as_slice(),
&trampoline_func.get_type(),
)?));
}
}
let results = func_sig
.results()
.iter()
.enumerate()
.map(|(idx, ty)| {
let ptr = unsafe {
builder.build_gep(
values,
&[
intrinsics.i32_ty.const_zero(),
intrinsics.i32_ty.const_int(idx.try_into().unwrap(), false),
],
"",
)
};
let ptr =
builder.build_pointer_cast(ptr, type_to_llvm_ptr(intrinsics, *ty)?, "");
Ok(builder.build_load(ptr, ""))
})
.collect::<Result<Vec<_>, CompileError>>()?;
Ok(())
if self.abi.is_sret(func_sig)? {
let sret = trampoline_func
.get_first_param()
.unwrap()
.into_pointer_value();
let mut struct_value = sret
.get_type()
.get_element_type()
.into_struct_type()
.get_undef();
for (idx, value) in results.iter().enumerate() {
let value = builder.build_bitcast(
*value,
type_to_llvm(&intrinsics, func_sig.results()[idx])?,
"",
);
struct_value = builder
.build_insert_value(struct_value, value, idx as u32, "")
.unwrap()
.into_struct_value();
}
builder.build_store(sret, struct_value);
builder.build_return(None);
} else {
builder.build_return(Some(&self.abi.pack_values_for_register_return(
&intrinsics,
&builder,
&results.as_slice(),
&trampoline_func.get_type(),
)?));
}
}
Ok(())
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
use super::{
abi,
abi::{Abi, X86_64SystemV},
intrinsics::{
tbaa_label, type_to_llvm, CtxType, FunctionCache, GlobalCache, Intrinsics, MemoryCache,
},
@@ -57,6 +57,7 @@ fn const_zero(ty: BasicTypeEnum) -> BasicValueEnum {
pub struct FuncTranslator {
ctx: Context,
target_machine: TargetMachine,
abi: Box<dyn Abi>,
}
impl FuncTranslator {
@@ -64,6 +65,7 @@ impl FuncTranslator {
Self {
ctx: Context::create(),
target_machine,
abi: Box::new(X86_64SystemV {}),
}
}
@@ -99,7 +101,9 @@ impl FuncTranslator {
.unwrap();
let intrinsics = Intrinsics::declare(&module, &self.ctx);
let (func_type, func_attrs) = abi::func_type_to_llvm(&self.ctx, &intrinsics, wasm_fn_type)?;
let (func_type, func_attrs) =
self.abi
.func_type_to_llvm(&self.ctx, &intrinsics, wasm_fn_type)?;
let func = module.add_function(&function_name, func_type, Some(Linkage::External));
for (attr, attr_loc) in &func_attrs {
@@ -203,7 +207,7 @@ impl FuncTranslator {
state,
function: func,
locals: params_locals,
ctx: CtxType::new(wasm_module, &func, &cache_builder),
ctx: CtxType::new(wasm_module, &func, &cache_builder, &self.abi),
unreachable_depth: 0,
memory_styles,
_table_styles,
@@ -211,6 +215,7 @@ impl FuncTranslator {
module_translation,
wasm_module,
symbol_registry,
abi: &self.abi,
};
fcg.ctx.add_func(
func_index,
@@ -1171,7 +1176,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
.map(|(v, i)| self.apply_pending_canonicalization(v, i));
if wasm_fn_type.results().is_empty() {
self.builder.build_return(None);
} else if abi::is_sret(wasm_fn_type)? {
} else if self.abi.is_sret(wasm_fn_type)? {
let sret = self
.function
.get_first_param()
@@ -1198,7 +1203,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
self.builder.build_return(None);
} else {
self.builder
.build_return(Some(&abi::pack_values_for_register_return(
.build_return(Some(&self.abi.pack_values_for_register_return(
&self.intrinsics,
&self.builder,
&results.collect::<Vec<_>>(),
@@ -1318,6 +1323,7 @@ pub struct LLVMFunctionCodeGenerator<'ctx, 'a> {
module_translation: &'a ModuleTranslationState,
wasm_module: &'a ModuleInfo,
symbol_registry: &'a dyn SymbolRegistry,
abi: &'a Box<dyn Abi>,
}
impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
@@ -2138,7 +2144,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
_ => *v,
});
let params = abi::args_to_call(
let params = self.abi.args_to_call(
&self.alloca_builder,
func_type,
callee_vmctx.into_pointer_value(),
@@ -2186,7 +2192,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
}
*/
abi::rets_from_call(&self.builder, &self.intrinsics, call_site, func_type)
self.abi
.rets_from_call(&self.builder, &self.intrinsics, call_site, func_type)
.iter()
.for_each(|ret| self.state.push1(*ret));
}
@@ -2357,7 +2364,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
self.builder.position_at_end(continue_block);
let (llvm_func_type, llvm_func_attrs) =
abi::func_type_to_llvm(&self.context, &self.intrinsics, func_type)?;
self.abi
.func_type_to_llvm(&self.context, &self.intrinsics, func_type)?;
let params = self.state.popn_save_extra(func_type.params().len())?;
@@ -2381,7 +2389,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
_ => *v,
});
let params = abi::args_to_call(
let params = self.abi.args_to_call(
&self.alloca_builder,
func_type,
ctx_ptr.into_pointer_value(),
@@ -2436,7 +2444,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
}
*/
abi::rets_from_call(&self.builder, &self.intrinsics, call_site, func_type)
self.abi
.rets_from_call(&self.builder, &self.intrinsics, call_site, func_type)
.iter()
.for_each(|ret| self.state.push1(*ret));
}

View File

@@ -4,7 +4,7 @@
//!
//! [llvm-intrinsics]: https://llvm.org/docs/LangRef.html#intrinsic-functions
use super::abi;
use super::abi::Abi;
use inkwell::{
attributes::{Attribute, AttributeLoc},
builder::Builder,
@@ -536,6 +536,7 @@ pub struct CtxType<'ctx, 'a> {
wasm_module: &'a WasmerCompilerModule,
cache_builder: &'a Builder<'ctx>,
abi: &'a Box<dyn Abi>,
cached_memories: HashMap<MemoryIndex, MemoryCache<'ctx>>,
cached_tables: HashMap<TableIndex, TableCache<'ctx>>,
@@ -553,12 +554,14 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> {
wasm_module: &'a WasmerCompilerModule,
func_value: &FunctionValue<'ctx>,
cache_builder: &'a Builder<'ctx>,
abi: &'a Box<dyn Abi>,
) -> CtxType<'ctx, 'a> {
CtxType {
ctx_ptr_value: abi::get_vmctx_ptr_param(func_value),
ctx_ptr_value: abi.get_vmctx_ptr_param(func_value),
wasm_module,
cache_builder,
abi,
cached_memories: HashMap::new(),
cached_tables: HashMap::new(),
@@ -937,7 +940,7 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> {
Entry::Vacant(entry) => {
debug_assert!(module.get_function(function_name).is_none());
let (llvm_func_type, llvm_func_attrs) =
abi::func_type_to_llvm(context, intrinsics, func_type)?;
self.abi.func_type_to_llvm(context, intrinsics, func_type)?;
let func =
module.add_function(function_name, llvm_func_type, Some(Linkage::External));
for (attr, attr_loc) in &llvm_func_attrs {
@@ -970,7 +973,7 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
let (llvm_func_type, llvm_func_attrs) =
abi::func_type_to_llvm(context, intrinsics, func_type)?;
self.abi.func_type_to_llvm(context, intrinsics, func_type)?;
debug_assert!(wasm_module.local_func_index(function_index).is_none());
let offset = offsets.vmctx_vmfunction_import(function_index);
let offset = intrinsics.i32_ty.const_int(offset.into(), false);