Merge pull request #2245 from rtfeldman/wasm-tag-eq

Wasm tag equality
This commit is contained in:
Folkert de Vries 2021-12-21 16:24:14 +01:00 committed by GitHub
commit 18187bc43f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 467 additions and 193 deletions

View file

@ -11,13 +11,10 @@ use crate::wasm_module::{Align, CodeBuilder, ValueType::*};
pub enum LowlevelBuildResult {
Done,
BuiltinCall(&'static str),
SpecializedEq,
SpecializedNotEq,
SpecializedHash,
NotImplemented,
}
pub fn decode_low_level<'a>(
pub fn dispatch_low_level<'a>(
code_builder: &mut CodeBuilder<'a>,
storage: &mut Storage<'a>,
lowlevel: LowLevel,
@ -525,109 +522,15 @@ pub fn decode_low_level<'a>(
WasmLayout::StackMemory { .. } => return NotImplemented,
}
}
Eq => {
use StoredValue::*;
match storage.get(&args[0]).to_owned() {
VirtualMachineStack { value_type, .. } | Local { value_type, .. } => {
match value_type {
I32 => code_builder.i32_eq(),
I64 => code_builder.i64_eq(),
F32 => code_builder.f32_eq(),
F64 => code_builder.f64_eq(),
}
}
StackMemory {
format,
location: location0,
..
} => {
if let StackMemory {
location: location1,
..
} = storage.get(&args[1]).to_owned()
{
let stack_frame_pointer = storage.stack_frame_pointer;
let compare_bytes = |code_builder: &mut CodeBuilder| {
let (local0, offset0) = location0.local_and_offset(stack_frame_pointer);
let (local1, offset1) = location1.local_and_offset(stack_frame_pointer);
code_builder.get_local(local0);
code_builder.i64_load(Align::Bytes8, offset0);
code_builder.get_local(local1);
code_builder.i64_load(Align::Bytes8, offset1);
code_builder.i64_eq();
code_builder.get_local(local0);
code_builder.i64_load(Align::Bytes8, offset0 + 8);
code_builder.get_local(local1);
code_builder.i64_load(Align::Bytes8, offset1 + 8);
code_builder.i64_eq();
code_builder.i32_and();
};
match format {
Decimal => {
// Both args are finite
let first = [args[0]];
let second = [args[1]];
decode_low_level(
code_builder,
storage,
LowLevel::NumIsFinite,
&first,
ret_layout,
);
decode_low_level(
code_builder,
storage,
LowLevel::NumIsFinite,
&second,
ret_layout,
);
code_builder.i32_and();
// AND they have the same bytes
compare_bytes(code_builder);
code_builder.i32_and();
}
Int128 => compare_bytes(code_builder),
Float128 => return NotImplemented,
DataStructure => return SpecializedEq,
}
}
}
}
}
NotEq => match storage.get(&args[0]) {
StoredValue::VirtualMachineStack { value_type, .. }
| StoredValue::Local { value_type, .. } => match value_type {
I32 => code_builder.i32_ne(),
I64 => code_builder.i64_ne(),
F32 => code_builder.f32_ne(),
F64 => code_builder.f64_ne(),
},
StoredValue::StackMemory { format, .. } => {
if matches!(format, DataStructure) {
return SpecializedNotEq;
} else {
decode_low_level(code_builder, storage, LowLevel::Eq, args, ret_layout);
code_builder.i32_eqz();
}
}
},
And => code_builder.i32_and(),
Or => code_builder.i32_or(),
Not => code_builder.i32_eqz(),
Hash => return SpecializedHash,
ExpectTrue => return NotImplemented,
PtrCast => {
// We don't need any instructions here, since we've already loaded the value.
// PtrCast just creates separate Symbols and Layouts for the argument and return value.
// This is used for pointer math in refcounting and for pointer equality
}
RefCountInc => return BuiltinCall(bitcode::UTILS_INCREF),
RefCountDec => return BuiltinCall(bitcode::UTILS_DECREF),
Eq | NotEq | Hash | PtrCast => {
internal_error!("{:?} should be handled in backend.rs", lowlevel)
}
}
Done
}