add memory.fill/memory.copy intrinsics

This commit is contained in:
2022-06-11 23:31:02 +02:00
parent 0a0d90c801
commit 0e7ea508cd

View File

@@ -1,9 +1,11 @@
use crate::ast::Type; use crate::ast::Type;
use std::collections::HashMap;
use enc::MemArg; use enc::MemArg;
use std::collections::HashMap;
use wasm_encoder as enc; use wasm_encoder as enc;
pub struct Intrinsics(HashMap<String, HashMap<Vec<Type>, (Type, enc::Instruction<'static>)>>); pub struct Intrinsics(
HashMap<String, HashMap<Vec<Type>, (Option<Type>, enc::Instruction<'static>)>>,
);
impl Intrinsics { impl Intrinsics {
pub fn new() -> Intrinsics { pub fn new() -> Intrinsics {
@@ -12,14 +14,11 @@ impl Intrinsics {
i i
} }
pub fn find_types( pub fn find_types(&self, name: &str) -> Option<HashMap<Vec<Type>, Option<Type>>> {
&self,
name: &str,
) -> Option<HashMap<Vec<Type>, Option<Type>>> {
self.0.get(name).map(|types| { self.0.get(name).map(|types| {
types types
.iter() .iter()
.map(|(params, (ret, _))| (params.clone(), Some(*ret))) .map(|(params, (ret, _))| (params.clone(), *ret))
.collect() .collect()
}) })
} }
@@ -34,87 +33,121 @@ impl Intrinsics {
fn add_instructions(&mut self) { fn add_instructions(&mut self) {
use enc::Instruction as I; use enc::Instruction as I;
use Type::*; use Type::*;
self.inst("i32.rotl", &[I32, I32], I32, I::I32Rotl); self.inst("i32.rotl", &[I32, I32], Some(I32), I::I32Rotl);
self.inst("i32.rotr", &[I32, I32], I32, I::I32Rotr); self.inst("i32.rotr", &[I32, I32], Some(I32), I::I32Rotr);
self.inst("i32.clz", &[I32], I32, I::I32Clz); self.inst("i32.clz", &[I32], Some(I32), I::I32Clz);
self.inst("i32.ctz", &[I32], I32, I::I32Ctz); self.inst("i32.ctz", &[I32], Some(I32), I::I32Ctz);
self.inst("i32.popcnt", &[I32], I32, I::I32Popcnt); self.inst("i32.popcnt", &[I32], Some(I32), I::I32Popcnt);
self.inst("i64.rotl", &[I64, I64], I64, I::I64Rotl); self.inst("i64.rotl", &[I64, I64], Some(I64), I::I64Rotl);
self.inst("i64.rotr", &[I64, I64], I64, I::I64Rotr); self.inst("i64.rotr", &[I64, I64], Some(I64), I::I64Rotr);
self.inst("i64.clz", &[I64], I64, I::I64Clz); self.inst("i64.clz", &[I64], Some(I64), I::I64Clz);
self.inst("i64.ctz", &[I64], I64, I::I64Ctz); self.inst("i64.ctz", &[I64], Some(I64), I::I64Ctz);
self.inst("i64.popcnt", &[I64], I64, I::I64Popcnt); self.inst("i64.popcnt", &[I64], Some(I64), I::I64Popcnt);
self.inst("f32/sqrt", &[F32], F32, I::F32Sqrt); self.inst("f32/sqrt", &[F32], Some(F32), I::F32Sqrt);
self.inst("f32/min", &[F32, F32], F32, I::F32Min); self.inst("f32/min", &[F32, F32], Some(F32), I::F32Min);
self.inst("f32/max", &[F32, F32], F32, I::F32Max); self.inst("f32/max", &[F32, F32], Some(F32), I::F32Max);
self.inst("f32/ceil", &[F32], F32, I::F32Ceil); self.inst("f32/ceil", &[F32], Some(F32), I::F32Ceil);
self.inst("f32/floor", &[F32], F32, I::F32Floor); self.inst("f32/floor", &[F32], Some(F32), I::F32Floor);
self.inst("f32/trunc", &[F32], F32, I::F32Trunc); self.inst("f32/trunc", &[F32], Some(F32), I::F32Trunc);
self.inst("f32/nearest", &[F32], F32, I::F32Nearest); self.inst("f32/nearest", &[F32], Some(F32), I::F32Nearest);
self.inst("f32/abs", &[F32], F32, I::F32Abs); self.inst("f32/abs", &[F32], Some(F32), I::F32Abs);
self.inst("f32.copysign", &[F32, F32], F32, I::F32Copysign); self.inst("f32.copysign", &[F32, F32], Some(F32), I::F32Copysign);
self.inst("f64/sqrt", &[F64], F64, I::F64Sqrt); self.inst("f64/sqrt", &[F64], Some(F64), I::F64Sqrt);
self.inst("f64/min", &[F64, F64], F64, I::F64Min); self.inst("f64/min", &[F64, F64], Some(F64), I::F64Min);
self.inst("f64/max", &[F64, F64], F64, I::F64Max); self.inst("f64/max", &[F64, F64], Some(F64), I::F64Max);
self.inst("f64/ceil", &[F64], F64, I::F64Ceil); self.inst("f64/ceil", &[F64], Some(F64), I::F64Ceil);
self.inst("f64/floor", &[F64], F64, I::F64Floor); self.inst("f64/floor", &[F64], Some(F64), I::F64Floor);
self.inst("f64/trunc", &[F64], F64, I::F64Trunc); self.inst("f64/trunc", &[F64], Some(F64), I::F64Trunc);
self.inst("f64/nearest", &[F64], F64, I::F64Nearest); self.inst("f64/nearest", &[F64], Some(F64), I::F64Nearest);
self.inst("f64/abs", &[F64], F64, I::F64Abs); self.inst("f64/abs", &[F64], Some(F64), I::F64Abs);
self.inst("f64.copysign", &[F64, F64], F64, I::F64Copysign); self.inst("f64.copysign", &[F64, F64], Some(F64), I::F64Copysign);
self.inst("i32.wrap_i64", &[I64], I32, I::I32WrapI64); self.inst("i32.wrap_i64", &[I64], Some(I32), I::I32WrapI64);
self.inst("i64.extend_i32_s", &[I32], I64, I::I64ExtendI32S); self.inst("i64.extend_i32_s", &[I32], Some(I64), I::I64ExtendI32S);
self.inst("i64.extend_i32_u", &[I32], I64, I::I64ExtendI32U); self.inst("i64.extend_i32_u", &[I32], Some(I64), I::I64ExtendI32U);
self.inst("i32.trunc_f32_s", &[F32], I32, I::I32TruncF32S); self.inst("i32.trunc_f32_s", &[F32], Some(I32), I::I32TruncF32S);
self.inst("i32.trunc_f64_s", &[F64], I32, I::I32TruncF64S); self.inst("i32.trunc_f64_s", &[F64], Some(I32), I::I32TruncF64S);
self.inst("i64.trunc_f32_s", &[F32], I64, I::I64TruncF32S); self.inst("i64.trunc_f32_s", &[F32], Some(I64), I::I64TruncF32S);
self.inst("i64.trunc_f64_s", &[F64], I64, I::I64TruncF64S); self.inst("i64.trunc_f64_s", &[F64], Some(I64), I::I64TruncF64S);
self.inst("i32.trunc_f32_u", &[F32], I32, I::I32TruncF32U); self.inst("i32.trunc_f32_u", &[F32], Some(I32), I::I32TruncF32U);
self.inst("i32.trunc_f64_u", &[F64], I32, I::I32TruncF64U); self.inst("i32.trunc_f64_u", &[F64], Some(I32), I::I32TruncF64U);
self.inst("i64.trunc_f32_u", &[F32], I64, I::I64TruncF32U); self.inst("i64.trunc_f32_u", &[F32], Some(I64), I::I64TruncF32U);
self.inst("i64.trunc_f64_u", &[F64], I64, I::I64TruncF64U); self.inst("i64.trunc_f64_u", &[F64], Some(I64), I::I64TruncF64U);
self.inst("f32.demote_f64", &[F64], F32, I::F32DemoteF64); self.inst("f32.demote_f64", &[F64], Some(F32), I::F32DemoteF64);
self.inst("f64.promote_f32", &[F32], F64, I::F64PromoteF32); self.inst("f64.promote_f32", &[F32], Some(F64), I::F64PromoteF32);
self.inst("f32.convert_i32_s", &[I32], F32, I::F32ConvertI32S); self.inst("f32.convert_i32_s", &[I32], Some(F32), I::F32ConvertI32S);
self.inst("f32.convert_i64_s", &[I64], F32, I::F32ConvertI32S); self.inst("f32.convert_i64_s", &[I64], Some(F32), I::F32ConvertI32S);
self.inst("f64.convert_i32_s", &[I32], F64, I::F32ConvertI32S); self.inst("f64.convert_i32_s", &[I32], Some(F64), I::F32ConvertI32S);
self.inst("f64.convert_i64_s", &[I64], F64, I::F32ConvertI32S); self.inst("f64.convert_i64_s", &[I64], Some(F64), I::F32ConvertI32S);
self.inst("f32.convert_i32_u", &[I32], F32, I::F32ConvertI32U); self.inst("f32.convert_i32_u", &[I32], Some(F32), I::F32ConvertI32U);
self.inst("f32.convert_i64_u", &[I64], F32, I::F32ConvertI32U); self.inst("f32.convert_i64_u", &[I64], Some(F32), I::F32ConvertI32U);
self.inst("f64.convert_i32_u", &[I32], F64, I::F32ConvertI32U); self.inst("f64.convert_i32_u", &[I32], Some(F64), I::F32ConvertI32U);
self.inst("f64.convert_i64_u", &[I64], F64, I::F32ConvertI32U); self.inst("f64.convert_i64_u", &[I64], Some(F64), I::F32ConvertI32U);
self.inst("i32.reinterpret_f32", &[F32], I32, I::I32ReinterpretF32); self.inst(
self.inst("i64.reinterpret_f64", &[F64], I64, I::I64ReinterpretF64); "i32.reinterpret_f32",
self.inst("f32.reinterpret_i32", &[I32], F32, I::F32ReinterpretI32); &[F32],
self.inst("f64.reinterpret_i64", &[I64], F64, I::F64ReinterpretI64); Some(I32),
I::I32ReinterpretF32,
);
self.inst(
"i64.reinterpret_f64",
&[F64],
Some(I64),
I::I64ReinterpretF64,
);
self.inst(
"f32.reinterpret_i32",
&[I32],
Some(F32),
I::F32ReinterpretI32,
);
self.inst(
"f64.reinterpret_i64",
&[I64],
Some(F64),
I::F64ReinterpretI64,
);
self.inst("i32.extend8_s", &[I32], I32, I::I32Extend8S); self.inst("i32.extend8_s", &[I32], Some(I32), I::I32Extend8S);
self.inst("i32.extend16_s", &[I32], I32, I::I32Extend16S); self.inst("i32.extend16_s", &[I32], Some(I32), I::I32Extend16S);
self.inst("i64.extend8_s", &[I64], I64, I::I64Extend8S); self.inst("i64.extend8_s", &[I64], Some(I64), I::I64Extend8S);
self.inst("i64.extend16_s", &[I64], I64, I::I64Extend16S); self.inst("i64.extend16_s", &[I64], Some(I64), I::I64Extend16S);
self.inst("i64.extend32_s", &[I64], I64, I::I64Extend32S); self.inst("i64.extend32_s", &[I64], Some(I64), I::I64Extend32S);
self.inst("i32.trunc_sat_f32_s", &[F32], I32, I::I32TruncSatF32S); self.inst("i32.trunc_sat_f32_s", &[F32], Some(I32), I::I32TruncSatF32S);
self.inst("i32.trunc_sat_f32_u", &[F32], I32, I::I32TruncSatF32U); self.inst("i32.trunc_sat_f32_u", &[F32], Some(I32), I::I32TruncSatF32U);
self.inst("i32.trunc_sat_f64_s", &[F64], I32, I::I32TruncSatF64S); self.inst("i32.trunc_sat_f64_s", &[F64], Some(I32), I::I32TruncSatF64S);
self.inst("i32.trunc_sat_f64_u", &[F64], I32, I::I32TruncSatF64U); self.inst("i32.trunc_sat_f64_u", &[F64], Some(I32), I::I32TruncSatF64U);
self.inst("i64.trunc_sat_f32_s", &[F32], I64, I::I64TruncSatF32S); self.inst("i64.trunc_sat_f32_s", &[F32], Some(I64), I::I64TruncSatF32S);
self.inst("i64.trunc_sat_f32_u", &[F32], I64, I::I64TruncSatF32U); self.inst("i64.trunc_sat_f32_u", &[F32], Some(I64), I::I64TruncSatF32U);
self.inst("i64.trunc_sat_f64_s", &[F64], I64, I::I64TruncSatF64S); self.inst("i64.trunc_sat_f64_s", &[F64], Some(I64), I::I64TruncSatF64S);
self.inst("i64.trunc_sat_f64_u", &[F64], I64, I::I64TruncSatF64U); self.inst("i64.trunc_sat_f64_u", &[F64], Some(I64), I::I64TruncSatF64U);
self.inst(
"memory.copy",
&[I32, I32, I32],
None,
I::MemoryCopy { src: 0, dst: 0 },
);
self.inst("memory.fill", &[I32, I32, I32], None, I::MemoryFill(0));
} }
fn inst(&mut self, name: &str, params: &[Type], ret: Type, ins: enc::Instruction<'static>) { fn inst(
&mut self,
name: &str,
params: &[Type],
ret: Option<Type>,
ins: enc::Instruction<'static>,
) {
if let Some(slash_idx) = name.find('/') { if let Some(slash_idx) = name.find('/') {
self.insert(name[(slash_idx + 1)..].to_string(), params, ret, &ins); self.insert(name[(slash_idx + 1)..].to_string(), params, ret, &ins);
let mut full_name = name[..slash_idx].to_string(); let mut full_name = name[..slash_idx].to_string();
@@ -130,7 +163,7 @@ impl Intrinsics {
&mut self, &mut self,
name: String, name: String,
params: &[Type], params: &[Type],
ret: Type, ret: Option<Type>,
ins: &enc::Instruction<'static>, ins: &enc::Instruction<'static>,
) { ) {
self.0 self.0
@@ -157,7 +190,7 @@ impl Intrinsics {
"i64.load32_u" => MemInstruction::new(I64, I::I64Load32_U, 2), "i64.load32_u" => MemInstruction::new(I64, I::I64Load32_U, 2),
"f32.load" => MemInstruction::new(F32, I::F32Load, 2), "f32.load" => MemInstruction::new(F32, I::F32Load, 2),
"f64.load" => MemInstruction::new(F64, I::F64Load, 3), "f64.load" => MemInstruction::new(F64, I::F64Load, 3),
_ => return None _ => return None,
}; };
return Some(ins); return Some(ins);
} }
@@ -175,7 +208,7 @@ impl Intrinsics {
"i64.store32" => MemInstruction::new(I64, I::I64Store32, 2), "i64.store32" => MemInstruction::new(I64, I::I64Store32, 2),
"f32.store" => MemInstruction::new(F32, I::F32Store, 2), "f32.store" => MemInstruction::new(F32, I::F32Store, 2),
"f64.store" => MemInstruction::new(F64, I::F64Store, 3), "f64.store" => MemInstruction::new(F64, I::F64Store, 3),
_ => return None _ => return None,
}; };
return Some(ins); return Some(ins);
} }
@@ -184,13 +217,19 @@ impl Intrinsics {
pub struct MemInstruction { pub struct MemInstruction {
pub type_: Type, pub type_: Type,
pub instruction: fn(MemArg) -> enc::Instruction<'static>, pub instruction: fn(MemArg) -> enc::Instruction<'static>,
pub natural_alignment: u32 pub natural_alignment: u32,
} }
impl MemInstruction { impl MemInstruction {
fn new(type_: Type, instruction: fn(MemArg) -> enc::Instruction<'static>, natural_alignment: u32) -> MemInstruction { fn new(
type_: Type,
instruction: fn(MemArg) -> enc::Instruction<'static>,
natural_alignment: u32,
) -> MemInstruction {
MemInstruction { MemInstruction {
type_, instruction, natural_alignment type_,
instruction,
natural_alignment,
} }
} }
} }