mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 14:25:32 +00:00
Unary operators, comparison opcodes, loops, etc.
This commit is contained in:
parent
7c439932f1
commit
08a2ec82b3
@ -115,6 +115,14 @@ impl ProtectedCaller for X64ExecutionContext {
|
||||
}
|
||||
|
||||
match self.functions[index].num_params {
|
||||
0 => unsafe {
|
||||
let ptr: extern "C" fn() -> i64 = ::std::mem::transmute(ptr);
|
||||
Ok(vec![Value::I32(ptr() as i32)])
|
||||
},
|
||||
1 => unsafe {
|
||||
let ptr: extern "C" fn(i64) -> i64 = ::std::mem::transmute(ptr);
|
||||
Ok(vec![Value::I32(ptr(value_to_i64(&_params[0])) as i32)])
|
||||
},
|
||||
2 => unsafe {
|
||||
let ptr: extern "C" fn(i64, i64) -> i64 = ::std::mem::transmute(ptr);
|
||||
Ok(vec![Value::I32(
|
||||
@ -221,6 +229,41 @@ impl X64FunctionCode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a unary operator.
|
||||
fn emit_unop_i32<F: FnOnce(&mut Assembler, &ValueStack, Register)>(
|
||||
assembler: &mut Assembler,
|
||||
value_stack: &mut ValueStack,
|
||||
f: F,
|
||||
) -> Result<(), CodegenError> {
|
||||
let a = value_stack.pop()?;
|
||||
if a.ty != WpType::I32 {
|
||||
return Err(CodegenError {
|
||||
message: "unop(i32) type mismatch",
|
||||
});
|
||||
}
|
||||
value_stack.push(WpType::I32);
|
||||
|
||||
match a.location {
|
||||
ValueLocation::Register(x) => {
|
||||
let reg = Register::from_scratch_reg(x);
|
||||
f(assembler, value_stack, reg);
|
||||
}
|
||||
ValueLocation::Stack => {
|
||||
dynasm!(
|
||||
assembler
|
||||
; mov eax, [rsp]
|
||||
);
|
||||
f(assembler, value_stack, Register::RAX);
|
||||
dynasm!(
|
||||
assembler
|
||||
; mov [rsp], eax
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a binary operator.
|
||||
///
|
||||
/// Guarantees that the first Register parameter to callback `f` will never be `Register::RAX`.
|
||||
@ -232,7 +275,7 @@ impl X64FunctionCode {
|
||||
let (a, b) = value_stack.pop2()?;
|
||||
if a.ty != WpType::I32 || b.ty != WpType::I32 {
|
||||
return Err(CodegenError {
|
||||
message: "I32Add type mismatch",
|
||||
message: "binop(i32) type mismatch",
|
||||
});
|
||||
}
|
||||
value_stack.push(WpType::I32);
|
||||
@ -351,6 +394,27 @@ impl X64FunctionCode {
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_cmp_i32<F: FnOnce(&mut Assembler)>(
|
||||
assembler: &mut Assembler,
|
||||
left: Register,
|
||||
right: Register,
|
||||
f: F,
|
||||
) {
|
||||
dynasm!(
|
||||
assembler
|
||||
; cmp Rd(left as u8), Rd(right as u8)
|
||||
);
|
||||
f(assembler);
|
||||
dynasm!(
|
||||
assembler
|
||||
; xor Rd(left as u8), Rd(left as u8)
|
||||
; jmp >label_end
|
||||
; label_true:
|
||||
; mov Rd(left as u8), 1
|
||||
; label_end:
|
||||
);
|
||||
}
|
||||
|
||||
fn emit_peek_into_ax(
|
||||
assembler: &mut Assembler,
|
||||
value_stack: &ValueStack,
|
||||
@ -392,7 +456,7 @@ impl X64FunctionCode {
|
||||
fn emit_pop_into_ax(
|
||||
assembler: &mut Assembler,
|
||||
value_stack: &mut ValueStack,
|
||||
) -> Result<(), CodegenError> {
|
||||
) -> Result<WpType, CodegenError> {
|
||||
let val = value_stack.pop()?;
|
||||
match val.location {
|
||||
ValueLocation::Register(x) => {
|
||||
@ -419,7 +483,7 @@ impl X64FunctionCode {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(val.ty)
|
||||
}
|
||||
|
||||
fn emit_leave_frame(
|
||||
@ -438,12 +502,6 @@ impl X64FunctionCode {
|
||||
}
|
||||
};
|
||||
|
||||
if ret_ty.is_some() && frame.loop_like {
|
||||
return Err(CodegenError {
|
||||
message: "return value is not supported for loops",
|
||||
});
|
||||
}
|
||||
|
||||
if value_stack.values.len() < frame.value_stack_depth_before + frame.returns.len() {
|
||||
return Err(CodegenError {
|
||||
message: "value stack underflow",
|
||||
@ -483,13 +541,15 @@ impl X64FunctionCode {
|
||||
|
||||
if !was_unreachable {
|
||||
Self::emit_leave_frame(assembler, &frame, value_stack, false)?;
|
||||
}
|
||||
|
||||
if value_stack.values.len() != frame.value_stack_depth_before {
|
||||
return Err(CodegenError {
|
||||
message: "value_stack.values.len() != frame.value_stack_depth_before",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// No need to actually unwind the stack here.
|
||||
value_stack.reset_depth(frame.value_stack_depth_before);
|
||||
}
|
||||
|
||||
if !frame.loop_like {
|
||||
dynasm!(
|
||||
@ -543,7 +603,9 @@ impl X64FunctionCode {
|
||||
&control_stack.frames[control_stack.frames.len() - 1 - relative_frame_offset]
|
||||
};
|
||||
|
||||
if !frame.loop_like {
|
||||
Self::emit_leave_frame(assembler, frame, value_stack, true)?;
|
||||
}
|
||||
|
||||
let mut sp_diff: usize = 0;
|
||||
|
||||
@ -747,6 +809,52 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
}
|
||||
}
|
||||
}
|
||||
Operator::SetLocal { local_index } => {
|
||||
let local_index = local_index as usize;
|
||||
if local_index >= self.locals.len() {
|
||||
return Err(CodegenError {
|
||||
message: "local out of bounds",
|
||||
});
|
||||
}
|
||||
let local = self.locals[local_index];
|
||||
let ty = Self::emit_pop_into_ax(assembler, &mut self.value_stack)?;
|
||||
if ty != local.ty {
|
||||
return Err(CodegenError {
|
||||
message: "SetLocal type mismatch",
|
||||
});
|
||||
}
|
||||
|
||||
if is_dword(get_size_of_type(&ty)?) {
|
||||
dynasm!(
|
||||
assembler
|
||||
; mov [rbp - (local.stack_offset as i32)], eax
|
||||
);
|
||||
} else {
|
||||
dynasm!(
|
||||
assembler
|
||||
; mov [rbp - (local.stack_offset as i32)], rax
|
||||
);
|
||||
}
|
||||
}
|
||||
Operator::I32Const { value } => {
|
||||
let location = self.value_stack.push(WpType::I32);
|
||||
match location {
|
||||
ValueLocation::Register(x) => {
|
||||
let reg = Register::from_scratch_reg(x);
|
||||
dynasm!(
|
||||
assembler
|
||||
; mov Rq(reg as u8), value
|
||||
);
|
||||
}
|
||||
ValueLocation::Stack => {
|
||||
dynasm!(
|
||||
assembler
|
||||
; sub rsp, 4
|
||||
; mov DWORD [rsp], value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Operator::I32Add => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
@ -847,6 +955,158 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32Eq => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; cmp Rd(left as u8), Rd(right as u8)
|
||||
; lahf
|
||||
; shr ax, 14
|
||||
; and eax, 1
|
||||
; mov Rd(left as u8), eax
|
||||
);
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32Eqz => {
|
||||
Self::emit_unop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; cmp Rd(reg as u8), 0
|
||||
; lahf
|
||||
; shr ax, 14
|
||||
; and eax, 1
|
||||
);
|
||||
if reg != Register::RAX {
|
||||
dynasm!(
|
||||
assembler
|
||||
; mov Rd(reg as u8), eax
|
||||
);
|
||||
}
|
||||
},
|
||||
)?;
|
||||
}
|
||||
// Comparison operators.
|
||||
// https://en.wikibooks.org/wiki/X86_Assembly/Control_Flow
|
||||
// TODO: Is reading flag register directly faster?
|
||||
Operator::I32LtS => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jl >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32LeS => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jle >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32GtS => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jg >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32GeS => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jge >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32LtU => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jb >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32LeU => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jbe >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32GtU => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; ja >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::I32GeU => {
|
||||
Self::emit_binop_i32(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, left, right| {
|
||||
Self::emit_cmp_i32(assembler, left, right, |assembler| {
|
||||
dynasm!(
|
||||
assembler
|
||||
; jae >label_true
|
||||
);
|
||||
});
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Operator::Block { ty } => {
|
||||
self.control_stack
|
||||
.as_mut()
|
||||
@ -862,6 +1122,13 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
value_stack_depth_before: self.value_stack.values.len(),
|
||||
});
|
||||
}
|
||||
Operator::Unreachable => {
|
||||
dynasm!(
|
||||
assembler
|
||||
; ud2
|
||||
);
|
||||
self.unreachable_depth = 1;
|
||||
}
|
||||
Operator::Drop => {
|
||||
let info = self.value_stack.pop()?;
|
||||
Self::gen_rt_pop(assembler, &info)?;
|
||||
@ -891,6 +1158,26 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Operator::Loop { ty } => {
|
||||
let label = assembler.new_dynamic_label();
|
||||
self.control_stack
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.frames
|
||||
.push(ControlFrame {
|
||||
label: label,
|
||||
loop_like: true,
|
||||
returns: match ty {
|
||||
WpType::EmptyBlockType => vec![],
|
||||
_ => vec![ty],
|
||||
},
|
||||
value_stack_depth_before: self.value_stack.values.len(),
|
||||
});
|
||||
dynasm!(
|
||||
assembler
|
||||
; =>label
|
||||
);
|
||||
}
|
||||
Operator::Br { relative_depth } => {
|
||||
Self::emit_jmp(
|
||||
assembler,
|
||||
|
Loading…
Reference in New Issue
Block a user