winch: Add full support for integer sub and add instructions (#5737)
This patch adds complete support for the `sub` and `add` WebAssembly instructions for x64, and complete support for the `add` WebAssembly instruction for aarch64. This patch also refactors how the binary operations get constructed within the `VisitOperator` trait implementation. The refactor adds methods in the `CodeGenContext` to abstract all the common steps to emit binary operations, making this process less repetitive and less brittle (e.g. omitting to push the resulting value to the stack, or omitting to free registers after used). This patch also improves test coverage and refactors the filetests directory to make it easier to add tests for other instructions.
This commit is contained in:
@@ -6,6 +6,8 @@ use std::collections::VecDeque;
|
||||
pub(crate) enum Val {
|
||||
/// I32 Constant.
|
||||
I32(i32),
|
||||
/// I64 Constant.
|
||||
I64(i64),
|
||||
/// A register.
|
||||
Reg(Reg),
|
||||
/// A local slot.
|
||||
@@ -20,6 +22,11 @@ impl Val {
|
||||
Self::I32(v)
|
||||
}
|
||||
|
||||
/// Create a new I64 constant value.
|
||||
pub fn i64(v: i64) -> Self {
|
||||
Self::I64(v)
|
||||
}
|
||||
|
||||
/// Create a new Reg value.
|
||||
pub fn reg(r: Reg) -> Self {
|
||||
Self::Reg(r)
|
||||
@@ -60,6 +67,17 @@ impl Val {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the integer representation of the value.
|
||||
///
|
||||
/// # Panics
|
||||
/// This method will panic if the value is not an i64.
|
||||
pub fn get_i64(&self) -> i64 {
|
||||
match self {
|
||||
Self::I64(v) => *v,
|
||||
v => panic!("expected value {:?} to be i64", v),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the value is an i32 constant.
|
||||
pub fn is_i32_const(&self) -> bool {
|
||||
match *self {
|
||||
@@ -67,6 +85,14 @@ impl Val {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the value is an i64 constant.
|
||||
pub fn is_i64_const(&self) -> bool {
|
||||
match *self {
|
||||
Self::I64(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The shadow stack used for compilation.
|
||||
@@ -89,7 +115,7 @@ impl Stack {
|
||||
}
|
||||
|
||||
/// Peek into the top in the stack.
|
||||
pub fn peek(&mut self) -> Option<&Val> {
|
||||
pub fn peek(&self) -> Option<&Val> {
|
||||
self.inner.back()
|
||||
}
|
||||
|
||||
@@ -98,7 +124,7 @@ impl Stack {
|
||||
self.inner.pop_back()
|
||||
}
|
||||
|
||||
/// Pops the element at the top of the stack if it is a const;
|
||||
/// Pops the element at the top of the stack if it is an i32 const;
|
||||
/// returns `None` otherwise.
|
||||
pub fn pop_i32_const(&mut self) -> Option<i32> {
|
||||
match self.peek() {
|
||||
@@ -107,6 +133,15 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pops the element at the top of the stack if it is an i64 const;
|
||||
/// returns `None` otherwise.
|
||||
pub fn pop_i64_const(&mut self) -> Option<i64> {
|
||||
match self.peek() {
|
||||
Some(v) => v.is_i64_const().then(|| self.pop().unwrap().get_i64()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Pops the element at the top of the stack if it is a register;
|
||||
/// returns `None` otherwise.
|
||||
pub fn pop_reg(&mut self) -> Option<Reg> {
|
||||
|
||||
Reference in New Issue
Block a user