mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-14 06:35:40 +00:00
Implemented missing integer operators and fixed division.
This commit is contained in:
parent
5a97a25e7c
commit
27b2061ffd
@ -517,64 +517,89 @@ impl X64FunctionCode {
|
|||||||
signed: bool,
|
signed: bool,
|
||||||
out: Register,
|
out: Register,
|
||||||
) {
|
) {
|
||||||
let dx_used = Register::RDX.is_used(value_stack);
|
let dx_save =
|
||||||
if dx_used {
|
Register::RDX.is_used(value_stack) && left != Register::RDX && right != Register::RDX;
|
||||||
|
if dx_save {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; push rdx
|
; push rdx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if right == Register::RAX {
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push r15
|
||||||
|
; mov r15d, Rd(right as u8)
|
||||||
|
; mov eax, Rd(left as u8)
|
||||||
|
; mov edx, 0
|
||||||
|
);
|
||||||
|
if signed {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; push rax
|
; idiv r15d
|
||||||
; 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 {
|
} else {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; mov eax, Rd(left as u8)
|
; div r15d
|
||||||
; mov edx, 0
|
|
||||||
);
|
);
|
||||||
if signed {
|
}
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; idiv Rd(right as u8)
|
; mov Rd(left as u8), Rd(out as u8)
|
||||||
);
|
; pop r15
|
||||||
} else {
|
);
|
||||||
dynasm!(
|
|
||||||
assembler
|
if dx_save {
|
||||||
; div Rd(right as u8)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; mov Rd(left as u8), Rd(out as u8)
|
; pop rdx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_div_i64(
|
||||||
|
assembler: &mut Assembler,
|
||||||
|
value_stack: &ValueStack,
|
||||||
|
left: Register,
|
||||||
|
right: Register,
|
||||||
|
signed: bool,
|
||||||
|
out: Register,
|
||||||
|
) {
|
||||||
|
let dx_save =
|
||||||
|
Register::RDX.is_used(value_stack) && left != Register::RDX && right != Register::RDX;
|
||||||
|
if dx_save {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push rdx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if dx_used {
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push r15
|
||||||
|
; mov r15, Rq(right as u8)
|
||||||
|
; mov rax, Rq(left as u8)
|
||||||
|
; mov rdx, 0
|
||||||
|
);
|
||||||
|
if signed {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; idiv r15
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; div r15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov Rq(left as u8), Rq(out as u8)
|
||||||
|
; pop r15
|
||||||
|
);
|
||||||
|
|
||||||
|
if dx_save {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; pop rdx
|
; pop rdx
|
||||||
@ -627,7 +652,7 @@ impl X64FunctionCode {
|
|||||||
fn emit_peek_into_ax(
|
fn emit_peek_into_ax(
|
||||||
assembler: &mut Assembler,
|
assembler: &mut Assembler,
|
||||||
value_stack: &ValueStack,
|
value_stack: &ValueStack,
|
||||||
) -> Result<(), CodegenError> {
|
) -> Result<WpType, CodegenError> {
|
||||||
let val = match value_stack.values.last() {
|
let val = match value_stack.values.last() {
|
||||||
Some(x) => *x,
|
Some(x) => *x,
|
||||||
None => {
|
None => {
|
||||||
@ -652,7 +677,7 @@ impl X64FunctionCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(val.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_pop_into_reg(
|
fn emit_pop_into_reg(
|
||||||
@ -1389,6 +1414,33 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Operator::TeeLocal { 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_peek_into_ax(assembler, &self.value_stack)?;
|
||||||
|
if ty != local.ty {
|
||||||
|
return Err(CodegenError {
|
||||||
|
message: "TeeLocal 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 } => {
|
Operator::I32Const { value } => {
|
||||||
let location = self.value_stack.push(WpType::I32);
|
let location = self.value_stack.push(WpType::I32);
|
||||||
match location {
|
match location {
|
||||||
@ -1396,7 +1448,7 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
let reg = Register::from_scratch_reg(x);
|
let reg = Register::from_scratch_reg(x);
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; mov Rq(reg as u8), value
|
; mov Rd(reg as u8), value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ValueLocation::Stack => {
|
ValueLocation::Stack => {
|
||||||
@ -1547,6 +1599,23 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
Operator::I32Ne => {
|
||||||
|
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
|
||||||
|
; xor eax, 1
|
||||||
|
; mov Rd(left as u8), eax
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
Operator::I32Eqz => {
|
Operator::I32Eqz => {
|
||||||
Self::emit_unop_i32(
|
Self::emit_unop_i32(
|
||||||
assembler,
|
assembler,
|
||||||
@ -1568,6 +1637,42 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
Operator::I32Clz => {
|
||||||
|
Self::emit_unop_i32(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; lzcnt Rd(reg as u8), Rd(reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32Ctz => {
|
||||||
|
Self::emit_unop_i32(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; tzcnt Rd(reg as u8), Rd(reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32Popcnt => {
|
||||||
|
Self::emit_unop_i32(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; popcnt Rd(reg as u8), Rd(reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
// Comparison operators.
|
// Comparison operators.
|
||||||
// https://en.wikibooks.org/wiki/X86_Assembly/Control_Flow
|
// https://en.wikibooks.org/wiki/X86_Assembly/Control_Flow
|
||||||
// TODO: Is reading flag register directly faster?
|
// TODO: Is reading flag register directly faster?
|
||||||
@ -1739,16 +1844,68 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Operator::I64DivU => {
|
Operator::I64DivU => {
|
||||||
unimplemented!();
|
Self::emit_binop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i64(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
false,
|
||||||
|
Register::RAX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Operator::I64DivS => {
|
Operator::I64DivS => {
|
||||||
unimplemented!();
|
Self::emit_binop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i64(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
true,
|
||||||
|
Register::RAX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Operator::I64RemU => {
|
Operator::I64RemU => {
|
||||||
unimplemented!();
|
Self::emit_binop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i64(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
false,
|
||||||
|
Register::RDX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Operator::I64RemS => {
|
Operator::I64RemS => {
|
||||||
unimplemented!();
|
Self::emit_binop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
Self::emit_div_i64(
|
||||||
|
assembler,
|
||||||
|
value_stack,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
true,
|
||||||
|
Register::RDX,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Operator::I64And => {
|
Operator::I64And => {
|
||||||
Self::emit_binop_i64(
|
Self::emit_binop_i64(
|
||||||
@ -1792,6 +1949,25 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
WpType::I32,
|
WpType::I32,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
Operator::I64Ne => {
|
||||||
|
Self::emit_binop(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, left, right| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; cmp Rq(left as u8), Rq(right as u8)
|
||||||
|
; lahf
|
||||||
|
; shr ax, 14
|
||||||
|
; and eax, 1
|
||||||
|
; xor eax, 1
|
||||||
|
; mov Rd(left as u8), eax
|
||||||
|
);
|
||||||
|
},
|
||||||
|
WpType::I64,
|
||||||
|
WpType::I32,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
Operator::I64Eqz => {
|
Operator::I64Eqz => {
|
||||||
Self::emit_unop(
|
Self::emit_unop(
|
||||||
assembler,
|
assembler,
|
||||||
@ -1815,6 +1991,42 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
WpType::I32,
|
WpType::I32,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
Operator::I64Clz => {
|
||||||
|
Self::emit_unop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; lzcnt Rq(reg as u8), Rq(reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I64Ctz => {
|
||||||
|
Self::emit_unop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; tzcnt Rq(reg as u8), Rq(reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I64Popcnt => {
|
||||||
|
Self::emit_unop_i64(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, value_stack, reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; popcnt Rq(reg as u8), Rq(reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
// Comparison operators.
|
// Comparison operators.
|
||||||
// https://en.wikibooks.org/wiki/X86_Assembly/Control_Flow
|
// https://en.wikibooks.org/wiki/X86_Assembly/Control_Flow
|
||||||
// TODO: Is reading flag register directly faster?
|
// TODO: Is reading flag register directly faster?
|
||||||
|
Loading…
Reference in New Issue
Block a user