mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-26 15:11:37 +00:00
Operators.
This commit is contained in:
@ -52,6 +52,22 @@ impl Register {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_used(&self, stack: &ValueStack) -> bool {
|
||||||
|
use self::Register::*;
|
||||||
|
for val in &stack.values {
|
||||||
|
match val.location {
|
||||||
|
ValueLocation::Register(x) => {
|
||||||
|
if Register::from_scratch_reg(x) == *self {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueLocation::Stack => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -202,6 +218,136 @@ impl X64FunctionCode {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits a binary operator.
|
||||||
|
///
|
||||||
|
/// Guarantees that the first Register parameter to callback `f` will never be `Register::RAX`.
|
||||||
|
fn emit_binop_i32<F: FnOnce(&mut Assembler, &ValueStack, Register, Register)>(
|
||||||
|
assembler: &mut Assembler,
|
||||||
|
value_stack: &mut ValueStack,
|
||||||
|
f: F,
|
||||||
|
) -> Result<(), CodegenError> {
|
||||||
|
let (a, b) = value_stack.pop2()?;
|
||||||
|
if a.ty != WpType::I32 || b.ty != WpType::I32 {
|
||||||
|
return Err(CodegenError {
|
||||||
|
message: "I32Add type mismatch",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
value_stack.push(WpType::I32);
|
||||||
|
|
||||||
|
if a.location.is_register() && b.location.is_register() {
|
||||||
|
// output is in a_reg.
|
||||||
|
f(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
Register::from_scratch_reg(a.location.get_register()?),
|
||||||
|
Register::from_scratch_reg(b.location.get_register()?),
|
||||||
|
);
|
||||||
|
} else if a.location.is_register() {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov eax, [rsp]
|
||||||
|
; add rsp, 4
|
||||||
|
);
|
||||||
|
f(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
Register::from_scratch_reg(a.location.get_register()?),
|
||||||
|
Register::RAX,
|
||||||
|
);
|
||||||
|
} else if b.location.is_register() {
|
||||||
|
unreachable!();
|
||||||
|
} else {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push rcx
|
||||||
|
; mov ecx, [rsp + 12]
|
||||||
|
; mov eax, [rsp + 8]
|
||||||
|
);
|
||||||
|
f(assembler, value_stack, Register::RCX, Register::RAX);
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov [rsp + 12], ecx
|
||||||
|
; pop rcx
|
||||||
|
; add rsp, 4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_div_i32(
|
||||||
|
assembler: &mut Assembler,
|
||||||
|
value_stack: &ValueStack,
|
||||||
|
left: Register,
|
||||||
|
right: Register,
|
||||||
|
signed: bool,
|
||||||
|
out: Register,
|
||||||
|
) {
|
||||||
|
let dx_used = Register::RDX.is_used(value_stack);
|
||||||
|
if dx_used {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push rdx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if right == Register::RAX {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push rax
|
||||||
|
; mov eax, Rd(left as u8)
|
||||||
|
; mov edx, 0
|
||||||
|
; mov Rd(left as u8), [rsp]
|
||||||
|
);
|
||||||
|
|
||||||
|
if signed {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; idiv Rd(left as u8)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; div Rd(left as u8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov Rd(left as u8), Rd(out as u8)
|
||||||
|
; pop rax
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov eax, Rd(left as u8)
|
||||||
|
; mov edx, 0
|
||||||
|
);
|
||||||
|
if signed {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; idiv Rd(right as u8)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; div Rd(right as u8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov Rd(left as u8), Rd(out as u8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if dx_used {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; pop rdx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionCodeGenerator for X64FunctionCode {
|
impl FunctionCodeGenerator for X64FunctionCode {
|
||||||
@ -329,46 +475,104 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operator::I32Add => {
|
Operator::I32Add => {
|
||||||
let (a, b) = self.value_stack.pop2()?;
|
Self::emit_binop_i32(
|
||||||
if a.ty != WpType::I32 || b.ty != WpType::I32 {
|
assembler,
|
||||||
return Err(CodegenError {
|
&mut self.value_stack,
|
||||||
message: "I32Add type mismatch",
|
|assembler, value_stack, left, right| {
|
||||||
});
|
dynasm!(
|
||||||
}
|
assembler
|
||||||
self.value_stack.push(WpType::I32);
|
; add Rd(left as u8), Rd(right as u8)
|
||||||
|
)
|
||||||
if a.location.is_register() && b.location.is_register() {
|
},
|
||||||
let (a_reg, b_reg) = (
|
)?;
|
||||||
Register::from_scratch_reg(a.location.get_register()?),
|
}
|
||||||
Register::from_scratch_reg(b.location.get_register()?),
|
Operator::I32Sub => {
|
||||||
);
|
Self::emit_binop_i32(
|
||||||
// output is in a_reg.
|
assembler,
|
||||||
dynasm!(
|
&mut self.value_stack,
|
||||||
assembler
|
|assembler, value_stack, left, right| {
|
||||||
; add Rd(a_reg as u8), Rd(b_reg as u8)
|
dynasm!(
|
||||||
);
|
assembler
|
||||||
} else if a.location.is_register() {
|
; sub Rd(left as u8), Rd(right as u8)
|
||||||
let a_reg = Register::from_scratch_reg(a.location.get_register()?);
|
)
|
||||||
dynasm!(
|
},
|
||||||
assembler
|
)?;
|
||||||
; mov eax, [rsp]
|
}
|
||||||
; add rsp, 4
|
Operator::I32Mul => {
|
||||||
; add Rd(a_reg as u8), eax
|
Self::emit_binop_i32(
|
||||||
);
|
assembler,
|
||||||
} else if b.location.is_register() {
|
&mut self.value_stack,
|
||||||
unreachable!();
|
|assembler, value_stack, left, right| {
|
||||||
} else {
|
dynasm!(
|
||||||
dynasm!(
|
assembler
|
||||||
assembler
|
; imul Rd(left as u8), Rd(right as u8)
|
||||||
; push rcx
|
)
|
||||||
; mov eax, [rsp + 12]
|
},
|
||||||
; mov ecx, [rsp + 8]
|
)?;
|
||||||
; add eax, ecx
|
}
|
||||||
; mov [rsp + 12], eax
|
Operator::I32DivU => {
|
||||||
; pop rcx
|
Self::emit_binop_i32(
|
||||||
; add rsp, 4
|
assembler,
|
||||||
);
|
&mut self.value_stack,
|
||||||
}
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i32(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
false,
|
||||||
|
Register::RAX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32DivS => {
|
||||||
|
Self::emit_binop_i32(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i32(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
true,
|
||||||
|
Register::RAX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32RemU => {
|
||||||
|
Self::emit_binop_i32(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i32(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
false,
|
||||||
|
Register::RDX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32RemS => {
|
||||||
|
Self::emit_binop_i32(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i32(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
true,
|
||||||
|
Register::RDX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Operator::Drop => {
|
Operator::Drop => {
|
||||||
let info = self.value_stack.pop()?;
|
let info = self.value_stack.pop()?;
|
||||||
|
Reference in New Issue
Block a user